Remove GameState class

This commit is contained in:
Gymnasiast 2024-03-26 15:08:17 +01:00
parent 28451027b1
commit fef1a27342
No known key found for this signature in database
GPG Key ID: DBFFF47AB2CA3EDD
18 changed files with 306 additions and 359 deletions

View File

@ -714,9 +714,7 @@ public:
{ {
if (_titleSequencePlayer == nullptr) if (_titleSequencePlayer == nullptr)
{ {
auto context = GetContext(); _titleSequencePlayer = OpenRCT2::Title::CreateTitleSequencePlayer();
auto gameState = context->GetGameState();
_titleSequencePlayer = OpenRCT2::Title::CreateTitleSequencePlayer(*gameState);
} }
return _titleSequencePlayer.get(); return _titleSequencePlayer.get();
} }

View File

@ -46,8 +46,6 @@ namespace OpenRCT2::Title
class TitleSequencePlayer final : public ITitleSequencePlayer class TitleSequencePlayer final : public ITitleSequencePlayer
{ {
private: private:
GameState& _gameState;
std::unique_ptr<TitleSequence> _sequence; std::unique_ptr<TitleSequence> _sequence;
int32_t _position = 0; int32_t _position = 0;
int32_t _waitCounter = 0; int32_t _waitCounter = 0;
@ -57,8 +55,7 @@ namespace OpenRCT2::Title
ScreenCoordsXY _previousViewPosition = {}; ScreenCoordsXY _previousViewPosition = {};
public: public:
explicit TitleSequencePlayer(GameState& gameState) explicit TitleSequencePlayer()
: _gameState(gameState)
{ {
} }
@ -248,7 +245,7 @@ namespace OpenRCT2::Title
{ {
if (Update()) if (Update())
{ {
_gameState.UpdateLogic(); gameStateUpdateLogic();
} }
else else
{ {
@ -431,8 +428,8 @@ namespace OpenRCT2::Title
} }
}; };
std::unique_ptr<ITitleSequencePlayer> CreateTitleSequencePlayer(GameState& gameState) std::unique_ptr<ITitleSequencePlayer> CreateTitleSequencePlayer()
{ {
return std::make_unique<TitleSequencePlayer>(gameState); return std::make_unique<TitleSequencePlayer>();
} }
} // namespace OpenRCT2::Title } // namespace OpenRCT2::Title

View File

@ -17,10 +17,8 @@ struct IScenarioRepository;
namespace OpenRCT2 namespace OpenRCT2
{ {
class GameState;
namespace Title namespace Title
{ {
[[nodiscard]] std::unique_ptr<ITitleSequencePlayer> CreateTitleSequencePlayer(GameState& gameState); [[nodiscard]] std::unique_ptr<ITitleSequencePlayer> CreateTitleSequencePlayer();
} // namespace Title } // namespace Title
} // namespace OpenRCT2 } // namespace OpenRCT2

View File

@ -123,7 +123,6 @@ namespace OpenRCT2
// Game states // Game states
std::unique_ptr<TitleScreen> _titleScreen; std::unique_ptr<TitleScreen> _titleScreen;
std::unique_ptr<GameState> _gameState;
DrawingEngine _drawingEngineType = DrawingEngine::Software; DrawingEngine _drawingEngineType = DrawingEngine::Software;
std::unique_ptr<IDrawingEngine> _drawingEngine; std::unique_ptr<IDrawingEngine> _drawingEngine;
@ -221,11 +220,6 @@ namespace OpenRCT2
} }
#endif #endif
GameState* GetGameState() override
{
return _gameState.get();
}
std::shared_ptr<IPlatformEnvironment> GetPlatformEnvironment() override std::shared_ptr<IPlatformEnvironment> GetPlatformEnvironment() override
{ {
return _env; return _env;
@ -477,14 +471,13 @@ namespace OpenRCT2
InputResetPlaceObjModifier(); InputResetPlaceObjModifier();
ViewportInitAll(); ViewportInitAll();
_gameState = std::make_unique<GameState>(); gameStateInitAll(GetGameState(), DEFAULT_MAP_SIZE);
_gameState->InitAll(DEFAULT_MAP_SIZE);
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
_scriptEngine.Initialise(); _scriptEngine.Initialise();
#endif #endif
_titleScreen = std::make_unique<TitleScreen>(*_gameState); _titleScreen = std::make_unique<TitleScreen>();
_uiContext->Initialise(); _uiContext->Initialise();
return true; return true;
@ -1199,7 +1192,7 @@ namespace OpenRCT2
} }
else else
{ {
_gameState->Tick(); gameStateTick();
} }
#ifdef __ENABLE_DISCORD__ #ifdef __ENABLE_DISCORD__

View File

@ -81,7 +81,6 @@ class NetworkBase;
namespace OpenRCT2 namespace OpenRCT2
{ {
class AssetPackManager; class AssetPackManager;
class GameState;
struct IPlatformEnvironment; struct IPlatformEnvironment;
struct IReplayManager; struct IReplayManager;
@ -125,7 +124,6 @@ namespace OpenRCT2
[[nodiscard]] virtual std::shared_ptr<Audio::IAudioContext> GetAudioContext() abstract; [[nodiscard]] virtual std::shared_ptr<Audio::IAudioContext> GetAudioContext() abstract;
[[nodiscard]] virtual std::shared_ptr<Ui::IUiContext> GetUiContext() abstract; [[nodiscard]] virtual std::shared_ptr<Ui::IUiContext> GetUiContext() abstract;
virtual GameState* GetGameState() abstract;
[[nodiscard]] virtual std::shared_ptr<IPlatformEnvironment> GetPlatformEnvironment() abstract; [[nodiscard]] virtual std::shared_ptr<IPlatformEnvironment> GetPlatformEnvironment() abstract;
virtual Localisation::LocalisationService& GetLocalisationService() abstract; virtual Localisation::LocalisationService& GetLocalisationService() abstract;
virtual IObjectManager& GetObjectManager() abstract; virtual IObjectManager& GetObjectManager() abstract;

View File

@ -105,7 +105,7 @@ namespace Editor
auto& gameState = GetGameState(); auto& gameState = GetGameState();
Audio::StopAll(); Audio::StopAll();
ObjectListLoad(); ObjectListLoad();
GetContext()->GetGameState()->InitAll(DEFAULT_MAP_SIZE); gameStateInitAll(gameState, DEFAULT_MAP_SIZE);
gScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR; gScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR;
gameState.EditorStep = EditorStep::ObjectSelection; gameState.EditorStep = EditorStep::ObjectSelection;
gameState.ParkFlags |= PARK_FLAGS_SHOW_REAL_GUEST_NAMES; gameState.ParkFlags |= PARK_FLAGS_SHOW_REAL_GUEST_NAMES;
@ -167,7 +167,7 @@ namespace Editor
ObjectManagerUnloadAllObjects(); ObjectManagerUnloadAllObjects();
ObjectListLoad(); ObjectListLoad();
GetContext()->GetGameState()->InitAll(DEFAULT_MAP_SIZE); gameStateInitAll(GetGameState(), DEFAULT_MAP_SIZE);
SetAllLandOwned(); SetAllLandOwned();
GetGameState().EditorStep = EditorStep::ObjectSelection; GetGameState().EditorStep = EditorStep::ObjectSelection;
ViewportInitAll(); ViewportInitAll();
@ -188,7 +188,7 @@ namespace Editor
ObjectManagerUnloadAllObjects(); ObjectManagerUnloadAllObjects();
ObjectListLoad(); ObjectListLoad();
GetContext()->GetGameState()->InitAll(DEFAULT_MAP_SIZE); gameStateInitAll(GetGameState(), DEFAULT_MAP_SIZE);
SetAllLandOwned(); SetAllLandOwned();
GetGameState().EditorStep = EditorStep::ObjectSelection; GetGameState().EditorStep = EditorStep::ObjectSelection;
ViewportInitAll(); ViewportInitAll();

View File

@ -58,338 +58,332 @@ namespace OpenRCT2
{ {
return _gameState; 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();
/** gInMapInitCode = true;
* Initialises the map, park etc. basically all S6 data. gameState.CurrentTicks = 0;
*/
void GameState::InitAll(const TileCoordsXY& mapSize)
{
PROFILED_FUNCTION();
auto& gameState = GetGameState(); MapInit(mapSize);
gInMapInitCode = true; gameState.Park.Initialise();
gameState.CurrentTicks = 0; FinanceInit();
BannerInit(gameState);
RideInitAll();
ResetAllEntities();
UpdateConsolidatedPatrolAreas();
ResetDate();
ClimateReset(ClimateType::CoolAndWet);
News::InitQueue();
MapInit(mapSize); gInMapInitCode = false;
gameState.Park.Initialise();
FinanceInit();
BannerInit(gameState);
RideInitAll();
ResetAllEntities();
UpdateConsolidatedPatrolAreas();
ResetDate();
ClimateReset(ClimateType::CoolAndWet);
News::InitQueue();
gInMapInitCode = false; GetGameState().NextGuestNumber = 1;
GetGameState().NextGuestNumber = 1; ContextInit();
ScenerySetDefaultPlacementConfiguration();
ContextInit(); auto intent = Intent(INTENT_ACTION_CLEAR_TILE_INSPECTOR_CLIPBOARD);
ScenerySetDefaultPlacementConfiguration(); ContextBroadcastIntent(&intent);
auto intent = Intent(INTENT_ACTION_CLEAR_TILE_INSPECTOR_CLIPBOARD); LoadPalette();
ContextBroadcastIntent(&intent);
LoadPalette(); CheatsReset();
ClearRestrictedScenery();
CheatsReset();
ClearRestrictedScenery();
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
auto& scriptEngine = GetContext()->GetScriptEngine(); auto& scriptEngine = GetContext()->GetScriptEngine();
scriptEngine.ClearParkStorage(); scriptEngine.ClearParkStorage();
#endif #endif
EntityTweener::Get().Reset(); EntityTweener::Get().Reset();
} }
/** /**
* Function will be called every kGameUpdateTimeMS. * Function will be called every kGameUpdateTimeMS.
* It has its own loop which might run multiple updates per call such as * 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, * 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. * another influence can be the game speed setting.
*/ */
void GameState::Tick() void gameStateTick()
{
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)
{ {
auto player = GetContext()->GetUiContext()->GetTitleSequencePlayer(); PROFILED_FUNCTION();
if (player != nullptr)
// 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 if (NetworkGetMode() == NETWORK_MODE_CLIENT && NetworkGetStatus() == NETWORK_STATUS_CONNECTED
&& NetworkGetAuthstatus() == NetworkAuth::Ok) && NetworkGetAuthstatus() == NetworkAuth::Ok)
{
numUpdates = std::clamp<uint32_t>(NetworkGetServerTick() - GetGameState().CurrentTicks, 0, 10);
}
else
{
// Determine how many times we need to update the game
if (gGameSpeed > 1)
{ {
// Update more often if game speed is above normal. numUpdates = std::clamp<uint32_t>(NetworkGetServerTick() - GetGameState().CurrentTicks, 0, 10);
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;
} }
else else
{ {
// NOTE: Here are a few special cases that would be normally handled in UpdateLogic. // Determine how many times we need to update the game
// If the game is paused it will not call UpdateLogic at all. if (gGameSpeed > 1)
numUpdates = 0;
if (NetworkGetMode() == NETWORK_MODE_SERVER)
{ {
// Make sure the client always knows about what tick the host is on. // Update more often if game speed is above normal.
NetworkSendTick(); 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 bool isPaused = GameIsPaused();
for (uint32_t i = 0; i < numUpdates; i++) if (NetworkGetMode() == NETWORK_MODE_SERVER && gConfigNetwork.PauseServerIfNoClients)
{
UpdateLogic();
if (gGameSpeed == 1)
{ {
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)) isPaused |= true;
{ }
InputSetFlag(INPUT_FLAG_VIEWPORT_SCROLLING, false); }
break;
} bool didRunSingleFrame = false;
if (isPaused)
{
if (gDoSingleUpdate && NetworkGetMode() == NETWORK_MODE_NONE)
{
didRunSingleFrame = true;
PauseToggle();
numUpdates = 1;
} }
else 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(); // Update the game one or more times
for (uint32_t i = 0; i < numUpdates; i++)
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())
{ {
CreateStateSnapshot(); gameStateUpdateLogic();
} if (gGameSpeed == 1)
// 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 if (InputGetState() == InputState::Reset || InputGetState() == InputState::Normal)
// as we won't pause the game on this event. {
CreateStateSnapshot(); 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 #ifdef ENABLE_SCRIPTING
// Stash the current day number before updating the date so that we // Stash the current day number before updating the date so that we
// know if the day number changes on this tick. // know if the day number changes on this tick.
auto day = gameState.Date.GetDay(); auto day = gameState.Date.GetDay();
#endif #endif
gameState.Date.Update(); gameState.Date.Update();
ScenarioUpdate(gameState); ScenarioUpdate(gameState);
ClimateUpdate(); ClimateUpdate();
MapUpdateTiles(); MapUpdateTiles();
// Temporarily remove provisional paths to prevent peep from interacting with them // Temporarily remove provisional paths to prevent peep from interacting with them
MapRemoveProvisionalElements(); MapRemoveProvisionalElements();
MapUpdatePathWideFlags(); MapUpdatePathWideFlags();
PeepUpdateAll(); PeepUpdateAll();
MapRestoreProvisionalElements(); MapRestoreProvisionalElements();
VehicleUpdateAll(); VehicleUpdateAll();
UpdateAllMiscEntities(); UpdateAllMiscEntities();
Ride::UpdateAll(); Ride::UpdateAll();
if (!(gScreenFlags & SCREEN_FLAGS_EDITOR)) if (!(gScreenFlags & SCREEN_FLAGS_EDITOR))
{ {
gameState.Park.Update(gameState.Date); gameState.Park.Update(gameState.Date);
} }
ResearchUpdate(); ResearchUpdate();
RideRatingsUpdateAll(); RideRatingsUpdateAll();
RideMeasurementsUpdate(); RideMeasurementsUpdate();
News::UpdateCurrentItem(); News::UpdateCurrentItem();
MapAnimationInvalidateAll(); MapAnimationInvalidateAll();
VehicleSoundsUpdate(); VehicleSoundsUpdate();
PeepUpdateCrowdNoise(); PeepUpdateCrowdNoise();
ClimateUpdateSound(); ClimateUpdateSound();
EditorOpenWindowsForCurrentStep(); EditorOpenWindowsForCurrentStep();
// Update windows // Update windows
// WindowDispatchUpdateAll(); // WindowDispatchUpdateAll();
// Start autosave timer after update // Start autosave timer after update
if (gLastAutoSaveUpdate == kAutosavePause) if (gLastAutoSaveUpdate == kAutosavePause)
{ {
gLastAutoSaveUpdate = Platform::GetTicks(); gLastAutoSaveUpdate = Platform::GetTicks();
} }
GameActions::ProcessQueue(); GameActions::ProcessQueue();
NetworkProcessPending(); NetworkProcessPending();
NetworkFlush(); NetworkFlush();
gameState.CurrentTicks++; gameState.CurrentTicks++;
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
auto& hookEngine = GetContext()->GetScriptEngine().GetHookEngine(); auto& hookEngine = GetContext()->GetScriptEngine().GetHookEngine();
hookEngine.Call(HOOK_TYPE::INTERVAL_TICK, true); hookEngine.Call(HOOK_TYPE::INTERVAL_TICK, true);
if (day != gameState.Date.GetDay()) if (day != gameState.Date.GetDay())
{ {
hookEngine.Call(HOOK_TYPE::INTERVAL_DAY, true); hookEngine.Call(HOOK_TYPE::INTERVAL_DAY, true);
} }
#endif #endif
gInUpdateCode = false; gInUpdateCode = false;
} }
} // namespace OpenRCT2
void GameState::CreateStateSnapshot()
{
PROFILED_FUNCTION();
IGameStateSnapshots* snapshots = GetContext()->GetGameStateSnapshots();
auto& snapshot = snapshots->CreateSnapshot();
snapshots->Capture(snapshot);
snapshots->LinkSnapshot(snapshot, GetGameState().CurrentTicks, ScenarioRandState().s0);
}

View File

@ -158,20 +158,8 @@ namespace OpenRCT2
GameState_t& GetGameState(); GameState_t& GetGameState();
/** void gameStateInitAll(GameState_t& gameState, const TileCoordsXY& mapSize);
* Class to update the state of the map and park. void gameStateTick();
*/ void gameStateUpdateLogic();
class GameState final
{
public:
GameState();
GameState(const GameState&) = delete;
void InitAll(const TileCoordsXY& mapSize);
void Tick();
void UpdateLogic();
private:
void CreateStateSnapshot();
};
} // namespace OpenRCT2 } // namespace OpenRCT2

View File

@ -59,7 +59,7 @@ static exitcode_t HandleSimulate(CommandLineArgEnumerator* argEnumerator)
Console::WriteLine("Running %d ticks...", ticks); Console::WriteLine("Running %d ticks...", ticks);
for (uint32_t i = 0; i < ticks; i++) for (uint32_t i = 0; i < ticks; i++)
{ {
context->GetGameState()->UpdateLogic(); gameStateUpdateLogic();
} }
Console::WriteLine("Completed: %s", GetAllEntitiesChecksum().ToString().c_str()); Console::WriteLine("Completed: %s", GetAllEntitiesChecksum().ToString().c_str());
} }

View File

@ -1063,8 +1063,7 @@ namespace OpenRCT2
if (cs.GetMode() == OrcaStream::Mode::READING) if (cs.GetMode() == OrcaStream::Mode::READING)
{ {
// TODO: Use the passed gameState instead of the global one. gameStateInitAll(gameState, gameState.MapSize);
OpenRCT2::GetContext()->GetGameState()->InitAll(gameState.MapSize);
auto numElements = cs.Read<uint32_t>(); auto numElements = cs.Read<uint32_t>();

View File

@ -326,8 +326,7 @@ namespace RCT1
gScenarioFileName = GetRCT1ScenarioName(); gScenarioFileName = GetRCT1ScenarioName();
// Do map initialisation, same kind of stuff done when loading scenario editor // Do map initialisation, same kind of stuff done when loading scenario editor
auto context = OpenRCT2::GetContext(); gameStateInitAll(gameState, { mapSize, mapSize });
context->GetGameState()->InitAll({ mapSize, mapSize });
gameState.EditorStep = EditorStep::ObjectSelection; gameState.EditorStep = EditorStep::ObjectSelection;
gameState.ParkFlags |= PARK_FLAGS_SHOW_REAL_GUEST_NAMES; gameState.ParkFlags |= PARK_FLAGS_SHOW_REAL_GUEST_NAMES;
gameState.ScenarioCategory = SCENARIO_CATEGORY_OTHER; gameState.ScenarioCategory = SCENARIO_CATEGORY_OTHER;

View File

@ -229,7 +229,7 @@ namespace RCT2
void Import(GameState_t& gameState) override void Import(GameState_t& gameState) override
{ {
Initialise(); Initialise(gameState);
gameState.EditorStep = _s6.Info.EditorStep; gameState.EditorStep = _s6.Info.EditorStep;
gameState.ScenarioCategory = static_cast<SCENARIO_CATEGORY>(_s6.Info.Category); gameState.ScenarioCategory = static_cast<SCENARIO_CATEGORY>(_s6.Info.Category);
@ -1719,9 +1719,9 @@ namespace RCT2
dst->position.y = src->y; 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 });
} }
/** /**

View File

@ -39,8 +39,7 @@ using namespace OpenRCT2;
bool gPreviewingTitleSequenceInGame; bool gPreviewingTitleSequenceInGame;
static TitleScreen* _singleton = nullptr; static TitleScreen* _singleton = nullptr;
TitleScreen::TitleScreen(GameState& gameState) TitleScreen::TitleScreen()
: _gameState(gameState)
{ {
_singleton = this; _singleton = this;
} }
@ -129,7 +128,7 @@ void TitleScreen::Load()
GetContext()->GetNetwork().Close(); GetContext()->GetNetwork().Close();
#endif #endif
OpenRCT2::Audio::StopAll(); OpenRCT2::Audio::StopAll();
GetContext()->GetGameState()->InitAll(DEFAULT_MAP_SIZE); gameStateInitAll(GetGameState(), DEFAULT_MAP_SIZE);
ViewportInitAll(); ViewportInitAll();
ContextOpenWindow(WindowClass::MainWindow); ContextOpenWindow(WindowClass::MainWindow);
CreateWindows(); CreateWindows();
@ -173,7 +172,7 @@ void TitleScreen::Tick()
} }
for (int32_t i = 0; i < numUpdates; i++) for (int32_t i = 0; i < numUpdates; i++)
{ {
_gameState.UpdateLogic(); gameStateUpdateLogic();
} }
UpdatePaletteEffects(); UpdatePaletteEffects();
// update_weather_animation(); // update_weather_animation();
@ -336,7 +335,7 @@ bool TitleScreen::TryLoadSequence(bool loadPreview)
_loadedTitleSequenceId = SIZE_MAX; _loadedTitleSequenceId = SIZE_MAX;
if (!loadPreview) if (!loadPreview)
{ {
GetContext()->GetGameState()->InitAll(DEFAULT_MAP_SIZE); gameStateInitAll(GetGameState(), DEFAULT_MAP_SIZE);
GameNotifyMapChanged(); GameNotifyMapChanged();
} }
return false; return false;

View File

@ -16,12 +16,10 @@ struct ITitleSequencePlayer;
namespace OpenRCT2 namespace OpenRCT2
{ {
class GameState;
class TitleScreen final class TitleScreen final
{ {
public: public:
TitleScreen(GameState& gameState); TitleScreen();
~TitleScreen(); ~TitleScreen();
ITitleSequencePlayer* GetSequencePlayer(); ITitleSequencePlayer* GetSequencePlayer();
@ -38,8 +36,6 @@ namespace OpenRCT2
void ChangePresetSequence(size_t preset); void ChangePresetSequence(size_t preset);
private: private:
GameState& _gameState;
ITitleSequencePlayer* _sequencePlayer = nullptr; ITitleSequencePlayer* _sequencePlayer = nullptr;
size_t _loadedTitleSequenceId = SIZE_MAX; size_t _loadedTitleSequenceId = SIZE_MAX;
size_t _currentSequence = SIZE_MAX; size_t _currentSequence = SIZE_MAX;

View File

@ -45,8 +45,6 @@ TEST(MultiLaunchTest, all)
// Check ride count to check load was successful // Check ride count to check load was successful
ASSERT_EQ(RideGetCount(), 134); ASSERT_EQ(RideGetCount(), 134);
auto gs = context->GetGameState();
ASSERT_NE(gs, nullptr);
auto& date = GetGameState().Date; auto& date = GetGameState().Date;
// NOTE: This value is saved in the SV6 file, after the import this will be the current state. // 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++) for (int j = 0; j < updatesToTest; j++)
{ {
gs->UpdateLogic(); gameStateUpdateLogic();
} }
ASSERT_EQ(date.GetMonthTicks(), 7862 + updatesToTest); ASSERT_EQ(date.GetMonthTicks(), 7862 + updatesToTest);

View File

@ -68,11 +68,11 @@ static std::unique_ptr<IContext> localStartGame(const std::string& parkPath)
return context; return context;
} }
template<class Fn> static bool updateUntil(GameState& gs, int maxSteps, Fn&& fn) template<class Fn> static bool updateUntil(int maxSteps, Fn&& fn)
{ {
while (maxSteps-- && !fn()) while (maxSteps-- && !fn())
{ {
gs.UpdateLogic(); gameStateUpdateLogic();
} }
return maxSteps > 0; return maxSteps > 0;
} }
@ -96,9 +96,6 @@ TEST_F(PlayTests, SecondGuestInQueueShouldNotRideIfNoFunds)
auto context = localStartGame(initStateFile); auto context = localStartGame(initStateFile);
ASSERT_NE(context.get(), nullptr); ASSERT_NE(context.get(), nullptr);
auto gs = context->GetGameState();
ASSERT_NE(gs, nullptr);
auto& gameState = GetGameState(); auto& gameState = GetGameState();
// Open park for free but charging for rides // Open park for free but charging for rides
@ -125,7 +122,7 @@ TEST_F(PlayTests, SecondGuestInQueueShouldNotRideIfNoFunds)
richGuest->CashInPocket = 3000; richGuest->CashInPocket = 3000;
// Wait for rich guest to get in queue // 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); ASSERT_TRUE(matched);
// Insert poor guest // Insert poor guest
@ -133,7 +130,7 @@ TEST_F(PlayTests, SecondGuestInQueueShouldNotRideIfNoFunds)
poorGuest->CashInPocket = 5; poorGuest->CashInPocket = 5;
// Wait for poor guest to get in queue // 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); ASSERT_TRUE(matched);
// Raise the price of the ride to a value poor guest can't pay // 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 // Verify that the poor guest goes back to walking without riding
// since it doesn't have enough money to pay for it // since it doesn't have enough money to pay for it
bool enteredTheRide = false; bool enteredTheRide = false;
matched = updateUntil(*gs, 10000, [&]() { matched = updateUntil(10000, [&]() {
enteredTheRide |= poorGuest->State == PeepState::OnRide; enteredTheRide |= poorGuest->State == PeepState::OnRide;
return poorGuest->State == PeepState::Walking || enteredTheRide; return poorGuest->State == PeepState::Walking || enteredTheRide;
}); });
@ -159,9 +156,6 @@ TEST_F(PlayTests, CarRideWithOneCarOnlyAcceptsTwoGuests)
auto context = localStartGame(initStateFile); auto context = localStartGame(initStateFile);
ASSERT_NE(context.get(), nullptr); ASSERT_NE(context.get(), nullptr);
auto gs = context->GetGameState();
ASSERT_NE(gs, nullptr);
auto& gameState = GetGameState(); auto& gameState = GetGameState();
// Open park for free but charging for rides // Open park for free but charging for rides
@ -191,7 +185,7 @@ TEST_F(PlayTests, CarRideWithOneCarOnlyAcceptsTwoGuests)
// Wait until one of them is riding // Wait until one of them is riding
auto guestIsOnRide = [](auto* g) { return g->State == PeepState::OnRide; }; 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); ASSERT_TRUE(matched);
// For the next few ticks at most two guests can be on the ride // 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); int numRiding = std::count_if(guests.begin(), guests.end(), guestIsOnRide);
ASSERT_LE(numRiding, 2); ASSERT_LE(numRiding, 2);
gs->UpdateLogic(); gameStateUpdateLogic();
} }
} }

View File

@ -81,9 +81,6 @@ TEST_P(ReplayTests, RunReplay)
bool initialised = context->Initialise(); bool initialised = context->Initialise();
ASSERT_TRUE(initialised); ASSERT_TRUE(initialised);
auto gs = context->GetGameState();
ASSERT_NE(gs, nullptr);
IReplayManager* replayManager = context->GetReplayManager(); IReplayManager* replayManager = context->GetReplayManager();
ASSERT_NE(replayManager, nullptr); ASSERT_NE(replayManager, nullptr);
@ -92,7 +89,7 @@ TEST_P(ReplayTests, RunReplay)
while (replayManager->IsReplaying()) while (replayManager->IsReplaying())
{ {
gs->UpdateLogic(); gameStateUpdateLogic();
if (replayManager->IsPlaybackStateMismatching()) if (replayManager->IsPlaybackStateMismatching())
break; break;
} }

View File

@ -138,10 +138,9 @@ static void RecordGameStateSnapshot(std::unique_ptr<IContext>& context, MemorySt
static void AdvanceGameTicks(uint32_t ticks, std::unique_ptr<IContext>& context) static void AdvanceGameTicks(uint32_t ticks, std::unique_ptr<IContext>& context)
{ {
auto* gameState = context->GetGameState();
for (uint32_t i = 0; i < ticks; i++) for (uint32_t i = 0; i < ticks; i++)
{ {
gameState->UpdateLogic(); gameStateUpdateLogic();
} }
} }