From 1250f67771353fb7d21b13d2fd4b53ef8bc3d818 Mon Sep 17 00:00:00 2001 From: nordsoft Date: Fri, 23 Dec 2022 16:33:35 +0400 Subject: [PATCH 01/54] Fix android build --- server/CVCMIServer.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/CVCMIServer.cpp b/server/CVCMIServer.cpp index 63bd636af..f31271a16 100644 --- a/server/CVCMIServer.cpp +++ b/server/CVCMIServer.cpp @@ -1124,8 +1124,7 @@ void CVCMIServer::create(const std::vector & args) std::vector argv = {foo}; for(auto & a : args) argv.push_back(a.c_str()); - - main(argv.size(), const_cast(foo)); + main(argv.size(), reinterpret_cast(const_cast(&*argv.begin()))); } #elif defined(SINGLE_PROCESS_APP) void CVCMIServer::create(boost::condition_variable * cond, const std::vector & args) From 339846a3078e163772ccdd3463959d5a56a6be91 Mon Sep 17 00:00:00 2001 From: nordsoft Date: Fri, 23 Dec 2022 16:40:52 +0400 Subject: [PATCH 02/54] Add build from beta branch for android --- .github/workflows/github.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github.yml b/.github/workflows/github.yml index 026e7b67e..010179540 100644 --- a/.github/workflows/github.yml +++ b/.github/workflows/github.yml @@ -244,7 +244,7 @@ jobs: - name: Trigger Android uses: peter-evans/repository-dispatch@v1 - if: ${{ (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master') && matrix.platform == 'mxe' }} + if: ${{ (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/beta' || github.ref == 'refs/heads/master') && matrix.platform == 'mxe' }} with: token: ${{ secrets.VCMI_ANDROID_ACCESS_TOKEN }} repository: vcmi/vcmi-android From 2953b8fe9d68b4e96ae2450cb39907568be49c17 Mon Sep 17 00:00:00 2001 From: nordsoft Date: Fri, 23 Dec 2022 19:09:28 +0400 Subject: [PATCH 03/54] Fix android build --- server/CVCMIServer.cpp | 4 +--- server/CVCMIServer.h | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/server/CVCMIServer.cpp b/server/CVCMIServer.cpp index f31271a16..b00935eb9 100644 --- a/server/CVCMIServer.cpp +++ b/server/CVCMIServer.cpp @@ -1118,12 +1118,10 @@ int main(int argc, char * argv[]) } #ifdef VCMI_ANDROID -void CVCMIServer::create(const std::vector & args) +void CVCMIServer::create() { const char * foo = "android-server"; std::vector argv = {foo}; - for(auto & a : args) - argv.push_back(a.c_str()); main(argv.size(), reinterpret_cast(const_cast(&*argv.begin()))); } #elif defined(SINGLE_PROCESS_APP) diff --git a/server/CVCMIServer.h b/server/CVCMIServer.h index 315d803de..fa84e044c 100644 --- a/server/CVCMIServer.h +++ b/server/CVCMIServer.h @@ -114,7 +114,7 @@ public: ui8 getIdOfFirstUnallocatedPlayer() const; #ifdef VCMI_ANDROID - static void create(const std::vector & args); + static void create(); #elif defined(SINGLE_PROCESS_APP) static void create(boost::condition_variable * cond, const std::vector & args); #endif From 33602c879d492923cecf6c9a4d898fa05a64d28f Mon Sep 17 00:00:00 2001 From: Andrii Danylchenko Date: Sun, 25 Dec 2022 12:03:32 +0200 Subject: [PATCH 04/54] #1286 - use iOS flow for Android resolutions management --- client/CMT.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/CMT.cpp b/client/CMT.cpp index 25c5c8f2e..bdda4da9b 100644 --- a/client/CMT.cpp +++ b/client/CMT.cpp @@ -1079,7 +1079,8 @@ static bool recreateWindow(int w, int h, int bpp, bool fullscreen, int displayIn if (displayIndex < 0) displayIndex = 0; } -#ifdef VCMI_IOS + +#if defined(VCMI_ANDROID) || defined(VCMI_IOS) SDL_GetWindowSize(mainWindow, &w, &h); #else if(!checkVideoMode(displayIndex, w, h)) From cb13064a623e1615f6acacacdee5f3350be497f4 Mon Sep 17 00:00:00 2001 From: Andrii Danylchenko Date: Mon, 26 Dec 2022 20:13:07 +0200 Subject: [PATCH 05/54] Socket buffered write. Write full cpack at once --- lib/serializer/Connection.cpp | 38 +++++++++++++++++++++++++++++++++++ lib/serializer/Connection.h | 5 +++++ 2 files changed, 43 insertions(+) diff --git a/lib/serializer/Connection.cpp b/lib/serializer/Connection.cpp index 40bb302a9..c5efa17ee 100644 --- a/lib/serializer/Connection.cpp +++ b/lib/serializer/Connection.cpp @@ -34,6 +34,7 @@ using namespace boost::asio::ip; void CConnection::init() { + enableBufferedWrite = false; socket->set_option(boost::asio::ip::tcp::no_delay(true)); try { @@ -72,6 +73,7 @@ CConnection::CConnection(std::string host, ui16 port, std::string Name, std::str int i; boost::system::error_code error = asio::error::host_not_found; socket = std::make_shared(*io_service); + tcp::resolver resolver(*io_service); tcp::resolver::iterator end, pom, endpoint_iterator = resolver.resolve(tcp::resolver::query(host, std::to_string(port)),error); if(error) @@ -138,8 +140,37 @@ CConnection::CConnection(std::shared_ptr acceptor, std::shared_ptr(data), size); + + return size; + } + try { int ret; @@ -153,6 +184,7 @@ int CConnection::write(const void * data, unsigned size) throw; } } + int CConnection::read(void * data, unsigned size) { try @@ -167,6 +199,7 @@ int CConnection::read(void * data, unsigned size) throw; } } + CConnection::~CConnection() { if(handler) @@ -229,7 +262,12 @@ void CConnection::sendPack(const CPack * pack) { boost::unique_lock lock(*mutexWrite); logNetwork->trace("Sending a pack of type %s", typeid(*pack).name()); + + enableBufferedWrite = true; + oser & pack; + + flushBuffers(); } void CConnection::disableStackSendingByID() diff --git a/lib/serializer/Connection.h b/lib/serializer/Connection.h index 63a161b56..45179b6b5 100644 --- a/lib/serializer/Connection.h +++ b/lib/serializer/Connection.h @@ -63,8 +63,13 @@ class DLL_LINKAGE CConnection int write(const void * data, unsigned size) override; int read(void * data, unsigned size) override; + void flushBuffers(); std::shared_ptr io_service; //can be empty if connection made from socket + + bool enableBufferedWrite; + boost::asio::streambuf writeBuffer; + public: BinaryDeserializer iser; BinarySerializer oser; From c271f9187f49c70f79165f307f3a398946adc14d Mon Sep 17 00:00:00 2001 From: Andrii Danylchenko Date: Mon, 26 Dec 2022 21:28:36 +0200 Subject: [PATCH 06/54] Connection buffered read cpack. --- lib/serializer/Connection.cpp | 41 +++++++++++++++++++++++++++-------- lib/serializer/Connection.h | 5 +++++ 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/lib/serializer/Connection.cpp b/lib/serializer/Connection.cpp index c5efa17ee..dcad536a8 100644 --- a/lib/serializer/Connection.cpp +++ b/lib/serializer/Connection.cpp @@ -162,17 +162,17 @@ void CConnection::flushBuffers() int CConnection::write(const void * data, unsigned size) { - if(enableBufferedWrite) - { - std::ostream ostream(&writeBuffer); - - ostream.write(static_cast(data), size); - - return size; - } - try { + if(enableBufferedWrite) + { + std::ostream ostream(&writeBuffer); + + ostream.write(static_cast(data), size); + + return size; + } + int ret; ret = static_cast(asio::write(*socket,asio::const_buffers_1(asio::const_buffer(data,size)))); return ret; @@ -189,6 +189,24 @@ int CConnection::read(void * data, unsigned size) { try { + if(enableBufferedRead) + { + auto available = readBuffer.size(); + + while(available < size) + { + auto bytesRead = socket->read_some(readBuffer.prepare(1024)); + readBuffer.commit(bytesRead); + available = readBuffer.size(); + } + + std::istream istream(&readBuffer); + + istream.read(static_cast(data), size); + + return size; + } + int ret = static_cast(asio::read(*socket,asio::mutable_buffers_1(asio::mutable_buffer(data,size)))); return ret; } @@ -243,6 +261,8 @@ void CConnection::reportState(vstd::CLoggerBase * out) CPack * CConnection::retrievePack() { + enableBufferedRead = true; + CPack * pack = nullptr; boost::unique_lock lock(*mutexRead); iser & pack; @@ -255,6 +275,9 @@ CPack * CConnection::retrievePack() { pack->c = this->shared_from_this(); } + + enableBufferedRead = false; + return pack; } diff --git a/lib/serializer/Connection.h b/lib/serializer/Connection.h index 45179b6b5..bbe79d6a0 100644 --- a/lib/serializer/Connection.h +++ b/lib/serializer/Connection.h @@ -21,6 +21,8 @@ namespace boost { namespace asio { + class streambuf; + namespace ip { class tcp; @@ -70,6 +72,9 @@ class DLL_LINKAGE CConnection bool enableBufferedWrite; boost::asio::streambuf writeBuffer; + bool enableBufferedRead; + boost::asio::streambuf readBuffer; + public: BinaryDeserializer iser; BinarySerializer oser; From a954cc08fbf32d535e37b81ab8262a742e5f00cb Mon Sep 17 00:00:00 2001 From: Andrii Danylchenko Date: Tue, 27 Dec 2022 12:55:31 +0200 Subject: [PATCH 07/54] Made intermediate class to hide some implementation details from header. --- lib/serializer/Connection.cpp | 22 +++++++++++++++------- lib/serializer/Connection.h | 7 ++----- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/lib/serializer/Connection.cpp b/lib/serializer/Connection.cpp index dcad536a8..f84b0c985 100644 --- a/lib/serializer/Connection.cpp +++ b/lib/serializer/Connection.cpp @@ -31,10 +31,18 @@ using namespace boost::asio::ip; #define LIL_ENDIAN #endif +struct ConnectionBuffers +{ + boost::asio::streambuf readBuffer; + boost::asio::streambuf writeBuffer; +}; void CConnection::init() { enableBufferedWrite = false; + enableBufferedRead = false; + connectionBuffers = std::make_unique(); + socket->set_option(boost::asio::ip::tcp::no_delay(true)); try { @@ -148,7 +156,7 @@ void CConnection::flushBuffers() try { - asio::write(*socket, writeBuffer); + asio::write(*socket, connectionBuffers->writeBuffer); } catch(...) { @@ -166,7 +174,7 @@ int CConnection::write(const void * data, unsigned size) { if(enableBufferedWrite) { - std::ostream ostream(&writeBuffer); + std::ostream ostream(&connectionBuffers->writeBuffer); ostream.write(static_cast(data), size); @@ -191,16 +199,16 @@ int CConnection::read(void * data, unsigned size) { if(enableBufferedRead) { - auto available = readBuffer.size(); + auto available = connectionBuffers->readBuffer.size(); while(available < size) { - auto bytesRead = socket->read_some(readBuffer.prepare(1024)); - readBuffer.commit(bytesRead); - available = readBuffer.size(); + auto bytesRead = socket->read_some(connectionBuffers->readBuffer.prepare(1024)); + connectionBuffers->readBuffer.commit(bytesRead); + available = connectionBuffers->readBuffer.size(); } - std::istream istream(&readBuffer); + std::istream istream(&connectionBuffers->readBuffer); istream.read(static_cast(data), size); diff --git a/lib/serializer/Connection.h b/lib/serializer/Connection.h index bbe79d6a0..478822885 100644 --- a/lib/serializer/Connection.h +++ b/lib/serializer/Connection.h @@ -21,8 +21,6 @@ namespace boost { namespace asio { - class streambuf; - namespace ip { class tcp; @@ -54,6 +52,7 @@ typedef boost::asio::basic_socket_acceptor io_service; //can be empty if connection made from socket bool enableBufferedWrite; - boost::asio::streambuf writeBuffer; - bool enableBufferedRead; - boost::asio::streambuf readBuffer; + std::unique_ptr connectionBuffers; public: BinaryDeserializer iser; From d6674e73cde1f2ff27cc4309edb321432c80e369 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Thu, 29 Dec 2022 18:38:44 +0200 Subject: [PATCH 08/54] Explicitly define build type to add NDEBUG flag --- debian/rules | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/rules b/debian/rules index 616e0d6d8..08301bc97 100755 --- a/debian/rules +++ b/debian/rules @@ -8,6 +8,7 @@ override_dh_auto_configure: dh_auto_configure -- \ -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON \ -DCMAKE_INSTALL_RPATH=/usr/lib/$(DEB_HOST_MULTIARCH)/vcmi \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DBIN_DIR=games \ -DFORCE_BUNDLED_FL=OFF \ -DENABLE_TEST=0 From 588b635d1cf3bfe0d7dc0a46a9b95afb16b7a9f0 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Mon, 26 Dec 2022 21:05:01 +0200 Subject: [PATCH 09/54] Workaround for a potential deadlock in MusicHandler --- client/CMusicHandler.cpp | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/client/CMusicHandler.cpp b/client/CMusicHandler.cpp index 60bd71adb..527608a8a 100644 --- a/client/CMusicHandler.cpp +++ b/client/CMusicHandler.cpp @@ -409,6 +409,8 @@ void CMusicHandler::release() void CMusicHandler::playMusic(const std::string & musicURI, bool loop, bool fromStart) { + boost::mutex::scoped_lock guard(mutex); + if (current && current->isPlaying() && current->isTrack(musicURI)) return; @@ -422,6 +424,8 @@ void CMusicHandler::playMusicFromSet(const std::string & musicSet, const std::st void CMusicHandler::playMusicFromSet(const std::string & whichSet, bool loop, bool fromStart) { + boost::mutex::scoped_lock guard(mutex); + auto selectedSet = musicsSet.find(whichSet); if (selectedSet == musicsSet.end()) { @@ -441,8 +445,6 @@ void CMusicHandler::queueNext(std::unique_ptr queued) if (!initialized) return; - boost::mutex::scoped_lock guard(mutex); - next = std::move(queued); if (current.get() == nullptr || !current->stop(1000)) @@ -487,13 +489,32 @@ void CMusicHandler::setVolume(ui32 percent) void CMusicHandler::musicFinishedCallback() { - boost::mutex::scoped_lock guard(mutex); + // boost::mutex::scoped_lock guard(mutex); + // FIXME: WORKAROUND FOR A POTENTIAL DEADLOCK + // It is possible for: + // 1) SDL thread to call this method on end of playback + // 2) VCMI code to call queueNext() method to queue new file + // this leads to: + // 1) SDL thread waiting to aquire music lock in this method (while keeping internal SDL mutex locked) + // 2) VCMI thread waiting to aquire internal SDL mutex (while keeping music mutex locked) + // Because of that (and lack of clear way to fix that) + // We will try to acquire lock here and if failed - do nothing + // This may break music playback till next song is enqued but won't deadlock the game + + if (!mutex.try_lock()) + { + logGlobal->error("Failed to aquire mutex! Unable to restart music!"); + return; + } if (current.get() != nullptr) { // if music is looped, play it again if (current->play()) + { + mutex.unlock(); return; + } else current.reset(); } @@ -503,6 +524,7 @@ void CMusicHandler::musicFinishedCallback() current.reset(next.release()); current->play(); } + mutex.unlock(); } MusicEntry::MusicEntry(CMusicHandler *owner, std::string setName, std::string musicURI, bool looped, bool fromStart): @@ -597,7 +619,7 @@ bool MusicEntry::play() bool MusicEntry::stop(int fade_ms) { - if (Mix_PlayingMusic()) + if (playing) { playing = false; loop = 0; From 61ed408f610a9a241e544d688bbffb0167f4fe3d Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 27 Dec 2022 00:52:28 +0200 Subject: [PATCH 10/54] Fix typo --- client/CMusicHandler.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/CMusicHandler.cpp b/client/CMusicHandler.cpp index 527608a8a..d52c81b83 100644 --- a/client/CMusicHandler.cpp +++ b/client/CMusicHandler.cpp @@ -495,15 +495,15 @@ void CMusicHandler::musicFinishedCallback() // 1) SDL thread to call this method on end of playback // 2) VCMI code to call queueNext() method to queue new file // this leads to: - // 1) SDL thread waiting to aquire music lock in this method (while keeping internal SDL mutex locked) - // 2) VCMI thread waiting to aquire internal SDL mutex (while keeping music mutex locked) + // 1) SDL thread waiting to acquire music lock in this method (while keeping internal SDL mutex locked) + // 2) VCMI thread waiting to acquire internal SDL mutex (while keeping music mutex locked) // Because of that (and lack of clear way to fix that) // We will try to acquire lock here and if failed - do nothing // This may break music playback till next song is enqued but won't deadlock the game if (!mutex.try_lock()) { - logGlobal->error("Failed to aquire mutex! Unable to restart music!"); + logGlobal->error("Failed to acquire mutex! Unable to restart music!"); return; } From e19dc41295891e27961de0b172ef3608232094b0 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 27 Dec 2022 16:51:19 +0200 Subject: [PATCH 11/54] Support Polish version of H3 data files --- config/filesystem.json | 4 ++++ lib/filesystem/CArchiveLoader.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/config/filesystem.json b/config/filesystem.json index 56aa27585..d4c3880e7 100644 --- a/config/filesystem.json +++ b/config/filesystem.json @@ -11,12 +11,16 @@ [ {"type" : "lod", "path" : "Data/H3ab_bmp.lod"}, {"type" : "lod", "path" : "Data/H3bitmap.lod"}, + {"type" : "lod", "path" : "Data/h3abp_bm.lod"}, // Polish version of H3 only + {"type" : "lod", "path" : "Data/H3pbitma.lod"}, // Polish version of H3 only {"type" : "dir", "path" : "Data"} ], "SPRITES/": [ {"type" : "lod", "path" : "Data/H3ab_spr.lod"}, {"type" : "lod", "path" : "Data/H3sprite.lod"}, + {"type" : "lod", "path" : "Data/h3abp_sp.lod"}, // Polish version of H3 only + {"type" : "lod", "path" : "Data/H3psprit.lod"}, // Polish version of H3 only {"type" : "dir", "path" : "Sprites"} ], "SOUNDS/": diff --git a/lib/filesystem/CArchiveLoader.cpp b/lib/filesystem/CArchiveLoader.cpp index b66d36627..21d67bc13 100644 --- a/lib/filesystem/CArchiveLoader.cpp +++ b/lib/filesystem/CArchiveLoader.cpp @@ -152,12 +152,12 @@ void CArchiveLoader::initSNDArchive(const std::string &mountPoint, CFileInputStr char filename[40]; reader.read(reinterpret_cast(filename), 40); - //for some reason entries in snd have format NAME\0WAVRUBBISH.... - //we need to replace first \0 with dot and take the 3 chars with extension (and drop the rest) + // for some reason entries in snd have format NAME\0WAVRUBBISH.... + // and Polish version does not have extension at all + // we need to replace first \0 with dot and add wav extension manuall - we don't expect other types here anyway ArchiveEntry entry; entry.name = filename; // till 1st \0 - entry.name += '.'; - entry.name += std::string(filename + entry.name.size(), 3); + entry.name += ".wav"; entry.offset = reader.readInt32(); entry.fullSize = reader.readInt32(); From 986c0c534da015708df268bf4181ca2eeee84d3d Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 27 Dec 2022 16:53:46 +0200 Subject: [PATCH 12/54] Main menu buttons are now defined using position of their center Fixes positioning of main menu buttons in localized versions of the game --- client/mainmenu/CMainMenu.cpp | 8 ++++++- config/mainmenu.json | 42 +++++++++++++++++------------------ 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/client/mainmenu/CMainMenu.cpp b/client/mainmenu/CMainMenu.cpp index 02879d9d8..f7421720a 100644 --- a/client/mainmenu/CMainMenu.cpp +++ b/client/mainmenu/CMainMenu.cpp @@ -236,7 +236,13 @@ std::shared_ptr CMenuEntry::createButton(CMenuScreen * parent, const Js if(posy < 0) posy = pos.h + posy; - return std::make_shared(Point(posx, posy), button["name"].String(), help, command, (int)button["hotkey"].Float()); + auto result = std::make_shared(Point(posx, posy), button["name"].String(), help, command, (int)button["hotkey"].Float()); + + if (button["center"].Bool()) + result->moveBy(Point(-result->pos.w/2, -result->pos.h/2)); + return result; + + } CMenuEntry::CMenuEntry(CMenuScreen * parent, const JsonNode & config) diff --git a/config/mainmenu.json b/config/mainmenu.json index 63170c59e..292e8cfb7 100644 --- a/config/mainmenu.json +++ b/config/mainmenu.json @@ -10,29 +10,29 @@ "background" : "gamselbk", //"scalable" : true, //background will be scaled to screen size //"video" : {"x": 8, "y": 105, "name":"CREDITS.SMK" },//Floating WoG logo. Disabled due to different position in various versions of H3. - //"images" : [],//Optioal, contains any additional images in the same format as video + //"images" : [],//Optional, contains any additional images in the same format as video "items" : [ { "name" : "main", "buttons": [ - {"x": 540, "y": 10, "name":"MMENUNG", "hotkey" : 110, "help": 3, "command": "to new"}, - {"x": 532, "y": 132, "name":"MMENULG", "hotkey" : 108, "help": 4, "command": "to load"}, - {"x": 524, "y": 251, "name":"MMENUHS", "hotkey" : 104, "help": 5, "command": "highscores"}, - {"x": 557, "y": 359, "name":"MMENUCR", "hotkey" : 99, "help": 6, "command": "to credits"}, - {"x": 586, "y": 468, "name":"MMENUQT", "hotkey" : 27, "help": 7, "command": "exit"} + {"x": 644, "y": 70, "center" : true, "name":"MMENUNG", "hotkey" : 110, "help": 3, "command": "to new"}, + {"x": 645, "y": 192, "center" : true, "name":"MMENULG", "hotkey" : 108, "help": 4, "command": "to load"}, + {"x": 643, "y": 296, "center" : true, "name":"MMENUHS", "hotkey" : 104, "help": 5, "command": "highscores"}, + {"x": 643, "y": 414, "center" : true, "name":"MMENUCR", "hotkey" : 99, "help": 6, "command": "to credits"}, + {"x": 643, "y": 520, "center" : true, "name":"MMENUQT", "hotkey" : 27, "help": 7, "command": "exit"} ] }, { "name" : "new", "buttons": [ - {"x": 545, "y": 4, "name":"GTSINGL", "hotkey" : 115, "help": 10, "command": "start single"}, - {"x": 568, "y": 120, "name":"GTMULTI", "hotkey" : 109, "help": 12, "command": "start multi"}, - {"x": 541, "y": 233, "name":"GTCAMPN", "hotkey" : 99, "help": 11, "command": "to campaign"}, - {"x": 545, "y": 358, "name":"GTTUTOR", "hotkey" : 116, "help": 13, "command": "start tutorial"}, - {"x": 582, "y": 464, "name":"GTBACK", "hotkey" : 27, "help": 14, "command": "to main"} + {"x": 649, "y": 65, "center" : true, "name":"GTSINGL", "hotkey" : 115, "help": 10, "command": "start single"}, + {"x": 649, "y": 180, "center" : true, "name":"GTMULTI", "hotkey" : 109, "help": 12, "command": "start multi"}, + {"x": 646, "y": 298, "center" : true, "name":"GTCAMPN", "hotkey" : 99, "help": 11, "command": "to campaign"}, + {"x": 647, "y": 412, "center" : true, "name":"GTTUTOR", "hotkey" : 116, "help": 13, "command": "start tutorial"}, + {"x": 645, "y": 517, "center" : true, "name":"GTBACK", "hotkey" : 27, "help": 14, "command": "to main"} ], "images": [ {"x": 114, "y": 312, "name":"NEWGAME"} ] }, @@ -40,11 +40,11 @@ "name" : "load", "buttons": [ - {"x": 545, "y": 8, "name":"GTSINGL", "hotkey" : 115, "help": 10, "command": "load single"}, - {"x": 568, "y": 120, "name":"GTMULTI", "hotkey" : 109, "help": 12, "command": "load multi"}, - {"x": 541, "y": 233, "name":"GTCAMPN", "hotkey" : 99, "help": 11, "command": "load campaign"}, - {"x": 545, "y": 358, "name":"GTTUTOR", "hotkey" : 116, "help": 13, "command": "load tutorial"}, - {"x": 582, "y": 464, "name":"GTBACK", "hotkey" : 27, "help": 14, "command": "to main"} + {"x": 649, "y": 65, "center" : true, "name":"GTSINGL", "hotkey" : 115, "help": 10, "command": "load single"}, + {"x": 649, "y": 180, "center" : true, "name":"GTMULTI", "hotkey" : 109, "help": 12, "command": "load multi"}, + {"x": 646, "y": 298, "center" : true, "name":"GTCAMPN", "hotkey" : 99, "help": 11, "command": "load campaign"}, + {"x": 647, "y": 412, "center" : true, "name":"GTTUTOR", "hotkey" : 116, "help": 13, "command": "load tutorial"}, + {"x": 645, "y": 517, "center" : true, "name":"GTBACK", "hotkey" : 27, "help": 14, "command": "to main"} ], "images": [ {"x": 114, "y": 312, "name":"LOADGAME"} ] }, @@ -52,11 +52,11 @@ "name" : "campaign", "buttons": [ - {"x": 535, "y": 4, "name":"CSSSOD", "hotkey" : 119, "command": "campaigns sod"}, - {"x": 494, "y": 117, "name":"CSSROE", "hotkey" : 114, "command": "campaigns roe"}, - {"x": 486, "y": 241, "name":"CSSARM", "hotkey" : 97, "command": "campaigns ab"}, - {"x": 550, "y": 358, "name":"CSSCUS", "hotkey" : 99, "command": "start campaign"}, - {"x": 582, "y": 464, "name":"GTBACK", "hotkey" : 27, "command": "to new"} + {"x": 634, "y": 67, "center" : true, "name":"CSSSOD", "hotkey" : 119, "command": "campaigns sod"}, + {"x": 637, "y": 181, "center" : true, "name":"CSSROE", "hotkey" : 114, "command": "campaigns roe"}, + {"x": 638, "y": 301, "center" : true, "name":"CSSARM", "hotkey" : 97, "command": "campaigns ab"}, + {"x": 638, "y": 413, "center" : true, "name":"CSSCUS", "hotkey" : 99, "command": "start campaign"}, + {"x": 639, "y": 518, "center" : true, "name":"CSSEXIT", "hotkey" : 27, "command": "to new"} ], } ] From ce76696af4ac1b6c62aac449d88e17ff5e5be1f3 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 27 Dec 2022 16:54:23 +0200 Subject: [PATCH 13/54] Detect slightly different gog.com installer file layout --- vcmibuilder | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vcmibuilder b/vcmibuilder index 08b78ab31..497de28ea 100755 --- a/vcmibuilder +++ b/vcmibuilder @@ -177,7 +177,7 @@ then cd "$data_dir" && innoextract "$gog_file" # some versions of gog.com installer (or innoextract tool?) place game files inside /app directory - if [[ -d "$data_dir"/app ]] + if [[ -d "$data_dir"/app/[Dd][Aa][Tt][Aa] ]] then data_dir="$data_dir"/app fi From b6735618f5ac057df2ed26f2f884fb6506b2bf10 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 27 Dec 2022 16:55:38 +0200 Subject: [PATCH 14/54] Formatting --- client/mainmenu/CMainMenu.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/mainmenu/CMainMenu.cpp b/client/mainmenu/CMainMenu.cpp index f7421720a..faa01c2a8 100644 --- a/client/mainmenu/CMainMenu.cpp +++ b/client/mainmenu/CMainMenu.cpp @@ -241,8 +241,6 @@ std::shared_ptr CMenuEntry::createButton(CMenuScreen * parent, const Js if (button["center"].Bool()) result->moveBy(Point(-result->pos.w/2, -result->pos.h/2)); return result; - - } CMenuEntry::CMenuEntry(CMenuScreen * parent, const JsonNode & config) From d3d8a6de1b29d922295799d6fc54783f9da9613e Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 27 Dec 2022 17:19:28 +0200 Subject: [PATCH 15/54] Fix directory test --- vcmibuilder | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/vcmibuilder b/vcmibuilder index 497de28ea..6d3555e24 100755 --- a/vcmibuilder +++ b/vcmibuilder @@ -87,6 +87,11 @@ warning () warn_user=true } +#checks whether specified directory exists. Also works with globs +dir_exists() { + [ -d "$1" ] +} + # check if selected options are correct. if [[ -n "$data_dir" ]] @@ -177,7 +182,7 @@ then cd "$data_dir" && innoextract "$gog_file" # some versions of gog.com installer (or innoextract tool?) place game files inside /app directory - if [[ -d "$data_dir"/app/[Dd][Aa][Tt][Aa] ]] + if dir_exists "$data_dir"/app/[Dd][Aa][Tt][Aa] then data_dir="$data_dir"/app fi From 90b669f50716b796380fbd89af7e80aaa7946766 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Mon, 26 Dec 2022 17:35:23 +0200 Subject: [PATCH 16/54] Fix order of dialogs on assembling artefacts after battle --- client/battle/CBattleInterface.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/client/battle/CBattleInterface.cpp b/client/battle/CBattleInterface.cpp index 62f455247..777981ab5 100644 --- a/client/battle/CBattleInterface.cpp +++ b/client/battle/CBattleInterface.cpp @@ -1275,6 +1275,7 @@ void CBattleInterface::battleFinished(const BattleResult& br) void CBattleInterface::displayBattleFinished() { CCS->curh->changeGraphic(ECursor::ADVENTURE,0); + curInt->waitWhileDialog(); if(settings["session"]["spectate"].Bool() && settings["session"]["spectate-skip-battle-result"].Bool()) { close(); From b1082aa6215f60b0ae8b0ab694d17dfd40bfba7d Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 27 Dec 2022 14:24:42 +0200 Subject: [PATCH 17/54] Do not attempt to display multiple assembly dialogs at once --- client/CPlayerInterface.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 651fe9461..9dbf79dfb 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -2273,6 +2273,8 @@ void CPlayerInterface::artifactRemoved(const ArtifactLocation &al) if (artWin) artWin->artifactRemoved(al); } + + waitWhileDialog(); } void CPlayerInterface::artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst) @@ -2287,6 +2289,8 @@ void CPlayerInterface::artifactMoved(const ArtifactLocation &src, const Artifact } if(!GH.objsToBlit.empty()) GH.objsToBlit.back()->redraw(); + + waitWhileDialog(); } void CPlayerInterface::artifactPossibleAssembling(const ArtifactLocation & dst) From 9f9798d3a4377d8021ee686af48d1f442190644b Mon Sep 17 00:00:00 2001 From: Andrii Danylchenko Date: Mon, 2 Jan 2023 14:11:02 +0200 Subject: [PATCH 18/54] Update android JNI bindings --- client/Client.cpp | 8 ++++++- client/widgets/TextControls.cpp | 37 --------------------------------- client/widgets/TextControls.h | 3 --- lib/CAndroidVMHelper.cpp | 5 ----- lib/CAndroidVMHelper.h | 2 -- 5 files changed, 7 insertions(+), 48 deletions(-) diff --git a/client/Client.cpp b/client/Client.cpp index 5ee3c6cb0..ded4b4d82 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -770,8 +770,14 @@ void CClient::reinitScripting() #endif } - #ifdef VCMI_ANDROID +extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_clientSetupJNI(JNIEnv * env, jobject cls) +{ + logNetwork->info("Received clientSetupJNI"); + + CAndroidVMHelper::cacheVM(env); +} + extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerClosed(JNIEnv * env, jobject cls) { logNetwork->info("Received server closed signal"); diff --git a/client/widgets/TextControls.cpp b/client/widgets/TextControls.cpp index 3fdf070e3..7dff297a8 100644 --- a/client/widgets/TextControls.cpp +++ b/client/widgets/TextControls.cpp @@ -488,9 +488,6 @@ CKeyboardFocusListener::CKeyboardFocusListener(CTextInput * textInput) void CKeyboardFocusListener::focusGot() { CSDL_Ext::startTextInput(&textInput->pos); -#ifdef VCMI_ANDROID - textInput->notifyAndroidTextInputChanged(textInput->text); -#endif usageIndex++; } @@ -552,9 +549,6 @@ void CTextInput::keyPressed(const SDL_KeyboardEvent & key) { redraw(); cb(text); -#ifdef VCMI_ANDROID - notifyAndroidTextInputChanged(text); -#endif } } @@ -563,10 +557,6 @@ void CTextInput::setText(const std::string & nText, bool callCb) CLabel::setText(nText); if(callCb) cb(text); - -#ifdef VCMI_ANDROID - notifyAndroidTextInputChanged(text); -#endif } bool CTextInput::captureThisEvent(const SDL_KeyboardEvent & key) @@ -592,10 +582,6 @@ void CTextInput::textInputed(const SDL_TextInputEvent & event) cb(text); } newText.clear(); - -#ifdef VCMI_ANDROID - notifyAndroidTextInputChanged(text); -#endif } void CTextInput::textEdited(const SDL_TextEditingEvent & event) @@ -606,11 +592,6 @@ void CTextInput::textEdited(const SDL_TextEditingEvent & event) newText = event.text; redraw(); cb(text + newText); - -#ifdef VCMI_ANDROID - auto editedText = text + newText; - notifyAndroidTextInputChanged(editedText); -#endif } void CTextInput::filenameFilter(std::string & text, const std::string &) @@ -657,24 +638,6 @@ void CTextInput::numberFilter(std::string & text, const std::string & oldText, i } } -#ifdef VCMI_ANDROID -void CTextInput::notifyAndroidTextInputChanged(std::string & text) -{ - if(!focus) - return; - - auto fun = [&text](JNIEnv * env, jclass cls, jmethodID method) - { - auto jtext = env->NewStringUTF(text.c_str()); - env->CallStaticVoidMethod(cls, method, jtext); - env->DeleteLocalRef(jtext); - }; - CAndroidVMHelper vmHelper; - vmHelper.callCustomMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "notifyTextInputChanged", - "(Ljava/lang/String;)V", fun, true); -} -#endif //VCMI_ANDROID - CFocusable::CFocusable() :CFocusable(std::make_shared()) { diff --git a/client/widgets/TextControls.h b/client/widgets/TextControls.h index 335d9c1c4..b4ba5c037 100644 --- a/client/widgets/TextControls.h +++ b/client/widgets/TextControls.h @@ -198,9 +198,6 @@ class CTextInput : public CLabel, public CFocusable protected: std::string visibleText() override; -#ifdef VCMI_ANDROID - void notifyAndroidTextInputChanged(std::string & text); -#endif public: CFunctionList cb; CFunctionList filters; diff --git a/lib/CAndroidVMHelper.cpp b/lib/CAndroidVMHelper.cpp index 075bf71dd..6ac49e164 100644 --- a/lib/CAndroidVMHelper.cpp +++ b/lib/CAndroidVMHelper.cpp @@ -21,11 +21,6 @@ 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); diff --git a/lib/CAndroidVMHelper.h b/lib/CAndroidVMHelper.h index 48e77d1ae..b46272d48 100644 --- a/lib/CAndroidVMHelper.h +++ b/lib/CAndroidVMHelper.h @@ -42,8 +42,6 @@ public: static void cacheVM(JNIEnv * env); - static void cacheVM(JavaVM * vm); - static constexpr const char * NATIVE_METHODS_DEFAULT_CLASS = "eu/vcmi/vcmi/NativeMethods"; }; From 7e8516f927945708ff0a0c664619c1f0f280d7e6 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Fri, 6 Jan 2023 23:29:33 +0200 Subject: [PATCH 19/54] Changed Sirens behavior to match H3 logic --- lib/mapObjects/MiscObjects.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index 309971b9e..e0fddbb16 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -1956,7 +1956,13 @@ void CGSirens::onHeroVisit( const CGHeroInstance * h ) const for (auto i = h->Slots().begin(); i != h->Slots().end(); i++) { - TQuantity drown = static_cast(i->second->count * 0.3); + // 1-sized stacks are not affected by sirens + if (i->second->count == 1) + continue; + + // tested H3 behavior: 30% (rounded up) of stack drowns + TQuantity drown = std::ceil(i->second->count * 0.3); + if(drown) { cb->changeStackCount(StackLocation(h, i->first), -drown); From 8526eba6fa82006409650f032aeb83e58276e86f Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Sat, 31 Dec 2022 17:55:22 +0200 Subject: [PATCH 20/54] Added checks to music player to detect potential freezes --- client/CMusicHandler.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/client/CMusicHandler.cpp b/client/CMusicHandler.cpp index d52c81b83..563627beb 100644 --- a/client/CMusicHandler.cpp +++ b/client/CMusicHandler.cpp @@ -89,7 +89,7 @@ CSoundHandler::CSoundHandler(): soundBase::battle02, soundBase::battle03, soundBase::battle04, soundBase::battle05, soundBase::battle06, soundBase::battle07 }; - + //predefine terrain set //TODO: support custom sounds for new terrains and load from json horseSounds = @@ -542,6 +542,20 @@ MusicEntry::MusicEntry(CMusicHandler *owner, std::string setName, std::string mu } MusicEntry::~MusicEntry() { + if (playing) + { + assert(0); + logGlobal->error("Attempt to delete music while playing!"); + Mix_HaltMusic(); + } + + if (loop == 0 && Mix_FadingMusic() != MIX_NO_FADING) + { + assert(0); + logGlobal->error("Attempt to delete music while fading out!"); + Mix_HaltMusic(); + } + logGlobal->trace("Del-ing music file %s", currentName); if (music) Mix_FreeMusic(music); @@ -619,7 +633,7 @@ bool MusicEntry::play() bool MusicEntry::stop(int fade_ms) { - if (playing) + if (Mix_PlayingMusic()) { playing = false; loop = 0; From 9308319ac7a42105ee0a8ee4c794a9b139376540 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Sun, 8 Jan 2023 18:05:00 +0200 Subject: [PATCH 21/54] Added workaround for ~200 ms lag occuring after hero move --- client/CPlayerInterface.cpp | 3 +++ client/windows/CAdvmapInterface.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 9dbf79dfb..b55e6d2bd 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -2550,6 +2550,9 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path) // (i == 0) means hero went through all the path adventureInt->updateMoveHero(h, (i != 0)); adventureInt->updateNextHero(h); + + // ugly workaround to force instant update of adventure map + adventureInt->animValHitCount = 8; } setMovementStatus(false); diff --git a/client/windows/CAdvmapInterface.cpp b/client/windows/CAdvmapInterface.cpp index 7706af146..99e676a36 100644 --- a/client/windows/CAdvmapInterface.cpp +++ b/client/windows/CAdvmapInterface.cpp @@ -1044,7 +1044,7 @@ void CAdvMapInt::show(SDL_Surface * to) { ++heroAnim; } - if(animValHitCount == 8) + if(animValHitCount >= 8) { CGI->mh->updateWater(); animValHitCount = 0; From 6379c5f6fae9a039089c4a7193f94372807ed7a1 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Sun, 8 Jan 2023 14:11:08 +0200 Subject: [PATCH 22/54] Install additional dll on Windows to get better style for Qt --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 95fe102a4..0a71610aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -506,6 +506,9 @@ if(WIN32) FILES ${integration_loc} DESTINATION ${BIN_DIR}/platforms ) + install( + FILES "$" + DESTINATION ${BIN_DIR}/styles) endif() endif() From e1880604806e649fb189b21ce632d991375e6c05 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Mon, 9 Jan 2023 23:27:38 +0200 Subject: [PATCH 23/54] Fix server shutdown on transferring artifact to commander --- server/CGameHandler.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 40e684973..943f0e5bc 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -3916,9 +3916,17 @@ bool CGameHandler::moveArtifact(const ArtifactLocation &al1, const ArtifactLocat moveArtifact(dst, ArtifactLocation(dst.artHolder, ArtifactPosition( (si32)dst.getHolderArtSet()->artifactsInBackpack.size() + GameConstants::BACKPACK_START))); } - auto hero = boost::get>(dst.artHolder); - if(ArtifactUtils::checkSpellbookIsNeeded(hero, srcArtifact->artType->id, dst.slot)) - giveHeroNewArtifact(hero, VLC->arth->objects[ArtifactID::SPELLBOOK], ArtifactPosition::SPELLBOOK); + + try + { + auto hero = boost::get>(dst.artHolder); + if(ArtifactUtils::checkSpellbookIsNeeded(hero, srcArtifact->artType->id, dst.slot)) + giveHeroNewArtifact(hero, VLC->arth->objects[ArtifactID::SPELLBOOK], ArtifactPosition::SPELLBOOK); + } + catch (boost::bad_get const &) + { + // object other than hero received an art - ignore + } MoveArtifact ma(&src, &dst); sendAndApply(&ma); From 9658ffba99c825cc46eb92082cbeb8252d14f690 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Mon, 9 Jan 2023 23:38:04 +0200 Subject: [PATCH 24/54] Allow disabling & deleting local mods other than vcmi mod --- launcher/modManager/cmodlist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/modManager/cmodlist.cpp b/launcher/modManager/cmodlist.cpp index e08c99ce4..1ec1313d0 100644 --- a/launcher/modManager/cmodlist.cpp +++ b/launcher/modManager/cmodlist.cpp @@ -124,7 +124,7 @@ bool CModEntry::isCompatible() const bool CModEntry::isEssential() const { - return getValue("storedLocaly").toBool(); + return getName() == "vcmi"; } bool CModEntry::isInstalled() const From e855a9db7c4be58a630043e3a1b6294249141a15 Mon Sep 17 00:00:00 2001 From: Andrey Filipenkov Date: Sat, 31 Dec 2022 16:31:34 +0300 Subject: [PATCH 25/54] [Conan] use profile includes for common parts --- CI/conan/base/apple | 7 +++++++ CI/conan/base/ios | 5 +++++ CI/conan/base/macos | 4 ++++ CI/conan/ios-arm64 | 13 ++----------- CI/conan/ios-armv7 | 13 ++----------- CI/conan/macos-arm | 12 ++---------- CI/conan/macos-intel | 12 ++---------- 7 files changed, 24 insertions(+), 42 deletions(-) create mode 100644 CI/conan/base/apple create mode 100644 CI/conan/base/ios create mode 100644 CI/conan/base/macos diff --git a/CI/conan/base/apple b/CI/conan/base/apple new file mode 100644 index 000000000..477761aa9 --- /dev/null +++ b/CI/conan/base/apple @@ -0,0 +1,7 @@ +[settings] +compiler=apple-clang +compiler.version=13 +compiler.libcxx=libc++ +build_type=Release +[conf] +tools.cmake.cmaketoolchain:generator = Ninja diff --git a/CI/conan/base/ios b/CI/conan/base/ios new file mode 100644 index 000000000..0f48cadf2 --- /dev/null +++ b/CI/conan/base/ios @@ -0,0 +1,5 @@ +include(apple) + +[settings] +os=iOS +os.sdk=iphoneos diff --git a/CI/conan/base/macos b/CI/conan/base/macos new file mode 100644 index 000000000..db13d6a90 --- /dev/null +++ b/CI/conan/base/macos @@ -0,0 +1,4 @@ +include(apple) + +[settings] +os=Macos diff --git a/CI/conan/ios-arm64 b/CI/conan/ios-arm64 index f702a6302..238bbcf8f 100644 --- a/CI/conan/ios-arm64 +++ b/CI/conan/ios-arm64 @@ -1,14 +1,5 @@ +include(base/ios) + [settings] -os=iOS os.version=12.0 -os.sdk=iphoneos arch=armv8 -compiler=apple-clang -compiler.version=13 -compiler.libcxx=libc++ -build_type=Release -[options] -[build_requires] -[env] -[conf] -tools.cmake.cmaketoolchain:generator = Ninja diff --git a/CI/conan/ios-armv7 b/CI/conan/ios-armv7 index 35a87253d..6bec961e7 100644 --- a/CI/conan/ios-armv7 +++ b/CI/conan/ios-armv7 @@ -1,14 +1,5 @@ +include(base/ios) + [settings] -os=iOS os.version=10.0 -os.sdk=iphoneos arch=armv7 -compiler=apple-clang -compiler.version=13 -compiler.libcxx=libc++ -build_type=Release -[options] -[build_requires] -[env] -[conf] -tools.cmake.cmaketoolchain:generator = Ninja diff --git a/CI/conan/macos-arm b/CI/conan/macos-arm index 99858c9b3..d3f06e078 100644 --- a/CI/conan/macos-arm +++ b/CI/conan/macos-arm @@ -1,13 +1,5 @@ +include(base/macos) + [settings] -os=Macos os.version=11.0 arch=armv8 -compiler=apple-clang -compiler.version=13 -compiler.libcxx=libc++ -build_type=Release -[options] -[build_requires] -[env] -[conf] -tools.cmake.cmaketoolchain:generator = Ninja diff --git a/CI/conan/macos-intel b/CI/conan/macos-intel index 510caaee4..b527e056b 100644 --- a/CI/conan/macos-intel +++ b/CI/conan/macos-intel @@ -1,13 +1,5 @@ +include(base/macos) + [settings] -os=Macos os.version=10.13 arch=x86_64 -compiler=apple-clang -compiler.version=13 -compiler.libcxx=libc++ -build_type=Release -[options] -[build_requires] -[env] -[conf] -tools.cmake.cmaketoolchain:generator = Ninja From 43ef6c075e14d5e14b0024c6811608d14c2a320a Mon Sep 17 00:00:00 2001 From: Andrey Filipenkov Date: Sat, 31 Dec 2022 16:32:11 +0300 Subject: [PATCH 26/54] [Conan] disable bitcode explicitly --- CI/conan/base/apple | 1 + 1 file changed, 1 insertion(+) diff --git a/CI/conan/base/apple b/CI/conan/base/apple index 477761aa9..18655d38b 100644 --- a/CI/conan/base/apple +++ b/CI/conan/base/apple @@ -4,4 +4,5 @@ compiler.version=13 compiler.libcxx=libc++ build_type=Release [conf] +tools.apple:enable_bitcode = False tools.cmake.cmaketoolchain:generator = Ninja From 427cae270462884dbe5c4ed03111dd47fc8f3271 Mon Sep 17 00:00:00 2001 From: Andrey Filipenkov Date: Sat, 31 Dec 2022 16:33:06 +0300 Subject: [PATCH 27/54] [Conan] fix building Boost.Locale with Apple-clang in versions >= 1.81 --- CI/conan/base/apple | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CI/conan/base/apple b/CI/conan/base/apple index 18655d38b..bdb33e3e6 100644 --- a/CI/conan/base/apple +++ b/CI/conan/base/apple @@ -3,6 +3,10 @@ compiler=apple-clang compiler.version=13 compiler.libcxx=libc++ build_type=Release + +# required for Boost.Locale in versions >= 1.81 +compiler.cppstd=11 + [conf] tools.apple:enable_bitcode = False tools.cmake.cmaketoolchain:generator = Ninja From 453217b4bb76951796f36153941fcd9e17fb44cf Mon Sep 17 00:00:00 2001 From: Andrey Filipenkov Date: Sat, 14 Jan 2023 13:55:42 +0300 Subject: [PATCH 28/54] [Conan] ignore SDL versions with broken sound --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index fd6108234..a3030c689 100644 --- a/conanfile.py +++ b/conanfile.py @@ -13,7 +13,7 @@ class VCMI(ConanFile): "minizip/[~1.2.12]", "onetbb/[^2021.3]", # Nullkiller AI "qt/[~5.15.2]", # launcher - "sdl/[~2.24.0]", + "sdl/[~2.26.1 || >=2.0.20 <=2.22.0]", # versions in between have broken sound "sdl_image/[~2.0.5]", "sdl_mixer/[~2.0.4]", "sdl_ttf/[~2.0.18]", From 0eef2412db1c9ec5eed247a426bdae534453905b Mon Sep 17 00:00:00 2001 From: Andrey Filipenkov Date: Sat, 14 Jan 2023 14:25:16 +0300 Subject: [PATCH 29/54] [Conan] switch to apple-clang 14 --- CI/conan/base/apple | 2 +- CI/conan/ios-armv7 | 3 +++ docs/conan.md | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CI/conan/base/apple b/CI/conan/base/apple index bdb33e3e6..ae85bc702 100644 --- a/CI/conan/base/apple +++ b/CI/conan/base/apple @@ -1,6 +1,6 @@ [settings] compiler=apple-clang -compiler.version=13 +compiler.version=14 compiler.libcxx=libc++ build_type=Release diff --git a/CI/conan/ios-armv7 b/CI/conan/ios-armv7 index 6bec961e7..54482ce16 100644 --- a/CI/conan/ios-armv7 +++ b/CI/conan/ios-armv7 @@ -3,3 +3,6 @@ include(base/ios) [settings] os.version=10.0 arch=armv7 + +# Xcode 13.x is the last version that can build for armv7 +compiler.version=13 diff --git a/docs/conan.md b/docs/conan.md index 3bd0308ef..f55ff5ba9 100644 --- a/docs/conan.md +++ b/docs/conan.md @@ -20,8 +20,8 @@ The following platforms are supported and known to work, others might require ch 1. Check if your build environment can use the prebuilt binaries: basically, that your compiler version (or Xcode major version) matches the information below. If you're unsure, simply advance to the next step. - - macOS: libraries are built with Apple clang 13 (Xcode 13.4.1), should be consumable by Xcode and Xcode CLT 13.x - - iOS: libraries are built with Apple clang 13 (Xcode 13.4.1), should be consumable by Xcode 13.x + - macOS: libraries are built with Apple clang 14 (Xcode 14.2), should be consumable by Xcode and Xcode CLT 14.x (older library versions are also available for Xcode 13, see Releases in the respective repo) + - iOS: libraries are built with Apple clang 14 (Xcode 14.2), should be consumable by Xcode 14.x (older library versions are also available for Xcode 13, see Releases in the respective repo) 2. Download the binaries archive and unpack it to `~/.conan` directory: From 9d3ad51de44ed3745bd7d67ccede8bb2e86e85b2 Mon Sep 17 00:00:00 2001 From: Andrey Filipenkov Date: Sat, 14 Jan 2023 14:37:08 +0300 Subject: [PATCH 30/54] [Conan][docs] fix examples of using our prebuilt binaries for macOS/iOS --- docs/conan.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/conan.md b/docs/conan.md index f55ff5ba9..6e0a2e834 100644 --- a/docs/conan.md +++ b/docs/conan.md @@ -85,7 +85,8 @@ conan install . \ --no-imports \ --build=never \ --profile:build=default \ - --profile:host=CI/conan/macos-intel + --profile:host=CI/conan/macos-intel \ + -o with_apple_system_libs=True cmake -S . -B build -G Xcode \ --toolchain conan-generated/conan_toolchain.cmake @@ -116,7 +117,8 @@ conan install . \ --no-imports \ --build=never \ --profile:build=default \ - --profile:host=CI/conan/ios-arm64 + --profile:host=CI/conan/ios-arm64 \ + -o with_apple_system_libs=True cmake --preset ios-conan ``` From b22c651b0f0c294691aa164d8ed7a7c8b3dbd1ea Mon Sep 17 00:00:00 2001 From: Andrey Filipenkov Date: Sat, 14 Jan 2023 14:37:59 +0300 Subject: [PATCH 31/54] [CI] switch Apple platforms to Xcode 14 --- CI/ios/before_install.sh | 4 ++-- CI/mac/before_install.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CI/ios/before_install.sh b/CI/ios/before_install.sh index 69e459d86..5f47b58f0 100755 --- a/CI/ios/before_install.sh +++ b/CI/ios/before_install.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash -echo DEVELOPER_DIR=/Applications/Xcode_13.4.1.app >> $GITHUB_ENV +echo DEVELOPER_DIR=/Applications/Xcode_14.2.app >> $GITHUB_ENV mkdir ~/.conan ; cd ~/.conan -curl -L 'https://github.com/vcmi/vcmi-ios-deps/releases/download/1.1/ios-arm64.xz' \ +curl -L 'https://github.com/vcmi/vcmi-ios-deps/releases/download/1.2/ios-arm64.txz' \ | tar -xf - diff --git a/CI/mac/before_install.sh b/CI/mac/before_install.sh index 5bd64351c..b4c46a693 100755 --- a/CI/mac/before_install.sh +++ b/CI/mac/before_install.sh @@ -1,9 +1,9 @@ #!/usr/bin/env bash -echo DEVELOPER_DIR=/Applications/Xcode_13.4.1.app >> $GITHUB_ENV +echo DEVELOPER_DIR=/Applications/Xcode_14.2.app >> $GITHUB_ENV brew install ninja mkdir ~/.conan ; cd ~/.conan -curl -L "https://github.com/vcmi/vcmi-deps-macos/releases/download/1.1/$DEPS_FILENAME.txz" \ +curl -L "https://github.com/vcmi/vcmi-deps-macos/releases/download/1.2/$DEPS_FILENAME.txz" \ | tar -xf - From efbed6000bda890f6b8571b4ea26e769f1183e56 Mon Sep 17 00:00:00 2001 From: Andrey Filipenkov Date: Sat, 14 Jan 2023 14:38:03 +0300 Subject: [PATCH 32/54] fix typo --- AI/Nullkiller/Analyzers/ObjectClusterizer.cpp | 1 - config/schemas/terrain.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/AI/Nullkiller/Analyzers/ObjectClusterizer.cpp b/AI/Nullkiller/Analyzers/ObjectClusterizer.cpp index 2acdef5e9..8c0829a36 100644 --- a/AI/Nullkiller/Analyzers/ObjectClusterizer.cpp +++ b/AI/Nullkiller/Analyzers/ObjectClusterizer.cpp @@ -202,7 +202,6 @@ void ObjectClusterizer::clusterize() Obj::WHIRLPOOL, Obj::BUOY, Obj::SIGN, - Obj::SIGN, Obj::GARRISON, Obj::MONSTER, Obj::GARRISON2, diff --git a/config/schemas/terrain.json b/config/schemas/terrain.json index b4be9e922..bcbabeaa8 100644 --- a/config/schemas/terrain.json +++ b/config/schemas/terrain.json @@ -54,7 +54,7 @@ "rockTerrain": { "type": "string", - "description": "The name of tock type terrain which will be used as borders in the underground" + "description": "The name of rock type terrain which will be used as borders in the underground" }, "river": { From 2f149141202eeedd2c3c604926af020dbfca718c Mon Sep 17 00:00:00 2001 From: Andrey Filipenkov Date: Sat, 14 Jan 2023 16:27:11 +0300 Subject: [PATCH 33/54] fix Boost deprecation warnings warnings introduced in v1.81 # Conflicts: # mapeditor/resourceExtractor/ResourceConverter.cpp --- client/CPlayerInterface.cpp | 2 +- lib/filesystem/CFilesystemLoader.cpp | 19 ++++++++++++++++--- .../resourceExtractor/ResourceConverter.cpp | 16 ++++++---------- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index b55e6d2bd..7192b1c88 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -1702,7 +1702,7 @@ int CPlayerInterface::getLastIndex( std::string namePrefix) else for (directory_iterator dir(gamesDir); dir != enddir; ++dir) { - if (is_regular(dir->status())) + if (is_regular_file(dir->status())) { std::string name = dir->path().filename().string(); if (starts_with(name, namePrefix) && ends_with(name, ".vcgm1")) diff --git a/lib/filesystem/CFilesystemLoader.cpp b/lib/filesystem/CFilesystemLoader.cpp index 122d22bf8..65d95ff6e 100644 --- a/lib/filesystem/CFilesystemLoader.cpp +++ b/lib/filesystem/CFilesystemLoader.cpp @@ -112,18 +112,31 @@ std::unordered_map CFilesystemLoader::listFiles(const std std::vector path; //vector holding relative path to our file bfs::recursive_directory_iterator enddir; +#if BOOST_VERSION >= 107200 // 1.72 + bfs::recursive_directory_iterator it(baseDirectory, bfs::directory_options::follow_directory_symlink); +#else bfs::recursive_directory_iterator it(baseDirectory, bfs::symlink_option::recurse); +#endif for(; it != enddir; ++it) { EResType::Type type; +#if BOOST_VERSION >= 107200 + const auto currentDepth = it.depth(); +#else + const auto currentDepth = it.level(); +#endif if (bfs::is_directory(it->status())) { - path.resize(it.level() + 1); + path.resize(currentDepth + 1); path.back() = it->path().filename(); // don't iterate into directory if depth limit reached - it.no_push(depth <= it.level()); +#if BOOST_VERSION >= 107200 + it.disable_recursion_pending(depth <= currentDepth); +#else + it.no_push(depth <= currentDepth); +#endif type = EResType::DIRECTORY; } @@ -134,7 +147,7 @@ std::unordered_map CFilesystemLoader::listFiles(const std { //reconstruct relative filename (not possible via boost AFAIK) bfs::path filename; - const size_t iterations = std::min((size_t)it.level(), path.size()); + const size_t iterations = std::min(static_cast(currentDepth), path.size()); if (iterations) { filename = path.front(); diff --git a/mapeditor/resourceExtractor/ResourceConverter.cpp b/mapeditor/resourceExtractor/ResourceConverter.cpp index d2be795b1..f08cd5e49 100644 --- a/mapeditor/resourceExtractor/ResourceConverter.cpp +++ b/mapeditor/resourceExtractor/ResourceConverter.cpp @@ -33,36 +33,32 @@ void ResourceConverter::convertExtractedResourceFiles(ConversionOptions conversi void ResourceConverter::doConvertPcxToPng(bool deleteOriginals) { - std::string filename; - bfs::path imagesPath = VCMIDirs::get().userExtractedPath() / "IMAGES"; bfs::directory_iterator end_iter; for(bfs::directory_iterator dir_itr(imagesPath); dir_itr != end_iter; ++dir_itr) { + const auto filename = dir_itr->path().filename(); try { if (!bfs::is_regular_file(dir_itr->status())) return; - std::string filePath = dir_itr->path().string(); - std::string fileStem = dir_itr->path().stem().string(); - filename = dir_itr->path().filename().string(); - std::string filenameLowerCase = boost::locale::to_lower(filename); + std::string filenameLowerCase = boost::algorithm::to_lower_copy(filename.string()); - if(bfs::extension(filenameLowerCase) == ".pcx") + if(boost::algorithm::to_lower_copy(filename.extension().string()) == ".pcx") { auto img = BitmapHandler::loadBitmap(filenameLowerCase); - bfs::path pngFilePath = imagesPath / (fileStem + ".png"); + bfs::path pngFilePath = imagesPath / (dir_itr->path().stem().string() + ".png"); img.save(pathToQString(pngFilePath), "PNG"); if(deleteOriginals) - bfs::remove(filePath); + bfs::remove(dir_itr->path()); } } catch(const std::exception & ex) { - logGlobal->info(filename + " " + ex.what() + "\n"); + logGlobal->info(filename.string() + " " + ex.what() + "\n"); } } } From 2de48624bcecebda677bca035bc50ad2b8c21ee6 Mon Sep 17 00:00:00 2001 From: Andrey Filipenkov Date: Sat, 14 Jan 2023 20:29:42 +0300 Subject: [PATCH 34/54] [iOS] fix linking QtCore --- launcher/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 5764c38a1..040bf52e1 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -128,6 +128,11 @@ enable_pch(vcmilauncher) if(APPLE_IOS) set(ICONS_DESTINATION ${DATA_DIR}) + # TODO: remove after fixing Conan's Qt recipe + if(XCODE_VERSION VERSION_GREATER_EQUAL 14.0) + target_link_libraries(vcmilauncher "-framework IOKit") + endif() + # workaround https://github.com/conan-io/conan-center-index/issues/13332 if(USING_CONAN) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/QIOSIntegrationPlugin.h From 7ccfcf51e9dfbc2011e51ee6303fcbd778574b70 Mon Sep 17 00:00:00 2001 From: Andrii Danylchenko Date: Sat, 7 Jan 2023 10:15:32 +0200 Subject: [PATCH 35/54] Handle 2 fingers gesture as rclick via SDL --- client/gui/CGuiHandler.cpp | 72 ++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/client/gui/CGuiHandler.cpp b/client/gui/CGuiHandler.cpp index 410e9b8ae..3fcd3d1c0 100644 --- a/client/gui/CGuiHandler.cpp +++ b/client/gui/CGuiHandler.cpp @@ -206,6 +206,24 @@ void CGuiHandler::handleEvents() } } +bool multifinger = false; +int lastFingerCount; + +void convertTouch(SDL_Event * current) +{ + int rLogicalWidth, rLogicalHeight; + + SDL_RenderGetLogicalSize(mainRenderer, &rLogicalWidth, &rLogicalHeight); + + int adjustedMouseY = (int)(current->tfinger.y * rLogicalHeight); + int adjustedMouseX = (int)(current->tfinger.x * rLogicalWidth); + + current->button.x = adjustedMouseX; + current->motion.x = adjustedMouseX; + current->button.y = adjustedMouseY; + current->motion.y = adjustedMouseY; +} + void CGuiHandler::handleCurrentEvent() { if(current->type == SDL_KEYDOWN || current->type == SDL_KEYUP) @@ -338,22 +356,54 @@ void CGuiHandler::handleCurrentEvent() it->textEdited(current->edit); } } - //todo: muiltitouch else if(current->type == SDL_MOUSEBUTTONUP) { - switch(current->button.button) + if(multifinger && lastFingerCount >= 1) { - case SDL_BUTTON_LEFT: - handleMouseButtonClick(lclickable, EIntObjMouseBtnType::LEFT, false); - break; - case SDL_BUTTON_RIGHT: - handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, false); - break; - case SDL_BUTTON_MIDDLE: - handleMouseButtonClick(mclickable, EIntObjMouseBtnType::MIDDLE, false); - break; + multifinger = false; + } + else + { + switch(current->button.button) + { + case SDL_BUTTON_LEFT: + handleMouseButtonClick(lclickable, EIntObjMouseBtnType::LEFT, false); + break; + case SDL_BUTTON_RIGHT: + handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, false); + break; + case SDL_BUTTON_MIDDLE: + handleMouseButtonClick(mclickable, EIntObjMouseBtnType::MIDDLE, false); + break; + } } } + else if(current->type == SDL_FINGERDOWN) + { + lastFingerCount = SDL_GetNumTouchFingers(current->tfinger.touchId); + + multifinger = lastFingerCount > 1; + + if(lastFingerCount == 2) + { + convertTouch(current); + handleMouseMotion(); + handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, true); + } + } + else if(current->type == SDL_FINGERUP) + { + lastFingerCount = SDL_GetNumTouchFingers(current->tfinger.touchId); + + if(multifinger) + { + multifinger = false; + convertTouch(current); + handleMouseMotion(); + handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, false); + } + } + current = nullptr; } //event end From 2b1511df998d1bfa1398259af85028dc3e598217 Mon Sep 17 00:00:00 2001 From: Andrii Danylchenko Date: Mon, 16 Jan 2023 13:39:45 +0200 Subject: [PATCH 36/54] SDL fix 2 finger touch when you remove fingers instantly --- client/gui/CGuiHandler.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/client/gui/CGuiHandler.cpp b/client/gui/CGuiHandler.cpp index 3fcd3d1c0..16e92e2e9 100644 --- a/client/gui/CGuiHandler.cpp +++ b/client/gui/CGuiHandler.cpp @@ -358,11 +358,7 @@ void CGuiHandler::handleCurrentEvent() } else if(current->type == SDL_MOUSEBUTTONUP) { - if(multifinger && lastFingerCount >= 1) - { - multifinger = false; - } - else + if(!multifinger || lastFingerCount < 1) { switch(current->button.button) { From c24b89fe0647e81028b64a374caf9420f7e38bc7 Mon Sep 17 00:00:00 2001 From: Andrii Danylchenko Date: Tue, 17 Jan 2023 12:04:57 +0200 Subject: [PATCH 37/54] 2 finger rclick block adwmap scrolling and disable for iOS --- client/gui/CGuiHandler.cpp | 20 ++++++++++---------- client/gui/CGuiHandler.h | 1 + client/windows/CAdvmapInterface.cpp | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/client/gui/CGuiHandler.cpp b/client/gui/CGuiHandler.cpp index 16e92e2e9..926ee3e6e 100644 --- a/client/gui/CGuiHandler.cpp +++ b/client/gui/CGuiHandler.cpp @@ -206,9 +206,6 @@ void CGuiHandler::handleEvents() } } -bool multifinger = false; -int lastFingerCount; - void convertTouch(SDL_Event * current) { int rLogicalWidth, rLogicalHeight; @@ -358,7 +355,7 @@ void CGuiHandler::handleCurrentEvent() } else if(current->type == SDL_MOUSEBUTTONUP) { - if(!multifinger || lastFingerCount < 1) + if(!multifinger) { switch(current->button.button) { @@ -374,13 +371,14 @@ void CGuiHandler::handleCurrentEvent() } } } +#ifndef VCMI_IOS else if(current->type == SDL_FINGERDOWN) { - lastFingerCount = SDL_GetNumTouchFingers(current->tfinger.touchId); + auto fingerCount = SDL_GetNumTouchFingers(current->tfinger.touchId); - multifinger = lastFingerCount > 1; + multifinger = fingerCount > 1; - if(lastFingerCount == 2) + if(fingerCount == 2) { convertTouch(current); handleMouseMotion(); @@ -389,16 +387,17 @@ void CGuiHandler::handleCurrentEvent() } else if(current->type == SDL_FINGERUP) { - lastFingerCount = SDL_GetNumTouchFingers(current->tfinger.touchId); + auto fingerCount = SDL_GetNumTouchFingers(current->tfinger.touchId); if(multifinger) { - multifinger = false; convertTouch(current); handleMouseMotion(); handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, false); + multifinger = fingerCount != 0; } } +#endif //VCMI_IOS current = nullptr; } //event end @@ -527,7 +526,8 @@ void CGuiHandler::renderFrame() CGuiHandler::CGuiHandler() - : lastClick(-500, -500),lastClickTime(0), defActionsDef(0), captureChildren(false) + : lastClick(-500, -500),lastClickTime(0), defActionsDef(0), captureChildren(false), + multifinger(false) { continueEventHandling = true; curInt = nullptr; diff --git a/client/gui/CGuiHandler.h b/client/gui/CGuiHandler.h index 7f6373dfb..d9aa2068d 100644 --- a/client/gui/CGuiHandler.h +++ b/client/gui/CGuiHandler.h @@ -101,6 +101,7 @@ public: Point lastClick; unsigned lastClickTime; + bool multifinger; ui8 defActionsDef; //default auto actions bool captureChildren; //all newly created objects will get their parents from stack and will be added to parents children list diff --git a/client/windows/CAdvmapInterface.cpp b/client/windows/CAdvmapInterface.cpp index 99e676a36..0af40cc55 100644 --- a/client/windows/CAdvmapInterface.cpp +++ b/client/windows/CAdvmapInterface.cpp @@ -180,7 +180,7 @@ void CTerrainRect::mouseMoved(const SDL_MouseMotionEvent & sEvent) void CTerrainRect::handleSwipeMove(const SDL_MouseMotionEvent & sEvent) { #if defined(VCMI_ANDROID) || defined(VCMI_IOS) - if(sEvent.state == 0) // any "button" is enough on mobile + if(sEvent.state == 0 || GH.multifinger) // any "button" is enough on mobile #else if((sEvent.state & SDL_BUTTON_MMASK) == 0) // swipe only works with middle mouse on other platforms #endif From 8f35bf8866da06944997580d2b7721b116617330 Mon Sep 17 00:00:00 2001 From: Andrii Danylchenko Date: Tue, 17 Jan 2023 10:22:11 +0200 Subject: [PATCH 38/54] Fix android UI shift when keyboard appears --- client/gui/SDL_Extensions.cpp | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/client/gui/SDL_Extensions.cpp b/client/gui/SDL_Extensions.cpp index 6cb332865..eb19a5e97 100644 --- a/client/gui/SDL_Extensions.cpp +++ b/client/gui/SDL_Extensions.cpp @@ -863,20 +863,10 @@ SDL_Color CSDL_Ext::makeColor(ui8 r, ui8 g, ui8 b, ui8 a) void CSDL_Ext::startTextInput(SDL_Rect * where) { - auto impl = [](SDL_Rect * where) - { - if (SDL_IsTextInputActive() == SDL_FALSE) - { - SDL_StartTextInput(); - } - SDL_SetTextInputRect(where); - }; - #ifdef VCMI_APPLE dispatch_async(dispatch_get_main_queue(), ^{ #endif -#ifdef VCMI_IOS // TODO ios: looks like SDL bug actually, try fixing there auto renderer = SDL_GetRenderer(mainWindow); float scaleX, scaleY; @@ -884,17 +874,26 @@ void CSDL_Ext::startTextInput(SDL_Rect * where) SDL_RenderGetScale(renderer, &scaleX, &scaleY); SDL_RenderGetViewport(renderer, &viewport); +#ifdef VCMI_IOS const auto nativeScale = iOS_utils::screenScale(); - auto rectInScreenCoordinates = *where; - rectInScreenCoordinates.x = (viewport.x + rectInScreenCoordinates.x) * scaleX / nativeScale; - rectInScreenCoordinates.y = (viewport.y + rectInScreenCoordinates.y) * scaleY / nativeScale; - rectInScreenCoordinates.w = rectInScreenCoordinates.w * scaleX / nativeScale; - rectInScreenCoordinates.h = rectInScreenCoordinates.h * scaleY / nativeScale; - impl(&rectInScreenCoordinates); -#else - impl(where); + + scaleX /= nativeScale; + scaleY /= nativeScale; #endif + auto rectInScreenCoordinates = *where; + rectInScreenCoordinates.x = (viewport.x + rectInScreenCoordinates.x) * scaleX; + rectInScreenCoordinates.y = (viewport.y + rectInScreenCoordinates.y) * scaleY; + rectInScreenCoordinates.w = rectInScreenCoordinates.w * scaleX; + rectInScreenCoordinates.h = rectInScreenCoordinates.h * scaleY; + + SDL_SetTextInputRect(&rectInScreenCoordinates); + + if (SDL_IsTextInputActive() == SDL_FALSE) + { + SDL_StartTextInput(); + } + #ifdef VCMI_APPLE }); #endif From 6c843bce0bf41e8b020a3dd679c33d0ce1ae5d26 Mon Sep 17 00:00:00 2001 From: Andrii Danylchenko Date: Mon, 16 Jan 2023 12:26:43 +0200 Subject: [PATCH 39/54] SDL relative pointer for android --- client/CMT.cpp | 10 +++- client/gui/CGuiHandler.cpp | 108 +++++++++++++++++++++++++++++------ client/gui/CGuiHandler.h | 7 +++ config/schemas/settings.json | 23 +++++++- 4 files changed, 127 insertions(+), 21 deletions(-) diff --git a/client/CMT.cpp b/client/CMT.cpp index bdda4da9b..a871e5f02 100644 --- a/client/CMT.cpp +++ b/client/CMT.cpp @@ -374,7 +374,8 @@ int main(int argc, char * argv[]) SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); #endif // VCMI_ANDROID - GH.mainFPSmng->init(); //(!)init here AFTER SDL_Init() while using SDL for FPS management + //(!)init here AFTER SDL_Init() while using SDL for FPS management + GH.init(); SDL_LogSetOutputFunction(&SDLLogCallback, nullptr); @@ -430,11 +431,18 @@ int main(int argc, char * argv[]) CCS->musich->setVolume((ui32)settings["general"]["music"].Float()); logGlobal->info("Initializing screen and sound handling: %d ms", pomtime.getDiff()); } + #ifdef VCMI_MAC // Ctrl+click should be treated as a right click on Mac OS X SDL_SetHint(SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK, "1"); #endif + if(GH.isPointerRelativeMode) + { + SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0"); + SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); + } + #ifndef VCMI_NO_THREADED_LOAD //we can properly play intro only in the main thread, so we have to move loading to the separate thread boost::thread loading(init); diff --git a/client/gui/CGuiHandler.cpp b/client/gui/CGuiHandler.cpp index 926ee3e6e..566e213fa 100644 --- a/client/gui/CGuiHandler.cpp +++ b/client/gui/CGuiHandler.cpp @@ -78,6 +78,13 @@ void CGuiHandler::processLists(const ui16 activityFlag, std::functioninit(); + isPointerRelativeMode = settings["general"]["userRelativePointer"].Bool(); + pointerSpeedMultiplier = settings["general"]["relativePointerSpeedMultiplier"].Float(); +} + void CGuiHandler::handleElementActivate(CIntObject * elem, ui16 activityFlag) { processLists(activityFlag,[&](std::list * lst){ @@ -206,7 +213,7 @@ void CGuiHandler::handleEvents() } } -void convertTouch(SDL_Event * current) +void CGuiHandler::convertTouchToMouse(SDL_Event * current) { int rLogicalWidth, rLogicalHeight; @@ -221,6 +228,58 @@ void convertTouch(SDL_Event * current) current->motion.y = adjustedMouseY; } +void CGuiHandler::fakeMoveCursor(float dx, float dy) +{ + int x, y, w, h; + + SDL_Event event; + SDL_MouseMotionEvent sme = {SDL_MOUSEMOTION, 0, 0, 0, 0, 0, 0, 0, 0}; + + sme.state = SDL_GetMouseState(&x, &y); + SDL_GetWindowSize(mainWindow, &w, &h); + + sme.x = CCS->curh->xpos + (int)(GH.pointerSpeedMultiplier * w * dx); + sme.y = CCS->curh->ypos + (int)(GH.pointerSpeedMultiplier * h * dy); + + vstd::abetween(sme.x, 0, w); + vstd::abetween(sme.y, 0, h); + + event.motion = sme; + SDL_PushEvent(&event); +} + +void CGuiHandler::fakeMouseMove() +{ + fakeMoveCursor(0, 0); +} + +void CGuiHandler::fakeMouseButtonEventRelativeMode(bool down, bool right) +{ + SDL_Event event; + SDL_MouseButtonEvent sme = {SDL_MOUSEBUTTONDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + if(!down) + { + sme.type = SDL_MOUSEBUTTONUP; + } + + sme.button = right ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT; + + sme.x = CCS->curh->xpos; + sme.y = CCS->curh->ypos; + + int windowX, windowY; + + SDL_RenderLogicalToWindow(mainRenderer, sme.x, sme.y, &windowX, &windowY); + + SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); + SDL_WarpMouse(windowX, windowY); + SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE); + + event.button = sme; + SDL_PushEvent(&event); +} + void CGuiHandler::handleCurrentEvent() { if(current->type == SDL_KEYDOWN || current->type == SDL_KEYUP) @@ -372,15 +431,31 @@ void CGuiHandler::handleCurrentEvent() } } #ifndef VCMI_IOS + else if(current->type == SDL_FINGERMOTION) + { + if(isPointerRelativeMode) + { + fakeMoveCursor(current->tfinger.dx, current->tfinger.dy); + } + } else if(current->type == SDL_FINGERDOWN) { auto fingerCount = SDL_GetNumTouchFingers(current->tfinger.touchId); multifinger = fingerCount > 1; - if(fingerCount == 2) + if(isPointerRelativeMode) { - convertTouch(current); + if(current->tfinger.x > 0.5) + { + bool isRightClick = current->tfinger.y < 0.5; + + fakeMouseButtonEventRelativeMode(true, isRightClick); + } + } + else if(fingerCount == 2) + { + convertTouchToMouse(current); handleMouseMotion(); handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, true); } @@ -389,9 +464,18 @@ void CGuiHandler::handleCurrentEvent() { auto fingerCount = SDL_GetNumTouchFingers(current->tfinger.touchId); - if(multifinger) + if(isPointerRelativeMode) { - convertTouch(current); + if(current->tfinger.x > 0.5) + { + bool isRightClick = current->tfinger.y < 0.5; + + fakeMouseButtonEventRelativeMode(false, isRightClick); + } + } + else if(multifinger) + { + convertTouchToMouse(current); handleMouseMotion(); handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, false); multifinger = fingerCount != 0; @@ -471,20 +555,6 @@ void CGuiHandler::handleMoveInterested(const SDL_MouseMotionEvent & motion) } } -void CGuiHandler::fakeMouseMove() -{ - SDL_Event event; - SDL_MouseMotionEvent sme = {SDL_MOUSEMOTION, 0, 0, 0, 0, 0, 0, 0, 0}; - int x, y; - - sme.state = SDL_GetMouseState(&x, &y); - sme.x = x; - sme.y = y; - - event.motion = sme; - SDL_PushEvent(&event); -} - void CGuiHandler::renderFrame() { diff --git a/client/gui/CGuiHandler.h b/client/gui/CGuiHandler.h index d9aa2068d..4baac9932 100644 --- a/client/gui/CGuiHandler.h +++ b/client/gui/CGuiHandler.h @@ -88,6 +88,10 @@ private: void handleMouseButtonClick(CIntObjectList & interestedObjs, EIntObjMouseBtnType btn, bool isPressed); void processLists(const ui16 activityFlag, std::function *)> cb); + void convertTouchToMouse(SDL_Event * current); + void fakeMoveCursor(float dx, float dy); + void fakeMouseButtonEventRelativeMode(bool down, bool right); + public: void handleElementActivate(CIntObject * elem, ui16 activityFlag); void handleElementDeActivate(CIntObject * elem, ui16 activityFlag); @@ -102,6 +106,8 @@ public: Point lastClick; unsigned lastClickTime; bool multifinger; + bool isPointerRelativeMode; + float pointerSpeedMultiplier; ui8 defActionsDef; //default auto actions bool captureChildren; //all newly created objects will get their parents from stack and will be added to parents children list @@ -110,6 +116,7 @@ public: CGuiHandler(); ~CGuiHandler(); + void init(); void renderFrame(); void totalRedraw(); //forces total redraw (using showAll), sets a flag, method gets called at the end of the rendering diff --git a/config/schemas/settings.json b/config/schemas/settings.json index 9baa638c6..0a774bd1a 100644 --- a/config/schemas/settings.json +++ b/config/schemas/settings.json @@ -17,7 +17,20 @@ "type" : "object", "default": {}, "additionalProperties" : false, - "required" : [ "playerName", "showfps", "music", "sound", "encoding", "swipe", "saveRandomMaps", "saveFrequency", "notifications", "extraDump" ], + "required" : [ + "playerName", + "showfps", + "music", + "sound", + "encoding", + "swipe", + "saveRandomMaps", + "saveFrequency", + "notifications", + "extraDump", + "userRelativePointer", + "relativePointerSpeedMultiplier" + ], "properties" : { "playerName" : { "type":"string", @@ -70,6 +83,14 @@ "extraDump" : { "type" : "boolean", "default" : false + }, + "userRelativePointer" : { + "type" : "boolean", + "default" : false + }, + "relativePointerSpeedMultiplier" : { + "type" : "number", + "default" : 1 } } }, From 9a765e5f679ae41c44b0c0c0b077171aa4c41bf1 Mon Sep 17 00:00:00 2001 From: Andrii Danylchenko Date: Wed, 18 Jan 2023 18:15:04 +0200 Subject: [PATCH 40/54] Remove not supported method, allow relative mode for iOS --- client/CMT.cpp | 2 ++ client/gui/CGuiHandler.cpp | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/client/CMT.cpp b/client/CMT.cpp index a871e5f02..828ef9ae8 100644 --- a/client/CMT.cpp +++ b/client/CMT.cpp @@ -437,11 +437,13 @@ int main(int argc, char * argv[]) SDL_SetHint(SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK, "1"); #endif +#ifdef SDL_HINT_MOUSE_TOUCH_EVENTS if(GH.isPointerRelativeMode) { SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0"); SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); } +#endif #ifndef VCMI_NO_THREADED_LOAD //we can properly play intro only in the main thread, so we have to move loading to the separate thread diff --git a/client/gui/CGuiHandler.cpp b/client/gui/CGuiHandler.cpp index 566e213fa..68f9468db 100644 --- a/client/gui/CGuiHandler.cpp +++ b/client/gui/CGuiHandler.cpp @@ -268,12 +268,17 @@ void CGuiHandler::fakeMouseButtonEventRelativeMode(bool down, bool right) sme.x = CCS->curh->xpos; sme.y = CCS->curh->ypos; - int windowX, windowY; + float xScale, yScale; + int w, h, rLogicalWidth, rLogicalHeight; - SDL_RenderLogicalToWindow(mainRenderer, sme.x, sme.y, &windowX, &windowY); + SDL_GetWindowSize(mainWindow, &w, &h); + SDL_RenderGetLogicalSize(mainRenderer, &rLogicalWidth, &rLogicalHeight); + SDL_RenderGetScale(mainRenderer, &xScale, &yScale); SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); - SDL_WarpMouse(windowX, windowY); + SDL_WarpMouse( + (int)(sme.x * xScale) + (w - rLogicalWidth * xScale) / 2, + (int)(sme.y * yScale + (h - rLogicalHeight * yScale) / 2)); SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE); event.button = sme; @@ -430,7 +435,6 @@ void CGuiHandler::handleCurrentEvent() } } } -#ifndef VCMI_IOS else if(current->type == SDL_FINGERMOTION) { if(isPointerRelativeMode) @@ -453,12 +457,14 @@ void CGuiHandler::handleCurrentEvent() fakeMouseButtonEventRelativeMode(true, isRightClick); } } +#ifndef VCMI_IOS else if(fingerCount == 2) { convertTouchToMouse(current); handleMouseMotion(); handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, true); } +#endif //VCMI_IOS } else if(current->type == SDL_FINGERUP) { @@ -473,6 +479,7 @@ void CGuiHandler::handleCurrentEvent() fakeMouseButtonEventRelativeMode(false, isRightClick); } } +#ifndef VCMI_IOS else if(multifinger) { convertTouchToMouse(current); @@ -480,8 +487,8 @@ void CGuiHandler::handleCurrentEvent() handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, false); multifinger = fingerCount != 0; } - } #endif //VCMI_IOS + } current = nullptr; } //event end From 54d62a5eb975144877c08d334001b86c05e09a1f Mon Sep 17 00:00:00 2001 From: Dydzio Date: Mon, 16 Jan 2023 21:47:08 +0100 Subject: [PATCH 41/54] Fix roads and rivers saving in map editor --- lib/mapping/MapFormatJson.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mapping/MapFormatJson.cpp b/lib/mapping/MapFormatJson.cpp index 0d58beff5..ad47bf732 100644 --- a/lib/mapping/MapFormatJson.cpp +++ b/lib/mapping/MapFormatJson.cpp @@ -1292,10 +1292,10 @@ std::string CMapSaverJson::writeTerrainTile(const TerrainTile & tile) out << tile.terType->typeCode << (int)tile.terView << flipCodes[tile.extTileFlags % 4]; if(tile.roadType->id != Road::NO_ROAD) - out << tile.roadType << (int)tile.roadDir << flipCodes[(tile.extTileFlags >> 4) % 4]; + out << tile.roadType->code << (int)tile.roadDir << flipCodes[(tile.extTileFlags >> 4) % 4]; if(tile.riverType->id != River::NO_RIVER) - out << tile.riverType << (int)tile.riverDir << flipCodes[(tile.extTileFlags >> 2) % 4]; + out << tile.riverType->code << (int)tile.riverDir << flipCodes[(tile.extTileFlags >> 2) % 4]; return out.str(); } From 1b3c07eda4a5ec24bbe8eef6e8a537779dc77432 Mon Sep 17 00:00:00 2001 From: Andrey Filipenkov Date: Thu, 19 Jan 2023 20:35:32 +0300 Subject: [PATCH 42/54] buy units starting from the highest level in the "buy all units" dialog --- client/windows/QuickRecruitmentWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/windows/QuickRecruitmentWindow.cpp b/client/windows/QuickRecruitmentWindow.cpp index e6ffb7492..07751d314 100644 --- a/client/windows/QuickRecruitmentWindow.cpp +++ b/client/windows/QuickRecruitmentWindow.cpp @@ -101,7 +101,7 @@ void QuickRecruitmentWindow::maxAllCards(std::vectorslider->getValue()) { From 11ec500dff8ad0e5584e010533d4850a033e7c90 Mon Sep 17 00:00:00 2001 From: Andrey Filipenkov Date: Sun, 22 Jan 2023 15:34:16 +0300 Subject: [PATCH 43/54] [iOS] use pinch gesture as Spacebar hotkey instead of Tab --- client/ios/GameChatKeyboardHandler.h | 4 +++- client/ios/GameChatKeyboardHandler.m | 36 ++++++++++++++-------------- client/ios/startSDL.mm | 2 +- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/client/ios/GameChatKeyboardHandler.h b/client/ios/GameChatKeyboardHandler.h index 01d8fd694..6d8f23c87 100644 --- a/client/ios/GameChatKeyboardHandler.h +++ b/client/ios/GameChatKeyboardHandler.h @@ -10,11 +10,13 @@ #import +#include + NS_ASSUME_NONNULL_BEGIN @interface GameChatKeyboardHandler : NSObject -- (void)triggerInput; ++ (void)sendKeyEventWithKeyCode:(SDL_KeyCode)keyCode; @end diff --git a/client/ios/GameChatKeyboardHandler.m b/client/ios/GameChatKeyboardHandler.m index 276ece8bb..4b1143caf 100644 --- a/client/ios/GameChatKeyboardHandler.m +++ b/client/ios/GameChatKeyboardHandler.m @@ -10,20 +10,8 @@ #import "GameChatKeyboardHandler.h" -#include - static int watchReturnKey(void * userdata, SDL_Event * event); -static void sendKeyEvent(SDL_KeyCode keyCode) -{ - SDL_Event keyEvent; - keyEvent.key = (SDL_KeyboardEvent){ - .type = SDL_KEYDOWN, - .keysym.sym = keyCode, - }; - SDL_PushEvent(&keyEvent); -} - @interface GameChatKeyboardHandler () @property (nonatomic) BOOL wasChatMessageSent; @@ -31,28 +19,40 @@ static void sendKeyEvent(SDL_KeyCode keyCode) @implementation GameChatKeyboardHandler -- (void)triggerInput { ++ (void)sendKeyEventWithKeyCode:(SDL_KeyCode)keyCode +{ + SDL_Event keyEvent; + keyEvent.key = (SDL_KeyboardEvent){ + .type = SDL_KEYDOWN, + .state = SDL_PRESSED, + .keysym.sym = keyCode, + }; + SDL_PushEvent(&keyEvent); +} + +- (instancetype)init { + self = [super init]; + __auto_type notificationCenter = NSNotificationCenter.defaultCenter; [notificationCenter addObserver:self selector:@selector(textDidBeginEditing:) name:UITextFieldTextDidBeginEditingNotification object:nil]; [notificationCenter addObserver:self selector:@selector(textDidEndEditing:) name:UITextFieldTextDidEndEditingNotification object:nil]; - self.wasChatMessageSent = NO; - sendKeyEvent(SDLK_TAB); + return self; } #pragma mark - Notifications - (void)textDidBeginEditing:(NSNotification *)n { + self.wasChatMessageSent = NO; + // watch for pressing Return to ignore sending Escape key after keyboard is closed SDL_AddEventWatch(watchReturnKey, (__bridge void *)self); } - (void)textDidEndEditing:(NSNotification *)n { - [NSNotificationCenter.defaultCenter removeObserver:self]; - // discard chat message if(!self.wasChatMessageSent) - sendKeyEvent(SDLK_ESCAPE); + [[self class] sendKeyEventWithKeyCode:SDLK_ESCAPE]; } @end diff --git a/client/ios/startSDL.mm b/client/ios/startSDL.mm index c9ada242b..ce2dbd0a6 100644 --- a/client/ios/startSDL.mm +++ b/client/ios/startSDL.mm @@ -95,7 +95,7 @@ - (void)handlePinch:(UIGestureRecognizer *)gesture { if(gesture.state != UIGestureRecognizerStateBegan || CSH->state != EClientState::GAMEPLAY) return; - [self.gameChatHandler triggerInput]; + [GameChatKeyboardHandler sendKeyEventWithKeyCode:SDLK_SPACE]; } #pragma mark - UIGestureRecognizerDelegate From 5b10903116049ecdf881acde9729547eb8e682da Mon Sep 17 00:00:00 2001 From: Andrey Filipenkov Date: Tue, 24 Jan 2023 18:35:07 +0300 Subject: [PATCH 44/54] reorder growth bonuses display to match oh3 --- lib/mapObjects/CGTownInstance.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index bb6a0bb8c..c5dee423e 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/lib/mapObjects/CGTownInstance.cpp @@ -553,24 +553,23 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const if(hasBuilt(BuildingID::HORDE_2)) ret.entries.push_back(GrowthInfo::Entry(subID, BuildingID::HORDE_2, creature->hordeGrowth)); - int dwellingBonus = 0; - if(const PlayerState *p = cb->getPlayerState(tempOwner, false)) - { - dwellingBonus = getDwellingBonus(creatures[level].second, p->dwellings); - } - - if(dwellingBonus) - ret.entries.push_back(GrowthInfo::Entry(VLC->generaltexth->allTexts[591], dwellingBonus));// \nExternal dwellings %+d + //statue-of-legion-like bonus: % to base+castle + TConstBonusListPtr bonuses2 = getBonuses(Selector::type()(Bonus::CREATURE_GROWTH_PERCENT)); + for(const auto & b : *bonuses2) + ret.entries.push_back(GrowthInfo::Entry(b->val * (base + castleBonus) / 100, b->Description())); //other *-of-legion-like bonuses (%d to growth cumulative with grail) TConstBonusListPtr bonuses = getBonuses(Selector::type()(Bonus::CREATURE_GROWTH).And(Selector::subtype()(level))); for(const auto & b : *bonuses) ret.entries.push_back(GrowthInfo::Entry(b->val, b->Description())); - //statue-of-legion-like bonus: % to base+castle - TConstBonusListPtr bonuses2 = getBonuses(Selector::type()(Bonus::CREATURE_GROWTH_PERCENT)); - for(const auto & b : *bonuses2) - ret.entries.push_back(GrowthInfo::Entry(b->val * (base + castleBonus) / 100, b->Description())); + int dwellingBonus = 0; + if(const PlayerState *p = cb->getPlayerState(tempOwner, false)) + { + dwellingBonus = getDwellingBonus(creatures[level].second, p->dwellings); + } + if(dwellingBonus) + ret.entries.push_back(GrowthInfo::Entry(VLC->generaltexth->allTexts[591], dwellingBonus));// \nExternal dwellings %+d if(hasBuilt(BuildingID::GRAIL)) //grail - +50% to ALL (so far added) growth ret.entries.push_back(GrowthInfo::Entry(subID, BuildingID::GRAIL, ret.totalGrowth() / 2)); From 90cb0cdc9b8287bb38c7a5253c3bae6ebd8733e0 Mon Sep 17 00:00:00 2001 From: Andrey Filipenkov Date: Tue, 24 Jan 2023 18:35:30 +0300 Subject: [PATCH 45/54] fix displaying growth bonus from Statue of Legion --- lib/HeroBonus.cpp | 6 +++--- lib/HeroBonus.h | 2 +- lib/mapObjects/CGTownInstance.cpp | 5 ++++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/HeroBonus.cpp b/lib/HeroBonus.cpp index 34e26ecc4..99fc2f07b 100644 --- a/lib/HeroBonus.cpp +++ b/lib/HeroBonus.cpp @@ -1576,7 +1576,7 @@ bool NBonus::hasOfType(const CBonusSystemNode *obj, Bonus::BonusType type, int s return false; } -std::string Bonus::Description() const +std::string Bonus::Description(boost::optional customValue) const { std::ostringstream str; @@ -1615,8 +1615,8 @@ std::string Bonus::Description() const str << description; } - if(val != 0) - str << " " << std::showpos << val; + if(auto value = customValue.value_or(val)) + str << " " << std::showpos << value; return str.str(); } diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index ef256cc77..ba47c93a8 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -510,7 +510,7 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this return (high << 16) + low; } - std::string Description() const; + std::string Description(boost::optional customValue = {}) const; JsonNode toJsonNode() const; std::string nameForBonus() const; // generate suitable name for bonus - e.g. for storing in json struct diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index c5dee423e..612f4459d 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/lib/mapObjects/CGTownInstance.cpp @@ -556,7 +556,10 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const //statue-of-legion-like bonus: % to base+castle TConstBonusListPtr bonuses2 = getBonuses(Selector::type()(Bonus::CREATURE_GROWTH_PERCENT)); for(const auto & b : *bonuses2) - ret.entries.push_back(GrowthInfo::Entry(b->val * (base + castleBonus) / 100, b->Description())); + { + const auto growth = b->val * (base + castleBonus) / 100; + ret.entries.push_back(GrowthInfo::Entry(growth, b->Description(growth))); + } //other *-of-legion-like bonuses (%d to growth cumulative with grail) TConstBonusListPtr bonuses = getBonuses(Selector::type()(Bonus::CREATURE_GROWTH).And(Selector::subtype()(level))); From 9addc83a6b7ea0fca0161134bb839508ec65b5f5 Mon Sep 17 00:00:00 2001 From: Andrey Filipenkov Date: Thu, 11 Aug 2022 15:15:20 +0300 Subject: [PATCH 46/54] generate ipa file with CPack directly --- CI/ios/post_pack.sh | 3 --- CMakeLists.txt | 1 + ios/zip2ipa.sh | 9 --------- 3 files changed, 1 insertion(+), 12 deletions(-) delete mode 100755 CI/ios/post_pack.sh delete mode 100755 ios/zip2ipa.sh diff --git a/CI/ios/post_pack.sh b/CI/ios/post_pack.sh deleted file mode 100755 index 8fc66bd3d..000000000 --- a/CI/ios/post_pack.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -"$1/ios/zip2ipa.sh" "$2" diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a71610aa..f736ce6d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -621,6 +621,7 @@ elseif(APPLE_MACOS AND NOT ENABLE_MONOLITHIC_INSTALL) add_subdirectory(osx) elseif(APPLE_IOS) set(CPACK_GENERATOR ZIP) + set(CPACK_ARCHIVE_FILE_EXTENSION ipa) set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF) set(CPACK_INSTALL_CMAKE_PROJECTS "${CMAKE_CURRENT_BINARY_DIR};${CMAKE_PROJECT_NAME};app;/") else() diff --git a/ios/zip2ipa.sh b/ios/zip2ipa.sh deleted file mode 100755 index 2c37459d1..000000000 --- a/ios/zip2ipa.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -generatedZip="$1" -if [[ -z "$generatedZip" ]]; then - echo 'generated zip not provided as param' - exit 1 -fi - -mv "$generatedZip" "$(basename "$generatedZip" .zip).ipa" From 035851bb380747c01e3e925f985966879eec6051 Mon Sep 17 00:00:00 2001 From: Andrey Filipenkov Date: Tue, 24 Jan 2023 20:18:09 +0300 Subject: [PATCH 47/54] add max version condition to Xcode workaround --- client/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 07fd813ae..174ffb1ed 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -234,8 +234,7 @@ elseif(APPLE_IOS) set_source_files_properties(${XCODE_RESOURCE_PATH} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) # workaround to prevent CMAKE_SKIP_PRECOMPILE_HEADERS being added as compile flag - # add max version condition when https://gitlab.kitware.com/cmake/cmake/-/merge_requests/7562 is merged - if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.22.0") + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.22.0" AND CMAKE_VERSION VERSION_LESS "3.25.0") set_source_files_properties(${XCODE_RESOURCE_PATH} PROPERTIES LANGUAGE CXX) endif() endforeach() From 4cfc93d2da700b9da33693a0dc7a73b2190af4b8 Mon Sep 17 00:00:00 2001 From: Andrii Danylchenko Date: Wed, 25 Jan 2023 08:59:59 +0200 Subject: [PATCH 48/54] Somehow it works but JNI signatures were incorrect --- client/Client.cpp | 8 ++++---- lib/CAndroidVMHelper.cpp | 2 +- server/CVCMIServer.cpp | 11 +++++++++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/client/Client.cpp b/client/Client.cpp index ded4b4d82..8a47e6920 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -771,14 +771,14 @@ void CClient::reinitScripting() } #ifdef VCMI_ANDROID -extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_clientSetupJNI(JNIEnv * env, jobject cls) +extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_clientSetupJNI(JNIEnv * env, jclass cls) { logNetwork->info("Received clientSetupJNI"); CAndroidVMHelper::cacheVM(env); } -extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerClosed(JNIEnv * env, jobject cls) +extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerClosed(JNIEnv * env, jclass cls) { logNetwork->info("Received server closed signal"); if (CSH) { @@ -786,13 +786,13 @@ extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerCl } } -extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerReady(JNIEnv * env, jobject cls) +extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerReady(JNIEnv * env, jclass cls) { logNetwork->info("Received server ready signal"); androidTestServerReadyFlag.store(true); } -extern "C" JNIEXPORT bool JNICALL Java_eu_vcmi_vcmi_NativeMethods_tryToSaveTheGame(JNIEnv * env, jobject cls) +extern "C" JNIEXPORT jboolean JNICALL Java_eu_vcmi_vcmi_NativeMethods_tryToSaveTheGame(JNIEnv * env, jclass cls) { logGlobal->info("Received emergency save game request"); if(!LOCPLINT || !LOCPLINT->cb) diff --git a/lib/CAndroidVMHelper.cpp b/lib/CAndroidVMHelper.cpp index 6ac49e164..b2d19eba7 100644 --- a/lib/CAndroidVMHelper.cpp +++ b/lib/CAndroidVMHelper.cpp @@ -96,7 +96,7 @@ jclass CAndroidVMHelper::findClass(const std::string & name, bool classloaded) return get()->FindClass(name.c_str()); } -extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_initClassloader(JNIEnv * baseEnv, jobject * cls) +extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_initClassloader(JNIEnv * baseEnv, jclass cls) { CAndroidVMHelper::cacheVM(baseEnv); CAndroidVMHelper envHelper; diff --git a/server/CVCMIServer.cpp b/server/CVCMIServer.cpp index b00935eb9..30d204985 100644 --- a/server/CVCMIServer.cpp +++ b/server/CVCMIServer.cpp @@ -28,6 +28,8 @@ #include "../lib/mapping/CMap.h" #include "../lib/rmg/CMapGenOptions.h" #ifdef VCMI_ANDROID +#include +#include #include "lib/CAndroidVMHelper.h" #elif !defined(VCMI_IOS) #include "../lib/Interprocess.h" @@ -1118,12 +1120,21 @@ int main(int argc, char * argv[]) } #ifdef VCMI_ANDROID + +extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_createServer(JNIEnv * env, jclass cls) +{ + __android_log_write(ANDROID_LOG_INFO, "VCMI", "Got jni call to init server"); + CAndroidVMHelper::cacheVM(env); + CVCMIServer::create(); +} + void CVCMIServer::create() { const char * foo = "android-server"; std::vector argv = {foo}; main(argv.size(), reinterpret_cast(const_cast(&*argv.begin()))); } + #elif defined(SINGLE_PROCESS_APP) void CVCMIServer::create(boost::condition_variable * cond, const std::vector & args) { From c097b6e8b99710920fa41f3c800ea2b574a572d4 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 31 Jan 2023 15:40:53 +0200 Subject: [PATCH 49/54] Added changelog for 1.1.1 --- ChangeLog | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/ChangeLog b/ChangeLog index 458aaf000..c37d9e80b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +# 1.1.0 -> 1.1.1 + +### GENERAL: +* Fixed missing sound in Polish version from gog.com +* Fixed positioning of main menu buttons in localized versions of H3 +* Fixed crash on transferring artifact to commander +* Fixed game freeze on receiving multiple artifact assembly dialogs after combat +* Fixed potential game freeze on end of music playback + +### ADVENTURE MAP: +* Fixed hero movement lag in single-player games +* Fixed number of drowned troops on visiting Sirens to match H3 + +### TOWNS: +* Fixed displaying growth bonus from Statue of Legion +* Growth bonus tooltip ordering now matches H3 +* Buy All Units dialog will now buy units starting from the highest level + +### LAUNCHER: +* Local mods can be disabled or uninstalled +* Fixed styling of Launcher interface + +### MAP EDITOR: +* Fixed saving of roads and rivers + 1.0.0 -> 1.1.0 GENERAL: From 5d6a16efd8a0dd47e80034105b20391f26b31561 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 31 Jan 2023 16:39:43 +0200 Subject: [PATCH 50/54] Updated 1.1.1 changelog Co-authored-by: Andrey Filipenkov --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index c37d9e80b..1af48f4d2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,10 +6,12 @@ * Fixed crash on transferring artifact to commander * Fixed game freeze on receiving multiple artifact assembly dialogs after combat * Fixed potential game freeze on end of music playback +* macOS/iOS: fixed sound glitches ### ADVENTURE MAP: * Fixed hero movement lag in single-player games * Fixed number of drowned troops on visiting Sirens to match H3 +* iOS: pinch gesture visits current object (Spacebar behavior) instead of activating in-game console ### TOWNS: * Fixed displaying growth bonus from Statue of Legion From 0c3b75597cf619776fd5311ea0c7772d4d6a35ac Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 31 Jan 2023 19:52:26 +0200 Subject: [PATCH 51/54] Update ChangeLog --- ChangeLog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ChangeLog b/ChangeLog index 1af48f4d2..b3685cf28 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,9 @@ * Fixed game freeze on receiving multiple artifact assembly dialogs after combat * Fixed potential game freeze on end of music playback * macOS/iOS: fixed sound glitches +* Android: upgraded version of SDL library +* Android: reworked right click gesture and relative pointer mode +* Improved map loading speed ### ADVENTURE MAP: * Fixed hero movement lag in single-player games From 0d60b87f3b0486c896cc1b0c5cc2a37d4e5687cc Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 31 Jan 2023 23:43:43 +0200 Subject: [PATCH 52/54] Fix assignment of hero type on object creation --- mapeditor/inspector/inspector.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mapeditor/inspector/inspector.cpp b/mapeditor/inspector/inspector.cpp index e575f660a..7dd6986f3 100644 --- a/mapeditor/inspector/inspector.cpp +++ b/mapeditor/inspector/inspector.cpp @@ -109,7 +109,8 @@ void Initializer::initialize(CGLighthouse * o) void Initializer::initialize(CGHeroInstance * o) { - if(!o) return; + if(!o) + return; o->tempOwner = defaultPlayer; if(o->ID == Obj::PRISON) @@ -119,9 +120,9 @@ void Initializer::initialize(CGHeroInstance * o) { for(auto t : VLC->heroh->objects) { - if(t->heroClass == VLC->heroh->classes.objects[o->subID].get()) + if(t->heroClass->getId() == HeroClassID(o->subID)) { - o->type = VLC->heroh->objects[o->subID]; + o->type = t; break; } } From 03f65bc24f2380bcb3bca952131075030c646bc8 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Thu, 2 Feb 2023 00:52:17 +0200 Subject: [PATCH 53/54] Update changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index b3685cf28..3f67f526c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -27,6 +27,7 @@ ### MAP EDITOR: * Fixed saving of roads and rivers +* Fixed placement of heroes on map 1.0.0 -> 1.1.0 From 0a63014041598fce2d8d3f0aa2555f4013dd2d3e Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Thu, 2 Feb 2023 00:52:35 +0200 Subject: [PATCH 54/54] Add 1.1.1 release information --- debian/changelog | 6 ++++++ launcher/eu.vcmi.VCMI.metainfo.xml | 1 + 2 files changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index 148a70e2f..8aa31b312 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +vcmi (1.1.1) jammy; urgency=medium + + * New upstream release + + -- Ivan Savenko Fri, 03 Feb 2023 12:00:00 +0200 + vcmi (1.1.0) jammy; urgency=medium * New upstream release diff --git a/launcher/eu.vcmi.VCMI.metainfo.xml b/launcher/eu.vcmi.VCMI.metainfo.xml index 227abec6c..6b51bed1b 100644 --- a/launcher/eu.vcmi.VCMI.metainfo.xml +++ b/launcher/eu.vcmi.VCMI.metainfo.xml @@ -38,6 +38,7 @@ https://github.com/vcmi/vcmi/issues https://vcmi.eu/faq/ +