From db7cd79cf7541cc041fefea87016943f150106d3 Mon Sep 17 00:00:00 2001 From: Ilya Zhuravlev Date: Thu, 20 Feb 2014 22:53:18 +0400 Subject: [PATCH] Android port. Conflicts: lib/vcmi_endian.h --- AI/BattleAI/BattleAI.cpp | 16 ++++++++++++---- AI/BattleAI/main.cpp | 10 ++++++++-- AI/StupidAI/StupidAI.cpp | 7 +++++-- AI/StupidAI/main.cpp | 10 ++++++++-- AI/VCAI/main.cpp | 10 ++++++++-- client/CMT.cpp | 11 +++++++++++ client/Client.cpp | 12 ++++++++++++ lib/CGameInterface.cpp | 27 +++++++++++++++++++++++++++ lib/VCMIDirs.cpp | 18 +++++++++++++++++- lib/logging/CLogger.cpp | 9 +++++++++ server/CVCMIServer.cpp | 14 +++++++++++--- 11 files changed, 128 insertions(+), 16 deletions(-) diff --git a/AI/BattleAI/BattleAI.cpp b/AI/BattleAI/BattleAI.cpp index e4092ef8f..29205a667 100644 --- a/AI/BattleAI/BattleAI.cpp +++ b/AI/BattleAI/BattleAI.cpp @@ -8,7 +8,7 @@ #include "../../lib/VCMI_Lib.h" using boost::optional; -shared_ptr cbc; +static shared_ptr cbc; #define LOGL(text) print(text) #define LOGFL(text, formattingEl) print(boost::str(boost::format(text) % formattingEl)) @@ -28,8 +28,12 @@ struct Priorities range::copy(VLC->objh->resVals, std::back_inserter(resourceTypeBaseValues)); stackEvaluator = [](const CStack*){ return 1.0; }; } -} priorities; +}; +Priorities *priorities = nullptr; + + +namespace { int distToNearestNeighbour(BattleHex hex, const ReachabilityInfo::TDistances& dists, BattleHex *chosenHex = nullptr) { @@ -52,6 +56,8 @@ bool isCloser(const EnemyInfo & ei1, const EnemyInfo & ei2, const ReachabilityIn return distToNearestNeighbour(ei1.s->position, dists) < distToNearestNeighbour(ei2.s->position, dists); } +} + template auto sum(const Container & c, Pred p) -> decltype(p(*std::begin(c))) { @@ -624,8 +630,10 @@ const TBonusListPtr StackWithBonuses::getAllBonuses(const CSelector &selector, c int AttackPossibility::damageDiff() const { - const auto dealtDmgValue = priorities.stackEvaluator(enemy) * damageDealt; - const auto receivedDmgValue = priorities.stackEvaluator(attack.attacker) * damageReceived; + if (!priorities) + priorities = new Priorities; + const auto dealtDmgValue = priorities->stackEvaluator(enemy) * damageDealt; + const auto receivedDmgValue = priorities->stackEvaluator(attack.attacker) * damageReceived; return dealtDmgValue - receivedDmgValue; } diff --git a/AI/BattleAI/main.cpp b/AI/BattleAI/main.cpp index 47028a238..5432c3037 100644 --- a/AI/BattleAI/main.cpp +++ b/AI/BattleAI/main.cpp @@ -7,7 +7,13 @@ #define strcpy_s(a, b, c) strncpy(a, c, b) #endif -const char *g_cszAiName = "Battle AI"; +#ifdef __ANDROID__ +#define GetGlobalAiVersion BattleAI_GetGlobalAiVersion +#define GetAiName BattleAI_GetAiName +#define GetNewBattleAI BattleAI_GetNewBattleAI +#endif + +static const char *g_cszAiName = "Battle AI"; extern "C" DLL_EXPORT int GetGlobalAiVersion() { @@ -22,4 +28,4 @@ extern "C" DLL_EXPORT void GetAiName(char* name) extern "C" DLL_EXPORT void GetNewBattleAI(shared_ptr &out) { out = make_shared(); -} \ No newline at end of file +} diff --git a/AI/StupidAI/StupidAI.cpp b/AI/StupidAI/StupidAI.cpp index 7718fe6aa..efaf30688 100644 --- a/AI/StupidAI/StupidAI.cpp +++ b/AI/StupidAI/StupidAI.cpp @@ -5,7 +5,7 @@ #include "../../CCallback.h" #include "../../lib/CCreatureHandler.h" -shared_ptr cbc; +static shared_ptr cbc; CStupidAI::CStupidAI(void) : side(-1) @@ -60,6 +60,8 @@ bool isMoreProfitable(const EnemyInfo &ei1, const EnemyInfo& ei2) return (ei1.adi-ei1.adr) < (ei2.adi - ei2.adr); } +namespace { + int distToNearestNeighbour(BattleHex hex, const ReachabilityInfo::TDistances& dists, BattleHex *chosenHex = nullptr) { int ret = 1000000; @@ -81,6 +83,8 @@ bool isCloser(const EnemyInfo & ei1, const EnemyInfo & ei2, const ReachabilityIn return distToNearestNeighbour(ei1.s->position, dists) < distToNearestNeighbour(ei2.s->position, dists); } +} + static bool willSecondHexBlockMoreEnemyShooters(const BattleHex &h1, const BattleHex &h2) { int shooters[2] = {0}; //count of shooters on hexes @@ -328,4 +332,3 @@ void CStupidAI::loadGame(CISer &h, const int version) //TODO to be implemented with saving/loading during the battles assert(0); } - diff --git a/AI/StupidAI/main.cpp b/AI/StupidAI/main.cpp index f8eec61cd..07cfedee2 100644 --- a/AI/StupidAI/main.cpp +++ b/AI/StupidAI/main.cpp @@ -7,7 +7,13 @@ #define strcpy_s(a, b, c) strncpy(a, c, b) #endif -const char *g_cszAiName = "Stupid AI 0.1"; +#ifdef __ANDROID__ +#define GetGlobalAiVersion StupidAI_GetGlobalAiVersion +#define GetAiName StupidAI_GetAiName +#define GetNewBattleAI StupidAI_GetNewBattleAI +#endif + +static const char *g_cszAiName = "Stupid AI 0.1"; extern "C" DLL_EXPORT int GetGlobalAiVersion() { @@ -22,4 +28,4 @@ extern "C" DLL_EXPORT void GetAiName(char* name) extern "C" DLL_EXPORT void GetNewBattleAI(shared_ptr &out) { out = make_shared(); -} \ No newline at end of file +} diff --git a/AI/VCAI/main.cpp b/AI/VCAI/main.cpp index cb743f567..26f3e52c6 100644 --- a/AI/VCAI/main.cpp +++ b/AI/VCAI/main.cpp @@ -5,7 +5,13 @@ #define strcpy_s(a, b, c) strncpy(a, c, b) #endif -const char *g_cszAiName = "VCAI"; +#ifdef __ANDROID__ +#define GetGlobalAiVersion VCAI_GetGlobalAiVersion +#define GetAiName VCAI_GetAiName +#define GetNewAI VCAI_GetNewAI +#endif + +static const char *g_cszAiName = "VCAI"; extern "C" DLL_EXPORT int GetGlobalAiVersion() { @@ -20,4 +26,4 @@ extern "C" DLL_EXPORT void GetAiName(char* name) extern "C" DLL_EXPORT void GetNewAI(shared_ptr &out) { out = make_shared(); -} \ No newline at end of file +} diff --git a/client/CMT.cpp b/client/CMT.cpp index aa6ce1ae8..6c99a2d7c 100644 --- a/client/CMT.cpp +++ b/client/CMT.cpp @@ -284,6 +284,10 @@ int main(int argc, char** argv) logGlobal->infoStream() << "Creating console and configuring logger: " << pomtime.getDiff(); logGlobal->infoStream() << "The log file will be saved to " << logPath; +#ifdef __ANDROID__ + // boost will crash without this + setenv("LANG", "C", 1); +#endif // Init filesystem and settings preinitDLL(::console); settings.init(); @@ -361,8 +365,13 @@ int main(int argc, char** argv) +#ifndef __ANDROID__ //we can properly play intro only in the main thread, so we have to move loading to the separate thread boost::thread loading(init); +#else + // on Android threaded init is broken + init(); +#endif if(!gNoGUI ) { @@ -372,7 +381,9 @@ int main(int argc, char** argv) } CSDL_Ext::update(screen); +#ifndef __ANDROID__ loading.join(); +#endif logGlobal->infoStream()<<"Initialization of VCMI (together): "< slock(shared->sr->mutex); while(!shared->sr->ready) { shared->sr->cond.wait(slock); } +#endif if(verbose) logNetwork->infoStream() << "Waiting for server: " << th.getDiff(); } CConnection * CServerHandler::connectToServer() { +#ifndef __ANDROID__ if(!shared->sr->ready) waitForServer(); +#else + waitForServer(); +#endif th.update(); //put breakpoint here to attach to server before it does something stupid CConnection *ret = justConnectToServer(settings["server"]["server"].String(), port); @@ -839,11 +849,13 @@ CServerHandler::CServerHandler(bool runServer /*= false*/) port = boost::lexical_cast(settings["server"]["port"].Float()); verbose = true; +#ifndef __ANDROID__ 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(logNetwork->errorStream() << "Cannot open interprocess memory: ";) +#endif } CServerHandler::~CServerHandler() diff --git a/lib/CGameInterface.cpp b/lib/CGameInterface.cpp index a01c67128..c438e0d55 100644 --- a/lib/CGameInterface.cpp +++ b/lib/CGameInterface.cpp @@ -22,7 +22,17 @@ * */ +#ifdef __ANDROID__ +// we can't use shared libraries on Android so here's a hack +extern "C" DLL_EXPORT void VCAI_GetAiName(char* name); +extern "C" DLL_EXPORT void VCAI_GetNewAI(shared_ptr &out); +extern "C" DLL_EXPORT void StupidAI_GetAiName(char* name); +extern "C" DLL_EXPORT void StupidAI_GetNewBattleAI(shared_ptr &out); + +extern "C" DLL_EXPORT void BattleAI_GetAiName(char* name); +extern "C" DLL_EXPORT void BattleAI_GetNewBattleAI(shared_ptr &out); +#endif template shared_ptr createAny(std::string dllname, std::string methodName) @@ -35,6 +45,21 @@ shared_ptr createAny(std::string dllname, std::string methodName) TGetAIFun getAI = nullptr; TGetNameFun getName = nullptr; +#ifdef __ANDROID__ + // this is awful but it seems using shared libraries on some devices is even worse + if (dllname.find("libVCAI.so") != std::string::npos) { + getName = (TGetNameFun)VCAI_GetAiName; + getAI = (TGetAIFun)VCAI_GetNewAI; + } else if (dllname.find("libStupidAI.so") != std::string::npos) { + getName = (TGetNameFun)StupidAI_GetAiName; + getAI = (TGetAIFun)StupidAI_GetNewBattleAI; + } else if (dllname.find("libBattleAI.so") != std::string::npos) { + getName = (TGetNameFun)BattleAI_GetAiName; + getAI = (TGetAIFun)BattleAI_GetNewBattleAI; + } else { + throw std::runtime_error("Don't know what to do with " + dllname + " and method " + methodName); + } +#else #ifdef _WIN32 HINSTANCE dll = LoadLibraryA(dllname.c_str()); @@ -69,6 +94,8 @@ shared_ptr createAny(std::string dllname, std::string methodName) throw std::runtime_error("Cannot find method " + methodName); } +#endif // __ANDROID__ + getName(temp); logGlobal->infoStream() << "Loaded " << temp; diff --git a/lib/VCMIDirs.cpp b/lib/VCMIDirs.cpp index 699938a00..35c6ad47c 100644 --- a/lib/VCMIDirs.cpp +++ b/lib/VCMIDirs.cpp @@ -158,11 +158,16 @@ std::string VCMIDirs::serverPath() const // $XDG_DATA_HOME, default: $HOME/.local/share std::string VCMIDirs::userDataPath() const { +#ifdef __ANDROID__ + // on Android HOME will be set to something like /sdcard/data/Android/is.xyz.vcmi/files/ + return std::string(getenv("HOME")); +#else if (getenv("XDG_DATA_HOME") != nullptr ) return std::string(getenv("XDG_DATA_HOME")) + "/vcmi"; if (getenv("HOME") != nullptr ) return std::string(getenv("HOME")) + "/.local/share" + "/vcmi"; return "."; +#endif } std::string VCMIDirs::userSavePath() const @@ -173,21 +178,29 @@ std::string VCMIDirs::userSavePath() const // $XDG_CACHE_HOME, default: $HOME/.cache std::string VCMIDirs::userCachePath() const { +#ifdef __ANDROID__ + return userDataPath() + "/cache"; +#else if (getenv("XDG_CACHE_HOME") != nullptr ) return std::string(getenv("XDG_CACHE_HOME")) + "/vcmi"; if (getenv("HOME") != nullptr ) return std::string(getenv("HOME")) + "/.cache" + "/vcmi"; return "."; +#endif } // $XDG_CONFIG_HOME, default: $HOME/.config std::string VCMIDirs::userConfigPath() const { +#ifdef __ANDROID__ + return userDataPath() + "/config"; +#else if (getenv("XDG_CONFIG_HOME") != nullptr ) return std::string(getenv("XDG_CONFIG_HOME")) + "/vcmi"; if (getenv("HOME") != nullptr ) return std::string(getenv("HOME")) + "/.config" + "/vcmi"; return "."; +#endif } // $XDG_DATA_DIRS, default: /usr/local/share/:/usr/share/ @@ -198,7 +211,9 @@ std::vector VCMIDirs::dataPaths() const // in vcmi fs last directory has highest priority std::vector ret; - +#ifdef __ANDROID__ + ret.push_back(userDataPath()); +#else if (getenv("HOME") != nullptr ) // compatibility, should be removed after 0.96 ret.push_back(std::string(getenv("HOME")) + "/.vcmi"); ret.push_back(M_DATA_DIR); @@ -216,6 +231,7 @@ std::vector VCMIDirs::dataPaths() const ret.push_back("/usr/share/"); ret.push_back("/usr/local/share/"); } +#endif return ret; } diff --git a/lib/logging/CLogger.cpp b/lib/logging/CLogger.cpp index b9f84a4cc..6832defa7 100644 --- a/lib/logging/CLogger.cpp +++ b/lib/logging/CLogger.cpp @@ -1,3 +1,7 @@ +#ifdef __ANDROID__ +#include +#endif + #include "StdInc.h" #include "CLogger.h" @@ -398,6 +402,11 @@ void CLogConsoleTarget::write(const LogRecord & record) if(threshold > record.level) return; std::string message = formatter.format(record); + +#ifdef __ANDROID__ + __android_log_print(ANDROID_LOG_INFO, "VCMI", "%s", message.c_str()); +#endif + bool printToStdErr = record.level >= ELogLevel::WARN; if(console) { diff --git a/server/CVCMIServer.cpp b/server/CVCMIServer.cpp index e1e47c6f4..0006ad594 100644 --- a/server/CVCMIServer.cpp +++ b/server/CVCMIServer.cpp @@ -19,7 +19,9 @@ #include "CVCMIServer.h" #include "../lib/StartInfo.h" #include "../lib/mapping/CMap.h" +#ifndef __ANDROID__ #include "../lib/Interprocess.h" +#endif #include "../lib/VCMI_Lib.h" #include "../lib/VCMIDirs.h" #include "CGameHandler.h" @@ -32,7 +34,7 @@ #include "../lib/UnlockGuard.h" -#if defined(__GNUC__) && !defined (__MINGW32__) +#if defined(__GNUC__) && !defined (__MINGW32__) && !defined(__ANDROID__) #include #endif @@ -41,7 +43,9 @@ std::string NAME = GameConstants::VCMI_VERSION + std::string(" (") + NAME_AFFIX using namespace boost; using namespace boost::asio; using namespace boost::asio::ip; +#ifndef __ANDROID__ namespace intpr = boost::interprocess; +#endif bool end2 = false; int port = 3030; @@ -391,6 +395,7 @@ void CVCMIServer::newPregame() void CVCMIServer::start() { +#ifndef __ANDROID__ ServerReady *sr = nullptr; intpr::mapped_region *mr; try @@ -407,13 +412,16 @@ void CVCMIServer::start() mr = new intpr::mapped_region(smo,intpr::read_write); sr = new(mr->get_address())ServerReady(); } +#endif boost::system::error_code error; logNetwork->infoStream()<<"Listening for connections at port " << acceptor->local_endpoint().port(); auto s = new tcp::socket(acceptor->get_io_service()); boost::thread acc(boost::bind(vaccept,acceptor,s,&error)); +#ifndef __ANDROID__ sr->setToTrueAndNotify(); delete mr; +#endif acc.join(); if (error) @@ -554,7 +562,7 @@ static void handleCommandOptions(int argc, char *argv[]) } } -#if defined(__GNUC__) && !defined (__MINGW32__) +#if defined(__GNUC__) && !defined (__MINGW32__) && !defined(__ANDROID__) void handleLinuxSignal(int sig) { const int STACKTRACE_SIZE = 100; @@ -585,7 +593,7 @@ int main(int argc, char** argv) { // Installs a sig sev segmentation violation handler // to log stacktrace - #if defined(__GNUC__) && !defined (__MINGW32__) + #if defined(__GNUC__) && !defined (__MINGW32__) && !defined(__ANDROID__) signal(SIGSEGV, handleLinuxSignal); #endif