Index: server/stdafx.h =================================================================== --- server/stdafx.h (revision 2178) +++ server/stdafx.h (working copy) @@ -15,8 +15,8 @@ #include "../global.h" #include -#include -#include +//#include +//#include #include #include #include Index: server/CVCMIServer.cpp =================================================================== --- server/CVCMIServer.cpp (revision 2178) +++ server/CVCMIServer.cpp (working copy) @@ -29,7 +29,7 @@ using namespace boost; using namespace boost::asio; using namespace boost::asio::ip; -namespace intpr = boost::interprocess; +//namespace intpr = boost::interprocess; bool end2 = false; int port = 3030; VCMIDirs GVCMIDirs; @@ -379,6 +379,7 @@ void CVCMIServer::start() { + /* ServerReady *sr = NULL; intpr::mapped_region *mr; try @@ -395,13 +396,17 @@ mr = new intpr::mapped_region(smo,intpr::read_write); sr = new(mr->get_address())ServerReady(); } + */ + notifyServerReady(); boost::system::error_code error; tlog0<<"Listening for connections at port " << acceptor->local_endpoint().port() << std::endl; tcp::socket * s = new tcp::socket(acceptor->io_service()); boost::thread acc(boost::bind(vaccept,acceptor,s,&error)); + /* sr->setToTrueAndNotify(); delete mr; + */ acc.join(); if (error) Index: server/CGameHandler.cpp =================================================================== --- server/CGameHandler.cpp (revision 2178) +++ server/CGameHandler.cpp (working copy) @@ -739,6 +739,7 @@ //gs = NULL; IObjectInterface::cb = this; applier = new CApplier; + tlog1 << "registerTypes3: " << __FILE__ << ":" << __LINE__ << std::endl; registerTypes3(*applier); visitObjectAfterVictory = false; battleEndCallback = NULL; @@ -1786,7 +1787,7 @@ iw.player = h1->tempOwner; iw.components.push_back(Component(Component::SEC_SKILL, 18, ScholarLevel, 0)); - iw.text.addTxt(MetaString::GENERAL_TXT, 139);//"%s, who has studied magic extensively, + iw.text.addTxt(MetaString::GENERAL_TXT, 139);//%s, who has studied magic extensively, iw.text.addReplacement(h1->name); if (cs2.spells.size())//if found new spell - apply Index: lib/CGameState.cpp =================================================================== --- lib/CGameState.cpp (revision 2178) +++ lib/CGameState.cpp (working copy) @@ -54,6 +54,7 @@ void foofoofoo() { //never called function to force instantation of templates + tlog1 << "registerTypes: " << __FILE__ << ":" << __LINE__ << std::endl; int *ccc = NULL; registerTypes((CISer&)*ccc); registerTypes((COSer&)*ccc); @@ -124,6 +125,7 @@ CObjectCallersHandler() { + tlog1 << "registerTypes1: " << __FILE__ << ":" << __LINE__ << std::endl; registerTypes1(*this); } @@ -797,6 +799,7 @@ gs = this; mx = new boost::shared_mutex(); applierGs = new CApplier; + tlog1 << "registerTypes2: " << __FILE__ << ":" << __LINE__ << std::endl; registerTypes2(*applierGs); objCaller = new CObjectCallersHandler; globalEffects.description = "Global effects"; Index: lib/Interprocess.h =================================================================== --- lib/Interprocess.h (revision 2178) +++ lib/Interprocess.h (working copy) @@ -1,3 +1,4 @@ +/* #include #include #include @@ -2,2 +3,3 @@ #include +*/ @@ -13,6 +15,7 @@ * */ +/* struct ServerReady { bool ready; @@ -51,4 +54,48 @@ delete mr; boost::interprocess::shared_memory_object::remove("vcmi_memory"); } -}; \ No newline at end of file +}; +*/ + +#include +#ifdef WIN32 +#include +#else +#include +#endif +#include "VCMIDirs.h" + +#define SERVER_READY_FILENAME "/VcmiServerReadyFlag.lock" + +void clearServerReady() +{ + unlink((GVCMIDirs.UserPath + SERVER_READY_FILENAME).c_str()); +} + +void waitServerReady() +{ + while(true) + { + FILE * ff = fopen((GVCMIDirs.UserPath + SERVER_READY_FILENAME).c_str(), "r"); + if(ff) + { + fclose(ff); + clearServerReady(); + break; + } +#ifdef WIN32 + Sleep(200); +#else + usleep(200000); +#endif + } +} + +void notifyServerReady() +{ + FILE * ff = fopen((GVCMIDirs.UserPath + SERVER_READY_FILENAME).c_str(), "w"); + if(!ff) + return; + fwrite("1", 1, 1, ff); + fclose(ff); +} Index: lib/Connection.h =================================================================== --- lib/Connection.h (revision 2178) +++ lib/Connection.h (working copy) @@ -82,7 +82,9 @@ { bool operator()(const std::type_info *a, const std::type_info *b) const { - return a->before(*b); + // Comparing pointers is bad bad practice, because type_info pointers to the same types + // are different inside shared library and the executable that links to that library + return strcmp(a->name(), b->name()) > 0; } }; Index: lib/ERMInterpreter.cpp =================================================================== --- lib/ERMInterpreter.cpp (revision 2178) +++ lib/ERMInterpreter.cpp (working copy) @@ -2546,7 +2546,8 @@ else if(symToFunc.find(opt.text) != symToFunc.end()) { VFunc f(symToFunc[opt.text]); - return f(erm->evalEach(exp.children.cdr())); + VOptionList ls = erm->evalEach(exp.children.cdr()); + return f(VermTreeIterator(ls)); } Index: lib/VCMIDirs.h =================================================================== --- lib/VCMIDirs.h (revision 2178) +++ lib/VCMIDirs.h (working copy) @@ -1,3 +1,6 @@ +#ifndef __VCMI__DIRS_H__ +#define __VCMI__DIRS_H__ + /* * UserHome.h, part of VCMI engine * @@ -13,7 +16,6 @@ using namespace boost::filesystem; #endif - /// Where to find the various VCMI files. This is mostly usefull for linux. class VCMIDirs { public: @@ -24,14 +26,25 @@ #ifdef _WIN32 UserPath = DATA_DIR; #else - // Find vcmi user directory and create it if necessary - std::string home_dir = getenv("HOME"); - UserPath = path(home_dir + "/.vcmi").string(); - - create_directory(UserPath); - create_directory(UserPath + "/config"); - create_directory(UserPath + "/Games"); + try { + // Find vcmi user directory and create it if necessary + std::string home_dir = "."; + if( getenv("HOME") != NULL ) + home_dir = getenv("HOME"); + UserPath = path(home_dir + "/.vcmi").string(); +#ifdef ANDROID + UserPath = DATA_DIR; #endif + create_directory(UserPath); + create_directory(UserPath + "/config"); + create_directory(UserPath + "/Games"); + } + catch(const std::exception & e) + { + } +#endif } }; extern VCMIDirs GVCMIDirs; + +#endif Index: CConsoleHandler.cpp =================================================================== --- CConsoleHandler.cpp (revision 2178) +++ CConsoleHandler.cpp (working copy) @@ -143,6 +143,7 @@ void CConsoleHandler::setColor(int level) { +#ifndef ANDROID TColor color; switch(level) { @@ -179,6 +180,7 @@ #else std::cout << color; #endif +#endif } int CConsoleHandler::run() Index: global.h =================================================================== --- global.h (revision 2178) +++ global.h (working copy) @@ -10,6 +10,10 @@ using boost::logic::tribool; #include #include +#ifdef ANDROID +#include +#include +#endif //filesystem version 3 causes problems (and it's default as of boost 1.46) #define BOOST_FILESYSTEM_VERSION 2 typedef boost::uint64_t ui64; //unsigned int 64 bits (8 bytes) @@ -618,20 +622,45 @@ class CLogger //logger, prints log info to console and saves in file { const int lvl; +#ifdef ANDROID + std::ostringstream buf; + int androidloglevel; + void outputAndroid() + { + int pos = buf.str().find("\n"); + while( pos >= 0 ) + { + __android_log_print(androidloglevel, "VCMI", "%s", buf.str().substr(0, pos).c_str() ); + buf.str( buf.str().substr(pos+1) ); + pos = buf.str().find("\n"); + } + } +#endif public: CLogger& operator<<(std::ostream& (*fun)(std::ostream&)) { +#ifdef ANDROID + buf << fun; + outputAndroid(); +#else if(lvl < CONSOLE_LOGGING_LEVEL) + { std::cout << fun; + } if((lvl < FILE_LOGGING_LEVEL) && logfile) *logfile << fun; +#endif return *this; } template CLogger & operator<<(const T & data) { +#ifdef ANDROID + buf << data; + outputAndroid(); +#else if(lvl < CONSOLE_LOGGING_LEVEL) { if(console) @@ -641,10 +670,25 @@ } if((lvl < FILE_LOGGING_LEVEL) && logfile) *logfile << data << std::flush; +#endif return *this; } - CLogger(const int Lvl) : lvl(Lvl) {} + CLogger(const int Lvl) : lvl(Lvl) + { +#ifdef ANDROID + androidloglevel = ANDROID_LOG_INFO; + switch(lvl) { + case 0: androidloglevel = ANDROID_LOG_INFO; break; + case 1: androidloglevel = ANDROID_LOG_FATAL; break; + case 2: androidloglevel = ANDROID_LOG_ERROR; break; + case 3: androidloglevel = ANDROID_LOG_WARN; break; + case 4: androidloglevel = ANDROID_LOG_INFO; break; + case 5: androidloglevel = ANDROID_LOG_DEBUG; break; + case 6: case -2: androidloglevel = ANDROID_LOG_VERBOSE; break; + } +#endif + } }; extern DLL_EXPORT CLogger tlog0; //green - standard progress info Index: client/Client.cpp =================================================================== --- client/Client.cpp (revision 2178) +++ client/Client.cpp (working copy) @@ -39,7 +39,7 @@ #include "../lib/RegisterTypes.cpp" extern std::string NAME; -namespace intpr = boost::interprocess; +//namespace intpr = boost::interprocess; /* * Client.cpp, part of VCMI engine @@ -89,7 +89,16 @@ connectionHandler = NULL; pathInfo = NULL; applier = new CApplier; + tlog1 << "registerTypes2: " << __FILE__ << ":" << __LINE__ << std::endl; registerTypes2(*applier); + tlog1 << "-----Start applier: registerTypes2" << std::endl; + for( std::map :: const_iterator it = applier->apps.begin(); + it != applier->apps.end(); it++ ) + { + tlog1 << "applier ID " << it->first << " ptr " << typeid(*it->second).name() << std::endl; + } + tlog1 << "-----End applier: registerTypes2" << std::endl; + IObjectInterface::cb = this; serv = NULL; gs = NULL; @@ -498,9 +507,9 @@ void CClient::handlePack( CPack * pack ) { - CBaseForCLApply *apply = applier->apps[typeList.getTypeID(pack)]; //find the applier - if(apply) + if(applier->apps.find(typeList.getTypeID(pack)) != applier->apps.end()) { + CBaseForCLApply *apply = applier->apps[typeList.getTypeID(pack)]; //find the applier apply->applyOnClBefore(this,pack); tlog5 << "\tMade first apply on cl\n"; gs->apply(pack); @@ -510,7 +519,7 @@ } else { - tlog1 << "Message cannot be applied, cannot find applier!\n"; + tlog1 << "Message cannot be applied, cannot find applier! TypeID " << typeList.getTypeID(pack) << std::endl; } delete pack; } @@ -628,18 +637,22 @@ startServer(); th.update(); + /* intpr::scoped_lock slock(shared->sr->mutex); while(!shared->sr->ready) { shared->sr->cond.wait(slock); } + */ + tlog0 << "Waiting for server..." << std::endl; + waitServerReady(); if(verbose) tlog0 << "Waiting for server: " << th.getDif() << std::endl; } CConnection * CServerHandler::connectToServer() { - if(!shared->sr->ready) + if(!serverThread) waitForServer(); th.update(); @@ -654,27 +667,31 @@ CServerHandler::CServerHandler(bool runServer /*= false*/) { serverThread = NULL; - shared = NULL; + //shared = NULL; port = boost::lexical_cast(conf.cc.port); verbose = false; + /* boost::interprocess::shared_memory_object::remove("vcmi_memory"); //if the application has previously crashed, the memory may not have been removed. to avoid problems - try to destroy it try { shared = new SharedMem(); } HANDLE_EXCEPTIONC(tlog1 << "Cannot open interprocess memory: ";) + */ } CServerHandler::~CServerHandler() { - delete shared; + //delete shared; delete serverThread; //detaches, not kills thread } void CServerHandler::callServer() { + clearServerReady(); setThreadName(-1, "CServerHandler::callServer"); std::string comm = std::string(BIN_DIR PATH_SEPARATOR SERVER_NAME " ") + port + " > server_log.txt"; + tlog0 << "Invoking VCMI server : " << comm << std::endl; std::system(comm.c_str()); tlog0 << "Server finished\n"; } Index: client/GUIBase.cpp =================================================================== --- client/GUIBase.cpp (revision 2178) +++ client/GUIBase.cpp (working copy) @@ -11,6 +11,7 @@ #include "../CThreadHelper.h" #include "CConfigHandler.h" #include + /* * GUIBase.cpp, part of VCMI engine @@ -364,6 +365,26 @@ } } HANDLE_EXCEPTION } + +void CGuiHandler::loopInitFromMainThread() +{ + setThreadName(-1, "CGuiHandler::run"); + CCS->curh->centerCursor(); + mainFPSmng->init(); // resets internal clock, needed for FPS manager +} + +bool CGuiHandler::loopFromMainThread() +{ + if(terminate) + return false; + if(curInt) + curInt->update(); // calls a update and drawing process of the loaded game interface object at the moment + + mainFPSmng->framerateDelay(); // holds a constant FPS + return true; +} + + CGuiHandler::CGuiHandler() :lastClick(-500, -500) Index: client/Client.h =================================================================== --- client/Client.h (revision 2178) +++ client/Client.h (working copy) @@ -43,7 +43,7 @@ public: timeHandler th; boost::thread *serverThread; //thread that called system to run server - SharedMem *shared; //interprocess memory (for waiting for server) + //SharedMem *shared; //interprocess memory (for waiting for server) bool verbose; //whether to print log msgs std::string port; //port number in text form Index: client/CPreGame.cpp =================================================================== --- client/CPreGame.cpp (revision 2178) +++ client/CPreGame.cpp (working copy) @@ -525,6 +525,7 @@ } applier = new CApplier; + tlog1 << "registerTypes4: " << __FILE__ << ":" << __LINE__ << std::endl; registerTypes4(*applier); serverHandlingThread = new boost::thread(&CSelectionScreen::handleConnection, this); } Index: client/CMT.cpp =================================================================== --- client/CMT.cpp (revision 2178) +++ client/CMT.cpp (working copy) @@ -92,8 +92,10 @@ void dispose(); void playIntro(); static void listenForEvents(); +static bool loopListenForEvents(bool block); void requestChangingResolution(); void startGame(StartInfo * options, CConnection *serv = NULL); + #ifndef _WIN32 #ifndef _GNU_SOURCE @@ -128,6 +130,7 @@ GDefaultOptions.settingsChanged(); } } + THC tlog0<<"\tLoading default system settings: "<soundh->init(); CCS->soundh->setVolume(GDefaultOptions.soundVolume); CCS->musich = new CMusicHandler; + //CGI->musich->init(); //CGI->musich->setVolume(GDefaultOptions.musicVolume); tlog0<<"\tInitializing sound: "<(CGI)->setFromLib(); @@ -186,11 +191,15 @@ } +#ifdef ANDROID +int SDL_main(int argc, char** argv) +#else #ifdef _WIN32 int _tmain(int argc, _TCHAR* argv[]) #else int main(int argc, char** argv) #endif +#endif { tlog0 << "Starting... " << std::endl; po::options_description opts("Allowed options"); @@ -237,7 +246,6 @@ console->start(); atexit(dispose); tlog0 <<"Creating console and logfile: "<playerInfos[1].color = 1; startGame(si); } + // Drawing and running event loop from non-main thread does not work at all on Andorid and crashes often on Linux +#if defined(ANDROID) || defined(LINUX) + GH.loopInitFromMainThread(); + while( GH.loopFromMainThread() ) + { + while( loopListenForEvents(false) ); + } +#else mainGUIThread = new boost::thread(&CGuiHandler::run, boost::ref(GH)); listenForEvents(); +#endif return 0; } @@ -559,10 +582,12 @@ tlog2 << "Warning: SDL says that " << bpp << "bpp is wrong and suggests " << suggestedBpp << std::endl; } +#ifndef ANDROID if(screen) //screen has been already initialized SDL_QuitSubSystem(SDL_INIT_VIDEO); SDL_InitSubSystem(SDL_INIT_VIDEO); +#endif if((screen = SDL_SetVideoMode(w, h, suggestedBpp, SDL_SWSURFACE|(fullscreen?SDL_FULLSCREEN:0))) == NULL) { @@ -607,14 +632,27 @@ setResolution = true; } + static void listenForEvents() { - while(1) //main SDL events loop - { + while(loopListenForEvents(true)); //main SDL events loop +} + +static bool loopListenForEvents(bool block) +{ SDL_Event *ev = new SDL_Event(); //tlog0 << "Waiting... "; - int ret = SDL_WaitEvent(ev); + int ret = 1; + if( block ) + ret = SDL_WaitEvent(ev); + else + { + if(!SDL_PollEvent(ev)) { + delete ev; + return false; + } + } //tlog0 << "got " << (int)ev->type; if (ret == 0 || (ev->type==SDL_QUIT) || (ev->type == SDL_KEYDOWN && ev->key.keysym.sym==SDLK_F4 && (ev->key.keysym.mod & KMOD_ALT))) @@ -633,7 +671,7 @@ SDL_Delay(750); SDL_Quit(); tlog0 << "Ending...\n"; - break; + return false; } else if(LOCPLINT && ev->type == SDL_KEYDOWN && ev->key.keysym.sym==SDLK_F4) { @@ -642,7 +680,7 @@ setScreenRes(conf.cc.screenx, conf.cc.screeny, conf.cc.bpp, full); GH.totalRedraw(); delete ev; - continue; + return true; } else if(ev->type == SDL_USEREVENT) { @@ -672,7 +710,7 @@ } delete ev; - continue; + return true; } //tlog0 << " pushing "; @@ -680,7 +718,7 @@ events.push(ev); eventsM.unlock(); //tlog0 << " done\n"; - } + return true; } void startGame(StartInfo * options, CConnection *serv/* = NULL*/) @@ -741,3 +779,4 @@ ev.user.code = 1; SDL_PushEvent(&ev); } + Index: client/GUIBase.h =================================================================== --- client/GUIBase.h (revision 2178) +++ client/GUIBase.h (working copy) @@ -546,6 +546,8 @@ CGuiHandler(); ~CGuiHandler(); void run(); // holds the main loop for the whole program after initialization and manages the update/rendering system + void loopInitFromMainThread(); + bool loopFromMainThread(); void totalRedraw(); //forces total redraw (using showAll), sets a flag, method gets called at the end of the rendering void simpleRedraw(); //update only top interface and draw background from buffer, sets a flag, method gets called at the end of the rendering