From 4d4e7ba4b15355c10f00d209ed4d238a3ec43e33 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 23 Jul 2017 00:19:09 +0100 Subject: [PATCH] Create new GameState class for updating the game --- src/openrct2/Context.cpp | 12 +- src/openrct2/Context.h | 2 + src/openrct2/Game.cpp | 205 ------------------ src/openrct2/Game.h | 2 - src/openrct2/GameState.cpp | 237 +++++++++++++++++++++ src/openrct2/GameState.h | 32 +++ src/openrct2/title/TitleScreen.cpp | 10 +- src/openrct2/title/TitleScreen.h | 55 ++--- src/openrct2/title/TitleSequencePlayer.cpp | 17 +- src/openrct2/title/TitleSequencePlayer.h | 7 +- 10 files changed, 335 insertions(+), 244 deletions(-) create mode 100644 src/openrct2/GameState.cpp create mode 100644 src/openrct2/GameState.h diff --git a/src/openrct2/Context.cpp b/src/openrct2/Context.cpp index 8f7c1cf470..dcab1f9008 100644 --- a/src/openrct2/Context.cpp +++ b/src/openrct2/Context.cpp @@ -38,6 +38,7 @@ #include "drawing/IDrawingEngine.h" #include "localisation/Localisation.h" #include "FileClassifier.h" +#include "GameState.h" #include "network/network.h" #include "object/ObjectManager.h" #include "object/ObjectRepository.h" @@ -106,6 +107,7 @@ namespace OpenRCT2 // Game states std::unique_ptr _titleScreen; std::unique_ptr _park; + std::unique_ptr _gameState; sint32 _drawingEngineType = DRAWING_ENGINE_SOFTWARE; std::unique_ptr _drawingEngine; @@ -166,6 +168,11 @@ namespace OpenRCT2 return _uiContext; } + GameState * GetGameState() override + { + return _gameState.get(); + } + Park * GetPark() override { return _park.get(); @@ -450,7 +457,8 @@ namespace OpenRCT2 viewport_init_all(); game_init_all(150); - _titleScreen = std::make_unique(); + _gameState = std::make_unique(); + _titleScreen = std::make_unique(_gameState.get()); _park = std::make_unique(); return true; } @@ -975,7 +983,7 @@ namespace OpenRCT2 } else { - game_update(); + _gameState->Update(); } #ifdef __ENABLE_DISCORD__ diff --git a/src/openrct2/Context.h b/src/openrct2/Context.h index b6e1cb243d..6224ca64e0 100644 --- a/src/openrct2/Context.h +++ b/src/openrct2/Context.h @@ -71,6 +71,7 @@ enum namespace OpenRCT2 { interface IPlatformEnvironment; + class GameState; class Park; namespace Audio @@ -102,6 +103,7 @@ namespace OpenRCT2 virtual std::shared_ptr GetAudioContext() abstract; virtual std::shared_ptr GetUiContext() abstract; + virtual GameState * GetGameState() abstract; virtual Park * GetPark() abstract; virtual std::shared_ptr GetPlatformEnvironment() abstract; virtual Localisation::LocalisationService& GetLocalisationService() abstract; diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index 8123a8ea04..f0329100ce 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -331,211 +331,6 @@ void update_palette_effects() } } } - -void game_update() -{ - gInUpdateCode = true; - - uint32 numUpdates; - - // 0x006E3AEC // screen_game_process_mouse_input(); - screenshot_check(); - game_handle_keyboard_input(); - - if (game_is_not_paused() && gPreviewingTitleSequenceInGame) - { - title_sequence_player_update((ITitleSequencePlayer *) title_get_sequence_player()); - } - - // Determine how many times we need to update the game - if (gGameSpeed > 1) - { - numUpdates = 1 << (gGameSpeed - 1); - } - else - { - numUpdates = gTicksSinceLastUpdate / GAME_UPDATE_TIME_MS; - numUpdates = Math::Clamp(1u, numUpdates, (uint32) GAME_MAX_UPDATES); - } - - if (network_get_mode() == NETWORK_MODE_CLIENT && network_get_status() == NETWORK_STATUS_CONNECTED && network_get_authstatus() == NETWORK_AUTH_OK) - { - if (network_get_server_tick() - gCurrentTicks >= 10) - { - // Make sure client doesn't fall behind the server too much - numUpdates += 10; - } - } - - if (game_is_paused()) - { - numUpdates = 0; - // Update the animation list. Note this does not - // increment the map animation. - map_animation_invalidate_all(); - - // Special case because we set numUpdates to 0, otherwise in game_logic_update. - network_update(); - - network_process_game_commands(); - } - - // Update the game one or more times - for (uint32 i = 0; i < numUpdates; i++) - { - game_logic_update(); - - if (gGameSpeed > 1) - continue; - - if (input_get_state() == INPUT_STATE_RESET || - input_get_state() == INPUT_STATE_NORMAL - ) - { - if (input_test_flag(INPUT_FLAG_VIEWPORT_SCROLLING)) - { - input_set_flag(INPUT_FLAG_VIEWPORT_SCROLLING, false); - break; - } - } - else - { - break; - } - } - - if (!gOpenRCT2Headless) - { - input_set_flag(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 (gCurrentTicks % 4 == 0) - gWindowMapFlashingFlags ^= (1 << 15); - - // Handle guest map flashing - gWindowMapFlashingFlags &= ~(1 << 1); - if (gWindowMapFlashingFlags & (1 << 0)) - gWindowMapFlashingFlags |= (1 << 1); - gWindowMapFlashingFlags &= ~(1 << 0); - - // Handle staff map flashing - gWindowMapFlashingFlags &= ~(1 << 3); - if (gWindowMapFlashingFlags & (1 << 2)) - gWindowMapFlashingFlags |= (1 << 3); - gWindowMapFlashingFlags &= ~(1 << 2); - - context_update_map_tooltip(); - - // Input - gUnk141F568 = gUnk13CA740; - - context_handle_input(); - } - - // Always perform autosave check, even when paused - if (!(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) && - !(gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER) && - !(gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER) - ) - { - scenario_autosave_check(); - } - - window_dispatch_update_all(); - - gGameCommandNestLevel = 0; - gInUpdateCode = false; -} - -void game_logic_update() -{ - gScreenAge++; - if (gScreenAge == 0) - gScreenAge--; - - network_update(); - - if (network_get_mode() == NETWORK_MODE_CLIENT && network_get_status() == NETWORK_STATUS_CONNECTED && network_get_authstatus() == NETWORK_AUTH_OK) - { - // Can't be in sync with server, round trips won't work if we are at same level. - if (gCurrentTicks >= network_get_server_tick()) - { - // Don't run past the server - return; - } - } - - if (network_get_mode() == NETWORK_MODE_SERVER) - { - // Send current tick out. - network_send_tick(); - } - else if (network_get_mode() == NETWORK_MODE_CLIENT) - { - // Check desync. - network_check_desynchronization(); - } - - sub_68B089(); - scenario_update(); - climate_update(); - map_update_tiles(); - // Temporarily remove provisional paths to prevent peep from interacting with them - map_remove_provisional_elements(); - map_update_path_wide_flags(); - peep_update_all(); - map_restore_provisional_elements(); - vehicle_update_all(); - sprite_misc_update_all(); - ride_update_all(); - GetContext()->GetPark()->Update(); - research_update(); - ride_ratings_update_all(); - ride_measurements_update(); - news_item_update_current(); - - map_animation_invalidate_all(); - vehicle_sounds_update(); - peep_update_crowd_noise(); - climate_update_sound(); - editor_open_windows_for_current_step(); - - // Update windows - //window_dispatch_update_all(); - - if (gErrorType != ERROR_TYPE_NONE) - { - rct_string_id title_text = STR_UNABLE_TO_LOAD_FILE; - rct_string_id body_text = gErrorStringId; - if (gErrorType == ERROR_TYPE_GENERIC) - { - title_text = gErrorStringId; - body_text = 0xFFFF; - } - gErrorType = ERROR_TYPE_NONE; - - context_show_error(title_text, body_text); - } - - // Start autosave timer after update - if (gLastAutoSaveUpdate == AUTOSAVE_PAUSE) - { - gLastAutoSaveUpdate = platform_get_ticks(); - } - - // Separated out processing commands in network_update which could call scenario_rand where gInUpdateCode is false. - // All commands that are received are first queued and then executed where gInUpdateCode is set to true. - network_process_game_commands(); - - network_flush(); - - gCurrentTicks++; - gScenarioTicks++; - gSavedAge++; -} - /** * * rct2: 0x0069C62C diff --git a/src/openrct2/Game.h b/src/openrct2/Game.h index 9616f34132..4f1feae745 100644 --- a/src/openrct2/Game.h +++ b/src/openrct2/Game.h @@ -161,8 +161,6 @@ void game_increase_game_speed(); void game_reduce_game_speed(); void game_create_windows(); -void game_update(); -void game_logic_update(); void reset_all_sprite_quadrant_placements(); void update_palette_effects(); diff --git a/src/openrct2/GameState.cpp b/src/openrct2/GameState.cpp new file mode 100644 index 0000000000..7b33fa8f59 --- /dev/null +++ b/src/openrct2/GameState.cpp @@ -0,0 +1,237 @@ +#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers +/***************************************************************************** +* OpenRCT2, an open source clone of Roller Coaster Tycoon 2. +* +* OpenRCT2 is the work of many authors, a full list can be found in contributors.md +* For more information, visit https://github.com/OpenRCT2/OpenRCT2 +* +* OpenRCT2 is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* A full copy of the GNU General Public License can be found in licence.txt +*****************************************************************************/ +#pragma endregion + +#include "GameState.h" +#include "Context.h" +#include "core/Math.hpp" +#include "Editor.h" +#include "Input.h" +#include "interface/Screenshot.h" +#include "management/NewsItem.h" +#include "network/network.h" +#include "OpenRCT2.h" +#include "platform/Platform2.h" +#include "scenario/Scenario.h" +#include "title/TitleScreen.h" +#include "title/TitleSequencePlayer.h" +#include "world/Climate.h" +#include "world/MapAnimation.h" +#include "world/Park.h" + +using namespace OpenRCT2; + +void GameState::Update() +{ + gInUpdateCode = true; + + uint32 numUpdates; + + // 0x006E3AEC // screen_game_process_mouse_input(); + screenshot_check(); + game_handle_keyboard_input(); + + if (game_is_not_paused() && gPreviewingTitleSequenceInGame) + { + title_sequence_player_update((ITitleSequencePlayer *) title_get_sequence_player()); + } + + // Determine how many times we need to update the game + if (gGameSpeed > 1) + { + numUpdates = 1 << (gGameSpeed - 1); + } + else + { + numUpdates = gTicksSinceLastUpdate / GAME_UPDATE_TIME_MS; + numUpdates = Math::Clamp(1, numUpdates, GAME_MAX_UPDATES); + } + + if (network_get_mode() == NETWORK_MODE_CLIENT && network_get_status() == NETWORK_STATUS_CONNECTED && network_get_authstatus() == NETWORK_AUTH_OK) + { + if (network_get_server_tick() - gCurrentTicks >= 10) + { + // Make sure client doesn't fall behind the server too much + numUpdates += 10; + } + } + + if (game_is_paused()) + { + numUpdates = 0; + // Update the animation list. Note this does not + // increment the map animation. + map_animation_invalidate_all(); + + // Special case because we set numUpdates to 0, otherwise in game_logic_update. + network_update(); + + network_process_game_commands(); + } + + // Update the game one or more times + for (uint32 i = 0; i < numUpdates; i++) + { + UpdateLogic(); + if (gGameSpeed == 1) + { + if (input_get_state() == INPUT_STATE_RESET || + input_get_state() == INPUT_STATE_NORMAL) + { + if (input_test_flag(INPUT_FLAG_VIEWPORT_SCROLLING)) + { + input_set_flag(INPUT_FLAG_VIEWPORT_SCROLLING, false); + break; + } + } + else + { + break; + } + } + } + + if (!gOpenRCT2Headless) + { + input_set_flag(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 (gCurrentTicks % 4 == 0) + gWindowMapFlashingFlags ^= (1 << 15); + + // Handle guest map flashing + gWindowMapFlashingFlags &= ~(1 << 1); + if (gWindowMapFlashingFlags & (1 << 0)) + gWindowMapFlashingFlags |= (1 << 1); + gWindowMapFlashingFlags &= ~(1 << 0); + + // Handle staff map flashing + gWindowMapFlashingFlags &= ~(1 << 3); + if (gWindowMapFlashingFlags & (1 << 2)) + gWindowMapFlashingFlags |= (1 << 3); + gWindowMapFlashingFlags &= ~(1 << 2); + + context_update_map_tooltip(); + + // Input + gUnk141F568 = gUnk13CA740; + + context_handle_input(); + } + + // Always perform autosave check, even when paused + if (!(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) && + !(gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER) && + !(gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER)) + { + scenario_autosave_check(); + } + + window_dispatch_update_all(); + + gGameCommandNestLevel = 0; + gInUpdateCode = false; +} + +void GameState::UpdateLogic() +{ + gScreenAge++; + if (gScreenAge == 0) + gScreenAge--; + + network_update(); + + if (network_get_mode() == NETWORK_MODE_CLIENT && + network_get_status() == NETWORK_STATUS_CONNECTED && + network_get_authstatus() == NETWORK_AUTH_OK) + { + // Can't be in sync with server, round trips won't work if we are at same level. + if (gCurrentTicks >= network_get_server_tick()) + { + // Don't run past the server + return; + } + } + + if (network_get_mode() == NETWORK_MODE_SERVER) + { + // Send current tick out. + network_send_tick(); + } + else if (network_get_mode() == NETWORK_MODE_CLIENT) + { + // Check desync. + network_check_desynchronization(); + } + + sub_68B089(); + scenario_update(); + climate_update(); + map_update_tiles(); + // Temporarily remove provisional paths to prevent peep from interacting with them + map_remove_provisional_elements(); + map_update_path_wide_flags(); + peep_update_all(); + map_restore_provisional_elements(); + vehicle_update_all(); + sprite_misc_update_all(); + ride_update_all(); + GetContext()->GetPark()->Update(); + research_update(); + ride_ratings_update_all(); + ride_measurements_update(); + news_item_update_current(); + + map_animation_invalidate_all(); + vehicle_sounds_update(); + peep_update_crowd_noise(); + climate_update_sound(); + editor_open_windows_for_current_step(); + + // Update windows + //window_dispatch_update_all(); + + if (gErrorType != ERROR_TYPE_NONE) + { + rct_string_id title_text = STR_UNABLE_TO_LOAD_FILE; + rct_string_id body_text = gErrorStringId; + if (gErrorType == ERROR_TYPE_GENERIC) + { + title_text = gErrorStringId; + body_text = 0xFFFF; + } + gErrorType = ERROR_TYPE_NONE; + + context_show_error(title_text, body_text); + } + + // Start autosave timer after update + if (gLastAutoSaveUpdate == AUTOSAVE_PAUSE) + { + gLastAutoSaveUpdate = Platform::GetTicks(); + } + + // Separated out processing commands in network_update which could call scenario_rand where gInUpdateCode is false. + // All commands that are received are first queued and then executed where gInUpdateCode is set to true. + network_process_game_commands(); + + network_flush(); + + gCurrentTicks++; + gScenarioTicks++; + gSavedAge++; +} diff --git a/src/openrct2/GameState.h b/src/openrct2/GameState.h new file mode 100644 index 0000000000..34ce3dea97 --- /dev/null +++ b/src/openrct2/GameState.h @@ -0,0 +1,32 @@ +#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers +/***************************************************************************** +* OpenRCT2, an open source clone of Roller Coaster Tycoon 2. +* +* OpenRCT2 is the work of many authors, a full list can be found in contributors.md +* For more information, visit https://github.com/OpenRCT2/OpenRCT2 +* +* OpenRCT2 is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* A full copy of the GNU General Public License can be found in licence.txt +*****************************************************************************/ +#pragma endregion + +#pragma once + +namespace OpenRCT2 +{ + /** + * Class to update the state of the map and park. + */ + class GameState + { + private: + + public: + void Update(); + void UpdateLogic(); + }; +} diff --git a/src/openrct2/title/TitleScreen.cpp b/src/openrct2/title/TitleScreen.cpp index 76e9b8e768..6547fb0f81 100644 --- a/src/openrct2/title/TitleScreen.cpp +++ b/src/openrct2/title/TitleScreen.cpp @@ -17,6 +17,7 @@ #include "../config/Config.h" #include "../Context.h" #include "../core/Console.hpp" +#include "../GameState.h" #include "../interface/Screenshot.h" #include "../network/network.h" #include "../OpenRCT2.h" @@ -35,10 +36,13 @@ #include "../interface/Window.h" #include "../localisation/Localisation.h" +using namespace OpenRCT2; + // TODO Remove when no longer required. static TitleScreen * _singleton = nullptr; -TitleScreen::TitleScreen() +TitleScreen::TitleScreen(GameState * gameState) + : _gameState(gameState) { _singleton = this; } @@ -170,7 +174,7 @@ void TitleScreen::Update() } for (sint32 i = 0; i < numUpdates; i++) { - game_logic_update(); + _gameState->UpdateLogic(); } update_palette_effects(); // update_rain_animation(); @@ -224,7 +228,7 @@ void TitleScreen::TitleInitialise() if (_sequencePlayer == nullptr) { IScenarioRepository * scenarioRepository = GetScenarioRepository(); - _sequencePlayer = CreateTitleSequencePlayer(scenarioRepository); + _sequencePlayer = CreateTitleSequencePlayer(scenarioRepository, _gameState); } size_t seqId = title_get_config_sequence(); if (seqId == SIZE_MAX) diff --git a/src/openrct2/title/TitleScreen.h b/src/openrct2/title/TitleScreen.h index 2652707dca..f8a07df2f6 100644 --- a/src/openrct2/title/TitleScreen.h +++ b/src/openrct2/title/TitleScreen.h @@ -22,35 +22,42 @@ interface ITitleSequencePlayer; -class TitleScreen final +namespace OpenRCT2 { -public: - ITitleSequencePlayer * GetSequencePlayer(); - size_t GetCurrentSequence(); - bool PreviewSequence(size_t value); - void StopPreviewingSequence(); - bool IsPreviewingSequence(); - bool ShouldHideVersionInfo(); - void SetHideVersionInfo(bool value); + class GameState; - TitleScreen(); - ~TitleScreen(); + class TitleScreen final + { + public: + TitleScreen(GameState * gameState); + ~TitleScreen(); - void Load(); - void Update(); - void CreateWindows(); - void ChangePresetSequence(size_t preset); + ITitleSequencePlayer * GetSequencePlayer(); + size_t GetCurrentSequence(); + bool PreviewSequence(size_t value); + void StopPreviewingSequence(); + bool IsPreviewingSequence(); + bool ShouldHideVersionInfo(); + void SetHideVersionInfo(bool value); -private: - ITitleSequencePlayer * _sequencePlayer = nullptr; - size_t _loadedTitleSequenceId = SIZE_MAX; - size_t _currentSequence = SIZE_MAX; - bool _hideVersionInfo = false; - bool _previewingSequence = false; + void Load(); + void Update(); + void CreateWindows(); + void ChangePresetSequence(size_t preset); - void TitleInitialise(); - bool TryLoadSequence(bool loadPreview = false); -}; + private: + GameState * const _gameState; + + ITitleSequencePlayer * _sequencePlayer = nullptr; + size_t _loadedTitleSequenceId = SIZE_MAX; + size_t _currentSequence = SIZE_MAX; + bool _hideVersionInfo = false; + bool _previewingSequence = false; + + void TitleInitialise(); + bool TryLoadSequence(bool loadPreview = false); + }; +} void title_load(); void title_create_windows(); diff --git a/src/openrct2/title/TitleSequencePlayer.cpp b/src/openrct2/title/TitleSequencePlayer.cpp index c22d0f0722..69aa958bd4 100644 --- a/src/openrct2/title/TitleSequencePlayer.cpp +++ b/src/openrct2/title/TitleSequencePlayer.cpp @@ -24,6 +24,7 @@ #include "../core/String.hpp" #include "../object/ObjectManager.h" #include "../OpenRCT2.h" +#include "../GameState.h" #include "../ParkImporter.h" #include "../scenario/ScenarioRepository.h" #include "../scenario/ScenarioSources.h" @@ -49,7 +50,8 @@ class TitleSequencePlayer final : public ITitleSequencePlayer private: static constexpr const char * SFMM_FILENAME = "Six Flags Magic Mountain.SC6"; - IScenarioRepository * _scenarioRepository = nullptr; + IScenarioRepository * const _scenarioRepository; + GameState * const _gameState; size_t _sequenceId = 0; TitleSequence * _sequence = nullptr; @@ -61,11 +63,12 @@ private: CoordsXY _viewCentreLocation = { 0 }; public: - explicit TitleSequencePlayer(IScenarioRepository * scenarioRepository) + explicit TitleSequencePlayer(IScenarioRepository * scenarioRepository, GameState * gameState) + : _scenarioRepository(scenarioRepository), + _gameState(gameState) { Guard::ArgumentNotNull(scenarioRepository); - - _scenarioRepository = scenarioRepository; + Guard::ArgumentNotNull(gameState); } ~TitleSequencePlayer() override @@ -213,7 +216,7 @@ public: { if (Update()) { - game_logic_update(); + _gameState->UpdateLogic(); } else { @@ -588,9 +591,9 @@ private: } }; -ITitleSequencePlayer * CreateTitleSequencePlayer(IScenarioRepository * scenarioRepository) +ITitleSequencePlayer * CreateTitleSequencePlayer(IScenarioRepository * scenarioRepository, GameState * gameState) { - return new TitleSequencePlayer(scenarioRepository); + return new TitleSequencePlayer(scenarioRepository, gameState); } bool gPreviewingTitleSequenceInGame = false; diff --git a/src/openrct2/title/TitleSequencePlayer.h b/src/openrct2/title/TitleSequencePlayer.h index 864a2cb5b0..3f987faed5 100644 --- a/src/openrct2/title/TitleSequencePlayer.h +++ b/src/openrct2/title/TitleSequencePlayer.h @@ -18,6 +18,11 @@ #include "../common.h" +namespace OpenRCT2 +{ + class GameState; +} + interface IScenarioRepository; interface ITitleSequencePlayer @@ -33,7 +38,7 @@ interface ITitleSequencePlayer virtual void Eject() abstract; }; -ITitleSequencePlayer * CreateTitleSequencePlayer(IScenarioRepository * scenarioRepository); +ITitleSequencePlayer * CreateTitleSequencePlayer(IScenarioRepository * scenarioRepository, OpenRCT2::GameState * gameState); // When testing title sequences within a normal game extern bool gPreviewingTitleSequenceInGame;