mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-27 21:49:10 +02:00
Android support (#299)
* AI libs registering shenanigans on android; * Fixed resolution aspect + mouse event scaling; * Proper server init/deinit (through android IPC); Enabled threaded init in CMT; * Prevented a deadlock in logger on some devices; * Fixed frozen intro frame after interrupting the video; Added android progressbar displaying during initial data loading; * Hacky fix for choppy animations during heroes movement (should look better now, but it's definitely not a good solution); * Changes/fixes for new android launcher building process; * Fixed app hang after getting SDL_QUIT when activity was destroyed; * Functioanal, configurable advmap swiping support; * VCMI changes cleanup; Added few missing VCMI_ANDROID guards on swipe mechanics; * Removed unneeded sleep in server startup code for android; * Removed android ioapi hack (fixed in newest ndk); * Removed unused android's library loading logic; * Added android's swipe option to settings schema; * Moved NO_STD_TOSTRING to be defined in global.h instead of build files;
This commit is contained in:
parent
f370cdf1c7
commit
b5daa24982
@ -15,6 +15,9 @@ set(battleAI_SRCS
|
||||
ThreatMap.cpp
|
||||
)
|
||||
|
||||
if (ANDROID) # android compiles ai libs into main lib directly, so we skip this library and just reuse sources list
|
||||
return()
|
||||
endif()
|
||||
add_library(BattleAI SHARED ${battleAI_SRCS})
|
||||
target_link_libraries(BattleAI vcmi)
|
||||
|
||||
|
@ -15,12 +15,6 @@
|
||||
#define strcpy_s(a, b, c) strncpy(a, c, b)
|
||||
#endif
|
||||
|
||||
#ifdef VCMI_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()
|
||||
|
@ -57,9 +57,15 @@ if (APPLE)
|
||||
add_definitions(-DFL_APPLE)
|
||||
endif()
|
||||
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY bin)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY bin)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY bin)
|
||||
if (NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY bin)
|
||||
endif()
|
||||
if (NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY bin)
|
||||
endif()
|
||||
if (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY bin)
|
||||
endif()
|
||||
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_CXX_FLAGS "-pedantic -Werror -Wall -Wextra ${CMAKE_CXX_FLAGS}")
|
||||
|
@ -7,12 +7,6 @@
|
||||
#define strcpy_s(a, b, c) strncpy(a, c, b)
|
||||
#endif
|
||||
|
||||
#ifdef VCMI_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()
|
||||
@ -28,4 +22,4 @@ extern "C" DLL_EXPORT void GetAiName(char* name)
|
||||
extern "C" DLL_EXPORT void GetNewBattleAI(std::shared_ptr<CBattleGameInterface> &out)
|
||||
{
|
||||
out = std::make_shared<CStupidAI>();
|
||||
}
|
||||
}
|
@ -17,16 +17,20 @@ set(VCAI_SRCS
|
||||
Fuzzy.cpp
|
||||
)
|
||||
|
||||
if (ANDROID) # android compiles ai libs into main lib directly, so we skip this library and just reuse sources list
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_library(VCAI SHARED ${VCAI_SRCS})
|
||||
if (FL_FOUND)
|
||||
target_link_libraries(VCAI ${FL_LIBRARIES} vcmi)
|
||||
target_link_libraries(VCAI ${FL_LIBRARIES} vcmi)
|
||||
else()
|
||||
target_link_libraries(VCAI fl-static vcmi)
|
||||
target_link_libraries(VCAI fl-static vcmi)
|
||||
endif()
|
||||
|
||||
set_target_properties(VCAI PROPERTIES ${PCH_PROPERTIES})
|
||||
cotire(VCAI)
|
||||
|
||||
if (NOT APPLE) # Already inside vcmiclient bundle
|
||||
install(TARGETS VCAI RUNTIME DESTINATION ${AI_LIB_DIR} LIBRARY DESTINATION ${AI_LIB_DIR})
|
||||
install(TARGETS VCAI RUNTIME DESTINATION ${AI_LIB_DIR} LIBRARY DESTINATION ${AI_LIB_DIR})
|
||||
endif()
|
||||
|
@ -5,12 +5,6 @@
|
||||
#define strcpy_s(a, b, c) strncpy(a, c, b)
|
||||
#endif
|
||||
|
||||
#ifdef VCMI_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()
|
||||
@ -26,4 +20,4 @@ extern "C" DLL_EXPORT void GetAiName(char* name)
|
||||
extern "C" DLL_EXPORT void GetNewAI(std::shared_ptr<CGlobalAI> &out)
|
||||
{
|
||||
out = std::make_shared<VCAI>();
|
||||
}
|
||||
}
|
17
Global.h
17
Global.h
@ -96,6 +96,10 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
|
||||
# define _NO_W32_PSEUDO_MODIFIERS // Exclude more macros for compiling with MinGW on Linux.
|
||||
#endif
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
# define NO_STD_TOSTRING // android runtime (gnustl) currently doesn't support std::to_string, so we provide our impl in this case
|
||||
#endif // VCMI_ANDROID
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* A macro to force inlining some of our functions */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
@ -698,3 +702,16 @@ namespace vstd
|
||||
}
|
||||
using vstd::operator-=;
|
||||
using vstd::make_unique;
|
||||
|
||||
#ifdef NO_STD_TOSTRING
|
||||
namespace std
|
||||
{
|
||||
template <typename T>
|
||||
inline std::string to_string(const T& value)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << value;
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
#endif // NO_STD_TOSTRING
|
||||
|
@ -49,6 +49,9 @@
|
||||
#ifdef VCMI_WINDOWS
|
||||
#include "SDL_syswm.h"
|
||||
#endif
|
||||
#ifdef VCMI_ANDROID
|
||||
#include "lib/CAndroidVMHelper.h"
|
||||
#endif
|
||||
#include "../lib/UnlockGuard.h"
|
||||
#include "CMT.h"
|
||||
|
||||
@ -203,7 +206,7 @@ void OSX_checkForUpdates();
|
||||
|
||||
#if defined(VCMI_WINDOWS) && !defined (__GNUC__)
|
||||
int wmain(int argc, wchar_t* argv[])
|
||||
#elif defined(VCMI_APPLE)
|
||||
#elif defined(VCMI_APPLE) || defined(VCMI_ANDROID)
|
||||
int SDL_main(int argc, char *argv[])
|
||||
#else
|
||||
int main(int argc, char** argv)
|
||||
@ -436,11 +439,6 @@ int main(int argc, char** argv)
|
||||
|
||||
logGlobal->infoStream()<<"\tInitializing video: "<<pomtime.getDiff();
|
||||
|
||||
#if defined(VCMI_ANDROID)
|
||||
//on Android threaded init is broken
|
||||
#define VCMI_NO_THREADED_LOAD
|
||||
#endif // defined
|
||||
|
||||
//initializing audio
|
||||
CCS->soundh = new CSoundHandler;
|
||||
CCS->soundh->init();
|
||||
@ -466,13 +464,22 @@ int main(int argc, char** argv)
|
||||
{
|
||||
if(!vm.count("battle") && !vm.count("nointro") && settings["video"]["showIntro"].Bool())
|
||||
playIntro();
|
||||
SDL_FillRect(screen,nullptr,0);
|
||||
SDL_SetRenderDrawColor(mainRenderer, 0, 0, 0, 255);
|
||||
SDL_RenderClear(mainRenderer);
|
||||
}
|
||||
|
||||
CSDL_Ext::update(screen);
|
||||
SDL_RenderPresent(mainRenderer);
|
||||
#ifndef VCMI_NO_THREADED_LOAD
|
||||
loading.join();
|
||||
#endif
|
||||
#ifdef VCMI_ANDROID // android loads the data quite slowly so we display native progressbar to prevent having only black screen for few seconds
|
||||
{
|
||||
CAndroidVMHelper vmHelper;
|
||||
vmHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "showProgress");
|
||||
#endif // ANDROID
|
||||
loading.join();
|
||||
#ifdef VCMI_ANDROID
|
||||
vmHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "hideProgress");
|
||||
}
|
||||
#endif // ANDROID
|
||||
#endif // THREADED
|
||||
logGlobal->infoStream()<<"Initialization of VCMI (together): "<<total.getDiff();
|
||||
|
||||
if(!vm.count("battle"))
|
||||
@ -1027,6 +1034,9 @@ static bool recreateWindow(int w, int h, int bpp, bool fullscreen, int displayIn
|
||||
|
||||
cleanupRenderer();
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
mainWindow = SDL_CreateWindow(NAME.c_str(), SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex),SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex), 0, 0, SDL_WINDOW_FULLSCREEN);
|
||||
#else
|
||||
if(fullscreen)
|
||||
{
|
||||
//in full-screen mode always use desktop resolution
|
||||
@ -1037,6 +1047,7 @@ static bool recreateWindow(int w, int h, int bpp, bool fullscreen, int displayIn
|
||||
{
|
||||
mainWindow = SDL_CreateWindow(NAME.c_str(), SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex),SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex), w, h, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(nullptr == mainWindow)
|
||||
{
|
||||
@ -1058,7 +1069,10 @@ static bool recreateWindow(int w, int h, int bpp, bool fullscreen, int displayIn
|
||||
|
||||
SDL_RenderSetLogicalSize(mainRenderer, w, h);
|
||||
|
||||
#ifndef VCMI_ANDROID
|
||||
// on android this stretches the game to fit the screen, not preserving aspect and apparently this also breaks coordinates scaling in mouse events
|
||||
SDL_RenderSetViewport(mainRenderer, nullptr);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@ -1149,9 +1163,19 @@ static void handleEvent(SDL_Event & ev)
|
||||
{
|
||||
if((ev.type==SDL_QUIT) ||(ev.type == SDL_KEYDOWN && ev.key.keysym.sym==SDLK_F4 && (ev.key.keysym.mod & KMOD_ALT)))
|
||||
{
|
||||
#ifdef VCMI_ANDROID
|
||||
handleQuit(false);
|
||||
#else
|
||||
handleQuit();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#ifdef VCMI_ANDROID
|
||||
else if (ev.type == SDL_KEYDOWN && ev.key.keysym.scancode == SDL_SCANCODE_AC_BACK)
|
||||
{
|
||||
handleQuit(true);
|
||||
}
|
||||
#endif
|
||||
else if(ev.type == SDL_KEYDOWN && ev.key.keysym.sym==SDLK_F4)
|
||||
{
|
||||
Settings full = settings.write["video"]["fullscreen"];
|
||||
|
@ -65,6 +65,10 @@ set(client_HEADERS
|
||||
gui/SDL_Compat.h
|
||||
)
|
||||
|
||||
if(ANDROID) # android needs client/server to be libraries, not executables, so we can't reuse the build part of this script
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
# OS X specific includes
|
||||
include_directories(${SPARKLE_INCLUDE_DIR})
|
||||
@ -133,4 +137,3 @@ cotire(vcmiclient)
|
||||
|
||||
|
||||
install(TARGETS vcmiclient DESTINATION ${BIN_DIR})
|
||||
|
||||
|
@ -353,7 +353,11 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
|
||||
for (int i=1; i<32; i+=2*speed)
|
||||
{
|
||||
movementPxStep(details, i, hp, hero);
|
||||
#ifndef VCMI_ANDROID
|
||||
// currently android doesn't seem to be able to handle all these full redraws here, so let's disable it so at least it looks less choppy;
|
||||
// most likely this is connected with the way that this manual animation+framerate handling is solved
|
||||
adventureInt->updateScreen = true;
|
||||
#endif
|
||||
adventureInt->show(screen);
|
||||
{
|
||||
//evil returns here ...
|
||||
@ -1647,7 +1651,11 @@ void CPlayerInterface::update()
|
||||
GH.updateTime();
|
||||
GH.handleEvents();
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
if (adventureInt && !adventureInt->isActive() && (adventureInt->swipeTargetPosition.x >= 0 || adventureInt->swipeTargetPosition.y >= 0))
|
||||
#else // !VCMI_ANDROID
|
||||
if (adventureInt && !adventureInt->isActive() && adventureInt->scrollingDir) //player forces map scrolling though interface is disabled
|
||||
#endif // !VCMI_ANDROID
|
||||
GH.totalRedraw();
|
||||
else
|
||||
GH.simpleRedraw();
|
||||
|
@ -43,6 +43,8 @@
|
||||
extern std::string NAME;
|
||||
#ifndef VCMI_ANDROID
|
||||
namespace intpr = boost::interprocess;
|
||||
#else
|
||||
#include "lib/CAndroidVMHelper.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -55,6 +57,10 @@ namespace intpr = boost::interprocess;
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
std::atomic_bool androidTestServerReadyFlag;
|
||||
#endif
|
||||
|
||||
template <typename T> class CApplyOnCL;
|
||||
|
||||
class CBaseForCLApply
|
||||
@ -913,8 +919,7 @@ std::string CClient::aiNameForPlayer(const PlayerSettings &ps, bool battleAI)
|
||||
{
|
||||
if(ps.name.size())
|
||||
{
|
||||
const boost::filesystem::path aiPath =
|
||||
VCMIDirs::get().libraryPath() / "AI" / VCMIDirs::get().libraryName(ps.name);
|
||||
const boost::filesystem::path aiPath = VCMIDirs::get().fullLibraryPath("AI", ps.name);
|
||||
if (boost::filesystem::exists(aiPath))
|
||||
return ps.name;
|
||||
}
|
||||
@ -940,7 +945,12 @@ void CServerHandler::startServer()
|
||||
|
||||
th.update();
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
CAndroidVMHelper envHelper;
|
||||
envHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "startServer", true);
|
||||
#else
|
||||
serverThread = new boost::thread(&CServerHandler::callServer, this); //runs server executable;
|
||||
#endif
|
||||
if(verbose)
|
||||
logNetwork->infoStream() << "Setting up thread calling server: " << th.getDiff();
|
||||
}
|
||||
@ -954,12 +964,22 @@ void CServerHandler::waitForServer()
|
||||
startServer();
|
||||
|
||||
th.update();
|
||||
|
||||
#ifndef VCMI_ANDROID
|
||||
intpr::scoped_lock<intpr::interprocess_mutex> slock(shared->sr->mutex);
|
||||
while(!shared->sr->ready)
|
||||
{
|
||||
shared->sr->cond.wait(slock);
|
||||
}
|
||||
#else
|
||||
logNetwork->infoStream() << "waiting for server";
|
||||
while (!androidTestServerReadyFlag.load())
|
||||
{
|
||||
logNetwork->infoStream() << "still waiting...";
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
|
||||
}
|
||||
logNetwork->infoStream() << "waiting for server finished...";
|
||||
androidTestServerReadyFlag = false;
|
||||
#endif
|
||||
if(verbose)
|
||||
logNetwork->infoStream() << "Waiting for server: " << th.getDiff();
|
||||
@ -1017,6 +1037,7 @@ CServerHandler::~CServerHandler()
|
||||
|
||||
void CServerHandler::callServer()
|
||||
{
|
||||
#ifndef VCMI_ANDROID
|
||||
setThreadName("CServerHandler::callServer");
|
||||
const std::string logName = (VCMIDirs::get().userCachePath() / "server_log.txt").string();
|
||||
const std::string comm = VCMIDirs::get().serverPath().string() + " --port=" + port + " > \"" + logName + '\"';
|
||||
@ -1032,6 +1053,7 @@ void CServerHandler::callServer()
|
||||
logNetwork->errorStream() << "Check " << logName << " for more info";
|
||||
exit(1);// exit in case of error. Othervice without working server VCMI will hang
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
CConnection * CServerHandler::justConnectToServer(const std::string &host, const std::string &port)
|
||||
@ -1062,3 +1084,23 @@ CConnection * CServerHandler::justConnectToServer(const std::string &host, const
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerReady(JNIEnv * env, jobject cls)
|
||||
{
|
||||
logNetwork->infoStream() << "Received server ready signal";
|
||||
androidTestServerReadyFlag.store(true);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT bool JNICALL Java_eu_vcmi_vcmi_NativeMethods_tryToSaveTheGame(JNIEnv * env, jobject cls)
|
||||
{
|
||||
logGlobal->infoStream() << "Received emergency save game request";
|
||||
if(!LOCPLINT || !LOCPLINT->cb)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LOCPLINT->cb->save("Saves/_Android_Autosave");
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
@ -116,13 +116,36 @@ void CTerrainRect::deactivate()
|
||||
|
||||
void CTerrainRect::clickLeft(tribool down, bool previousState)
|
||||
{
|
||||
if (adventureInt->mode == EAdvMapMode::WORLD_VIEW)
|
||||
if(adventureInt->mode == EAdvMapMode::WORLD_VIEW)
|
||||
return;
|
||||
if ((down==false) || indeterminate(down))
|
||||
if(indeterminate(down))
|
||||
return;
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
if(adventureInt->swipeEnabled)
|
||||
{
|
||||
if(down == true)
|
||||
{
|
||||
swipeInitialRealPos = int3(GH.current->motion.x, GH.current->motion.y, 0);
|
||||
swipeInitialMapPos = int3(adventureInt->position);
|
||||
return; // if swipe is enabled, we don't process "down" events and wait for "up" (to make sure this wasn't a swiping gesture)
|
||||
}
|
||||
else if(isSwiping) // only accept this touch if it wasn't a swipe
|
||||
{
|
||||
isSwiping = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
if(down == false)
|
||||
return;
|
||||
#ifdef VCMI_ANDROID
|
||||
}
|
||||
#endif
|
||||
int3 mp = whichTileIsIt();
|
||||
if (mp.x<0 || mp.y<0 || mp.x >= LOCPLINT->cb->getMapSize().x || mp.y >= LOCPLINT->cb->getMapSize().y)
|
||||
if(mp.x < 0 || mp.y < 0 || mp.x >= LOCPLINT->cb->getMapSize().x || mp.y >= LOCPLINT->cb->getMapSize().y)
|
||||
return;
|
||||
|
||||
adventureInt->tileLClicked(mp);
|
||||
@ -130,17 +153,59 @@ void CTerrainRect::clickLeft(tribool down, bool previousState)
|
||||
|
||||
void CTerrainRect::clickRight(tribool down, bool previousState)
|
||||
{
|
||||
if (adventureInt->mode == EAdvMapMode::WORLD_VIEW)
|
||||
#ifdef VCMI_ANDROID
|
||||
if(adventureInt->swipeEnabled && isSwiping)
|
||||
return;
|
||||
#endif
|
||||
if(adventureInt->mode == EAdvMapMode::WORLD_VIEW)
|
||||
return;
|
||||
int3 mp = whichTileIsIt();
|
||||
|
||||
if (CGI->mh->map->isInTheMap(mp) && down)
|
||||
if(CGI->mh->map->isInTheMap(mp) && down)
|
||||
adventureInt->tileRClicked(mp);
|
||||
}
|
||||
|
||||
void CTerrainRect::mouseMoved(const SDL_MouseMotionEvent & sEvent)
|
||||
{
|
||||
int3 tHovered = whichTileIsIt(sEvent.x,sEvent.y);
|
||||
handleHover(sEvent);
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
if(!adventureInt->swipeEnabled || sEvent.state == 0)
|
||||
return;
|
||||
|
||||
handleSwipeMove(sEvent);
|
||||
#endif // !VCMI_ANDROID
|
||||
}
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
|
||||
void CTerrainRect::handleSwipeMove(const SDL_MouseMotionEvent & sEvent)
|
||||
{
|
||||
if(!isSwiping)
|
||||
{
|
||||
// try to distinguish if this touch was meant to be a swipe or just fat-fingering press
|
||||
if(abs(sEvent.x - swipeInitialRealPos.x) > SwipeTouchSlop ||
|
||||
abs(sEvent.y - swipeInitialRealPos.y) > SwipeTouchSlop)
|
||||
{
|
||||
isSwiping = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(isSwiping)
|
||||
{
|
||||
adventureInt->swipeTargetPosition.x =
|
||||
swipeInitialMapPos.x + static_cast<si32>(swipeInitialRealPos.x - sEvent.x) / 32;
|
||||
adventureInt->swipeTargetPosition.y =
|
||||
swipeInitialMapPos.y + static_cast<si32>(swipeInitialRealPos.y - sEvent.y) / 32;
|
||||
adventureInt->swipeMovementRequested = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // VCMI_ANDROID
|
||||
|
||||
void CTerrainRect::handleHover(const SDL_MouseMotionEvent &sEvent)
|
||||
{
|
||||
int3 tHovered = whichTileIsIt(sEvent.x, sEvent.y);
|
||||
int3 pom = adventureInt->verifyPos(tHovered);
|
||||
|
||||
if(tHovered != pom) //tile outside the map
|
||||
@ -150,12 +215,12 @@ void CTerrainRect::mouseMoved(const SDL_MouseMotionEvent & sEvent)
|
||||
}
|
||||
|
||||
if (pom != curHoveredTile)
|
||||
{
|
||||
curHoveredTile = pom;
|
||||
else
|
||||
return;
|
||||
|
||||
adventureInt->tileHovered(pom);
|
||||
adventureInt->tileHovered(pom);
|
||||
}
|
||||
}
|
||||
|
||||
void CTerrainRect::hover(bool on)
|
||||
{
|
||||
if (!on)
|
||||
@ -470,6 +535,10 @@ CAdvMapInt::CAdvMapInt():
|
||||
spellBeingCasted(nullptr), position(int3(0, 0, 0)), selection(nullptr),
|
||||
updateScreen(false), anim(0), animValHitCount(0), heroAnim(0), heroAnimValHitCount(0),
|
||||
activeMapPanel(nullptr), duringAITurn(false), scrollingDir(0), scrollingState(false)
|
||||
#ifdef VCMI_ANDROID
|
||||
, swipeEnabled(settings["general"]["swipe"].Bool()), swipeMovementRequested(false),
|
||||
swipeTargetPosition(int3(-1, -1, -1))
|
||||
#endif
|
||||
{
|
||||
adventureInt = this;
|
||||
pos.x = pos.y = 0;
|
||||
@ -938,42 +1007,19 @@ void CAdvMapInt::show(SDL_Surface * to)
|
||||
}
|
||||
++heroAnim;
|
||||
|
||||
int scrollSpeed = settings["adventure"]["scrollSpeed"].Float();
|
||||
//if advmap needs updating AND (no dialog is shown OR ctrl is pressed)
|
||||
if((animValHitCount % (4/scrollSpeed)) == 0
|
||||
&& (
|
||||
(GH.topInt() == this)
|
||||
|| isCtrlKeyDown()
|
||||
)
|
||||
)
|
||||
#ifdef VCMI_ANDROID
|
||||
if(swipeEnabled)
|
||||
{
|
||||
if( (scrollingDir & LEFT) && (position.x>-CGI->mh->frameW) )
|
||||
position.x--;
|
||||
|
||||
if( (scrollingDir & RIGHT) && (position.x < CGI->mh->map->width - CGI->mh->tilesW + CGI->mh->frameW) )
|
||||
position.x++;
|
||||
|
||||
if( (scrollingDir & UP) && (position.y>-CGI->mh->frameH) )
|
||||
position.y--;
|
||||
|
||||
if( (scrollingDir & DOWN) && (position.y < CGI->mh->map->height - CGI->mh->tilesH + CGI->mh->frameH) )
|
||||
position.y++;
|
||||
|
||||
if(scrollingDir)
|
||||
{
|
||||
setScrollingCursor(scrollingDir);
|
||||
scrollingState = true;
|
||||
updateScreen = true;
|
||||
minimap.redraw();
|
||||
if (mode == EAdvMapMode::WORLD_VIEW)
|
||||
terrain.redraw();
|
||||
}
|
||||
else if(scrollingState)
|
||||
{
|
||||
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
|
||||
scrollingState = false;
|
||||
}
|
||||
handleSwipeUpdate();
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif // !VCMI_ANDROID
|
||||
handleMapScrollingUpdate();
|
||||
#ifdef VCMI_ANDROID
|
||||
}
|
||||
#endif
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
gems[i]->setFrame(LOCPLINT->playerID.getNum());
|
||||
if(updateScreen)
|
||||
@ -1002,6 +1048,59 @@ void CAdvMapInt::show(SDL_Surface * to)
|
||||
statusbar.showAll(to);
|
||||
}
|
||||
|
||||
void CAdvMapInt::handleMapScrollingUpdate()
|
||||
{
|
||||
int scrollSpeed = settings["adventure"]["scrollSpeed"].Float();
|
||||
//if advmap needs updating AND (no dialog is shown OR ctrl is pressed)
|
||||
if((animValHitCount % (4 / scrollSpeed)) == 0
|
||||
&& ((GH.topInt() == this) || isCtrlKeyDown()))
|
||||
{
|
||||
if((scrollingDir & LEFT) && (position.x > -CGI->mh->frameW))
|
||||
position.x--;
|
||||
|
||||
if((scrollingDir & RIGHT) && (position.x < CGI->mh->map->width - CGI->mh->tilesW + CGI->mh->frameW))
|
||||
position.x++;
|
||||
|
||||
if((scrollingDir & UP) && (position.y > -CGI->mh->frameH))
|
||||
position.y--;
|
||||
|
||||
if((scrollingDir & DOWN) && (position.y < CGI->mh->map->height - CGI->mh->tilesH + CGI->mh->frameH))
|
||||
position.y++;
|
||||
|
||||
if(scrollingDir)
|
||||
{
|
||||
setScrollingCursor(scrollingDir);
|
||||
scrollingState = true;
|
||||
updateScreen = true;
|
||||
minimap.redraw();
|
||||
if(mode == EAdvMapMode::WORLD_VIEW)
|
||||
terrain.redraw();
|
||||
}
|
||||
else if(scrollingState)
|
||||
{
|
||||
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
|
||||
scrollingState = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
|
||||
void CAdvMapInt::handleSwipeUpdate()
|
||||
{
|
||||
if(swipeMovementRequested)
|
||||
{
|
||||
position.x = swipeTargetPosition.x;
|
||||
position.y = swipeTargetPosition.y;
|
||||
CCS->curh->changeGraphic(ECursor::DEFAULT, 0);
|
||||
updateScreen = true;
|
||||
minimap.redraw();
|
||||
swipeMovementRequested = false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void CAdvMapInt::selectionChanged()
|
||||
{
|
||||
const CGTownInstance *to = LOCPLINT->towns[townList.getSelectedIndex()];
|
||||
@ -1315,6 +1414,10 @@ void CAdvMapInt::select(const CArmedInstance *sel, bool centerView /*= true*/)
|
||||
|
||||
void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent )
|
||||
{
|
||||
#ifdef VCMI_ANDROID
|
||||
if(swipeEnabled)
|
||||
return;
|
||||
#endif
|
||||
// adventure map scrolling with mouse
|
||||
// currently disabled in world view mode (as it is in OH3), but should work correctly if mode check is removed
|
||||
if(!isCtrlKeyDown() && isActive() && mode == EAdvMapMode::NORMAL)
|
||||
|
@ -56,6 +56,16 @@ class CTerrainRect
|
||||
SDL_Surface * fadeSurface;
|
||||
EMapAnimRedrawStatus lastRedrawStatus;
|
||||
CFadeAnimation * fadeAnim;
|
||||
|
||||
int3 swipeInitialMapPos;
|
||||
int3 swipeInitialRealPos;
|
||||
bool isSwiping;
|
||||
static constexpr float SwipeTouchSlop = 16.0f;
|
||||
|
||||
void handleHover(const SDL_MouseMotionEvent &sEvent);
|
||||
#ifdef VCMI_ANDROID
|
||||
void handleSwipeMove(const SDL_MouseMotionEvent &sEvent);
|
||||
#endif // VCMI_ANDROID
|
||||
public:
|
||||
int tilesw, tilesh; //width and height of terrain to blit in tiles
|
||||
int3 curHoveredTile;
|
||||
@ -80,6 +90,7 @@ public:
|
||||
/// animates view by caching current surface and crossfading it with normal screen
|
||||
void fadeFromCurrentView();
|
||||
bool needsAnimUpdate();
|
||||
|
||||
};
|
||||
|
||||
/// Resources bar which shows information about how many gold, crystals,... you have
|
||||
@ -121,6 +132,11 @@ public:
|
||||
enum{LEFT=1, RIGHT=2, UP=4, DOWN=8};
|
||||
ui8 scrollingDir; //uses enum: LEFT RIGHT, UP, DOWN
|
||||
bool scrollingState;
|
||||
#ifdef VCMI_ANDROID
|
||||
bool swipeEnabled;
|
||||
bool swipeMovementRequested;
|
||||
int3 swipeTargetPosition;
|
||||
#endif // !VCMI_ANDROID
|
||||
|
||||
enum{NA, INGAME, WAITING} state;
|
||||
|
||||
@ -242,6 +258,12 @@ public:
|
||||
|
||||
/// changes current adventure map mode; used to switch between default view and world view; scale is ignored if EAdvMapMode == NORMAL
|
||||
void changeMode(EAdvMapMode newMode, float newScale = 0.36f);
|
||||
|
||||
void handleMapScrollingUpdate();
|
||||
#ifdef VCMI_ANDROID
|
||||
void handleSwipeUpdate();
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
extern CAdvMapInt *adventureInt;
|
||||
|
@ -17,7 +17,7 @@
|
||||
"type" : "object",
|
||||
"default": {},
|
||||
"additionalProperties" : false,
|
||||
"required" : [ "playerName", "showfps", "music", "sound", "encoding" ],
|
||||
"required" : [ "playerName", "showfps", "music", "sound", "encoding", "swipe" ],
|
||||
"properties" : {
|
||||
"playerName" : {
|
||||
"type":"string",
|
||||
@ -38,7 +38,11 @@
|
||||
"encoding" : {
|
||||
"type" : "string",
|
||||
"default" : "CP1252"
|
||||
}
|
||||
},
|
||||
"swipe" : {
|
||||
"type" : "boolean",
|
||||
"default" : false
|
||||
},
|
||||
}
|
||||
},
|
||||
"video" : {
|
||||
|
@ -38,7 +38,11 @@ namespace ELogLevel
|
||||
case ERROR:
|
||||
return "error";
|
||||
default:
|
||||
#ifdef NO_STD_TOSTRING
|
||||
return "invalid";
|
||||
#else
|
||||
return std::string("invalid (") + std::to_string(level) + ")";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
105
lib/CAndroidVMHelper.cpp
Normal file
105
lib/CAndroidVMHelper.cpp
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* CAndroidVMHelper.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "CAndroidVMHelper.h"
|
||||
|
||||
static JavaVM * vmCache = nullptr;
|
||||
|
||||
/// cached java classloader so that we can find our classes from other threads
|
||||
static jobject vcmiClassLoader;
|
||||
static jmethodID vcmiFindClassMethod;
|
||||
|
||||
void CAndroidVMHelper::cacheVM(JNIEnv * env)
|
||||
{
|
||||
env->GetJavaVM(&vmCache);
|
||||
}
|
||||
|
||||
void CAndroidVMHelper::cacheVM(JavaVM * vm)
|
||||
{
|
||||
vmCache = vm;
|
||||
}
|
||||
|
||||
CAndroidVMHelper::CAndroidVMHelper()
|
||||
{
|
||||
auto res = vmCache->GetEnv((void **) &envPtr, JNI_VERSION_1_1);
|
||||
if(res == JNI_EDETACHED)
|
||||
{
|
||||
auto attachRes = vmCache->AttachCurrentThread(&envPtr, nullptr);
|
||||
if(attachRes == JNI_OK)
|
||||
{
|
||||
detachInDestructor = true; // only detach if we actually attached env
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
detachInDestructor = false;
|
||||
}
|
||||
}
|
||||
|
||||
CAndroidVMHelper::~CAndroidVMHelper()
|
||||
{
|
||||
if(envPtr && detachInDestructor)
|
||||
{
|
||||
vmCache->DetachCurrentThread();
|
||||
envPtr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEnv * CAndroidVMHelper::get()
|
||||
{
|
||||
return envPtr;
|
||||
}
|
||||
|
||||
jclass CAndroidVMHelper::findClassloadedClass(const std::string & name)
|
||||
{
|
||||
auto env = get();
|
||||
return static_cast<jclass>(env->CallObjectMethod(vcmiClassLoader, vcmiFindClassMethod,
|
||||
env->NewStringUTF(name.c_str())));;
|
||||
}
|
||||
|
||||
void CAndroidVMHelper::callStaticVoidMethod(const std::string & cls, const std::string & method,
|
||||
bool classloaded /*=false*/)
|
||||
{
|
||||
auto env = get();
|
||||
auto javaHelper = findClass(cls, classloaded);
|
||||
auto methodId = env->GetStaticMethodID(javaHelper, method.c_str(), "()V");
|
||||
env->CallStaticVoidMethod(javaHelper, methodId);
|
||||
}
|
||||
|
||||
std::string CAndroidVMHelper::callStaticStringMethod(const std::string & cls, const std::string & method,
|
||||
bool classloaded /*=false*/)
|
||||
{
|
||||
auto env = get();
|
||||
auto javaHelper = findClass(cls, classloaded);
|
||||
auto methodId = env->GetStaticMethodID(javaHelper, method.c_str(), "()Ljava/lang/String;");
|
||||
jstring jres = static_cast<jstring>(env->CallStaticObjectMethod(javaHelper, methodId));
|
||||
return std::string(env->GetStringUTFChars(jres, nullptr));
|
||||
}
|
||||
|
||||
jclass CAndroidVMHelper::findClass(const std::string & name, bool classloaded)
|
||||
{
|
||||
if(classloaded)
|
||||
{
|
||||
return findClassloadedClass(name);
|
||||
}
|
||||
return get()->FindClass(name.c_str());
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_initClassloader(JNIEnv * baseEnv, jobject * cls)
|
||||
{
|
||||
CAndroidVMHelper::cacheVM(baseEnv);
|
||||
CAndroidVMHelper envHelper;
|
||||
auto env = envHelper.get();
|
||||
auto anyVCMIClass = env->FindClass(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS);
|
||||
jclass classClass = env->GetObjectClass(anyVCMIClass);
|
||||
auto classLoaderClass = env->FindClass("java/lang/ClassLoader");
|
||||
auto getClassLoaderMethod = env->GetMethodID(classClass, "getClassLoader", "()Ljava/lang/ClassLoader;");
|
||||
vcmiClassLoader = (jclass) env->NewGlobalRef(env->CallObjectMethod(anyVCMIClass, getClassLoaderMethod));
|
||||
vcmiFindClassMethod = env->GetMethodID(classLoaderClass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
||||
}
|
41
lib/CAndroidVMHelper.h
Normal file
41
lib/CAndroidVMHelper.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* CAndroidVMHelper.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <jni.h>
|
||||
#include <string>
|
||||
|
||||
/// helper class that allows access to java vm to communicate with java code from native
|
||||
class CAndroidVMHelper
|
||||
{
|
||||
JNIEnv * envPtr;
|
||||
bool detachInDestructor;
|
||||
|
||||
jclass findClass(const std::string & name, bool classloaded);
|
||||
|
||||
public:
|
||||
CAndroidVMHelper();
|
||||
|
||||
~CAndroidVMHelper();
|
||||
|
||||
JNIEnv * get();
|
||||
|
||||
jclass findClassloadedClass(const std::string & name);
|
||||
|
||||
void callStaticVoidMethod(const std::string & cls, const std::string & method, bool classloaded = false);
|
||||
|
||||
std::string callStaticStringMethod(const std::string & cls, const std::string & method, bool classloaded = false);
|
||||
|
||||
static void cacheVM(JNIEnv * env);
|
||||
|
||||
static void cacheVM(JavaVM * vm);
|
||||
|
||||
static constexpr const char * NATIVE_METHODS_DEFAULT_CLASS = "eu/vcmi/vcmi/NativeMethods";
|
||||
};
|
@ -5,13 +5,21 @@
|
||||
#include "VCMIDirs.h"
|
||||
|
||||
#ifdef VCMI_WINDOWS
|
||||
#include <windows.h> //for .dll libs
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#include <windows.h> //for .dll libs
|
||||
#elif !defined VCMI_ANDROID
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include "serializer/BinaryDeserializer.h"
|
||||
#include "serializer/BinarySerializer.h"
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
|
||||
#include "AI/VCAI/VCAI.h"
|
||||
#include "AI/BattleAI/BattleAI.h"
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* CGameInterface.cpp, part of VCMI engine
|
||||
*
|
||||
@ -22,50 +30,22 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef VCMI_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(std::shared_ptr<CGlobalAI> &out);
|
||||
|
||||
extern "C" DLL_EXPORT void StupidAI_GetAiName(char* name);
|
||||
extern "C" DLL_EXPORT void StupidAI_GetNewBattleAI(std::shared_ptr<CGlobalAI> &out);
|
||||
|
||||
extern "C" DLL_EXPORT void BattleAI_GetAiName(char* name);
|
||||
extern "C" DLL_EXPORT void BattleAI_GetNewBattleAI(std::shared_ptr<CBattleGameInterface> &out);
|
||||
#endif
|
||||
|
||||
template<typename rett>
|
||||
std::shared_ptr<rett> createAny(const boost::filesystem::path& libpath, const std::string& methodName)
|
||||
std::shared_ptr<rett> createAny(const boost::filesystem::path & libpath, const std::string & methodName)
|
||||
{
|
||||
typedef void(*TGetAIFun)(std::shared_ptr<rett>&);
|
||||
typedef void(*TGetNameFun)(char*);
|
||||
#ifdef VCMI_ANDROID
|
||||
// android currently doesn't support loading libs dynamically, so the access to the known libraries
|
||||
// is possible only via specializations of this template
|
||||
throw std::runtime_error("Could not resolve ai library " + libpath.generic_string());
|
||||
#else
|
||||
typedef void(* TGetAIFun)(std::shared_ptr<rett> &);
|
||||
typedef void(* TGetNameFun)(char *);
|
||||
|
||||
char temp[150];
|
||||
|
||||
TGetAIFun getAI = nullptr;
|
||||
TGetNameFun getName = nullptr;
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
// this is awful but it seems using shared libraries on some devices is even worse
|
||||
const std::string filename = libpath.filename().string();
|
||||
if (filename == "libVCAI.so")
|
||||
{
|
||||
getName = (TGetNameFun)VCAI_GetAiName;
|
||||
getAI = (TGetAIFun)VCAI_GetNewAI;
|
||||
}
|
||||
else if (filename == "libStupidAI.so")
|
||||
{
|
||||
getName = (TGetNameFun)StupidAI_GetAiName;
|
||||
getAI = (TGetAIFun)StupidAI_GetNewBattleAI;
|
||||
}
|
||||
else if (filename == "libBattleAI.so")
|
||||
{
|
||||
getName = (TGetNameFun)BattleAI_GetAiName;
|
||||
getAI = (TGetAIFun)BattleAI_GetNewBattleAI;
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Don't know what to do with " + libpath.string() + " and method " + methodName);
|
||||
#else // !VCMI_ANDROID
|
||||
#ifdef VCMI_WINDOWS
|
||||
HMODULE dll = LoadLibraryW(libpath.c_str());
|
||||
if (dll)
|
||||
@ -83,6 +63,7 @@ std::shared_ptr<rett> createAny(const boost::filesystem::path& libpath, const st
|
||||
else
|
||||
logGlobal->errorStream() << "Error: " << dlerror();
|
||||
#endif // VCMI_WINDOWS
|
||||
|
||||
if (!dll)
|
||||
{
|
||||
logGlobal->errorStream() << "Cannot open dynamic library ("<<libpath<<"). Throwing...";
|
||||
@ -98,7 +79,6 @@ std::shared_ptr<rett> createAny(const boost::filesystem::path& libpath, const st
|
||||
#endif
|
||||
throw std::runtime_error("Cannot find method " + methodName);
|
||||
}
|
||||
#endif // VCMI_ANDROID
|
||||
|
||||
getName(temp);
|
||||
logGlobal->infoStream() << "Loaded " << temp;
|
||||
@ -109,14 +89,31 @@ std::shared_ptr<rett> createAny(const boost::filesystem::path& libpath, const st
|
||||
logGlobal->error("Cannot get AI!");
|
||||
|
||||
return ret;
|
||||
#endif //!VCMI_ANDROID
|
||||
}
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
|
||||
template<>
|
||||
std::shared_ptr<CGlobalAI> createAny(const boost::filesystem::path & libpath, const std::string & methodName)
|
||||
{
|
||||
return std::make_shared<VCAI>();
|
||||
}
|
||||
|
||||
template<>
|
||||
std::shared_ptr<CBattleGameInterface> createAny(const boost::filesystem::path & libpath, const std::string & methodName)
|
||||
{
|
||||
return std::make_shared<CBattleAI>();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template<typename rett>
|
||||
std::shared_ptr<rett> createAnyAI(std::string dllname, const std::string& methodName)
|
||||
std::shared_ptr<rett> createAnyAI(std::string dllname, const std::string & methodName)
|
||||
{
|
||||
logGlobal->infoStream() << "Opening " << dllname;
|
||||
const boost::filesystem::path filePath =
|
||||
VCMIDirs::get().libraryPath() / "AI" / VCMIDirs::get().libraryName(dllname);
|
||||
|
||||
const boost::filesystem::path filePath = VCMIDirs::get().fullLibraryPath("AI", dllname);
|
||||
auto ret = createAny<rett>(filePath, methodName);
|
||||
ret->dllName = std::move(dllname);
|
||||
return ret;
|
||||
@ -127,7 +124,7 @@ std::shared_ptr<CGlobalAI> CDynLibHandler::getNewAI(std::string dllname)
|
||||
return createAnyAI<CGlobalAI>(dllname, "GetNewAI");
|
||||
}
|
||||
|
||||
std::shared_ptr<CBattleGameInterface> CDynLibHandler::getNewBattleAI(std::string dllname )
|
||||
std::shared_ptr<CBattleGameInterface> CDynLibHandler::getNewBattleAI(std::string dllname)
|
||||
{
|
||||
return createAnyAI<CBattleGameInterface>(dllname, "GetNewBattleAI");
|
||||
}
|
||||
@ -137,9 +134,10 @@ std::shared_ptr<CScriptingModule> CDynLibHandler::getNewScriptingModule(std::str
|
||||
return createAny<CScriptingModule>(dllname, "GetNewModule");
|
||||
}
|
||||
|
||||
BattleAction CGlobalAI::activeStack( const CStack * stack )
|
||||
BattleAction CGlobalAI::activeStack(const CStack * stack)
|
||||
{
|
||||
BattleAction ba; ba.actionType = Battle::DEFEND;
|
||||
BattleAction ba;
|
||||
ba.actionType = Battle::DEFEND;
|
||||
ba.stackNumber = stack->ID;
|
||||
return ba;
|
||||
}
|
||||
@ -159,7 +157,8 @@ void CAdventureAI::battleCatapultAttacked(const CatapultAttack & ca)
|
||||
battleAI->battleCatapultAttacked(ca);
|
||||
}
|
||||
|
||||
void CAdventureAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side)
|
||||
void CAdventureAI::battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile,
|
||||
const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side)
|
||||
{
|
||||
assert(!battleAI);
|
||||
assert(cbc);
|
||||
@ -173,7 +172,7 @@ void CAdventureAI::battleStacksAttacked(const std::vector<BattleStackAttacked> &
|
||||
battleAI->battleStacksAttacked(bsa);
|
||||
}
|
||||
|
||||
void CAdventureAI::actionStarted(const BattleAction &action)
|
||||
void CAdventureAI::actionStarted(const BattleAction & action)
|
||||
{
|
||||
battleAI->actionStarted(action);
|
||||
}
|
||||
@ -183,7 +182,7 @@ void CAdventureAI::battleNewRoundFirst(int round)
|
||||
battleAI->battleNewRoundFirst(round);
|
||||
}
|
||||
|
||||
void CAdventureAI::actionFinished(const BattleAction &action)
|
||||
void CAdventureAI::actionFinished(const BattleAction & action)
|
||||
{
|
||||
battleAI->actionFinished(action);
|
||||
}
|
||||
@ -213,23 +212,24 @@ void CAdventureAI::battleStackMoved(const CStack * stack, std::vector<BattleHex>
|
||||
battleAI->battleStackMoved(stack, dest, distance);
|
||||
}
|
||||
|
||||
void CAdventureAI::battleAttack(const BattleAttack *ba)
|
||||
void CAdventureAI::battleAttack(const BattleAttack * ba)
|
||||
{
|
||||
battleAI->battleAttack(ba);
|
||||
}
|
||||
|
||||
void CAdventureAI::battleSpellCast(const BattleSpellCast *sc)
|
||||
void CAdventureAI::battleSpellCast(const BattleSpellCast * sc)
|
||||
{
|
||||
battleAI->battleSpellCast(sc);
|
||||
}
|
||||
|
||||
void CAdventureAI::battleEnd(const BattleResult *br)
|
||||
void CAdventureAI::battleEnd(const BattleResult * br)
|
||||
{
|
||||
battleAI->battleEnd(br);
|
||||
battleAI.reset();
|
||||
}
|
||||
|
||||
void CAdventureAI::battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom)
|
||||
void CAdventureAI::battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain,
|
||||
bool tentHeal, si32 lifeDrainFrom)
|
||||
{
|
||||
battleAI->battleStacksHealedRes(healedStacks, lifeDrain, tentHeal, lifeDrainFrom);
|
||||
}
|
||||
|
@ -127,6 +127,8 @@ set(lib_SRCS
|
||||
registerTypes/TypesMapObjects3.cpp
|
||||
registerTypes/TypesPregamePacks.cpp
|
||||
registerTypes/TypesServerPacks.cpp
|
||||
|
||||
${VCMILIB_ADDITIONAL_SOURCES}
|
||||
)
|
||||
|
||||
set(lib_HEADERS
|
||||
@ -180,6 +182,10 @@ if(WIN32)
|
||||
set_target_properties(vcmi PROPERTIES OUTPUT_NAME VCMI_lib)
|
||||
endif()
|
||||
|
||||
if (ANDROID)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set_target_properties(vcmi PROPERTIES ${PCH_PROPERTIES})
|
||||
cotire(vcmi)
|
||||
|
||||
|
@ -15,6 +15,11 @@ namespace bfs = boost::filesystem;
|
||||
|
||||
bfs::path IVCMIDirs::userSavePath() const { return userDataPath() / "Saves"; }
|
||||
|
||||
bfs::path IVCMIDirs::fullLibraryPath(const std::string &desiredFolder, const std::string &baseLibName) const
|
||||
{
|
||||
return libraryPath() / desiredFolder / libraryName(baseLibName);
|
||||
}
|
||||
|
||||
void IVCMIDirs::init()
|
||||
{
|
||||
// TODO: Log errors
|
||||
@ -24,6 +29,11 @@ void IVCMIDirs::init()
|
||||
bfs::create_directories(userSavePath());
|
||||
}
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
#include "CAndroidVMHelper.h"
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef VCMI_WINDOWS
|
||||
|
||||
#ifdef __MINGW32__
|
||||
@ -532,26 +542,55 @@ bfs::path VCMIDirsXDG::libraryPath() const { return M_LIB_DIR; }
|
||||
bfs::path VCMIDirsXDG::binaryPath() const { return M_BIN_DIR; }
|
||||
|
||||
std::string VCMIDirsXDG::libraryName(const std::string& basename) const { return "lib" + basename + ".so"; }
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
|
||||
class VCMIDirsAndroid : public VCMIDirsXDG
|
||||
{
|
||||
std::string basePath;
|
||||
std::string internalPath;
|
||||
std::string nativePath;
|
||||
public:
|
||||
boost::filesystem::path userDataPath() const override;
|
||||
boost::filesystem::path userCachePath() const override;
|
||||
boost::filesystem::path userConfigPath() const override;
|
||||
bfs::path fullLibraryPath(const std::string & desiredFolder, const std::string & baseLibName) const override;
|
||||
bfs::path libraryPath() const override;
|
||||
bfs::path userDataPath() const override;
|
||||
bfs::path userCachePath() const override;
|
||||
bfs::path userConfigPath() const override;
|
||||
|
||||
std::vector<boost::filesystem::path> dataPaths() const override;
|
||||
std::vector<bfs::path> dataPaths() const override;
|
||||
|
||||
void init() override;
|
||||
};
|
||||
|
||||
// on Android HOME will be set to something like /sdcard/data/Android/is.xyz.vcmi/files/
|
||||
bfs::path VCMIDirsAndroid::userDataPath() const { return getenv("HOME"); }
|
||||
bfs::path VCMIDirsAndroid::libraryPath() const { return nativePath; }
|
||||
bfs::path VCMIDirsAndroid::userDataPath() const { return basePath; }
|
||||
bfs::path VCMIDirsAndroid::userCachePath() const { return userDataPath() / "cache"; }
|
||||
bfs::path VCMIDirsAndroid::userConfigPath() const { return userDataPath() / "config"; }
|
||||
|
||||
bfs::path VCMIDirsAndroid::fullLibraryPath(const std::string & desiredFolder, const std::string & baseLibName) const
|
||||
{
|
||||
// ignore passed folder (all libraries in android are dumped into a single folder)
|
||||
return libraryPath() / libraryName(baseLibName);
|
||||
}
|
||||
|
||||
std::vector<bfs::path> VCMIDirsAndroid::dataPaths() const
|
||||
{
|
||||
return std::vector<bfs::path>(1, userDataPath());
|
||||
std::vector<bfs::path> paths(2);
|
||||
paths.push_back(internalPath);
|
||||
paths.push_back(userDataPath());
|
||||
return paths;
|
||||
}
|
||||
|
||||
void VCMIDirsAndroid::init()
|
||||
{
|
||||
// asks java code to retrieve needed paths from environment
|
||||
CAndroidVMHelper envHelper;
|
||||
basePath = envHelper.callStaticStringMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "dataRoot");
|
||||
internalPath = envHelper.callStaticStringMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "internalDataRoot");
|
||||
nativePath = envHelper.callStaticStringMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "nativePath");
|
||||
IVCMIDirs::init();
|
||||
}
|
||||
|
||||
#endif // VCMI_ANDROID
|
||||
#endif // VCMI_APPLE, VCMI_XDG
|
||||
#endif // VCMI_WINDOWS, VCMI_UNIX
|
||||
@ -569,7 +608,8 @@ namespace VCMIDirs
|
||||
static VCMIDirsXDG singleton;
|
||||
#elif defined(VCMI_APPLE)
|
||||
static VCMIDirsOSX singleton;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static bool initialized = false;
|
||||
if (!initialized)
|
||||
{
|
||||
@ -584,3 +624,4 @@ namespace VCMIDirs
|
||||
return singleton;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,48 +11,53 @@
|
||||
|
||||
class DLL_LINKAGE IVCMIDirs
|
||||
{
|
||||
public:
|
||||
// Path to user-specific data directory
|
||||
virtual boost::filesystem::path userDataPath() const = 0;
|
||||
public:
|
||||
// Path to user-specific data directory
|
||||
virtual boost::filesystem::path userDataPath() const = 0;
|
||||
|
||||
// Path to "cache" directory, can be used for any non-essential files
|
||||
virtual boost::filesystem::path userCachePath() const = 0;
|
||||
// Path to "cache" directory, can be used for any non-essential files
|
||||
virtual boost::filesystem::path userCachePath() const = 0;
|
||||
|
||||
// Path to writeable directory with user configs
|
||||
virtual boost::filesystem::path userConfigPath() const = 0;
|
||||
// Path to writeable directory with user configs
|
||||
virtual boost::filesystem::path userConfigPath() const = 0;
|
||||
|
||||
// Path to saved games
|
||||
virtual boost::filesystem::path userSavePath() const;
|
||||
// Path to saved games
|
||||
virtual boost::filesystem::path userSavePath() const;
|
||||
|
||||
// Paths to global system-wide data directories. First items have higher priority
|
||||
virtual std::vector<boost::filesystem::path> dataPaths() const = 0;
|
||||
// Paths to global system-wide data directories. First items have higher priority
|
||||
virtual std::vector<boost::filesystem::path> dataPaths() const = 0;
|
||||
|
||||
// Full path to client executable, including server name (e.g. /usr/bin/vcmiclient)
|
||||
virtual boost::filesystem::path clientPath() const = 0;
|
||||
// Full path to client executable, including server name (e.g. /usr/bin/vcmiclient)
|
||||
virtual boost::filesystem::path clientPath() const = 0;
|
||||
|
||||
// Full path to server executable, including server name (e.g. /usr/bin/vcmiserver)
|
||||
virtual boost::filesystem::path serverPath() const = 0;
|
||||
// Full path to server executable, including server name (e.g. /usr/bin/vcmiserver)
|
||||
virtual boost::filesystem::path serverPath() const = 0;
|
||||
|
||||
// Path where vcmi libraries can be found (in AI and Scripting subdirectories)
|
||||
virtual boost::filesystem::path libraryPath() const = 0;
|
||||
// Path where vcmi libraries can be found (in AI and Scripting subdirectories)
|
||||
virtual boost::filesystem::path libraryPath() const = 0;
|
||||
|
||||
// Path where vcmi binaries can be found
|
||||
virtual boost::filesystem::path binaryPath() const = 0;
|
||||
// absolute path to passed library (needed due to android libs being placed in single dir, not respecting original lib dirs;
|
||||
// by default just concats libraryPath, given folder and libraryName
|
||||
virtual boost::filesystem::path fullLibraryPath(const std::string & desiredFolder,
|
||||
const std::string & baseLibName) const;
|
||||
|
||||
// Returns system-specific name for dynamic libraries ( StupidAI => "libStupidAI.so" or "StupidAI.dll")
|
||||
virtual std::string libraryName(const std::string& basename) const = 0;
|
||||
// virtual std::string libraryName(const char* basename) const = 0; ?
|
||||
// virtual std::string libraryName(std::string&& basename) const = 0;?
|
||||
// Path where vcmi binaries can be found
|
||||
virtual boost::filesystem::path binaryPath() const = 0;
|
||||
|
||||
virtual std::string genHelpString() const = 0;
|
||||
|
||||
// Creates not existed, but required directories.
|
||||
// Updates directories what change name/path between versions.
|
||||
// Function called automatically.
|
||||
virtual void init();
|
||||
// Returns system-specific name for dynamic libraries ( StupidAI => "libStupidAI.so" or "StupidAI.dll")
|
||||
virtual std::string libraryName(const std::string & basename) const = 0;
|
||||
// virtual std::string libraryName(const char* basename) const = 0; ?
|
||||
// virtual std::string libraryName(std::string&& basename) const = 0;?
|
||||
|
||||
virtual std::string genHelpString() const = 0;
|
||||
|
||||
// Creates not existed, but required directories.
|
||||
// Updates directories what change name/path between versions.
|
||||
// Function called automatically.
|
||||
virtual void init();
|
||||
};
|
||||
|
||||
namespace VCMIDirs
|
||||
{
|
||||
extern DLL_LINKAGE const IVCMIDirs& get();
|
||||
extern DLL_LINKAGE const IVCMIDirs & get();
|
||||
}
|
||||
|
@ -345,8 +345,8 @@ void CLogConsoleTarget::write(const LogRecord & record)
|
||||
std::string message = formatter.format(record);
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
__android_log_write(ELogLevel::toAndroid(record.level), "VCMI", message.c_str());
|
||||
#endif
|
||||
__android_log_write(ELogLevel::toAndroid(record.level), ("VCMI-" + record.domain.getName()).c_str(), message.c_str());
|
||||
#else
|
||||
|
||||
const bool printToStdErr = record.level >= ELogLevel::WARN;
|
||||
if(console)
|
||||
@ -364,6 +364,7 @@ void CLogConsoleTarget::write(const LogRecord & record)
|
||||
else
|
||||
std::cout << message << std::endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CLogConsoleTarget::isColoredOutputEnabled() const { return coloredOutputEnabled; }
|
||||
|
@ -12,6 +12,10 @@ set(server_SRCS
|
||||
NetPacksServer.cpp
|
||||
)
|
||||
|
||||
if(ANDROID) # android needs client/server to be libraries, not executables, so we can't reuse the build part of this script
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_executable(vcmiserver ${server_SRCS})
|
||||
|
||||
target_link_libraries(vcmiserver vcmi ${Boost_LIBRARIES} ${SYSTEM_LIBS})
|
||||
@ -27,4 +31,3 @@ cotire(vcmiserver)
|
||||
if (NOT APPLE) # Already inside vcmiclient bundle
|
||||
install(TARGETS vcmiserver DESTINATION ${BIN_DIR})
|
||||
endif()
|
||||
|
||||
|
@ -19,7 +19,9 @@
|
||||
#include "../lib/StartInfo.h"
|
||||
#include "../lib/mapping/CMap.h"
|
||||
#include "../lib/rmg/CMapGenOptions.h"
|
||||
#ifndef VCMI_ANDROID
|
||||
#ifdef VCMI_ANDROID
|
||||
#include "lib/CAndroidVMHelper.h"
|
||||
#else
|
||||
#include "../lib/Interprocess.h"
|
||||
#endif
|
||||
#include "../lib/VCMI_Lib.h"
|
||||
@ -417,18 +419,24 @@ void CVCMIServer::start()
|
||||
#ifndef VCMI_ANDROID
|
||||
sr->setToTrueAndNotify();
|
||||
delete mr;
|
||||
#else
|
||||
{ // in block to clean-up vm helper after use, because we don't need to keep this thread attached to vm
|
||||
CAndroidVMHelper envHelper;
|
||||
envHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "onServerReady");
|
||||
logNetwork->info("Sending server ready message to client");
|
||||
}
|
||||
#endif
|
||||
|
||||
acc.join();
|
||||
if (error)
|
||||
{
|
||||
logNetwork->warnStream()<<"Got connection but there is an error " << error;
|
||||
logNetwork->warnStream() << "Got connection but there is an error " << error;
|
||||
return;
|
||||
}
|
||||
logNetwork->info("We've accepted someone... ");
|
||||
firstConnection = new CConnection(s,NAME);
|
||||
firstConnection = new CConnection(s, NAME);
|
||||
logNetwork->info("Got connection!");
|
||||
while(!end2)
|
||||
while (!end2)
|
||||
{
|
||||
ui8 mode;
|
||||
*firstConnection >> mode;
|
||||
@ -490,6 +498,8 @@ void CVCMIServer::loadGame()
|
||||
gh.run(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void handleCommandOptions(int argc, char *argv[])
|
||||
{
|
||||
namespace po = boost::program_options;
|
||||
@ -567,15 +577,16 @@ int main(int argc, char** argv)
|
||||
// to log stacktrace
|
||||
#if defined(__GNUC__) && !defined (__MINGW32__) && !defined(VCMI_ANDROID)
|
||||
signal(SIGSEGV, handleLinuxSignal);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
console = new CConsoleHandler;
|
||||
CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() / "VCMI_Server_log.txt", console);
|
||||
logConfig.configureDefault();
|
||||
logGlobal->info(NAME);
|
||||
|
||||
|
||||
handleCommandOptions(argc, argv);
|
||||
if(cmdLineOptions.count("port"))
|
||||
if (cmdLineOptions.count("port"))
|
||||
port = cmdLineOptions["port"].as<int>();
|
||||
logNetwork->info("Port %d will be used.", port);
|
||||
|
||||
@ -592,18 +603,18 @@ int main(int argc, char** argv)
|
||||
|
||||
try
|
||||
{
|
||||
while(!end2)
|
||||
while (!end2)
|
||||
{
|
||||
server.start();
|
||||
}
|
||||
io_service.run();
|
||||
}
|
||||
catch(boost::system::system_error &e) //for boost errors just log, not crash - probably client shut down connection
|
||||
catch (boost::system::system_error &e) //for boost errors just log, not crash - probably client shut down connection
|
||||
{
|
||||
logNetwork->error(e.what());
|
||||
end2 = true;
|
||||
}
|
||||
catch(...)
|
||||
catch (...)
|
||||
{
|
||||
handleException();
|
||||
}
|
||||
@ -615,9 +626,23 @@ int main(int argc, char** argv)
|
||||
//and return non-zero status so client can detect error
|
||||
throw;
|
||||
}
|
||||
#ifdef VCMI_ANDROID
|
||||
CAndroidVMHelper envHelper;
|
||||
envHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "killServer");
|
||||
#endif
|
||||
delete VLC;
|
||||
VLC = nullptr;
|
||||
CResourceHandler::clear();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
|
||||
void CVCMIServer::create()
|
||||
{
|
||||
const char * foo[1] = {"android-server"};
|
||||
main(1, const_cast<char **>(foo));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -57,8 +57,13 @@ public:
|
||||
void newGame();
|
||||
void loadGame();
|
||||
void newPregame();
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
static void create();
|
||||
#endif
|
||||
};
|
||||
|
||||
struct StartInfo;
|
||||
class CPregameServer
|
||||
{
|
||||
public:
|
||||
|
Loading…
x
Reference in New Issue
Block a user