diff --git a/src/openrct2-ui/UiContext.cpp b/src/openrct2-ui/UiContext.cpp index 16faf0a902..26a1461289 100644 --- a/src/openrct2-ui/UiContext.cpp +++ b/src/openrct2-ui/UiContext.cpp @@ -714,9 +714,7 @@ public: { if (_titleSequencePlayer == nullptr) { - auto context = GetContext(); - auto gameState = context->GetGameState(); - _titleSequencePlayer = OpenRCT2::Title::CreateTitleSequencePlayer(*gameState); + _titleSequencePlayer = OpenRCT2::Title::CreateTitleSequencePlayer(); } return _titleSequencePlayer.get(); } diff --git a/src/openrct2-ui/title/TitleSequencePlayer.cpp b/src/openrct2-ui/title/TitleSequencePlayer.cpp index bb2ce35133..edbc2ff7f6 100644 --- a/src/openrct2-ui/title/TitleSequencePlayer.cpp +++ b/src/openrct2-ui/title/TitleSequencePlayer.cpp @@ -46,8 +46,6 @@ namespace OpenRCT2::Title class TitleSequencePlayer final : public ITitleSequencePlayer { private: - GameState& _gameState; - std::unique_ptr _sequence; int32_t _position = 0; int32_t _waitCounter = 0; @@ -57,8 +55,7 @@ namespace OpenRCT2::Title ScreenCoordsXY _previousViewPosition = {}; public: - explicit TitleSequencePlayer(GameState& gameState) - : _gameState(gameState) + explicit TitleSequencePlayer() { } @@ -248,7 +245,7 @@ namespace OpenRCT2::Title { if (Update()) { - _gameState.UpdateLogic(); + gameStateUpdateLogic(); } else { @@ -431,8 +428,8 @@ namespace OpenRCT2::Title } }; - std::unique_ptr CreateTitleSequencePlayer(GameState& gameState) + std::unique_ptr CreateTitleSequencePlayer() { - return std::make_unique(gameState); + return std::make_unique(); } } // namespace OpenRCT2::Title diff --git a/src/openrct2-ui/title/TitleSequencePlayer.h b/src/openrct2-ui/title/TitleSequencePlayer.h index 9937b0d2b2..d43fe983bd 100644 --- a/src/openrct2-ui/title/TitleSequencePlayer.h +++ b/src/openrct2-ui/title/TitleSequencePlayer.h @@ -17,10 +17,8 @@ struct IScenarioRepository; namespace OpenRCT2 { - class GameState; - namespace Title { - [[nodiscard]] std::unique_ptr CreateTitleSequencePlayer(GameState& gameState); + [[nodiscard]] std::unique_ptr CreateTitleSequencePlayer(); } // namespace Title } // namespace OpenRCT2 diff --git a/src/openrct2/Context.cpp b/src/openrct2/Context.cpp index 972fa59bd9..6396187ef3 100644 --- a/src/openrct2/Context.cpp +++ b/src/openrct2/Context.cpp @@ -123,7 +123,6 @@ namespace OpenRCT2 // Game states std::unique_ptr _titleScreen; - std::unique_ptr _gameState; DrawingEngine _drawingEngineType = DrawingEngine::Software; std::unique_ptr _drawingEngine; @@ -221,11 +220,6 @@ namespace OpenRCT2 } #endif - GameState* GetGameState() override - { - return _gameState.get(); - } - std::shared_ptr GetPlatformEnvironment() override { return _env; @@ -477,14 +471,13 @@ namespace OpenRCT2 InputResetPlaceObjModifier(); ViewportInitAll(); - _gameState = std::make_unique(); - _gameState->InitAll(DEFAULT_MAP_SIZE); + gameStateInitAll(GetGameState(), DEFAULT_MAP_SIZE); #ifdef ENABLE_SCRIPTING _scriptEngine.Initialise(); #endif - _titleScreen = std::make_unique(*_gameState); + _titleScreen = std::make_unique(); _uiContext->Initialise(); return true; @@ -1199,7 +1192,7 @@ namespace OpenRCT2 } else { - _gameState->Tick(); + gameStateTick(); } #ifdef __ENABLE_DISCORD__ diff --git a/src/openrct2/Context.h b/src/openrct2/Context.h index 6d54798190..42b3b1c96a 100644 --- a/src/openrct2/Context.h +++ b/src/openrct2/Context.h @@ -81,7 +81,6 @@ class NetworkBase; namespace OpenRCT2 { class AssetPackManager; - class GameState; struct IPlatformEnvironment; struct IReplayManager; @@ -125,7 +124,6 @@ namespace OpenRCT2 [[nodiscard]] virtual std::shared_ptr GetAudioContext() abstract; [[nodiscard]] virtual std::shared_ptr GetUiContext() abstract; - virtual GameState* GetGameState() abstract; [[nodiscard]] virtual std::shared_ptr GetPlatformEnvironment() abstract; virtual Localisation::LocalisationService& GetLocalisationService() abstract; virtual IObjectManager& GetObjectManager() abstract; diff --git a/src/openrct2/Editor.cpp b/src/openrct2/Editor.cpp index 174f7ad753..ac17caefe6 100644 --- a/src/openrct2/Editor.cpp +++ b/src/openrct2/Editor.cpp @@ -105,7 +105,7 @@ namespace Editor auto& gameState = GetGameState(); Audio::StopAll(); ObjectListLoad(); - GetContext()->GetGameState()->InitAll(DEFAULT_MAP_SIZE); + gameStateInitAll(gameState, DEFAULT_MAP_SIZE); gScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR; gameState.EditorStep = EditorStep::ObjectSelection; gameState.ParkFlags |= PARK_FLAGS_SHOW_REAL_GUEST_NAMES; @@ -167,7 +167,7 @@ namespace Editor ObjectManagerUnloadAllObjects(); ObjectListLoad(); - GetContext()->GetGameState()->InitAll(DEFAULT_MAP_SIZE); + gameStateInitAll(GetGameState(), DEFAULT_MAP_SIZE); SetAllLandOwned(); GetGameState().EditorStep = EditorStep::ObjectSelection; ViewportInitAll(); @@ -188,7 +188,7 @@ namespace Editor ObjectManagerUnloadAllObjects(); ObjectListLoad(); - GetContext()->GetGameState()->InitAll(DEFAULT_MAP_SIZE); + gameStateInitAll(GetGameState(), DEFAULT_MAP_SIZE); SetAllLandOwned(); GetGameState().EditorStep = EditorStep::ObjectSelection; ViewportInitAll(); diff --git a/src/openrct2/GameState.cpp b/src/openrct2/GameState.cpp index 7486b48c42..02fccbd2ca 100644 --- a/src/openrct2/GameState.cpp +++ b/src/openrct2/GameState.cpp @@ -58,338 +58,332 @@ namespace OpenRCT2 { return _gameState; } -} // namespace OpenRCT2 -GameState::GameState() -{ -} + /** + * Initialises the map, park etc. basically all S6 data. + */ + void gameStateInitAll(GameState_t& gameState, const TileCoordsXY& mapSize) + { + PROFILED_FUNCTION(); -/** - * Initialises the map, park etc. basically all S6 data. - */ -void GameState::InitAll(const TileCoordsXY& mapSize) -{ - PROFILED_FUNCTION(); + gInMapInitCode = true; + gameState.CurrentTicks = 0; - auto& gameState = GetGameState(); - gInMapInitCode = true; - gameState.CurrentTicks = 0; + MapInit(mapSize); + gameState.Park.Initialise(); + FinanceInit(); + BannerInit(gameState); + RideInitAll(); + ResetAllEntities(); + UpdateConsolidatedPatrolAreas(); + ResetDate(); + ClimateReset(ClimateType::CoolAndWet); + News::InitQueue(); - MapInit(mapSize); - gameState.Park.Initialise(); - FinanceInit(); - BannerInit(gameState); - RideInitAll(); - ResetAllEntities(); - UpdateConsolidatedPatrolAreas(); - ResetDate(); - ClimateReset(ClimateType::CoolAndWet); - News::InitQueue(); + gInMapInitCode = false; - gInMapInitCode = false; + GetGameState().NextGuestNumber = 1; - GetGameState().NextGuestNumber = 1; + ContextInit(); + ScenerySetDefaultPlacementConfiguration(); - ContextInit(); - ScenerySetDefaultPlacementConfiguration(); + auto intent = Intent(INTENT_ACTION_CLEAR_TILE_INSPECTOR_CLIPBOARD); + ContextBroadcastIntent(&intent); - auto intent = Intent(INTENT_ACTION_CLEAR_TILE_INSPECTOR_CLIPBOARD); - ContextBroadcastIntent(&intent); + LoadPalette(); - LoadPalette(); - - CheatsReset(); - ClearRestrictedScenery(); + CheatsReset(); + ClearRestrictedScenery(); #ifdef ENABLE_SCRIPTING - auto& scriptEngine = GetContext()->GetScriptEngine(); - scriptEngine.ClearParkStorage(); + auto& scriptEngine = GetContext()->GetScriptEngine(); + scriptEngine.ClearParkStorage(); #endif - EntityTweener::Get().Reset(); -} + EntityTweener::Get().Reset(); + } -/** - * Function will be called every kGameUpdateTimeMS. - * It has its own loop which might run multiple updates per call such as - * when operating as a client it may run multiple updates to catch up with the server tick, - * another influence can be the game speed setting. - */ -void GameState::Tick() -{ - PROFILED_FUNCTION(); - - // Normal game play will update only once every kGameUpdateTimeMS - uint32_t numUpdates = 1; - - // 0x006E3AEC // screen_game_process_mouse_input(); - ScreenshotCheck(); - GameHandleKeyboardInput(); - - if (GameIsNotPaused() && gPreviewingTitleSequenceInGame) + /** + * Function will be called every kGameUpdateTimeMS. + * It has its own loop which might run multiple updates per call such as + * when operating as a client it may run multiple updates to catch up with the server tick, + * another influence can be the game speed setting. + */ + void gameStateTick() { - auto player = GetContext()->GetUiContext()->GetTitleSequencePlayer(); - if (player != nullptr) + PROFILED_FUNCTION(); + + // Normal game play will update only once every kGameUpdateTimeMS + uint32_t numUpdates = 1; + + // 0x006E3AEC // screen_game_process_mouse_input(); + ScreenshotCheck(); + GameHandleKeyboardInput(); + + if (GameIsNotPaused() && gPreviewingTitleSequenceInGame) { - player->Update(); + auto player = GetContext()->GetUiContext()->GetTitleSequencePlayer(); + if (player != nullptr) + { + player->Update(); + } } - } - NetworkUpdate(); + NetworkUpdate(); - if (NetworkGetMode() == NETWORK_MODE_CLIENT && NetworkGetStatus() == NETWORK_STATUS_CONNECTED - && NetworkGetAuthstatus() == NetworkAuth::Ok) - { - numUpdates = std::clamp(NetworkGetServerTick() - GetGameState().CurrentTicks, 0, 10); - } - else - { - // Determine how many times we need to update the game - if (gGameSpeed > 1) + if (NetworkGetMode() == NETWORK_MODE_CLIENT && NetworkGetStatus() == NETWORK_STATUS_CONNECTED + && NetworkGetAuthstatus() == NetworkAuth::Ok) { - // Update more often if game speed is above normal. - numUpdates = 1 << (gGameSpeed - 1); - } - } - - bool isPaused = GameIsPaused(); - if (NetworkGetMode() == NETWORK_MODE_SERVER && gConfigNetwork.PauseServerIfNoClients) - { - // If we are headless we always have 1 player (host), pause if no one else is around. - if (gOpenRCT2Headless && NetworkGetNumPlayers() == 1) - { - isPaused |= true; - } - } - - bool didRunSingleFrame = false; - if (isPaused) - { - if (gDoSingleUpdate && NetworkGetMode() == NETWORK_MODE_NONE) - { - didRunSingleFrame = true; - PauseToggle(); - numUpdates = 1; + numUpdates = std::clamp(NetworkGetServerTick() - GetGameState().CurrentTicks, 0, 10); } else { - // NOTE: Here are a few special cases that would be normally handled in UpdateLogic. - // If the game is paused it will not call UpdateLogic at all. - numUpdates = 0; - - if (NetworkGetMode() == NETWORK_MODE_SERVER) + // Determine how many times we need to update the game + if (gGameSpeed > 1) { - // Make sure the client always knows about what tick the host is on. - NetworkSendTick(); + // Update more often if game speed is above normal. + numUpdates = 1 << (gGameSpeed - 1); } - - // Keep updating the money effect even when paused. - UpdateMoneyEffect(); - - // Update the animation list. Note this does not - // increment the map animation. - MapAnimationInvalidateAll(); - - // Post-tick network update - NetworkProcessPending(); - - // Post-tick game actions. - GameActions::ProcessQueue(); } - } - // Update the game one or more times - for (uint32_t i = 0; i < numUpdates; i++) - { - UpdateLogic(); - if (gGameSpeed == 1) + bool isPaused = GameIsPaused(); + if (NetworkGetMode() == NETWORK_MODE_SERVER && gConfigNetwork.PauseServerIfNoClients) { - if (InputGetState() == InputState::Reset || InputGetState() == InputState::Normal) + // If we are headless we always have 1 player (host), pause if no one else is around. + if (gOpenRCT2Headless && NetworkGetNumPlayers() == 1) { - if (InputTestFlag(INPUT_FLAG_VIEWPORT_SCROLLING)) - { - InputSetFlag(INPUT_FLAG_VIEWPORT_SCROLLING, false); - break; - } + isPaused |= true; + } + } + + bool didRunSingleFrame = false; + if (isPaused) + { + if (gDoSingleUpdate && NetworkGetMode() == NETWORK_MODE_NONE) + { + didRunSingleFrame = true; + PauseToggle(); + numUpdates = 1; } else { - break; + // NOTE: Here are a few special cases that would be normally handled in UpdateLogic. + // If the game is paused it will not call UpdateLogic at all. + numUpdates = 0; + + if (NetworkGetMode() == NETWORK_MODE_SERVER) + { + // Make sure the client always knows about what tick the host is on. + NetworkSendTick(); + } + + // Keep updating the money effect even when paused. + UpdateMoneyEffect(); + + // Update the animation list. Note this does not + // increment the map animation. + MapAnimationInvalidateAll(); + + // Post-tick network update + NetworkProcessPending(); + + // Post-tick game actions. + GameActions::ProcessQueue(); } } - // Don't call UpdateLogic again if the game was just paused. - isPaused |= GameIsPaused(); - if (isPaused) - break; - } - NetworkFlush(); - - if (!gOpenRCT2Headless) - { - InputSetFlag(INPUT_FLAG_VIEWPORT_SCROLLING, false); - - // the flickering frequency is reduced by 4, compared to the original - // it was done due to inability to reproduce original frequency - // and decision that the original one looks too fast - if (gCurrentRealTimeTicks % 4 == 0) - gWindowMapFlashingFlags ^= MapFlashingFlags::SwitchColour; - - // Handle guest map flashing - gWindowMapFlashingFlags &= ~MapFlashingFlags::FlashGuests; - if (gWindowMapFlashingFlags & MapFlashingFlags::GuestListOpen) - gWindowMapFlashingFlags |= MapFlashingFlags::FlashGuests; - gWindowMapFlashingFlags &= ~MapFlashingFlags::GuestListOpen; - - // Handle staff map flashing - gWindowMapFlashingFlags &= ~MapFlashingFlags::FlashStaff; - if (gWindowMapFlashingFlags & MapFlashingFlags::StaffListOpen) - gWindowMapFlashingFlags |= MapFlashingFlags::FlashStaff; - gWindowMapFlashingFlags &= ~MapFlashingFlags::StaffListOpen; - - ContextUpdateMapTooltip(); - } - - // Always perform autosave check, even when paused - if (!(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) && !(gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER) - && !(gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER)) - { - ScenarioAutosaveCheck(); - } - - WindowDispatchUpdateAll(); - - if (didRunSingleFrame && GameIsNotPaused() && !(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO)) - { - PauseToggle(); - } - - gDoSingleUpdate = false; -} - -void GameState::UpdateLogic() -{ - PROFILED_FUNCTION(); - - gInUpdateCode = true; - - gScreenAge++; - if (gScreenAge == 0) - gScreenAge--; - - GetContext()->GetReplayManager()->Update(); - - NetworkUpdate(); - - if (NetworkGetMode() == NETWORK_MODE_SERVER) - { - if (NetworkGamestateSnapshotsEnabled()) + // Update the game one or more times + for (uint32_t i = 0; i < numUpdates; i++) { - CreateStateSnapshot(); - } - - // Send current tick out. - NetworkSendTick(); - } - else if (NetworkGetMode() == NETWORK_MODE_CLIENT) - { - // Don't run past the server, this condition can happen during map changes. - if (NetworkGetServerTick() == GetGameState().CurrentTicks) - { - gInUpdateCode = false; - return; - } - - // Check desync. - bool desynced = NetworkCheckDesynchronisation(); - if (desynced) - { - // If desync debugging is enabled and we are still connected request the specific game state from server. - if (NetworkGamestateSnapshotsEnabled() && NetworkGetStatus() == NETWORK_STATUS_CONNECTED) + gameStateUpdateLogic(); + if (gGameSpeed == 1) { - // Create snapshot from this tick so we can compare it later - // as we won't pause the game on this event. - CreateStateSnapshot(); + if (InputGetState() == InputState::Reset || InputGetState() == InputState::Normal) + { + if (InputTestFlag(INPUT_FLAG_VIEWPORT_SCROLLING)) + { + InputSetFlag(INPUT_FLAG_VIEWPORT_SCROLLING, false); + break; + } + } + else + { + break; + } + } + // Don't call UpdateLogic again if the game was just paused. + isPaused |= GameIsPaused(); + if (isPaused) + break; + } - NetworkRequestGamestateSnapshot(); + NetworkFlush(); + + if (!gOpenRCT2Headless) + { + InputSetFlag(INPUT_FLAG_VIEWPORT_SCROLLING, false); + + // the flickering frequency is reduced by 4, compared to the original + // it was done due to inability to reproduce original frequency + // and decision that the original one looks too fast + if (gCurrentRealTimeTicks % 4 == 0) + gWindowMapFlashingFlags ^= MapFlashingFlags::SwitchColour; + + // Handle guest map flashing + gWindowMapFlashingFlags &= ~MapFlashingFlags::FlashGuests; + if (gWindowMapFlashingFlags & MapFlashingFlags::GuestListOpen) + gWindowMapFlashingFlags |= MapFlashingFlags::FlashGuests; + gWindowMapFlashingFlags &= ~MapFlashingFlags::GuestListOpen; + + // Handle staff map flashing + gWindowMapFlashingFlags &= ~MapFlashingFlags::FlashStaff; + if (gWindowMapFlashingFlags & MapFlashingFlags::StaffListOpen) + gWindowMapFlashingFlags |= MapFlashingFlags::FlashStaff; + gWindowMapFlashingFlags &= ~MapFlashingFlags::StaffListOpen; + + ContextUpdateMapTooltip(); + } + + // Always perform autosave check, even when paused + if (!(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) && !(gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER) + && !(gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER)) + { + ScenarioAutosaveCheck(); + } + + WindowDispatchUpdateAll(); + + if (didRunSingleFrame && GameIsNotPaused() && !(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO)) + { + PauseToggle(); + } + + gDoSingleUpdate = false; + } + + static void gameStateCreateStateSnapshot() + { + PROFILED_FUNCTION(); + + IGameStateSnapshots* snapshots = GetContext()->GetGameStateSnapshots(); + + auto& snapshot = snapshots->CreateSnapshot(); + snapshots->Capture(snapshot); + snapshots->LinkSnapshot(snapshot, GetGameState().CurrentTicks, ScenarioRandState().s0); + } + + void gameStateUpdateLogic() + { + PROFILED_FUNCTION(); + + gInUpdateCode = true; + + gScreenAge++; + if (gScreenAge == 0) + gScreenAge--; + + GetContext()->GetReplayManager()->Update(); + + NetworkUpdate(); + + if (NetworkGetMode() == NETWORK_MODE_SERVER) + { + if (NetworkGamestateSnapshotsEnabled()) + { + gameStateCreateStateSnapshot(); + } + + // Send current tick out. + NetworkSendTick(); + } + else if (NetworkGetMode() == NETWORK_MODE_CLIENT) + { + // Don't run past the server, this condition can happen during map changes. + if (NetworkGetServerTick() == GetGameState().CurrentTicks) + { + gInUpdateCode = false; + return; + } + + // Check desync. + bool desynced = NetworkCheckDesynchronisation(); + if (desynced) + { + // If desync debugging is enabled and we are still connected request the specific game state from server. + if (NetworkGamestateSnapshotsEnabled() && NetworkGetStatus() == NETWORK_STATUS_CONNECTED) + { + // Create snapshot from this tick so we can compare it later + // as we won't pause the game on this event. + gameStateCreateStateSnapshot(); + + NetworkRequestGamestateSnapshot(); + } } } - } - auto& gameState = GetGameState(); + auto& gameState = GetGameState(); #ifdef ENABLE_SCRIPTING - // Stash the current day number before updating the date so that we - // know if the day number changes on this tick. - auto day = gameState.Date.GetDay(); + // Stash the current day number before updating the date so that we + // know if the day number changes on this tick. + auto day = gameState.Date.GetDay(); #endif - gameState.Date.Update(); + gameState.Date.Update(); - ScenarioUpdate(gameState); - ClimateUpdate(); - MapUpdateTiles(); - // Temporarily remove provisional paths to prevent peep from interacting with them - MapRemoveProvisionalElements(); - MapUpdatePathWideFlags(); - PeepUpdateAll(); - MapRestoreProvisionalElements(); - VehicleUpdateAll(); - UpdateAllMiscEntities(); - Ride::UpdateAll(); + ScenarioUpdate(gameState); + ClimateUpdate(); + MapUpdateTiles(); + // Temporarily remove provisional paths to prevent peep from interacting with them + MapRemoveProvisionalElements(); + MapUpdatePathWideFlags(); + PeepUpdateAll(); + MapRestoreProvisionalElements(); + VehicleUpdateAll(); + UpdateAllMiscEntities(); + Ride::UpdateAll(); - if (!(gScreenFlags & SCREEN_FLAGS_EDITOR)) - { - gameState.Park.Update(gameState.Date); - } + if (!(gScreenFlags & SCREEN_FLAGS_EDITOR)) + { + gameState.Park.Update(gameState.Date); + } - ResearchUpdate(); - RideRatingsUpdateAll(); - RideMeasurementsUpdate(); - News::UpdateCurrentItem(); + ResearchUpdate(); + RideRatingsUpdateAll(); + RideMeasurementsUpdate(); + News::UpdateCurrentItem(); - MapAnimationInvalidateAll(); - VehicleSoundsUpdate(); - PeepUpdateCrowdNoise(); - ClimateUpdateSound(); - EditorOpenWindowsForCurrentStep(); + MapAnimationInvalidateAll(); + VehicleSoundsUpdate(); + PeepUpdateCrowdNoise(); + ClimateUpdateSound(); + EditorOpenWindowsForCurrentStep(); - // Update windows - // WindowDispatchUpdateAll(); + // Update windows + // WindowDispatchUpdateAll(); - // Start autosave timer after update + // Start autosave timer after update if (gLastAutoSaveUpdate == kAutosavePause) - { - gLastAutoSaveUpdate = Platform::GetTicks(); - } + { + gLastAutoSaveUpdate = Platform::GetTicks(); + } - GameActions::ProcessQueue(); + GameActions::ProcessQueue(); - NetworkProcessPending(); - NetworkFlush(); + NetworkProcessPending(); + NetworkFlush(); - gameState.CurrentTicks++; + gameState.CurrentTicks++; #ifdef ENABLE_SCRIPTING - auto& hookEngine = GetContext()->GetScriptEngine().GetHookEngine(); - hookEngine.Call(HOOK_TYPE::INTERVAL_TICK, true); + auto& hookEngine = GetContext()->GetScriptEngine().GetHookEngine(); + hookEngine.Call(HOOK_TYPE::INTERVAL_TICK, true); - if (day != gameState.Date.GetDay()) - { - hookEngine.Call(HOOK_TYPE::INTERVAL_DAY, true); - } + if (day != gameState.Date.GetDay()) + { + hookEngine.Call(HOOK_TYPE::INTERVAL_DAY, true); + } #endif - gInUpdateCode = false; -} - -void GameState::CreateStateSnapshot() -{ - PROFILED_FUNCTION(); - - IGameStateSnapshots* snapshots = GetContext()->GetGameStateSnapshots(); - - auto& snapshot = snapshots->CreateSnapshot(); - snapshots->Capture(snapshot); - snapshots->LinkSnapshot(snapshot, GetGameState().CurrentTicks, ScenarioRandState().s0); -} - + gInUpdateCode = false; + } +} // namespace OpenRCT2 diff --git a/src/openrct2/GameState.h b/src/openrct2/GameState.h index b0742f8ea6..4f84655950 100644 --- a/src/openrct2/GameState.h +++ b/src/openrct2/GameState.h @@ -158,20 +158,8 @@ namespace OpenRCT2 GameState_t& GetGameState(); - /** - * Class to update the state of the map and park. - */ - class GameState final - { - public: - GameState(); - GameState(const GameState&) = delete; + void gameStateInitAll(GameState_t& gameState, const TileCoordsXY& mapSize); + void gameStateTick(); + void gameStateUpdateLogic(); - void InitAll(const TileCoordsXY& mapSize); - void Tick(); - void UpdateLogic(); - - private: - void CreateStateSnapshot(); - }; } // namespace OpenRCT2 diff --git a/src/openrct2/command_line/SimulateCommands.cpp b/src/openrct2/command_line/SimulateCommands.cpp index 8660f56fb4..9c6d3253a6 100644 --- a/src/openrct2/command_line/SimulateCommands.cpp +++ b/src/openrct2/command_line/SimulateCommands.cpp @@ -59,7 +59,7 @@ static exitcode_t HandleSimulate(CommandLineArgEnumerator* argEnumerator) Console::WriteLine("Running %d ticks...", ticks); for (uint32_t i = 0; i < ticks; i++) { - context->GetGameState()->UpdateLogic(); + gameStateUpdateLogic(); } Console::WriteLine("Completed: %s", GetAllEntitiesChecksum().ToString().c_str()); } diff --git a/src/openrct2/park/ParkFile.cpp b/src/openrct2/park/ParkFile.cpp index 51ce303c33..851da7182f 100644 --- a/src/openrct2/park/ParkFile.cpp +++ b/src/openrct2/park/ParkFile.cpp @@ -1063,8 +1063,7 @@ namespace OpenRCT2 if (cs.GetMode() == OrcaStream::Mode::READING) { - // TODO: Use the passed gameState instead of the global one. - OpenRCT2::GetContext()->GetGameState()->InitAll(gameState.MapSize); + gameStateInitAll(gameState, gameState.MapSize); auto numElements = cs.Read(); diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index b7c34cc69c..7df50b82ea 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -326,8 +326,7 @@ namespace RCT1 gScenarioFileName = GetRCT1ScenarioName(); // Do map initialisation, same kind of stuff done when loading scenario editor - auto context = OpenRCT2::GetContext(); - context->GetGameState()->InitAll({ mapSize, mapSize }); + gameStateInitAll(gameState, { mapSize, mapSize }); gameState.EditorStep = EditorStep::ObjectSelection; gameState.ParkFlags |= PARK_FLAGS_SHOW_REAL_GUEST_NAMES; gameState.ScenarioCategory = SCENARIO_CATEGORY_OTHER; diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index 4be0af6967..b7ab65bcff 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -229,7 +229,7 @@ namespace RCT2 void Import(GameState_t& gameState) override { - Initialise(); + Initialise(gameState); gameState.EditorStep = _s6.Info.EditorStep; gameState.ScenarioCategory = static_cast(_s6.Info.Category); @@ -1719,9 +1719,9 @@ namespace RCT2 dst->position.y = src->y; } - void Initialise() + void Initialise(GameState_t& gameState) { - OpenRCT2::GetContext()->GetGameState()->InitAll({ _s6.MapSize, _s6.MapSize }); + gameStateInitAll(gameState, { _s6.MapSize, _s6.MapSize }); } /** diff --git a/src/openrct2/title/TitleScreen.cpp b/src/openrct2/title/TitleScreen.cpp index 790663cd98..ba68b02eeb 100644 --- a/src/openrct2/title/TitleScreen.cpp +++ b/src/openrct2/title/TitleScreen.cpp @@ -39,8 +39,7 @@ using namespace OpenRCT2; bool gPreviewingTitleSequenceInGame; static TitleScreen* _singleton = nullptr; -TitleScreen::TitleScreen(GameState& gameState) - : _gameState(gameState) +TitleScreen::TitleScreen() { _singleton = this; } @@ -129,7 +128,7 @@ void TitleScreen::Load() GetContext()->GetNetwork().Close(); #endif OpenRCT2::Audio::StopAll(); - GetContext()->GetGameState()->InitAll(DEFAULT_MAP_SIZE); + gameStateInitAll(GetGameState(), DEFAULT_MAP_SIZE); ViewportInitAll(); ContextOpenWindow(WindowClass::MainWindow); CreateWindows(); @@ -173,7 +172,7 @@ void TitleScreen::Tick() } for (int32_t i = 0; i < numUpdates; i++) { - _gameState.UpdateLogic(); + gameStateUpdateLogic(); } UpdatePaletteEffects(); // update_weather_animation(); @@ -336,7 +335,7 @@ bool TitleScreen::TryLoadSequence(bool loadPreview) _loadedTitleSequenceId = SIZE_MAX; if (!loadPreview) { - GetContext()->GetGameState()->InitAll(DEFAULT_MAP_SIZE); + gameStateInitAll(GetGameState(), DEFAULT_MAP_SIZE); GameNotifyMapChanged(); } return false; diff --git a/src/openrct2/title/TitleScreen.h b/src/openrct2/title/TitleScreen.h index c86d1a1b36..eeadff5d4f 100644 --- a/src/openrct2/title/TitleScreen.h +++ b/src/openrct2/title/TitleScreen.h @@ -16,12 +16,10 @@ struct ITitleSequencePlayer; namespace OpenRCT2 { - class GameState; - class TitleScreen final { public: - TitleScreen(GameState& gameState); + TitleScreen(); ~TitleScreen(); ITitleSequencePlayer* GetSequencePlayer(); @@ -38,8 +36,6 @@ namespace OpenRCT2 void ChangePresetSequence(size_t preset); private: - GameState& _gameState; - ITitleSequencePlayer* _sequencePlayer = nullptr; size_t _loadedTitleSequenceId = SIZE_MAX; size_t _currentSequence = SIZE_MAX; diff --git a/test/tests/MultiLaunch.cpp b/test/tests/MultiLaunch.cpp index 83451d6ab3..a28d1a4acb 100644 --- a/test/tests/MultiLaunch.cpp +++ b/test/tests/MultiLaunch.cpp @@ -45,8 +45,6 @@ TEST(MultiLaunchTest, all) // Check ride count to check load was successful ASSERT_EQ(RideGetCount(), 134); - auto gs = context->GetGameState(); - ASSERT_NE(gs, nullptr); auto& date = GetGameState().Date; // NOTE: This value is saved in the SV6 file, after the import this will be the current state. @@ -55,7 +53,7 @@ TEST(MultiLaunchTest, all) for (int j = 0; j < updatesToTest; j++) { - gs->UpdateLogic(); + gameStateUpdateLogic(); } ASSERT_EQ(date.GetMonthTicks(), 7862 + updatesToTest); diff --git a/test/tests/PlayTests.cpp b/test/tests/PlayTests.cpp index 360c2911f9..655ab02450 100644 --- a/test/tests/PlayTests.cpp +++ b/test/tests/PlayTests.cpp @@ -68,11 +68,11 @@ static std::unique_ptr localStartGame(const std::string& parkPath) return context; } -template static bool updateUntil(GameState& gs, int maxSteps, Fn&& fn) +template static bool updateUntil(int maxSteps, Fn&& fn) { while (maxSteps-- && !fn()) { - gs.UpdateLogic(); + gameStateUpdateLogic(); } return maxSteps > 0; } @@ -96,9 +96,6 @@ TEST_F(PlayTests, SecondGuestInQueueShouldNotRideIfNoFunds) auto context = localStartGame(initStateFile); ASSERT_NE(context.get(), nullptr); - auto gs = context->GetGameState(); - ASSERT_NE(gs, nullptr); - auto& gameState = GetGameState(); // Open park for free but charging for rides @@ -125,7 +122,7 @@ TEST_F(PlayTests, SecondGuestInQueueShouldNotRideIfNoFunds) richGuest->CashInPocket = 3000; // Wait for rich guest to get in queue - bool matched = updateUntil(*gs, 1000, [&]() { return richGuest->State == PeepState::Queuing; }); + bool matched = updateUntil(1000, [&]() { return richGuest->State == PeepState::Queuing; }); ASSERT_TRUE(matched); // Insert poor guest @@ -133,7 +130,7 @@ TEST_F(PlayTests, SecondGuestInQueueShouldNotRideIfNoFunds) poorGuest->CashInPocket = 5; // Wait for poor guest to get in queue - matched = updateUntil(*gs, 1000, [&]() { return poorGuest->State == PeepState::Queuing; }); + matched = updateUntil(1000, [&]() { return poorGuest->State == PeepState::Queuing; }); ASSERT_TRUE(matched); // Raise the price of the ride to a value poor guest can't pay @@ -142,7 +139,7 @@ TEST_F(PlayTests, SecondGuestInQueueShouldNotRideIfNoFunds) // Verify that the poor guest goes back to walking without riding // since it doesn't have enough money to pay for it bool enteredTheRide = false; - matched = updateUntil(*gs, 10000, [&]() { + matched = updateUntil(10000, [&]() { enteredTheRide |= poorGuest->State == PeepState::OnRide; return poorGuest->State == PeepState::Walking || enteredTheRide; }); @@ -159,9 +156,6 @@ TEST_F(PlayTests, CarRideWithOneCarOnlyAcceptsTwoGuests) auto context = localStartGame(initStateFile); ASSERT_NE(context.get(), nullptr); - auto gs = context->GetGameState(); - ASSERT_NE(gs, nullptr); - auto& gameState = GetGameState(); // Open park for free but charging for rides @@ -191,7 +185,7 @@ TEST_F(PlayTests, CarRideWithOneCarOnlyAcceptsTwoGuests) // Wait until one of them is riding auto guestIsOnRide = [](auto* g) { return g->State == PeepState::OnRide; }; - bool matched = updateUntil(*gs, 10000, [&]() { return std::any_of(guests.begin(), guests.end(), guestIsOnRide); }); + bool matched = updateUntil(10000, [&]() { return std::any_of(guests.begin(), guests.end(), guestIsOnRide); }); ASSERT_TRUE(matched); // For the next few ticks at most two guests can be on the ride @@ -199,6 +193,6 @@ TEST_F(PlayTests, CarRideWithOneCarOnlyAcceptsTwoGuests) { int numRiding = std::count_if(guests.begin(), guests.end(), guestIsOnRide); ASSERT_LE(numRiding, 2); - gs->UpdateLogic(); + gameStateUpdateLogic(); } } diff --git a/test/tests/ReplayTests.cpp b/test/tests/ReplayTests.cpp index 08cf427093..1e9dce8861 100644 --- a/test/tests/ReplayTests.cpp +++ b/test/tests/ReplayTests.cpp @@ -81,9 +81,6 @@ TEST_P(ReplayTests, RunReplay) bool initialised = context->Initialise(); ASSERT_TRUE(initialised); - auto gs = context->GetGameState(); - ASSERT_NE(gs, nullptr); - IReplayManager* replayManager = context->GetReplayManager(); ASSERT_NE(replayManager, nullptr); @@ -92,7 +89,7 @@ TEST_P(ReplayTests, RunReplay) while (replayManager->IsReplaying()) { - gs->UpdateLogic(); + gameStateUpdateLogic(); if (replayManager->IsPlaybackStateMismatching()) break; } diff --git a/test/tests/S6ImportExportTests.cpp b/test/tests/S6ImportExportTests.cpp index 4a49064e25..4e132acc4a 100644 --- a/test/tests/S6ImportExportTests.cpp +++ b/test/tests/S6ImportExportTests.cpp @@ -138,10 +138,9 @@ static void RecordGameStateSnapshot(std::unique_ptr& context, MemorySt static void AdvanceGameTicks(uint32_t ticks, std::unique_ptr& context) { - auto* gameState = context->GetGameState(); for (uint32_t i = 0; i < ticks; i++) { - gameState->UpdateLogic(); + gameStateUpdateLogic(); } }