From ab232d15699d6bc87dfef3e9ff4985bc502d346c Mon Sep 17 00:00:00 2001 From: florianessl Date: Sun, 3 Mar 2024 16:25:54 +0100 Subject: [PATCH 1/4] Simple implementation for AntiLagSwitch --- src/game_config_game.cpp | 10 ++++++++++ src/game_config_game.h | 1 + src/game_map.cpp | 4 ++++ src/player.cpp | 6 ++++-- 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/game_config_game.cpp b/src/game_config_game.cpp index 359158a33e..6ce8f9382c 100644 --- a/src/game_config_game.cpp +++ b/src/game_config_game.cpp @@ -87,6 +87,7 @@ void Game_ConfigGame::LoadFromArgs(CmdlineParser& cp) { patch_common_this_event.Lock(false); patch_key_patch.Lock(false); patch_rpg2k3_commands.Lock(false); + patch_anti_lag_switch.Lock(false); patch_override = true; continue; } @@ -105,6 +106,11 @@ void Game_ConfigGame::LoadFromArgs(CmdlineParser& cp) { patch_key_patch.Set(true); } else if (v == "rpg2k3-cmds" || v == "rpg2k3-commands") { patch_rpg2k3_commands.Set(true); + } else if (v.rfind("anti-lag-switch=") == 0) { + int num = static_cast(std::strtol(v.substr(16).c_str(), nullptr, 0)); + if (num > 0) { + patch_anti_lag_switch.Set(num); + } } } patch_override = true; @@ -151,4 +157,8 @@ void Game_ConfigGame::LoadFromStream(Filesystem_Stream::InputStream& is) { if (patch_rpg2k3_commands.FromIni(ini)) { patch_override = true; } + + if (patch_anti_lag_switch.FromIni(ini)) { + patch_override = true; + } } diff --git a/src/game_config_game.h b/src/game_config_game.h index 3064a2d3cb..c91d5d1e22 100644 --- a/src/game_config_game.h +++ b/src/game_config_game.h @@ -44,6 +44,7 @@ struct Game_ConfigGame { BoolConfigParam patch_unlock_pics{ "Unlock Pictures", "Allow picture commands while a message is shown", "Patch", "PicUnlock", false }; BoolConfigParam patch_key_patch{ "Ineluki Key Patch", "Support \"Ineluki Key Patch\"", "Patch", "KeyPatch", false }; BoolConfigParam patch_rpg2k3_commands{ "RPG2k3 Event Commands", "Enable support for RPG2k3 event commands", "Patch", "RPG2k3Commands", false }; + ConfigParam patch_anti_lag_switch{ "Anti-Lag Switch", "Disable event page refreshes when switch is set", "Patch", "AntiLagSwitch", 0 }; // Command line only BoolConfigParam patch_support{ "Support patches", "When OFF all patch support is disabled", "", "", true }; diff --git a/src/game_map.cpp b/src/game_map.cpp index 29858b3133..486273f080 100644 --- a/src/game_map.cpp +++ b/src/game_map.cpp @@ -1512,6 +1512,10 @@ void Game_Map::SetPositionY(int y, bool reset_panorama) { } bool Game_Map::GetNeedRefresh() { + if (Player::game_config.patch_anti_lag_switch.Get() && Main_Data::game_switches->Get(Player::game_config.patch_anti_lag_switch.Get())) { + return false; + } + return need_refresh; } diff --git a/src/player.cpp b/src/player.cpp index 2279b02d49..72a87d3c94 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -825,8 +825,8 @@ void Player::CreateGameObjects() { } } - Output::Debug("Patch configuration: dynrpg={} maniac={} key-patch={} common-this={} pic-unlock={} 2k3-commands={}", - Player::IsPatchDynRpg(), Player::IsPatchManiac(), Player::IsPatchKeyPatch(), game_config.patch_common_this_event.Get(), game_config.patch_unlock_pics.Get(), game_config.patch_rpg2k3_commands.Get()); + Output::Debug("Patch configuration: dynrpg={} maniac={} key-patch={} common-this={} pic-unlock={} 2k3-commands={} anti-lag-switch={}", + Player::IsPatchDynRpg(), Player::IsPatchManiac(), Player::IsPatchKeyPatch(), game_config.patch_common_this_event.Get(), game_config.patch_unlock_pics.Get(), game_config.patch_rpg2k3_commands.Get(), game_config.patch_anti_lag_switch.Get()); ResetGameObjects(); @@ -1403,6 +1403,8 @@ Engine options: pic-unlock - Pictures are not blocked by messages rpg2k3-cmds - Support all RPG Maker 2003 event commands in any version of the engine + anti-lag-switch=[switch-id] + - Disable event page refreshes via switch --no-patch Disable all engine patches. --project-path PATH Instead of using the working directory, the game in PATH is used. From 74bb6600f60ebe7b8a45aedc61a47dbfc3595f4f Mon Sep 17 00:00:00 2001 From: florianessl Date: Sun, 3 Mar 2024 16:26:47 +0100 Subject: [PATCH 2/4] Implemented experimental "map event caches" to drastically increase performance when doing a lot of operations with game_switches & game_variables --- src/game_interpreter.cpp | 29 +++++++++++--------- src/game_map.cpp | 57 +++++++++++++++++++++++++++++++++++++++- src/game_map.h | 14 ++++++++++ 3 files changed, 87 insertions(+), 13 deletions(-) diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index acb5227440..12fe1c7b57 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -441,7 +441,7 @@ void Game_Interpreter::Update(bool reset_loop_count) { const int key = _keyinput.CheckInput(); Main_Data::game_variables->Set(_keyinput.variable, key); - Game_Map::SetNeedRefresh(true); + Game_Map::SetNeedRefreshForVarChange(_keyinput.variable); if (key == 0) { ++_keyinput.wait_frames; break; @@ -1066,15 +1066,15 @@ bool Game_Interpreter::CommandControlSwitches(lcf::rpg::EventCommand const& com) } else { Main_Data::game_switches->Flip(start); } + Game_Map::SetNeedRefreshForSwitchChange(start); } else { if (val < 2) { Main_Data::game_switches->SetRange(start, end, val == 0); } else { Main_Data::game_switches->FlipRange(start, end); } + Game_Map::SetNeedRefresh(true); } - - Game_Map::SetNeedRefresh(true); } return true; @@ -1338,6 +1338,7 @@ bool Game_Interpreter::CommandControlVariables(lcf::rpg::EventCommand const& com Main_Data::game_variables->BitShiftRight(start, value); break; } + Game_Map::SetNeedRefreshForVarChange(start); } else if (com.parameters[4] == 1) { // Multiple variables - Direct variable lookup int var_id = com.parameters[5]; @@ -1376,6 +1377,7 @@ bool Game_Interpreter::CommandControlVariables(lcf::rpg::EventCommand const& com Main_Data::game_variables->BitShiftRightRangeVariable(start, end, var_id); break; } + Game_Map::SetNeedRefresh(true); } else if (com.parameters[4] == 2) { // Multiple variables - Indirect variable lookup int var_id = com.parameters[5]; @@ -1414,6 +1416,7 @@ bool Game_Interpreter::CommandControlVariables(lcf::rpg::EventCommand const& com Main_Data::game_variables->BitShiftRightRangeVariableIndirect(start, end, var_id); break; } + Game_Map::SetNeedRefresh(true); } else if (com.parameters[4] == 3) { // Multiple variables - random int rmax = max(com.parameters[5], com.parameters[6]); @@ -1453,6 +1456,7 @@ bool Game_Interpreter::CommandControlVariables(lcf::rpg::EventCommand const& com Main_Data::game_variables->BitShiftRightRangeRandom(start, end, rmin, rmax); break; } + Game_Map::SetNeedRefresh(true); } else { // Multiple variables - constant switch (operation) { @@ -1490,9 +1494,8 @@ bool Game_Interpreter::CommandControlVariables(lcf::rpg::EventCommand const& com Main_Data::game_variables->BitShiftRightRange(start, end, value); break; } + Game_Map::SetNeedRefresh(true); } - - Game_Map::SetNeedRefresh(true); } return true; @@ -2284,7 +2287,9 @@ bool Game_Interpreter::CommandMemorizeLocation(lcf::rpg::EventCommand const& com Main_Data::game_variables->Set(var_map_id, Game_Map::GetMapId()); Main_Data::game_variables->Set(var_x, player->GetX()); Main_Data::game_variables->Set(var_y, player->GetY()); - Game_Map::SetNeedRefresh(true); + Game_Map::SetNeedRefreshForVarChange(var_map_id); + Game_Map::SetNeedRefreshForVarChange(var_x); + Game_Map::SetNeedRefreshForVarChange(var_y); return true; } @@ -2394,7 +2399,7 @@ bool Game_Interpreter::CommandStoreTerrainID(lcf::rpg::EventCommand const& com) int y = ValueOrVariable(com.parameters[0], com.parameters[2]); int var_id = com.parameters[3]; Main_Data::game_variables->Set(var_id, Game_Map::GetTerrainTag(x, y)); - Game_Map::SetNeedRefresh(true); + Game_Map::SetNeedRefreshForVarChange(var_id); return true; } @@ -2404,7 +2409,7 @@ bool Game_Interpreter::CommandStoreEventID(lcf::rpg::EventCommand const& com) { int var_id = com.parameters[3]; auto* ev = Game_Map::GetEventAt(x, y, false); Main_Data::game_variables->Set(var_id, ev ? ev->GetId() : 0); - Game_Map::SetNeedRefresh(true); + Game_Map::SetNeedRefreshForVarChange(var_id); return true; } @@ -3200,7 +3205,7 @@ bool Game_Interpreter::CommandKeyInputProc(lcf::rpg::EventCommand const& com) { if (wait) { // While waiting the variable is reset to 0 each frame. Main_Data::game_variables->Set(var_id, 0); - Game_Map::SetNeedRefresh(true); + Game_Map::SetNeedRefreshForVarChange(var_id); } if (wait && Game_Message::IsMessageActive()) { @@ -3315,7 +3320,7 @@ bool Game_Interpreter::CommandKeyInputProc(lcf::rpg::EventCommand const& com) { int key = _keyinput.CheckInput(); Main_Data::game_variables->Set(_keyinput.variable, key); - Game_Map::SetNeedRefresh(true); + Game_Map::SetNeedRefreshForVarChange(_keyinput.variable); return true; } @@ -3757,7 +3762,7 @@ bool Game_Interpreter::CommandLoop(lcf::rpg::EventCommand const& com) { // code int loop_count_var = com.parameters[4]; if (loop_count_var > 0) { Main_Data::game_variables->Set(loop_count_var, begin_loop_val); - Game_Map::SetNeedRefresh(true); + Game_Map::SetNeedRefreshForVarChange(loop_count_var); } return true; @@ -3844,7 +3849,7 @@ bool Game_Interpreter::CommandEndLoop(lcf::rpg::EventCommand const& com) { // co int loop_count_var = com.parameters[4]; if (loop_count_var > 0) { Main_Data::game_variables->Set(loop_count_var, cur_loop_val); - Game_Map::SetNeedRefresh(true); + Game_Map::SetNeedRefreshForVarChange(loop_count_var); } } diff --git a/src/game_map.cpp b/src/game_map.cpp index 486273f080..26c9c4f237 100644 --- a/src/game_map.cpp +++ b/src/game_map.cpp @@ -72,6 +72,8 @@ namespace { std::vector passages_up; std::vector events; std::vector common_events; + std::unordered_map> events_cache_by_switch; + std::unordered_map> events_cache_by_variable; std::unique_ptr map; @@ -132,6 +134,8 @@ void Game_Map::InitCommonEvents() { void Game_Map::Dispose() { events.clear(); + events_cache_by_switch.clear(); + events_cache_by_variable.clear(); map.reset(); map_info = {}; panorama = {}; @@ -356,9 +360,37 @@ void Game_Map::SetupCommon() { // Create the map events events.reserve(map->events.size()); - for (const auto& ev : map->events) { + for (auto& ev : map->events) { events.emplace_back(GetMapId(), &ev); + + for (const auto& pg : ev.pages) { + if (pg.condition.flags.switch_a) { + AddEventToSwitchCache(ev, pg.condition.switch_a_id); + } + if (pg.condition.flags.switch_b) { + AddEventToSwitchCache(ev, pg.condition.switch_b_id); + } + if (pg.condition.flags.variable) { + AddEventToVariableCache(ev, pg.condition.variable_id); + } + } + } +} + +void Game_Map::AddEventToSwitchCache(lcf::rpg::Event& ev, int switch_id) { + if (events_cache_by_switch.find(switch_id) == events_cache_by_switch.end()) { + std::unique_ptr cache = std::make_unique(); + events_cache_by_switch[switch_id] = std::move(cache); + } + events_cache_by_switch[switch_id]->AddEvent(ev); +} + +void Game_Map::AddEventToVariableCache(lcf::rpg::Event& ev, int var_id) { + if (events_cache_by_variable.find(var_id) == events_cache_by_variable.end()) { + std::unique_ptr cache = std::make_unique(); + events_cache_by_variable[var_id] = std::move(cache); } + events_cache_by_variable[var_id]->AddEvent(ev); } void Game_Map::PrepareSave(lcf::rpg::Save& save) { @@ -1523,6 +1555,29 @@ void Game_Map::SetNeedRefresh(bool refresh) { need_refresh = refresh; } + +void MapEventCache::AddEvent(lcf::rpg::Event& ev) { + for (const auto& ev2 : events) { + if (ev.ID == ev2.ID) + return; + } + events.emplace_back(ev); +} + +void Game_Map::SetNeedRefreshForSwitchChange(int switch_id) { + if (need_refresh) + return; + if (events_cache_by_switch.find(switch_id) != events_cache_by_switch.end()) + SetNeedRefresh(true); +} + +void Game_Map::SetNeedRefreshForVarChange(int var_id) { + if (need_refresh) + return; + if (events_cache_by_variable.find(var_id) != events_cache_by_variable.end()) + SetNeedRefresh(true); +} + std::vector& Game_Map::GetPassagesDown() { return passages_down; } diff --git a/src/game_map.h b/src/game_map.h index 2533347d38..4a6b41f230 100644 --- a/src/game_map.h +++ b/src/game_map.h @@ -73,6 +73,14 @@ class MapUpdateAsyncContext { bool message = false; }; +class MapEventCache { + public: + void AddEvent(lcf::rpg::Event& ev); + + private: + std::vector events; +}; + /** * Game_Map namespace */ @@ -679,6 +687,12 @@ namespace Game_Map { FileRequestAsync* RequestMap(int map_id); + void SetNeedRefreshForSwitchChange(int switch_id); + void SetNeedRefreshForVarChange(int var_id); + + void AddEventToSwitchCache(lcf::rpg::Event& ev, int switch_id); + void AddEventToVariableCache(lcf::rpg::Event& ev, int var_id); + namespace Parallax { struct Params { std::string name; From 2ddbaca9fae317dac0d72f223a7f191548685b53 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Tue, 12 Mar 2024 22:40:28 +0100 Subject: [PATCH 3/4] Use individual cli options for patches. Useful for the anti lag switch and further patches that require an argument. Update documentation. --- resources/unix/easyrpg-player.6.adoc | 57 ++++++++++++++++++--------- src/cmdline_parser.h | 20 +++++++++- src/game_config.cpp | 32 ++++----------- src/game_config_game.cpp | 58 ++++++++++++++++++++++------ src/player.cpp | 33 +++++++++------- 5 files changed, 130 insertions(+), 70 deletions(-) diff --git a/resources/unix/easyrpg-player.6.adoc b/resources/unix/easyrpg-player.6.adoc index 7285d3cd7a..cffb48af30 100644 --- a/resources/unix/easyrpg-player.6.adoc +++ b/resources/unix/easyrpg-player.6.adoc @@ -78,19 +78,36 @@ NOTE: For games that only use ASCII (English games) use '1252'. Disable support for the Runtime Package (RTP). Will lead to checkerboard graphics and silent music/sound effects in games depending on the RTP. -*--patch* _PATCH_A_ [_PATCH_B_ _..._]:: - Instead of autodetecting patches used by this game, force emulation of certain - patches. - - 'common-this' - Support for __This Event__ in common events - - 'dynrpg' - DynRPG patch by Cherry - - 'key-patch' - Key Patch by Ineluki - - 'maniac' - Maniac Patch by BingShan - - 'pic-unlock' - Pictures are not blocked by messages - - 'rpg2k3-cmds' - Support RPG Maker 2003 event commands in all engines +*--patch-anti-lag-switch*:: _SWITCH_ + Disables event page refreshing when the switch 'SWITCH' is set to 'ON'. + +*--patch-common-this*:: + Enable usage of __This Event__ in common events in any version of the engine. + By default, this behaviour is only enabled for RPG Maker 2003 v1.12. + +*--patch-dynrpg*:: + Enable limited support for the DynRPG patch from Cherry. The patches are not + loaded from DLL files, but re-implemented by the engine. + +*--patch-key-patch*:: + Enable support for the Key Patch by Ineluki. + +*--patch-maniac*:: + Enable support for the Maniac Patch by BingShan. + +*--patch-pic-unlock*:: + Picture movement is not interrupted by messages in any version of the engine. + By default, this behaviour is only enabled for RPG Maker 2003 v1.12. + +*--patch-rpg2k3-cmds*:: + Support all RPG Maker 2003 event commands in any version of the engine. *--no-patch*:: Disable all engine patches. +NOTE: Providing any patch option disables the patch autodetection of the engine. +To disable a single patch, prefix any of the patch options with **--no-**. + *--project-path* _PATH_:: Instead of using the working directory, the game in 'PATH' is used. @@ -111,8 +128,7 @@ NOTE: For games that only use ASCII (English games) use '1252'. Instead of storing save files in the game directory they are stored in 'PATH'. The directory must exist. -NOTE: When using the game browser all games will share the same save -directory! +NOTE: When using the game browser all games will share the same save directory! *--seed* _SEED_:: Seeds the random number generator. @@ -282,25 +298,28 @@ Options in section 'Game': *Engine*=_ENGINE_:: Same as *--engine*. -Options in section 'Patch' (see also *--patch*): +Options in section 'Patch' (see also options starting with *--patch*): + +*AntiLagSwitch*=_SWITCH_:: + Same as *--patch-anti-lag-switch* 'SWITCH'. *CommonThisEvent*=_1_:: - Same as *--patch common-this*. + Same as *--patch-common-this*. *DynRPG*=_1_:: - Same as *--patch dynrpg*. + Same as *--patch-dynrpg*. *KeyPatch*=_1_:: - Same as *--patch key-patch*. + Same as *--patch-key-patch*. *Maniac*=_1_:: - Same as *--patch maniac*. + Same as *--patch-maniac*. *PicUnlock*=_1_:: - Same as *--patch pic-unlock*. + Same as *--patch-pic-unlock*. *RPG2k3Commands*=_1_:: - Same as *--patch rpg2k3-commands*. + Same as *--patch-rpg2k3-commands*. NOTE: Providing any patch option disables the patch autodetection of the engine. @@ -344,7 +363,7 @@ Options in section 'RPG_RT': Set a custom screen height. -NOTE: These resolution options invented by the Maniac Patch but they are +NOTE: These resolution options were invented by the Maniac Patch but they are processed even when the patch is disabled. Using a custom resolution disables *--game-resolution*. diff --git a/src/cmdline_parser.h b/src/cmdline_parser.h index 1536661e78..84e30a6f45 100644 --- a/src/cmdline_parser.h +++ b/src/cmdline_parser.h @@ -64,6 +64,24 @@ class CmdlineArg { return ptr[i + 1]; } + /** + * Use this with boolean arguments of structure --option and --no-option + * to decide if the --no- prefix was used or not. + * + * @return Whether the command line argument does not start with --no- + */ + bool ArgIsOn() const { + return !ArgIsOff(); + } + + /** + * @see ArgIsOn + * @return Whether the command line argument starts with --no- + */ + bool ArgIsOff() const { + return Arg().substr(0, 5) == "--no-"; + } + /** * Gets an argument value to an integer * @@ -89,7 +107,7 @@ class CmdlineArg { /** Commandline parser class which is used to search through command line arguments. */ class CmdlineParser { public: - /** + /** * Construct with given arguments * * @param arguments main() argv as vector of strings diff --git a/src/game_config.cpp b/src/game_config.cpp index c7b83450c5..48ba6a3bef 100644 --- a/src/game_config.cpp +++ b/src/game_config.cpp @@ -243,12 +243,8 @@ void Game_Config::LoadFromArgs(CmdlineParser& cp) { long li_value = 0; std::string str_value; - if (cp.ParseNext(arg, 0, "--vsync")) { - video.vsync.Set(true); - continue; - } - if (cp.ParseNext(arg, 0, "--no-vsync")) { - video.vsync.Set(false); + if (cp.ParseNext(arg, 0, {"--vsync", "--no-vsync"})) { + video.vsync.Set(arg.ArgIsOn()); continue; } if (cp.ParseNext(arg, 1, "--fps-limit")) { @@ -261,20 +257,12 @@ void Game_Config::LoadFromArgs(CmdlineParser& cp) { video.fps_limit.Set(0); continue; } - if (cp.ParseNext(arg, 0, "--show-fps")) { - video.show_fps.Set(true); - continue; - } - if (cp.ParseNext(arg, 0, "--no-show-fps")) { - video.show_fps.Set(false); + if (cp.ParseNext(arg, 0, {"--show-fps", "--no-show-fps"})) { + video.show_fps.Set(arg.ArgIsOn()); continue; } - if (cp.ParseNext(arg, 0, "--fps-render-window")) { - video.fps_render_window.Set(true); - continue; - } - if (cp.ParseNext(arg, 0, "--no-fps-render-window")) { - video.fps_render_window.Set(false); + if (cp.ParseNext(arg, 0, {"--fps-render-window", "--no-fps-render-window"})) { + video.fps_render_window.Set(arg.ArgIsOn()); continue; } if (cp.ParseNext(arg, 0, "--window")) { @@ -291,12 +279,8 @@ void Game_Config::LoadFromArgs(CmdlineParser& cp) { } continue; } - if (cp.ParseNext(arg, 0, "--stretch")) { - video.stretch.Set(true); - continue; - } - if (cp.ParseNext(arg, 0, "--no-stretch")) { - video.stretch.Set(false); + if (cp.ParseNext(arg, 0, {"--stretch", "--no-stretch"})) { + video.stretch.Set(arg.ArgIsOn()); continue; } if (cp.ParseNext(arg, 1, "--scaling")) { diff --git a/src/game_config_game.cpp b/src/game_config_game.cpp index 6ce8f9382c..bc44224dd1 100644 --- a/src/game_config_game.cpp +++ b/src/game_config_game.cpp @@ -64,12 +64,10 @@ void Game_ConfigGame::LoadFromArgs(CmdlineParser& cp) { while (!cp.Done()) { CmdlineArg arg; - if (cp.ParseNext(arg, 0, "--new-game")) { - new_game.Set(true); - continue; - } - if (cp.ParseNext(arg, 0, "--no-new-game")) { - new_game.Set(false); + long li_value = 0; + + if (cp.ParseNext(arg, 0, {"--new-game", "--no-new-game"})) { + new_game.Set(arg.ArgIsOn()); continue; } if (cp.ParseNext(arg, 1, "--engine")) { @@ -91,7 +89,50 @@ void Game_ConfigGame::LoadFromArgs(CmdlineParser& cp) { patch_override = true; continue; } + if (cp.ParseNext(arg, 0, {"--patch-dynrpg", "--no-patch-dynrpg"})) { + patch_dynrpg.Set(arg.ArgIsOn()); + patch_override = true; + continue; + } + if (cp.ParseNext(arg, 0, {"--patch-maniac", "--no-patch-maniac"})) { + patch_maniac.Set(arg.ArgIsOn()); + patch_override = true; + continue; + } + if (cp.ParseNext(arg, 0, {"--patch-common-this", "--no-patch-common-this"})) { + patch_common_this_event.Set(arg.ArgIsOn()); + patch_override = true; + continue; + } + if (cp.ParseNext(arg, 0, {"--patch-pic-unlock", "--no-patch-pic-unlock"})) { + patch_unlock_pics.Set(arg.ArgIsOn()); + patch_override = true; + continue; + } + if (cp.ParseNext(arg, 0, {"--patch-key-patch", "--no-patch-key-patch"})) { + patch_key_patch.Set(arg.ArgIsOn()); + patch_override = true; + continue; + } + if (cp.ParseNext(arg, 0, {"--patch-rpg2k3-cmds", "--patch-rpg2k3-commands", "--no-patch-rpg2k3-cmds", "--no-patch-rpg2k3-commands"})) { + patch_rpg2k3_commands.Set(arg.ArgIsOn()); + patch_override = true; + continue; + } + if (cp.ParseNext(arg, 1, "--patch-antilag-switch")) { + if (arg.ParseValue(0, li_value)) { + patch_anti_lag_switch.Set(li_value); + patch_override = true; + } + continue; + } + if (cp.ParseNext(arg, 0, "--no-patch-antilag-switch")) { + patch_anti_lag_switch.Set(0); + patch_override = true; + continue; + } if (cp.ParseNext(arg, 6, "--patch")) { + // For backwards compatibility only for (int i = 0; i < arg.NumValues(); ++i) { const auto& v = arg.Value(i); if (v == "dynrpg") { @@ -106,11 +147,6 @@ void Game_ConfigGame::LoadFromArgs(CmdlineParser& cp) { patch_key_patch.Set(true); } else if (v == "rpg2k3-cmds" || v == "rpg2k3-commands") { patch_rpg2k3_commands.Set(true); - } else if (v.rfind("anti-lag-switch=") == 0) { - int num = static_cast(std::strtol(v.substr(16).c_str(), nullptr, 0)); - if (num > 0) { - patch_anti_lag_switch.Set(num); - } } } patch_override = true; diff --git a/src/player.cpp b/src/player.cpp index 72a87d3c94..ac36d0b7d8 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -612,11 +612,11 @@ Game_Config Player::ParseCommandLine() { } continue; } - if (cp.ParseNext(arg, 0, "--no-audio") || cp.ParseNext(arg, 0, "--disable-audio")) { + if (cp.ParseNext(arg, 0, {"--no-audio", "--disable-audio"})) { no_audio_flag = true; continue; } - if (cp.ParseNext(arg, 0, "--no-rtp") || cp.ParseNext(arg, 0, "--disable-rtp")) { + if (cp.ParseNext(arg, 0, {"--no-rtp", "--disable-rtp"})) { no_rtp_flag = true; continue; } @@ -1393,19 +1393,20 @@ Engine options: --new-game Skip the title scene and start a new game directly. --no-log-color Disable colors in terminal log. --no-rtp Disable support for the Runtime Package (RTP). - --patch PATCH... Instead of autodetecting patches used by this game, force - emulation of certain patches. - Options: - common-this - "This Event" in common events - dynrpg - DynRPG patch by Cherry - key-patch - Key Patch by Ineluki - maniac - Maniac Patch by BingShan - pic-unlock - Pictures are not blocked by messages - rpg2k3-cmds - Support all RPG Maker 2003 event commands - in any version of the engine - anti-lag-switch=[switch-id] - - Disable event page refreshes via switch - --no-patch Disable all engine patches. + --patch-anti-lag-switch SWITCH + Disables event page refreshing when the switch SWITCH is + enabled. + --patch-common-this Enable usage of "This Event" in common events in any + version of the engine. + --patch-dynrpg Enable support of DynRPG patch by Cherry (very limited). + --patch-key-patch Enable Key Patch by Ineluki. + --patch-maniac Enable Maniac Patch by BingShan. + --patch-pic-unlock Picture movement is not interrupted by messages in any + version of the engine. + --patch-rpg2k3-cmds Support all RPG Maker 2003 event commands in any version + of the engine. + --no-patch Disable all engine patches. To disable a single patch, + prefix any of the patch options with --no- --project-path PATH Instead of using the working directory, the game in PATH is used. --record-input FILE Record all button inputs to FILE. @@ -1418,6 +1419,8 @@ Engine options: will share the same save directory! --seed N Seeds the random number generator with N. +Providing any patch option disables the patch autodetection of the engine. + Video options: --fps-limit In combination with --no-vsync sets a custom frames per second limit. The default is 60 FPS. Use --no-fps-limit From 1ed93394bf35052cfda12deec3e62d4a136017f3 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Tue, 12 Mar 2024 23:01:37 +0100 Subject: [PATCH 4/4] Improve MapEventCache data structure. Get rid of the unnecessary pointer. --- src/game_interpreter.cpp | 5 ++-- src/game_map.cpp | 41 ++++++++++++++++------------ src/game_map.h | 59 +++++++++++++++++++++------------------- 3 files changed, 56 insertions(+), 49 deletions(-) diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index 12fe1c7b57..57e03237de 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -450,6 +450,7 @@ void Game_Interpreter::Update(bool reset_loop_count) { // 10 per second Main_Data::game_variables->Set(_keyinput.time_variable, (_keyinput.wait_frames * 10) / Game_Clock::GetTargetGameFps()); + Game_Map::SetNeedRefreshForVarChange(_keyinput.time_variable); } _keyinput.wait = false; } @@ -2287,9 +2288,7 @@ bool Game_Interpreter::CommandMemorizeLocation(lcf::rpg::EventCommand const& com Main_Data::game_variables->Set(var_map_id, Game_Map::GetMapId()); Main_Data::game_variables->Set(var_x, player->GetX()); Main_Data::game_variables->Set(var_y, player->GetY()); - Game_Map::SetNeedRefreshForVarChange(var_map_id); - Game_Map::SetNeedRefreshForVarChange(var_x); - Game_Map::SetNeedRefreshForVarChange(var_y); + Game_Map::SetNeedRefreshForVarChange({var_map_id, var_x, var_y}); return true; } diff --git a/src/game_map.cpp b/src/game_map.cpp index 26c9c4f237..b9cbe26bf8 100644 --- a/src/game_map.cpp +++ b/src/game_map.cpp @@ -17,6 +17,7 @@ // Headers #include +#include #include #include #include @@ -72,8 +73,8 @@ namespace { std::vector passages_up; std::vector events; std::vector common_events; - std::unordered_map> events_cache_by_switch; - std::unordered_map> events_cache_by_variable; + std::unordered_map events_cache_by_switch; + std::unordered_map events_cache_by_variable; std::unique_ptr map; @@ -378,19 +379,11 @@ void Game_Map::SetupCommon() { } void Game_Map::AddEventToSwitchCache(lcf::rpg::Event& ev, int switch_id) { - if (events_cache_by_switch.find(switch_id) == events_cache_by_switch.end()) { - std::unique_ptr cache = std::make_unique(); - events_cache_by_switch[switch_id] = std::move(cache); - } - events_cache_by_switch[switch_id]->AddEvent(ev); + events_cache_by_switch[switch_id].AddEvent(ev); } void Game_Map::AddEventToVariableCache(lcf::rpg::Event& ev, int var_id) { - if (events_cache_by_variable.find(var_id) == events_cache_by_variable.end()) { - std::unique_ptr cache = std::make_unique(); - events_cache_by_variable[var_id] = std::move(cache); - } - events_cache_by_variable[var_id]->AddEvent(ev); + events_cache_by_variable[var_id].AddEvent(ev); } void Game_Map::PrepareSave(lcf::rpg::Save& save) { @@ -1544,7 +1537,8 @@ void Game_Map::SetPositionY(int y, bool reset_panorama) { } bool Game_Map::GetNeedRefresh() { - if (Player::game_config.patch_anti_lag_switch.Get() && Main_Data::game_switches->Get(Player::game_config.patch_anti_lag_switch.Get())) { + int anti_lag_switch = Player::game_config.patch_anti_lag_switch.Get(); + if (anti_lag_switch > 0 && Main_Data::game_switches->Get(anti_lag_switch)) { return false; } @@ -1555,13 +1549,12 @@ void Game_Map::SetNeedRefresh(bool refresh) { need_refresh = refresh; } - void MapEventCache::AddEvent(lcf::rpg::Event& ev) { - for (const auto& ev2 : events) { - if (ev.ID == ev2.ID) - return; + auto id = ev.ID; + + if (std::find(event_ids.begin(), event_ids.end(), id) == event_ids.end()) { + event_ids.emplace_back(id); } - events.emplace_back(ev); } void Game_Map::SetNeedRefreshForSwitchChange(int switch_id) { @@ -1578,6 +1571,18 @@ void Game_Map::SetNeedRefreshForVarChange(int var_id) { SetNeedRefresh(true); } +void Game_Map::SetNeedRefreshForSwitchChange(std::initializer_list switch_ids) { + for (auto switch_id: switch_ids) { + SetNeedRefreshForSwitchChange(switch_id); + } +} + +void Game_Map::SetNeedRefreshForVarChange(std::initializer_list var_ids) { + for (auto var_id: var_ids) { + SetNeedRefreshForVarChange(var_id); + } +} + std::vector& Game_Map::GetPassagesDown() { return passages_down; } diff --git a/src/game_map.h b/src/game_map.h index 4a6b41f230..e9ea966e28 100644 --- a/src/game_map.h +++ b/src/game_map.h @@ -20,6 +20,7 @@ // Headers #include +#include #include #include #include @@ -47,38 +48,38 @@ struct BattleArgs; constexpr int SCREEN_TILE_SIZE = 256; class MapUpdateAsyncContext { - public: - MapUpdateAsyncContext() = default; - - static MapUpdateAsyncContext FromCommonEvent(int ce, AsyncOp aop); - static MapUpdateAsyncContext FromMapEvent(int ce, AsyncOp aop); - static MapUpdateAsyncContext FromForegroundEvent(AsyncOp aop); - static MapUpdateAsyncContext FromMessage(AsyncOp aop); - - AsyncOp GetAsyncOp() const; - - int GetParallelCommonEvent() const; - int GetParallelMapEvent() const; - - bool IsForegroundEvent() const; - bool IsParallelCommonEvent() const; - bool IsParallelMapEvent() const; - bool IsMessage() const; - bool IsActive() const; - private: - AsyncOp async_op = {}; - int common_event = 0; - int map_event = 0; - bool foreground_event = false; - bool message = false; +public: + MapUpdateAsyncContext() = default; + + static MapUpdateAsyncContext FromCommonEvent(int ce, AsyncOp aop); + static MapUpdateAsyncContext FromMapEvent(int ce, AsyncOp aop); + static MapUpdateAsyncContext FromForegroundEvent(AsyncOp aop); + static MapUpdateAsyncContext FromMessage(AsyncOp aop); + + AsyncOp GetAsyncOp() const; + + int GetParallelCommonEvent() const; + int GetParallelMapEvent() const; + + bool IsForegroundEvent() const; + bool IsParallelCommonEvent() const; + bool IsParallelMapEvent() const; + bool IsMessage() const; + bool IsActive() const; +private: + AsyncOp async_op = {}; + int common_event = 0; + int map_event = 0; + bool foreground_event = false; + bool message = false; }; class MapEventCache { - public: - void AddEvent(lcf::rpg::Event& ev); +public: + void AddEvent(lcf::rpg::Event& ev); - private: - std::vector events; +private: + std::vector event_ids; }; /** @@ -689,6 +690,8 @@ namespace Game_Map { void SetNeedRefreshForSwitchChange(int switch_id); void SetNeedRefreshForVarChange(int var_id); + void SetNeedRefreshForSwitchChange(std::initializer_list switch_ids); + void SetNeedRefreshForVarChange(std::initializer_list var_ids); void AddEventToSwitchCache(lcf::rpg::Event& ev, int switch_id); void AddEventToVariableCache(lcf::rpg::Event& ev, int var_id);