OpenRCT2/src/openrct2/Context.cpp

1718 lines
54 KiB
C++
Raw Permalink Normal View History

/*****************************************************************************
* Copyright (c) 2014-2024 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
2017-09-04 23:17:35 +02:00
#ifdef __EMSCRIPTEN__
2018-07-21 16:17:06 +02:00
# include <emscripten.h>
2017-09-04 23:17:35 +02:00
#endif // __EMSCRIPTEN__
2018-11-21 23:16:04 +01:00
2022-09-18 17:15:42 +02:00
#include "AssetPackManager.h"
#include "Context.h"
2018-06-22 23:25:16 +02:00
#include "Editor.h"
#include "FileClassifier.h"
#include "Game.h"
#include "GameState.h"
#include "GameStateSnapshots.h"
2018-06-22 23:25:16 +02:00
#include "Input.h"
#include "OpenRCT2.h"
#include "ParkImporter.h"
#include "PlatformEnvironment.h"
#include "ReplayManager.h"
2018-06-22 23:25:16 +02:00
#include "Version.h"
#include "actions/GameAction.h"
2018-06-22 23:25:16 +02:00
#include "audio/AudioContext.h"
#include "audio/audio.h"
#include "config/Config.h"
#include "core/Console.hpp"
#include "core/File.h"
#include "core/FileScanner.h"
#include "core/FileStream.h"
#include "core/Guard.hpp"
#include "core/Http.h"
#include "core/MemoryStream.h"
#include "core/Path.hpp"
#include "core/String.hpp"
#include "core/Timer.hpp"
#include "drawing/IDrawingEngine.h"
2021-12-07 21:55:27 +01:00
#include "drawing/Image.h"
2018-06-22 23:25:16 +02:00
#include "drawing/LightFX.h"
2021-11-24 16:19:52 +01:00
#include "entity/EntityRegistry.h"
#include "entity/EntityTweener.h"
2018-06-22 23:25:16 +02:00
#include "interface/Chat.h"
#include "interface/InteractiveConsole.h"
#include "interface/StdInOutConsole.h"
2018-06-22 23:25:16 +02:00
#include "interface/Viewport.h"
#include "localisation/Date.h"
2021-12-12 00:06:06 +01:00
#include "localisation/Formatter.h"
#include "localisation/Localisation.h"
2018-06-22 23:25:16 +02:00
#include "localisation/LocalisationService.h"
#include "network/DiscordService.h"
2021-08-17 05:20:07 +02:00
#include "network/NetworkBase.h"
#include "network/network.h"
#include "object/ObjectManager.h"
#include "object/ObjectRepository.h"
#include "paint/Painter.h"
2022-04-23 15:45:15 +02:00
#include "park/ParkFile.h"
2018-01-18 13:55:34 +01:00
#include "platform/Crash.h"
#include "platform/Platform.h"
#include "profiling/Profiling.h"
#include "rct2/RCT2.h"
#include "ride/TrackData.h"
#include "ride/TrackDesignRepository.h"
2018-03-19 23:28:40 +01:00
#include "scenario/Scenario.h"
#include "scenario/ScenarioRepository.h"
#include "scenes/game/GameScene.h"
2024-04-26 20:35:16 +02:00
#include "scenes/intro/IntroScene.h"
#include "scenes/preloader/PreloaderScene.h"
#include "scenes/title/TitleScene.h"
#include "scenes/title/TitleSequenceManager.h"
2018-03-19 00:35:58 +01:00
#include "scripting/HookEngine.h"
#include "scripting/ScriptEngine.h"
2018-06-22 23:25:16 +02:00
#include "ui/UiContext.h"
#include "ui/WindowManager.h"
2017-12-13 13:02:24 +01:00
#include "util/Util.h"
2018-06-22 23:25:16 +02:00
#include "world/Park.h"
2018-11-21 23:16:04 +01:00
#include <cmath>
#include <exception>
#include <future>
2018-11-21 23:16:04 +01:00
#include <iterator>
#include <memory>
#include <string>
using namespace OpenRCT2;
using namespace OpenRCT2::Drawing;
2018-04-24 14:18:05 +02:00
using namespace OpenRCT2::Localisation;
using namespace OpenRCT2::Paint;
using namespace OpenRCT2::Scripting;
using namespace OpenRCT2::Ui;
using OpenRCT2::Audio::IAudioContext;
namespace OpenRCT2
{
class Context final : public IContext
{
private:
// Dependencies
std::shared_ptr<IPlatformEnvironment> const _env;
std::shared_ptr<IAudioContext> const _audioContext;
std::shared_ptr<IUiContext> const _uiContext;
// Services
std::unique_ptr<LocalisationService> _localisationService;
std::unique_ptr<IObjectRepository> _objectRepository;
std::unique_ptr<IObjectManager> _objectManager;
std::unique_ptr<ITrackDesignRepository> _trackDesignRepository;
std::unique_ptr<IScenarioRepository> _scenarioRepository;
std::unique_ptr<IReplayManager> _replayManager;
std::unique_ptr<IGameStateSnapshots> _gameStateSnapshots;
2022-09-18 17:15:42 +02:00
std::unique_ptr<AssetPackManager> _assetPackManager;
2017-11-10 21:23:23 +01:00
#ifdef __ENABLE_DISCORD__
std::unique_ptr<DiscordService> _discordService;
2017-11-10 21:23:23 +01:00
#endif
2018-06-22 23:25:16 +02:00
StdInOutConsole _stdInOutConsole;
#ifdef ENABLE_SCRIPTING
ScriptEngine _scriptEngine;
2020-02-23 13:55:48 +01:00
#endif
2021-08-17 05:20:07 +02:00
#ifndef DISABLE_NETWORK
NetworkBase _network;
#endif
// Scenes
std::unique_ptr<PreloaderScene> _preloaderScene;
2024-04-26 20:35:16 +02:00
std::unique_ptr<IntroScene> _introScene;
std::unique_ptr<TitleScene> _titleScene;
std::unique_ptr<GameScene> _gameScene;
IScene* _activeScene = nullptr;
DrawingEngine _drawingEngineType = DrawingEngine::Software;
std::unique_ptr<IDrawingEngine> _drawingEngine;
std::unique_ptr<Painter> _painter;
2018-06-22 23:25:16 +02:00
bool _initialised = false;
Timer _timer;
float _ticksAccumulator = 0.0f;
float _realtimeAccumulator = 0.0f;
float _timeScale = 1.0f;
2018-06-22 23:25:16 +02:00
bool _variableFrame = false;
// If set, will end the OpenRCT2 game loop. Intentionally private to this module so that the flag can not be set back to
// false.
bool _finished = false;
std::future<void> _versionCheckFuture;
NewVersionInfo _newVersionInfo;
bool _hasNewVersionInfo = false;
public:
// Singleton of Context.
// Remove this when GetContext() is no longer called so that
// multiple instances can be created in parallel
2018-06-22 23:25:16 +02:00
static Context* Instance;
public:
Context(
const std::shared_ptr<IPlatformEnvironment>& env, const std::shared_ptr<IAudioContext>& audioContext,
2018-04-27 19:47:57 +02:00
const std::shared_ptr<IUiContext>& uiContext)
2018-06-22 23:25:16 +02:00
: _env(env)
, _audioContext(audioContext)
, _uiContext(uiContext)
, _localisationService(std::make_unique<LocalisationService>(env))
2024-04-23 19:52:52 +02:00
, _objectRepository(CreateObjectRepository(_env))
, _objectManager(CreateObjectManager(*_objectRepository))
, _trackDesignRepository(CreateTrackDesignRepository(_env))
, _scenarioRepository(CreateScenarioRepository(_env))
, _replayManager(CreateReplayManager())
, _gameStateSnapshots(CreateGameStateSnapshots())
#ifdef ENABLE_SCRIPTING
, _scriptEngine(_stdInOutConsole, *env)
2021-08-17 05:20:07 +02:00
#endif
#ifndef DISABLE_NETWORK
, _network(*this)
2020-02-23 13:55:48 +01:00
#endif
2020-02-22 19:04:27 +01:00
, _painter(std::make_unique<Painter>(uiContext))
{
// Can't have more than one context currently.
Guard::Assert(Instance == nullptr);
Instance = this;
}
~Context() override
{
2018-12-17 12:58:12 +01:00
// NOTE: We must shutdown all systems here before Instance is set back to null.
// If objects use GetContext() in their destructor things won't go well.
#ifdef ENABLE_SCRIPTING
_scriptEngine.StopUnloadRegisterAllPlugins();
#endif
GameActions::ClearQueue();
2021-08-17 09:36:18 +02:00
#ifndef DISABLE_NETWORK
2021-08-17 05:20:07 +02:00
_network.Close();
2021-08-17 09:36:18 +02:00
#endif
WindowCloseAll();
// Unload objects after closing all windows, this is to overcome windows like
// the object selection window which loads objects when closed.
if (_objectManager != nullptr)
{
_objectManager->UnloadAll();
}
GfxObjectCheckAllImagesFreed();
GfxUnloadCsg();
GfxUnloadG2();
GfxUnloadG1();
Audio::Close();
Instance = nullptr;
}
std::shared_ptr<IAudioContext> GetAudioContext() override
2017-03-28 20:58:15 +02:00
{
return _audioContext;
2017-03-28 20:58:15 +02:00
}
std::shared_ptr<IUiContext> GetUiContext() override
{
return _uiContext;
}
#ifdef ENABLE_SCRIPTING
Scripting::ScriptEngine& GetScriptEngine() override
{
return _scriptEngine;
}
2020-02-23 13:55:48 +01:00
#endif
std::shared_ptr<IPlatformEnvironment> GetPlatformEnvironment() override
{
return _env;
}
Localisation::LocalisationService& GetLocalisationService() override
2018-04-24 14:18:05 +02:00
{
return *_localisationService;
2018-04-24 14:18:05 +02:00
}
IObjectManager& GetObjectManager() override
{
return *_objectManager;
}
IObjectRepository& GetObjectRepository() override
{
return *_objectRepository;
}
2018-06-22 23:25:16 +02:00
ITrackDesignRepository* GetTrackDesignRepository() override
{
return _trackDesignRepository.get();
}
2018-06-22 23:25:16 +02:00
IScenarioRepository* GetScenarioRepository() override
{
return _scenarioRepository.get();
}
IReplayManager* GetReplayManager() override
{
return _replayManager.get();
}
IGameStateSnapshots* GetGameStateSnapshots() override
{
return _gameStateSnapshots.get();
}
2022-09-18 17:15:42 +02:00
AssetPackManager* GetAssetPackManager() override
{
return _assetPackManager.get();
}
DrawingEngine GetDrawingEngineType() override
{
return _drawingEngineType;
}
2018-06-22 23:25:16 +02:00
IDrawingEngine* GetDrawingEngine() override
{
return _drawingEngine.get();
}
2021-08-17 05:20:07 +02:00
Paint::Painter* GetPainter() override
2019-02-19 16:03:08 +01:00
{
return _painter.get();
}
2021-08-17 05:20:07 +02:00
#ifndef DISABLE_NETWORK
NetworkBase& GetNetwork() override
{
return _network;
}
#endif
2018-06-22 23:25:16 +02:00
int32_t RunOpenRCT2(int argc, const char** argv) override
{
if (Initialise())
{
Launch();
2019-10-05 18:57:07 +02:00
return EXIT_SUCCESS;
}
2019-10-05 18:57:07 +02:00
return EXIT_FAILURE;
}
IScene* GetPreloaderScene() override
{
if (auto* scene = _preloaderScene.get())
return scene;
_preloaderScene = std::make_unique<PreloaderScene>(*this);
return _preloaderScene.get();
}
IScene* GetIntroScene() override
{
if (auto* scene = _introScene.get())
return scene;
_introScene = std::make_unique<IntroScene>(*this);
2024-04-26 20:35:16 +02:00
return _introScene.get();
}
IScene* GetTitleScene() override
{
if (auto* scene = _titleScene.get())
return scene;
_titleScene = std::make_unique<TitleScene>(*this);
return _titleScene.get();
}
IScene* GetGameScene() override
{
if (auto* scene = _gameScene.get())
return scene;
_gameScene = std::make_unique<GameScene>(*this);
return _gameScene.get();
}
IScene* GetEditorScene() override
{
// TODO: Implement me.
return nullptr;
}
IScene* GetActiveScene() override
{
return _activeScene;
}
void SetActiveScene(IScene* screen) override
{
if (_activeScene != nullptr)
_activeScene->Stop();
_activeScene = screen;
if (_activeScene)
_activeScene->Load();
}
2018-06-22 23:25:16 +02:00
void WriteLine(const std::string& s) override
2018-03-11 23:25:34 +01:00
{
_stdInOutConsole.WriteLine(s);
}
2021-02-13 01:15:27 +01:00
void WriteErrorLine(const std::string& s) override
{
_stdInOutConsole.WriteLineError(s);
}
/**
* Causes the OpenRCT2 game loop to finish.
*/
2017-05-06 22:53:51 +02:00
void Finish() override
{
_finished = true;
}
2017-07-28 19:43:48 +02:00
void Quit() override
{
gSavePromptMode = PromptMode::Quit;
2022-11-06 21:49:07 +01:00
ContextOpenWindow(WindowClass::SavePrompt);
2017-07-28 19:43:48 +02:00
}
bool Initialise() final override
{
if (_initialised)
{
throw std::runtime_error("Context already initialised.");
}
_initialised = true;
CrashInit();
2024-05-10 12:10:21 +02:00
if (String::Equals(Config::Get().general.LastRunVersion, OPENRCT2_VERSION))
{
gOpenRCT2ShowChangelog = false;
}
else
{
gOpenRCT2ShowChangelog = true;
2024-05-10 12:10:21 +02:00
Config::Get().general.LastRunVersion = OPENRCT2_VERSION;
Config::Save();
}
try
{
2024-05-10 12:10:21 +02:00
_localisationService->OpenLanguage(Config::Get().general.Language);
}
catch (const std::exception& e)
{
LOG_ERROR("Failed to open configured language: %s", e.what());
try
{
_localisationService->OpenLanguage(LANGUAGE_ENGLISH_UK);
}
catch (const std::exception& eFallback)
{
LOG_FATAL("Failed to open fallback language: %s", eFallback.what());
auto uiContext = GetContext()->GetUiContext();
uiContext->ShowMessageBox("Failed to load language file!\nYour installation may be damaged.");
return false;
}
}
// TODO add configuration option to allow multiple instances
// if (!gOpenRCT2Headless && !Platform::LockSingleInstance()) {
// LOG_FATAL("OpenRCT2 is already running.");
// return false;
// } //This comment was relocated so it would stay where it was in relation to the following lines of code.
if (!gOpenRCT2Headless)
{
auto rct2InstallPath = GetOrPromptRCT2Path();
if (rct2InstallPath.empty())
{
return false;
}
_env->SetBasePath(DIRBASE::RCT2, rct2InstallPath);
}
2022-09-18 17:15:42 +02:00
if (!gOpenRCT2Headless)
{
_assetPackManager = std::make_unique<AssetPackManager>();
}
2017-11-10 21:23:23 +01:00
#ifdef __ENABLE_DISCORD__
if (!gOpenRCT2Headless)
{
_discordService = std::make_unique<DiscordService>();
}
2017-11-10 21:23:23 +01:00
#endif
2022-01-10 13:02:11 +01:00
if (Platform::ProcessIsElevated())
{
2018-04-24 14:18:05 +02:00
std::string elevationWarning = _localisationService->GetString(STR_ADMIN_NOT_RECOMMENDED);
if (gOpenRCT2Headless)
{
Console::Error::WriteLine(elevationWarning.c_str());
}
else
{
_uiContext->ShowMessageBox(elevationWarning);
}
}
if (Platform::IsRunningInWine())
{
std::string wineWarning = _localisationService->GetString(STR_WINE_NOT_RECOMMENDED);
if (gOpenRCT2Headless)
{
Console::Error::WriteLine(wineWarning.c_str());
}
else
{
_uiContext->ShowMessageBox(wineWarning);
}
}
if (!gOpenRCT2Headless)
{
2017-06-26 00:45:19 +02:00
_uiContext->CreateWindow();
}
EnsureUserContentDirectoriesExist();
if (!gOpenRCT2Headless)
{
Audio::Init();
Audio::PopulateDevices();
Audio::InitRideSoundsAndInfo();
2024-05-10 12:10:21 +02:00
Audio::gGameSoundsOff = !Config::Get().sound.MasterSoundEnabled;
}
2023-01-16 21:14:50 +01:00
ChatInit();
CopyOriginalUserFilesOver();
if (!gOpenRCT2NoGraphics)
{
if (!LoadBaseGraphics())
{
return false;
}
LightFXInit();
}
InputResetPlaceObjModifier();
2023-01-16 21:14:50 +01:00
ViewportInitAll();
2017-07-23 00:42:14 +02:00
ContextInit();
if (!gOpenRCT2Headless)
{
auto* preloaderScene = static_cast<PreloaderScene*>(GetPreloaderScene());
SetActiveScene(preloaderScene);
// TODO: preload the title scene in another (parallel) job.
preloaderScene->AddJob([this]() { InitialiseRepositories(); });
}
else
{
InitialiseRepositories();
}
#ifdef ENABLE_SCRIPTING
_scriptEngine.Initialise();
#endif
2018-03-24 20:30:10 +01:00
_uiContext->Initialise();
return true;
}
private:
void InitialiseRepositories()
{
if (!_initialised)
{
throw std::runtime_error("Context needs to be initialised first.");
}
auto currentLanguage = _localisationService->GetCurrentLanguage();
OpenProgress(STR_CHECKING_OBJECT_FILES);
_objectRepository->LoadOrConstruct(currentLanguage);
OpenProgress(STR_LOADING_GENERIC);
2024-05-18 13:12:08 +02:00
Audio::LoadAudioObjects();
if (!gOpenRCT2Headless)
{
OpenProgress(STR_CHECKING_ASSET_PACKS);
_assetPackManager->Scan();
_assetPackManager->LoadEnabledAssetPacks();
_assetPackManager->Reload();
}
OpenProgress(STR_CHECKING_TRACK_DESIGN_FILES);
_trackDesignRepository->Scan(currentLanguage);
OpenProgress(STR_CHECKING_SCENARIO_FILES);
_scenarioRepository->Scan(currentLanguage);
OpenProgress(STR_CHECKING_TITLE_SEQUENCES);
TitleSequenceManager::Scan();
OpenProgress(STR_LOADING_GENERIC);
}
public:
void InitialiseDrawingEngine() final override
{
assert(_drawingEngine == nullptr);
2024-05-10 12:10:21 +02:00
_drawingEngineType = Config::Get().general.DrawingEngine;
auto drawingEngineFactory = _uiContext->GetDrawingEngineFactory();
auto drawingEngine = drawingEngineFactory->Create(_drawingEngineType, _uiContext);
if (drawingEngine == nullptr)
{
if (_drawingEngineType == DrawingEngine::Software)
{
_drawingEngineType = DrawingEngine::None;
LOG_FATAL("Unable to create a drawing engine.");
exit(-1);
}
else
{
LOG_ERROR("Unable to create drawing engine. Falling back to software.");
// Fallback to software
2024-05-10 12:10:21 +02:00
Config::Get().general.DrawingEngine = DrawingEngine::Software;
Config::Save();
DrawingEngineInit();
}
}
else
{
try
{
drawingEngine->Initialise();
2024-05-10 12:10:21 +02:00
drawingEngine->SetVSync(Config::Get().general.UseVSync);
_drawingEngine = std::move(drawingEngine);
}
2018-06-22 23:25:16 +02:00
catch (const std::exception& ex)
{
if (_drawingEngineType == DrawingEngine::Software)
{
_drawingEngineType = DrawingEngine::None;
LOG_ERROR(ex.what());
LOG_FATAL("Unable to initialise a drawing engine.");
exit(-1);
}
else
{
LOG_ERROR(ex.what());
LOG_ERROR("Unable to initialise drawing engine. Falling back to software.");
// Fallback to software
2024-05-10 12:10:21 +02:00
Config::Get().general.DrawingEngine = DrawingEngine::Software;
Config::Save();
DrawingEngineInit();
}
}
}
WindowCheckAllValidZoom();
}
void DisposeDrawingEngine() final override
{
_drawingEngine = nullptr;
}
void OpenProgress(StringId captionStringId) override
{
auto captionString = _localisationService->GetString(captionStringId);
auto intent = Intent(INTENT_ACTION_PROGRESS_OPEN);
intent.PutExtra(INTENT_EXTRA_MESSAGE, captionString);
ContextOpenIntent(&intent);
}
void SetProgress(uint32_t currentProgress, uint32_t totalCount, StringId format = STR_NONE) override
{
auto intent = Intent(INTENT_ACTION_PROGRESS_SET);
intent.PutExtra(INTENT_EXTRA_PROGRESS_OFFSET, currentProgress);
intent.PutExtra(INTENT_EXTRA_PROGRESS_TOTAL, totalCount);
intent.PutExtra(INTENT_EXTRA_STRING_ID, format);
ContextOpenIntent(&intent);
}
void CloseProgress() override
{
auto intent = Intent(INTENT_ACTION_PROGRESS_CLOSE);
ContextOpenIntent(&intent);
}
bool LoadParkFromFile(const u8string& path, bool loadTitleScreenOnFail = false, bool asScenario = false) final override
2017-07-02 20:10:22 +02:00
{
LOG_VERBOSE("Context::LoadParkFromFile(%s)", path.c_str());
struct CrashAdditionalFileRegistration
{
CrashAdditionalFileRegistration(const std::string& path)
{
// Register the file for crash upload if it asserts while loading.
CrashRegisterAdditionalFile("load_park", path);
}
~CrashAdditionalFileRegistration()
{
// Deregister park file in case it was processed without hitting an assert.
CrashUnregisterAdditionalFile("load_park");
}
} crash_additional_file_registration(path);
try
{
if (String::IEquals(Path::GetExtension(path), ".sea"))
2020-07-09 23:33:45 +02:00
{
2022-03-18 23:21:23 +01:00
auto data = DecryptSea(fs::u8path(path));
2020-07-09 23:33:45 +02:00
auto ms = MemoryStream(data.data(), data.size(), MEMORY_ACCESS::READ);
if (!LoadParkFromStream(&ms, path, loadTitleScreenOnFail, asScenario))
{
throw std::runtime_error(".sea file may have been renamed.");
}
return true;
2020-07-09 23:33:45 +02:00
}
2021-09-15 22:22:15 +02:00
auto fs = FileStream(path, FILE_MODE_OPEN);
if (!LoadParkFromStream(&fs, path, loadTitleScreenOnFail, asScenario))
2020-07-09 23:33:45 +02:00
{
2021-09-15 22:22:15 +02:00
return false;
2020-07-09 23:33:45 +02:00
}
2021-09-15 22:22:15 +02:00
return true;
}
2018-06-22 23:25:16 +02:00
catch (const std::exception& e)
{
Console::Error::WriteLine(e.what());
if (loadTitleScreenOnFail)
{
SetActiveScene(GetTitleScene());
}
auto windowManager = _uiContext->GetWindowManager();
windowManager->ShowError(STR_FAILED_TO_LOAD_FILE_CONTAINS_INVALID_DATA, STR_NONE, {});
}
return false;
2017-07-02 20:10:22 +02:00
}
bool LoadParkFromStream(
IStream* stream, const std::string& path, bool loadTitleScreenFirstOnFail = false,
bool asScenario = false) final override
Feature: Preview title sequences in-game Title sequences can now be played back in-game, allowing for much easier editing. Improved title sequence playback in general. Clicking play while on a different title sequence will play the new one. Clicking stop will make the title screen go back to the config title sequence. And the closing the title sequence window will also make the game go back to the config title sequence, and reload the sequence if it was modified. Changes made to title sequences in-game are now correctly loaded in the title screen. Starting a title sequence within the editor will now always reset it even if it's the current playing sequence. (Not for playing in the editor though). Get Location in title sequence command editor now has 100% accuracy compared to before where it would usually get some offset value. Added `get_map_coordinates_from_pos_window` which will allow getting the viewport coordinates of a specific window even if the input coordinates are under another window. This has use with getting 2D positions from the main window without the other windows getting in the way. Options window will now always specify the config title sequence in the dropdown and not the current title sequence. Made a global variable `gLoadKeepWindowsOpen`, in game.h to keep windows open when loading a park. When loading a title sequence park in-game. The sequence player will force-close all park-specific windows ahead of time. Skipping while testing title sequences no longer needs to reload the park if the current playback position is already before the target position and ahead of the load position. Added changelog entry.
2017-10-30 12:07:01 +01:00
{
try
Feature: Preview title sequences in-game Title sequences can now be played back in-game, allowing for much easier editing. Improved title sequence playback in general. Clicking play while on a different title sequence will play the new one. Clicking stop will make the title screen go back to the config title sequence. And the closing the title sequence window will also make the game go back to the config title sequence, and reload the sequence if it was modified. Changes made to title sequences in-game are now correctly loaded in the title screen. Starting a title sequence within the editor will now always reset it even if it's the current playing sequence. (Not for playing in the editor though). Get Location in title sequence command editor now has 100% accuracy compared to before where it would usually get some offset value. Added `get_map_coordinates_from_pos_window` which will allow getting the viewport coordinates of a specific window even if the input coordinates are under another window. This has use with getting 2D positions from the main window without the other windows getting in the way. Options window will now always specify the config title sequence in the dropdown and not the current title sequence. Made a global variable `gLoadKeepWindowsOpen`, in game.h to keep windows open when loading a park. When loading a title sequence park in-game. The sequence player will force-close all park-specific windows ahead of time. Skipping while testing title sequences no longer needs to reload the park if the current playback position is already before the target position and ahead of the load position. Added changelog entry.
2017-10-30 12:07:01 +01:00
{
ClassifiedFileInfo info;
if (!TryClassifyFile(stream, &info))
Feature: Preview title sequences in-game Title sequences can now be played back in-game, allowing for much easier editing. Improved title sequence playback in general. Clicking play while on a different title sequence will play the new one. Clicking stop will make the title screen go back to the config title sequence. And the closing the title sequence window will also make the game go back to the config title sequence, and reload the sequence if it was modified. Changes made to title sequences in-game are now correctly loaded in the title screen. Starting a title sequence within the editor will now always reset it even if it's the current playing sequence. (Not for playing in the editor though). Get Location in title sequence command editor now has 100% accuracy compared to before where it would usually get some offset value. Added `get_map_coordinates_from_pos_window` which will allow getting the viewport coordinates of a specific window even if the input coordinates are under another window. This has use with getting 2D positions from the main window without the other windows getting in the way. Options window will now always specify the config title sequence in the dropdown and not the current title sequence. Made a global variable `gLoadKeepWindowsOpen`, in game.h to keep windows open when loading a park. When loading a title sequence park in-game. The sequence player will force-close all park-specific windows ahead of time. Skipping while testing title sequences no longer needs to reload the park if the current playback position is already before the target position and ahead of the load position. Added changelog entry.
2017-10-30 12:07:01 +01:00
{
throw std::runtime_error("Unable to detect file type");
}
if (info.Type != FILE_TYPE::PARK && info.Type != FILE_TYPE::SAVED_GAME && info.Type != FILE_TYPE::SCENARIO)
{
throw std::runtime_error("Invalid file type.");
}
std::unique_ptr<IParkImporter> parkImporter;
if (info.Type == FILE_TYPE::PARK)
{
parkImporter = ParkImporter::CreateParkFile(*_objectRepository);
}
else if (info.Version <= kFileTypeS4Cutoff)
{
// Save is an S4 (RCT1 format)
parkImporter = ParkImporter::CreateS4();
}
else
{
// Save is an S6 (RCT2 format)
parkImporter = ParkImporter::CreateS6(*_objectRepository);
}
Feature: Preview title sequences in-game Title sequences can now be played back in-game, allowing for much easier editing. Improved title sequence playback in general. Clicking play while on a different title sequence will play the new one. Clicking stop will make the title screen go back to the config title sequence. And the closing the title sequence window will also make the game go back to the config title sequence, and reload the sequence if it was modified. Changes made to title sequences in-game are now correctly loaded in the title screen. Starting a title sequence within the editor will now always reset it even if it's the current playing sequence. (Not for playing in the editor though). Get Location in title sequence command editor now has 100% accuracy compared to before where it would usually get some offset value. Added `get_map_coordinates_from_pos_window` which will allow getting the viewport coordinates of a specific window even if the input coordinates are under another window. This has use with getting 2D positions from the main window without the other windows getting in the way. Options window will now always specify the config title sequence in the dropdown and not the current title sequence. Made a global variable `gLoadKeepWindowsOpen`, in game.h to keep windows open when loading a park. When loading a title sequence park in-game. The sequence player will force-close all park-specific windows ahead of time. Skipping while testing title sequences no longer needs to reload the park if the current playback position is already before the target position and ahead of the load position. Added changelog entry.
2017-10-30 12:07:01 +01:00
auto result = parkImporter->LoadFromStream(stream, info.Type == FILE_TYPE::SCENARIO, false, path.c_str());
// From this point onwards the currently loaded park will be corrupted if loading fails
// so reload the title screen if that happens.
loadTitleScreenFirstOnFail = true;
GameUnloadScripts();
_objectManager->LoadObjects(result.RequiredObjects);
// TODO: Have a separate GameState and exchange once loaded.
auto& gameState = ::GetGameState();
parkImporter->Import(gameState);
gScenarioSavePath = path;
gCurrentLoadedPath = path;
gFirstTimeSaving = true;
GameFixSaveVars();
MapAnimationAutoCreate();
EntityTweener::Get().Reset();
gScreenAge = 0;
gLastAutoSaveUpdate = kAutosavePause;
2021-08-17 09:36:18 +02:00
#ifndef DISABLE_NETWORK
bool sendMap = false;
2021-08-17 09:36:18 +02:00
#endif
if (!asScenario && (info.Type == FILE_TYPE::PARK || info.Type == FILE_TYPE::SAVED_GAME))
{
2021-08-17 09:36:18 +02:00
#ifndef DISABLE_NETWORK
if (_network.GetMode() == NETWORK_MODE_CLIENT)
Feature: Preview title sequences in-game Title sequences can now be played back in-game, allowing for much easier editing. Improved title sequence playback in general. Clicking play while on a different title sequence will play the new one. Clicking stop will make the title screen go back to the config title sequence. And the closing the title sequence window will also make the game go back to the config title sequence, and reload the sequence if it was modified. Changes made to title sequences in-game are now correctly loaded in the title screen. Starting a title sequence within the editor will now always reset it even if it's the current playing sequence. (Not for playing in the editor though). Get Location in title sequence command editor now has 100% accuracy compared to before where it would usually get some offset value. Added `get_map_coordinates_from_pos_window` which will allow getting the viewport coordinates of a specific window even if the input coordinates are under another window. This has use with getting 2D positions from the main window without the other windows getting in the way. Options window will now always specify the config title sequence in the dropdown and not the current title sequence. Made a global variable `gLoadKeepWindowsOpen`, in game.h to keep windows open when loading a park. When loading a title sequence park in-game. The sequence player will force-close all park-specific windows ahead of time. Skipping while testing title sequences no longer needs to reload the park if the current playback position is already before the target position and ahead of the load position. Added changelog entry.
2017-10-30 12:07:01 +01:00
{
_network.Close();
}
2021-08-17 09:36:18 +02:00
#endif
GameLoadInit();
2021-08-17 09:36:18 +02:00
#ifndef DISABLE_NETWORK
if (_network.GetMode() == NETWORK_MODE_SERVER)
{
sendMap = true;
}
2021-08-17 09:36:18 +02:00
#endif
}
else
{
ScenarioBegin(gameState);
2021-08-17 09:36:18 +02:00
#ifndef DISABLE_NETWORK
if (_network.GetMode() == NETWORK_MODE_SERVER)
{
sendMap = true;
Feature: Preview title sequences in-game Title sequences can now be played back in-game, allowing for much easier editing. Improved title sequence playback in general. Clicking play while on a different title sequence will play the new one. Clicking stop will make the title screen go back to the config title sequence. And the closing the title sequence window will also make the game go back to the config title sequence, and reload the sequence if it was modified. Changes made to title sequences in-game are now correctly loaded in the title screen. Starting a title sequence within the editor will now always reset it even if it's the current playing sequence. (Not for playing in the editor though). Get Location in title sequence command editor now has 100% accuracy compared to before where it would usually get some offset value. Added `get_map_coordinates_from_pos_window` which will allow getting the viewport coordinates of a specific window even if the input coordinates are under another window. This has use with getting 2D positions from the main window without the other windows getting in the way. Options window will now always specify the config title sequence in the dropdown and not the current title sequence. Made a global variable `gLoadKeepWindowsOpen`, in game.h to keep windows open when loading a park. When loading a title sequence park in-game. The sequence player will force-close all park-specific windows ahead of time. Skipping while testing title sequences no longer needs to reload the park if the current playback position is already before the target position and ahead of the load position. Added changelog entry.
2017-10-30 12:07:01 +01:00
}
if (_network.GetMode() == NETWORK_MODE_CLIENT)
Feature: Preview title sequences in-game Title sequences can now be played back in-game, allowing for much easier editing. Improved title sequence playback in general. Clicking play while on a different title sequence will play the new one. Clicking stop will make the title screen go back to the config title sequence. And the closing the title sequence window will also make the game go back to the config title sequence, and reload the sequence if it was modified. Changes made to title sequences in-game are now correctly loaded in the title screen. Starting a title sequence within the editor will now always reset it even if it's the current playing sequence. (Not for playing in the editor though). Get Location in title sequence command editor now has 100% accuracy compared to before where it would usually get some offset value. Added `get_map_coordinates_from_pos_window` which will allow getting the viewport coordinates of a specific window even if the input coordinates are under another window. This has use with getting 2D positions from the main window without the other windows getting in the way. Options window will now always specify the config title sequence in the dropdown and not the current title sequence. Made a global variable `gLoadKeepWindowsOpen`, in game.h to keep windows open when loading a park. When loading a title sequence park in-game. The sequence player will force-close all park-specific windows ahead of time. Skipping while testing title sequences no longer needs to reload the park if the current playback position is already before the target position and ahead of the load position. Added changelog entry.
2017-10-30 12:07:01 +01:00
{
_network.Close();
Feature: Preview title sequences in-game Title sequences can now be played back in-game, allowing for much easier editing. Improved title sequence playback in general. Clicking play while on a different title sequence will play the new one. Clicking stop will make the title screen go back to the config title sequence. And the closing the title sequence window will also make the game go back to the config title sequence, and reload the sequence if it was modified. Changes made to title sequences in-game are now correctly loaded in the title screen. Starting a title sequence within the editor will now always reset it even if it's the current playing sequence. (Not for playing in the editor though). Get Location in title sequence command editor now has 100% accuracy compared to before where it would usually get some offset value. Added `get_map_coordinates_from_pos_window` which will allow getting the viewport coordinates of a specific window even if the input coordinates are under another window. This has use with getting 2D positions from the main window without the other windows getting in the way. Options window will now always specify the config title sequence in the dropdown and not the current title sequence. Made a global variable `gLoadKeepWindowsOpen`, in game.h to keep windows open when loading a park. When loading a title sequence park in-game. The sequence player will force-close all park-specific windows ahead of time. Skipping while testing title sequences no longer needs to reload the park if the current playback position is already before the target position and ahead of the load position. Added changelog entry.
2017-10-30 12:07:01 +01:00
}
2021-08-17 09:36:18 +02:00
#endif
Feature: Preview title sequences in-game Title sequences can now be played back in-game, allowing for much easier editing. Improved title sequence playback in general. Clicking play while on a different title sequence will play the new one. Clicking stop will make the title screen go back to the config title sequence. And the closing the title sequence window will also make the game go back to the config title sequence, and reload the sequence if it was modified. Changes made to title sequences in-game are now correctly loaded in the title screen. Starting a title sequence within the editor will now always reset it even if it's the current playing sequence. (Not for playing in the editor though). Get Location in title sequence command editor now has 100% accuracy compared to before where it would usually get some offset value. Added `get_map_coordinates_from_pos_window` which will allow getting the viewport coordinates of a specific window even if the input coordinates are under another window. This has use with getting 2D positions from the main window without the other windows getting in the way. Options window will now always specify the config title sequence in the dropdown and not the current title sequence. Made a global variable `gLoadKeepWindowsOpen`, in game.h to keep windows open when loading a park. When loading a title sequence park in-game. The sequence player will force-close all park-specific windows ahead of time. Skipping while testing title sequences no longer needs to reload the park if the current playback position is already before the target position and ahead of the load position. Added changelog entry.
2017-10-30 12:07:01 +01:00
}
// This ensures that the newly loaded save reflects the user's
// 'show real names of guests' option, now that it's a global setting
2024-05-10 12:10:21 +02:00
PeepUpdateNames(Config::Get().general.ShowRealNamesOfGuests);
2021-08-17 09:36:18 +02:00
#ifndef DISABLE_NETWORK
if (sendMap)
Feature: Preview title sequences in-game Title sequences can now be played back in-game, allowing for much easier editing. Improved title sequence playback in general. Clicking play while on a different title sequence will play the new one. Clicking stop will make the title screen go back to the config title sequence. And the closing the title sequence window will also make the game go back to the config title sequence, and reload the sequence if it was modified. Changes made to title sequences in-game are now correctly loaded in the title screen. Starting a title sequence within the editor will now always reset it even if it's the current playing sequence. (Not for playing in the editor though). Get Location in title sequence command editor now has 100% accuracy compared to before where it would usually get some offset value. Added `get_map_coordinates_from_pos_window` which will allow getting the viewport coordinates of a specific window even if the input coordinates are under another window. This has use with getting 2D positions from the main window without the other windows getting in the way. Options window will now always specify the config title sequence in the dropdown and not the current title sequence. Made a global variable `gLoadKeepWindowsOpen`, in game.h to keep windows open when loading a park. When loading a title sequence park in-game. The sequence player will force-close all park-specific windows ahead of time. Skipping while testing title sequences no longer needs to reload the park if the current playback position is already before the target position and ahead of the load position. Added changelog entry.
2017-10-30 12:07:01 +01:00
{
_network.ServerSendMap();
Feature: Preview title sequences in-game Title sequences can now be played back in-game, allowing for much easier editing. Improved title sequence playback in general. Clicking play while on a different title sequence will play the new one. Clicking stop will make the title screen go back to the config title sequence. And the closing the title sequence window will also make the game go back to the config title sequence, and reload the sequence if it was modified. Changes made to title sequences in-game are now correctly loaded in the title screen. Starting a title sequence within the editor will now always reset it even if it's the current playing sequence. (Not for playing in the editor though). Get Location in title sequence command editor now has 100% accuracy compared to before where it would usually get some offset value. Added `get_map_coordinates_from_pos_window` which will allow getting the viewport coordinates of a specific window even if the input coordinates are under another window. This has use with getting 2D positions from the main window without the other windows getting in the way. Options window will now always specify the config title sequence in the dropdown and not the current title sequence. Made a global variable `gLoadKeepWindowsOpen`, in game.h to keep windows open when loading a park. When loading a title sequence park in-game. The sequence player will force-close all park-specific windows ahead of time. Skipping while testing title sequences no longer needs to reload the park if the current playback position is already before the target position and ahead of the load position. Added changelog entry.
2017-10-30 12:07:01 +01:00
}
2021-08-17 09:36:18 +02:00
#endif
#ifdef USE_BREAKPAD
if (_network.GetMode() == NETWORK_MODE_NONE)
{
StartSilentRecord();
}
#endif
if (result.SemiCompatibleVersion)
{
auto windowManager = _uiContext->GetWindowManager();
auto ft = Formatter();
ft.Add<uint32_t>(result.TargetVersion);
ft.Add<uint32_t>(OpenRCT2::PARK_FILE_CURRENT_VERSION);
windowManager->ShowError(STR_WARNING_PARK_VERSION_TITLE, STR_WARNING_PARK_VERSION_MESSAGE, ft);
}
else if (HasObjectsThatUseFallbackImages())
{
Console::Error::WriteLine("Park has objects which require RCT1 linked. Fallback images will be used.");
auto windowManager = _uiContext->GetWindowManager();
windowManager->ShowError(STR_PARK_USES_FALLBACK_IMAGES_WARNING, STR_EMPTY, Formatter());
}
return true;
Feature: Preview title sequences in-game Title sequences can now be played back in-game, allowing for much easier editing. Improved title sequence playback in general. Clicking play while on a different title sequence will play the new one. Clicking stop will make the title screen go back to the config title sequence. And the closing the title sequence window will also make the game go back to the config title sequence, and reload the sequence if it was modified. Changes made to title sequences in-game are now correctly loaded in the title screen. Starting a title sequence within the editor will now always reset it even if it's the current playing sequence. (Not for playing in the editor though). Get Location in title sequence command editor now has 100% accuracy compared to before where it would usually get some offset value. Added `get_map_coordinates_from_pos_window` which will allow getting the viewport coordinates of a specific window even if the input coordinates are under another window. This has use with getting 2D positions from the main window without the other windows getting in the way. Options window will now always specify the config title sequence in the dropdown and not the current title sequence. Made a global variable `gLoadKeepWindowsOpen`, in game.h to keep windows open when loading a park. When loading a title sequence park in-game. The sequence player will force-close all park-specific windows ahead of time. Skipping while testing title sequences no longer needs to reload the park if the current playback position is already before the target position and ahead of the load position. Added changelog entry.
2017-10-30 12:07:01 +01:00
}
catch (const ObjectLoadException& e)
Feature: Preview title sequences in-game Title sequences can now be played back in-game, allowing for much easier editing. Improved title sequence playback in general. Clicking play while on a different title sequence will play the new one. Clicking stop will make the title screen go back to the config title sequence. And the closing the title sequence window will also make the game go back to the config title sequence, and reload the sequence if it was modified. Changes made to title sequences in-game are now correctly loaded in the title screen. Starting a title sequence within the editor will now always reset it even if it's the current playing sequence. (Not for playing in the editor though). Get Location in title sequence command editor now has 100% accuracy compared to before where it would usually get some offset value. Added `get_map_coordinates_from_pos_window` which will allow getting the viewport coordinates of a specific window even if the input coordinates are under another window. This has use with getting 2D positions from the main window without the other windows getting in the way. Options window will now always specify the config title sequence in the dropdown and not the current title sequence. Made a global variable `gLoadKeepWindowsOpen`, in game.h to keep windows open when loading a park. When loading a title sequence park in-game. The sequence player will force-close all park-specific windows ahead of time. Skipping while testing title sequences no longer needs to reload the park if the current playback position is already before the target position and ahead of the load position. Added changelog entry.
2017-10-30 12:07:01 +01:00
{
Console::Error::WriteLine("Unable to open park: missing objects");
// If loading the SV6 or SV4 failed return to the title screen if requested.
if (loadTitleScreenFirstOnFail)
{
SetActiveScene(GetTitleScene());
}
// The path needs to be duplicated as it's a const here
// which the window function doesn't like
auto intent = Intent(WindowClass::ObjectLoadError);
intent.PutExtra(INTENT_EXTRA_PATH, path);
intent.PutExtra(INTENT_EXTRA_LIST, const_cast<ObjectEntryDescriptor*>(e.MissingObjects.data()));
intent.PutExtra(INTENT_EXTRA_LIST_COUNT, static_cast<uint32_t>(e.MissingObjects.size()));
auto windowManager = _uiContext->GetWindowManager();
windowManager->OpenIntent(&intent);
Feature: Preview title sequences in-game Title sequences can now be played back in-game, allowing for much easier editing. Improved title sequence playback in general. Clicking play while on a different title sequence will play the new one. Clicking stop will make the title screen go back to the config title sequence. And the closing the title sequence window will also make the game go back to the config title sequence, and reload the sequence if it was modified. Changes made to title sequences in-game are now correctly loaded in the title screen. Starting a title sequence within the editor will now always reset it even if it's the current playing sequence. (Not for playing in the editor though). Get Location in title sequence command editor now has 100% accuracy compared to before where it would usually get some offset value. Added `get_map_coordinates_from_pos_window` which will allow getting the viewport coordinates of a specific window even if the input coordinates are under another window. This has use with getting 2D positions from the main window without the other windows getting in the way. Options window will now always specify the config title sequence in the dropdown and not the current title sequence. Made a global variable `gLoadKeepWindowsOpen`, in game.h to keep windows open when loading a park. When loading a title sequence park in-game. The sequence player will force-close all park-specific windows ahead of time. Skipping while testing title sequences no longer needs to reload the park if the current playback position is already before the target position and ahead of the load position. Added changelog entry.
2017-10-30 12:07:01 +01:00
}
catch (const UnsupportedRideTypeException&)
{
Console::Error::WriteLine("Unable to open park: unsupported ride types");
// If loading the SV6 or SV4 failed return to the title screen if requested.
if (loadTitleScreenFirstOnFail)
{
SetActiveScene(GetTitleScene());
}
auto windowManager = _uiContext->GetWindowManager();
windowManager->ShowError(STR_FILE_CONTAINS_UNSUPPORTED_RIDE_TYPES, STR_NONE, {});
}
catch (const UnsupportedVersionException& e)
{
Console::Error::WriteLine("Unable to open park: unsupported park version");
if (loadTitleScreenFirstOnFail)
{
SetActiveScene(GetTitleScene());
}
auto windowManager = _uiContext->GetWindowManager();
Formatter ft;
2022-04-24 15:51:41 +02:00
/*if (e.TargetVersion < PARK_FILE_MIN_SUPPORTED_VERSION)
2022-04-23 15:45:15 +02:00
{
ft.Add<uint32_t>(e.TargetVersion);
windowManager->ShowError(STR_ERROR_PARK_VERSION_TITLE, STR_ERROR_PARK_VERSION_TOO_OLD_MESSAGE, ft);
}
2022-04-24 15:51:41 +02:00
else*/
2022-04-23 15:45:15 +02:00
{
if (e.MinVersion == e.TargetVersion)
{
ft.Add<uint32_t>(e.TargetVersion);
ft.Add<uint32_t>(OpenRCT2::PARK_FILE_CURRENT_VERSION);
windowManager->ShowError(STR_ERROR_PARK_VERSION_TITLE, STR_ERROR_PARK_VERSION_TOO_NEW_MESSAGE_2, ft);
}
else
{
ft.Add<uint32_t>(e.TargetVersion);
ft.Add<uint32_t>(e.MinVersion);
ft.Add<uint32_t>(OpenRCT2::PARK_FILE_CURRENT_VERSION);
windowManager->ShowError(STR_ERROR_PARK_VERSION_TITLE, STR_ERROR_PARK_VERSION_TOO_NEW_MESSAGE, ft);
}
2022-04-23 15:45:15 +02:00
}
}
catch (const std::exception& e)
{
// If loading the SV6 or SV4 failed return to the title screen if requested.
if (loadTitleScreenFirstOnFail)
{
SetActiveScene(GetTitleScene());
}
Console::Error::WriteLine(e.what());
}
Feature: Preview title sequences in-game Title sequences can now be played back in-game, allowing for much easier editing. Improved title sequence playback in general. Clicking play while on a different title sequence will play the new one. Clicking stop will make the title screen go back to the config title sequence. And the closing the title sequence window will also make the game go back to the config title sequence, and reload the sequence if it was modified. Changes made to title sequences in-game are now correctly loaded in the title screen. Starting a title sequence within the editor will now always reset it even if it's the current playing sequence. (Not for playing in the editor though). Get Location in title sequence command editor now has 100% accuracy compared to before where it would usually get some offset value. Added `get_map_coordinates_from_pos_window` which will allow getting the viewport coordinates of a specific window even if the input coordinates are under another window. This has use with getting 2D positions from the main window without the other windows getting in the way. Options window will now always specify the config title sequence in the dropdown and not the current title sequence. Made a global variable `gLoadKeepWindowsOpen`, in game.h to keep windows open when loading a park. When loading a title sequence park in-game. The sequence player will force-close all park-specific windows ahead of time. Skipping while testing title sequences no longer needs to reload the park if the current playback position is already before the target position and ahead of the load position. Added changelog entry.
2017-10-30 12:07:01 +01:00
return false;
}
private:
bool HasObjectsThatUseFallbackImages()
{
2024-03-27 21:26:07 +01:00
for (auto objectType : getAllObjectTypes())
{
auto maxObjectsOfType = static_cast<ObjectEntryIndex>(getObjectEntryGroupCount(objectType));
for (ObjectEntryIndex i = 0; i < maxObjectsOfType; i++)
{
auto obj = _objectManager->GetLoadedObject(objectType, i);
if (obj != nullptr)
{
if (obj->UsesFallbackImages())
return true;
}
}
}
return false;
}
std::string GetOrPromptRCT2Path()
{
auto result = std::string();
2022-01-27 14:21:46 +01:00
if (gCustomRCT2DataPath.empty())
{
// Check install directory
2024-05-10 12:10:21 +02:00
if (Config::Get().general.RCT2Path.empty() || !Platform::OriginalGameDataExists(Config::Get().general.RCT2Path))
{
LOG_VERBOSE(
2024-05-10 12:10:21 +02:00
"install directory does not exist or invalid directory selected, %s",
Config::Get().general.RCT2Path.c_str());
if (!Config::FindOrBrowseInstallDirectory())
{
2024-05-10 12:10:21 +02:00
auto path = Config::GetDefaultPath();
2018-06-22 23:25:16 +02:00
Console::Error::WriteLine(
"An RCT2 install directory must be specified! Please edit \"game_path\" in %s.\n", path.c_str());
return std::string();
}
}
2024-05-10 12:10:21 +02:00
result = Config::Get().general.RCT2Path;
}
else
{
2022-01-27 14:21:46 +01:00
result = gCustomRCT2DataPath;
}
return result;
}
bool LoadBaseGraphics()
{
if (!GfxLoadG1(*_env))
{
return false;
}
GfxLoadG2();
GfxLoadCsg();
FontSpriteInitialiseCharacters();
return true;
}
void SwitchToStartUpScene()
{
if (gOpenRCT2Headless)
{
// NONE or OPEN are the only allowed actions for headless mode
if (gOpenRCT2StartupAction != StartupAction::Open)
{
gOpenRCT2StartupAction = StartupAction::None;
}
}
else
{
2024-05-10 12:10:21 +02:00
if ((gOpenRCT2StartupAction == StartupAction::Title) && Config::Get().general.PlayIntro)
{
gOpenRCT2StartupAction = StartupAction::Intro;
}
}
IScene* nextScene{};
2018-06-22 23:25:16 +02:00
switch (gOpenRCT2StartupAction)
{
case StartupAction::Intro:
{
nextScene = GetIntroScene();
break;
}
case StartupAction::Title:
{
nextScene = GetTitleScene();
break;
}
case StartupAction::Open:
{
2018-06-22 23:25:16 +02:00
// A path that includes "://" is illegal with all common filesystems, so it is almost certainly a URL
// This way all cURL supported protocols, like http, ftp, scp and smb are automatically handled
if (strstr(gOpenRCT2StartupActionPath, "://") != nullptr)
{
2018-06-22 23:25:16 +02:00
#ifndef DISABLE_HTTP
// Download park and open it using its temporary filename
auto data = DownloadPark(gOpenRCT2StartupActionPath);
if (data.empty())
2018-06-22 23:25:16 +02:00
{
nextScene = GetTitleScene();
break;
2018-06-22 23:25:16 +02:00
}
auto ms = MemoryStream(data.data(), data.size(), MEMORY_ACCESS::READ);
2018-06-22 23:25:16 +02:00
if (!LoadParkFromStream(&ms, gOpenRCT2StartupActionPath, true))
{
2018-06-22 23:25:16 +02:00
Console::Error::WriteLine("Failed to load '%s'", gOpenRCT2StartupActionPath);
nextScene = GetTitleScene();
break;
}
2018-06-22 23:25:16 +02:00
#endif
2017-07-02 20:10:22 +02:00
}
2018-06-22 23:25:16 +02:00
else
2017-07-02 20:10:22 +02:00
{
2018-06-22 23:25:16 +02:00
try
{
if (!LoadParkFromFile(gOpenRCT2StartupActionPath, true))
{
nextScene = GetTitleScene();
break;
2018-06-22 23:25:16 +02:00
}
}
catch (const std::exception& ex)
{
Console::Error::WriteLine("Failed to load '%s'", gOpenRCT2StartupActionPath);
Console::Error::WriteLine("%s", ex.what());
nextScene = GetTitleScene();
break;
2018-06-22 23:25:16 +02:00
}
2017-07-02 20:10:22 +02:00
}
// Successfully loaded a file
nextScene = GetGameScene();
break;
}
case StartupAction::Edit:
{
if (String::SizeOf(gOpenRCT2StartupActionPath) == 0)
{
Editor::Load();
nextScene = GetGameScene();
}
2024-05-02 23:11:53 +02:00
else if (Editor::LoadLandscape(gOpenRCT2StartupActionPath))
{
nextScene = GetGameScene();
}
else
{
nextScene = GetTitleScene();
}
break;
}
default:
{
nextScene = GetTitleScene();
}
}
SetActiveScene(nextScene);
InitNetworkGame(nextScene == GetGameScene());
}
void InitNetworkGame(bool isGameScene)
{
if (isGameScene)
{
#ifndef DISABLE_NETWORK
if (gNetworkStart == NETWORK_MODE_SERVER)
{
if (gNetworkStartPort == 0)
{
2024-05-10 12:10:21 +02:00
gNetworkStartPort = Config::Get().network.DefaultPort;
2018-06-22 23:25:16 +02:00
}
if (gNetworkStartAddress.empty())
{
2024-05-10 12:10:21 +02:00
gNetworkStartAddress = Config::Get().network.ListenAddress;
}
if (gCustomPassword.empty())
{
2024-05-10 12:10:21 +02:00
_network.SetPassword(Config::Get().network.DefaultPassword.c_str());
}
else
{
_network.SetPassword(gCustomPassword);
}
_network.BeginServer(gNetworkStartPort, gNetworkStartAddress);
}
else
#endif // DISABLE_NETWORK
{
GameLoadScripts();
GameNotifyMapChanged();
}
}
#ifndef DISABLE_NETWORK
else if (gNetworkStart == NETWORK_MODE_CLIENT)
{
if (gNetworkStartPort == 0)
{
2024-05-10 12:10:21 +02:00
gNetworkStartPort = Config::Get().network.DefaultPort;
}
_network.BeginClient(gNetworkStartHost, gNetworkStartPort);
}
#endif // DISABLE_NETWORK
}
/**
* Launches the game, after command line arguments have been parsed and processed.
*/
void Launch()
{
if (!_versionCheckFuture.valid())
{
_versionCheckFuture = std::async(std::launch::async, [this] {
_newVersionInfo = GetLatestVersion();
if (!String::StartsWith(gVersionInfoTag, _newVersionInfo.tag))
{
_hasNewVersionInfo = true;
}
});
}
if (!gOpenRCT2Headless)
{
_preloaderScene->SetOnComplete([&]() { SwitchToStartUpScene(); });
}
else
{
SwitchToStartUpScene();
}
2018-03-18 01:31:02 +01:00
_stdInOutConsole.Start();
RunGameLoop();
}
bool ShouldDraw()
{
if (gOpenRCT2Headless)
return false;
if (_uiContext->IsMinimised())
return false;
return true;
}
bool ShouldRunVariableFrame()
{
if (!ShouldDraw())
return false;
2024-05-10 12:10:21 +02:00
if (!Config::Get().general.UncapFPS)
2018-06-22 23:25:16 +02:00
return false;
if (gGameSpeed > 4)
return false;
return true;
}
/**
2018-06-22 23:25:16 +02:00
* Run the main game loop until the finished flag is set.
*/
void RunGameLoop()
{
PROFILED_FUNCTION();
LOG_VERBOSE("begin openrct2 loop");
_finished = false;
2017-09-04 23:17:35 +02:00
#ifndef __EMSCRIPTEN__
_variableFrame = ShouldRunVariableFrame();
do
{
2017-09-07 13:31:28 +02:00
RunFrame();
2018-06-22 23:25:16 +02:00
} while (!_finished);
2017-09-04 23:17:35 +02:00
#else
2018-06-22 23:25:16 +02:00
emscripten_set_main_loop_arg(
[](void* vctx) -> {
auto ctx = reinterpret_cast<Context*>(vctx);
ctx->RunFrame();
2018-06-22 23:25:16 +02:00
},
this, 0, 1);
2017-09-04 23:17:35 +02:00
#endif // __EMSCRIPTEN__
LOG_VERBOSE("finish openrct2 loop");
}
void RunFrame()
{
PROFILED_FUNCTION();
const auto deltaTime = _timer.GetElapsedTimeAndRestart().count();
// Make sure we catch the state change and reset it.
bool useVariableFrame = ShouldRunVariableFrame();
if (_variableFrame != useVariableFrame)
{
_variableFrame = useVariableFrame;
// Switching from variable to fixed frame requires reseting
// of entity positions back to end of tick positions
auto& tweener = EntityTweener::Get();
tweener.Restore();
tweener.Reset();
}
UpdateTimeAccumulators(deltaTime);
if (useVariableFrame)
{
RunVariableFrame(deltaTime);
}
else
{
RunFixedFrame(deltaTime);
}
}
void UpdateTimeAccumulators(float deltaTime)
{
// Ticks
float scaledDeltaTime = deltaTime * _timeScale;
_ticksAccumulator = std::min(_ticksAccumulator + scaledDeltaTime, kGameUpdateMaxThreshold);
// Real Time.
_realtimeAccumulator = std::min(_realtimeAccumulator + deltaTime, kGameUpdateMaxThreshold);
while (_realtimeAccumulator >= kGameUpdateTimeMS)
{
gCurrentRealTimeTicks++;
_realtimeAccumulator -= kGameUpdateTimeMS;
}
}
void RunFixedFrame(float deltaTime)
{
PROFILED_FUNCTION();
2017-06-26 00:45:19 +02:00
_uiContext->ProcessMessages();
if (_ticksAccumulator < kGameUpdateTimeMS)
{
const auto sleepTimeSec = (kGameUpdateTimeMS - _ticksAccumulator);
Platform::Sleep(static_cast<uint32_t>(sleepTimeSec * 1000.f));
return;
}
while (_ticksAccumulator >= kGameUpdateTimeMS)
{
2021-12-02 16:35:31 +01:00
Tick();
_ticksAccumulator -= kGameUpdateTimeMS;
}
ContextHandleInput();
WindowUpdateAll();
if (ShouldDraw())
{
Draw();
}
}
void RunVariableFrame(float deltaTime)
{
PROFILED_FUNCTION();
const bool shouldDraw = ShouldDraw();
auto& tweener = EntityTweener::Get();
2017-06-26 00:45:19 +02:00
_uiContext->ProcessMessages();
while (_ticksAccumulator >= kGameUpdateTimeMS)
{
// Get the original position of each sprite
if (shouldDraw)
tweener.PreTick();
2021-12-02 16:35:31 +01:00
Tick();
_ticksAccumulator -= kGameUpdateTimeMS;
// Get the next position of each sprite
if (shouldDraw)
tweener.PostTick();
}
ContextHandleInput();
WindowUpdateAll();
if (shouldDraw)
{
const float alpha = std::min(_ticksAccumulator / kGameUpdateTimeMS, 1.0f);
tweener.Tween(alpha);
Draw();
}
}
void Draw()
{
PROFILED_FUNCTION();
_drawingEngine->BeginDraw();
_painter->Paint(*_drawingEngine);
_drawingEngine->EndDraw();
}
2021-12-02 16:35:31 +01:00
void Tick()
2017-06-26 00:45:19 +02:00
{
PROFILED_FUNCTION();
// TODO: This variable has been never "variable" in time, some code expects
// this to be 40Hz (25 ms). Refactor this once the UI is decoupled.
gCurrentDeltaTime = static_cast<uint16_t>(kGameUpdateTimeMS * 1000.0f);
if (GameIsNotPaused())
2017-06-26 00:45:19 +02:00
{
gPaletteEffectFrame += gCurrentDeltaTime;
2017-06-26 00:45:19 +02:00
}
DateUpdateRealTimeOfDay();
2017-06-26 00:45:19 +02:00
if (_activeScene)
_activeScene->Tick();
2017-06-26 00:45:19 +02:00
2017-11-10 21:23:23 +01:00
#ifdef __ENABLE_DISCORD__
if (_discordService != nullptr)
{
2021-12-02 16:35:31 +01:00
_discordService->Tick();
2017-11-10 21:23:23 +01:00
}
#endif
2023-01-16 21:14:50 +01:00
ChatUpdate();
#ifdef ENABLE_SCRIPTING
2021-12-02 16:35:31 +01:00
_scriptEngine.Tick();
2020-02-23 13:55:48 +01:00
#endif
_stdInOutConsole.ProcessEvalQueue();
2021-12-02 16:35:31 +01:00
_uiContext->Tick();
2017-06-26 00:45:19 +02:00
}
/**
* Ensure that the custom user content folders are present
*/
void EnsureUserContentDirectoriesExist()
{
EnsureDirectoriesExist(
DIRBASE::USER,
{
DIRID::OBJECT,
DIRID::SAVE,
DIRID::SCENARIO,
DIRID::TRACK,
DIRID::LANDSCAPE,
DIRID::HEIGHTMAP,
2020-04-26 15:52:57 +02:00
DIRID::PLUGIN,
DIRID::THEME,
DIRID::SEQUENCE,
DIRID::REPLAY,
DIRID::LOG_DESYNCS,
DIRID::CRASH,
});
}
void EnsureDirectoriesExist(const DIRBASE dirBase, const std::initializer_list<DIRID>& dirIds)
{
for (const auto& dirId : dirIds)
{
auto path = _env->GetDirectoryPath(dirBase, dirId);
if (!Path::CreateDirectory(path))
LOG_ERROR("Unable to create directory '%s'.", path.c_str());
}
}
/**
2018-06-22 23:25:16 +02:00
* Copy saved games and landscapes to user directory
*/
void CopyOriginalUserFilesOver()
{
CopyOriginalUserFilesOver(DIRID::SAVE, "*.sv6");
CopyOriginalUserFilesOver(DIRID::LANDSCAPE, "*.sc6");
}
2018-06-22 23:25:16 +02:00
void CopyOriginalUserFilesOver(DIRID dirid, const std::string& pattern)
{
auto src = _env->GetDirectoryPath(DIRBASE::RCT2, dirid);
auto dst = _env->GetDirectoryPath(DIRBASE::USER, dirid);
CopyOriginalUserFilesOver(src, dst, pattern);
}
2018-06-22 23:25:16 +02:00
void CopyOriginalUserFilesOver(const std::string& srcRoot, const std::string& dstRoot, const std::string& pattern)
{
LOG_VERBOSE("CopyOriginalUserFilesOver('%s', '%s', '%s')", srcRoot.c_str(), dstRoot.c_str(), pattern.c_str());
auto scanPattern = Path::Combine(srcRoot, pattern);
auto scanner = Path::ScanDirectory(scanPattern, true);
while (scanner->Next())
{
auto src = std::string(scanner->GetPath());
auto dst = Path::Combine(dstRoot, scanner->GetPathRelative());
auto dstDirectory = Path::GetDirectory(dst);
// Create the directory if necessary
if (!Path::CreateDirectory(dstDirectory))
{
Console::Error::WriteLine("Could not create directory %s.", dstDirectory.c_str());
break;
}
// Only copy the file if it doesn't already exist
if (!File::Exists(dst))
{
Console::WriteLine("Copying '%s' to '%s'", src.c_str(), dst.c_str());
if (!File::Copy(src, dst, false))
{
Console::Error::WriteLine("Failed to copy '%s' to '%s'", src.c_str(), dst.c_str());
}
}
}
}
#ifndef DISABLE_HTTP
std::vector<uint8_t> DownloadPark(const std::string& url)
{
// Download park to buffer in memory
Http::Request request;
request.url = url;
request.method = Http::Method::GET;
Http::Response res;
try
{
res = Do(request);
if (res.status != Http::Status::Ok)
throw std::runtime_error("bad http status");
}
catch (std::exception& e)
{
Console::Error::WriteLine("Failed to download '%s', cause %s", request.url.c_str(), e.what());
return {};
}
std::vector<uint8_t> parkData;
parkData.resize(res.body.size());
std::memcpy(parkData.data(), res.body.c_str(), parkData.size());
return parkData;
}
#endif
bool HasNewVersionInfo() const override
{
return _hasNewVersionInfo;
}
const NewVersionInfo* GetNewVersionInfo() const override
{
return &_newVersionInfo;
}
void SetTimeScale(float newScale) override
{
_timeScale = std::clamp(newScale, kGameMinTimeScale, kGameMaxTimeScale);
}
float GetTimeScale() const override
{
return _timeScale;
}
};
2018-06-22 23:25:16 +02:00
Context* Context::Instance = nullptr;
std::unique_ptr<IContext> CreateContext()
{
return CreateContext(CreatePlatformEnvironment(), Audio::CreateDummyAudioContext(), CreateDummyUiContext());
}
std::unique_ptr<IContext> CreateContext(
const std::shared_ptr<IPlatformEnvironment>& env, const std::shared_ptr<Audio::IAudioContext>& audioContext,
2018-04-27 19:47:57 +02:00
const std::shared_ptr<IUiContext>& uiContext)
{
return std::make_unique<Context>(env, audioContext, uiContext);
}
2018-06-22 23:25:16 +02:00
IContext* GetContext()
{
return Context::Instance;
}
2018-06-22 23:25:16 +02:00
} // namespace OpenRCT2
2022-11-06 21:49:07 +01:00
void ContextInit()
{
2018-02-01 18:49:14 +01:00
GetContext()->GetUiContext()->GetWindowManager()->Init();
}
2017-09-10 11:02:16 +02:00
2022-11-06 21:49:07 +01:00
bool ContextLoadParkFromStream(void* stream)
2018-02-01 18:49:14 +01:00
{
return GetContext()->LoadParkFromStream(static_cast<IStream*>(stream), "");
2018-02-01 18:49:14 +01:00
}
Feature: Preview title sequences in-game Title sequences can now be played back in-game, allowing for much easier editing. Improved title sequence playback in general. Clicking play while on a different title sequence will play the new one. Clicking stop will make the title screen go back to the config title sequence. And the closing the title sequence window will also make the game go back to the config title sequence, and reload the sequence if it was modified. Changes made to title sequences in-game are now correctly loaded in the title screen. Starting a title sequence within the editor will now always reset it even if it's the current playing sequence. (Not for playing in the editor though). Get Location in title sequence command editor now has 100% accuracy compared to before where it would usually get some offset value. Added `get_map_coordinates_from_pos_window` which will allow getting the viewport coordinates of a specific window even if the input coordinates are under another window. This has use with getting 2D positions from the main window without the other windows getting in the way. Options window will now always specify the config title sequence in the dropdown and not the current title sequence. Made a global variable `gLoadKeepWindowsOpen`, in game.h to keep windows open when loading a park. When loading a title sequence park in-game. The sequence player will force-close all park-specific windows ahead of time. Skipping while testing title sequences no longer needs to reload the park if the current playback position is already before the target position and ahead of the load position. Added changelog entry.
2017-10-30 12:07:01 +01:00
void OpenRCT2WriteFullVersionInfo(utf8* buffer, size_t bufferSize)
2018-02-01 18:49:14 +01:00
{
String::Set(buffer, bufferSize, gVersionInfoFull);
}
void OpenRCT2Finish()
2018-02-01 18:49:14 +01:00
{
GetContext()->Finish();
}
2022-11-06 21:49:07 +01:00
void ContextSetCurrentCursor(CursorID cursor)
2018-02-01 18:49:14 +01:00
{
GetContext()->GetUiContext()->SetCursor(cursor);
2018-02-01 18:49:14 +01:00
}
2017-03-25 18:42:14 +01:00
2022-11-06 21:49:07 +01:00
void ContextUpdateCursorScale()
2018-02-01 18:49:14 +01:00
{
2024-05-10 12:10:21 +02:00
GetContext()->GetUiContext()->SetCursorScale(static_cast<uint8_t>(std::round(Config::Get().general.WindowScale)));
2018-02-01 18:49:14 +01:00
}
2017-12-09 17:08:38 +01:00
2022-11-06 21:49:07 +01:00
void ContextHideCursor()
2018-02-01 18:49:14 +01:00
{
GetContext()->GetUiContext()->SetCursorVisible(false);
}
2017-03-25 18:42:14 +01:00
2022-11-06 21:49:07 +01:00
void ContextShowCursor()
2018-02-01 18:49:14 +01:00
{
GetContext()->GetUiContext()->SetCursorVisible(true);
}
2017-03-25 18:42:14 +01:00
2022-11-06 21:49:07 +01:00
ScreenCoordsXY ContextGetCursorPosition()
2018-02-01 18:49:14 +01:00
{
return GetContext()->GetUiContext()->GetCursorPosition();
2018-02-01 18:49:14 +01:00
}
2017-03-25 18:42:14 +01:00
2022-11-06 21:49:07 +01:00
ScreenCoordsXY ContextGetCursorPositionScaled()
2018-02-01 18:49:14 +01:00
{
2022-11-06 21:49:07 +01:00
auto cursorCoords = ContextGetCursorPosition();
2018-02-01 18:49:14 +01:00
// Compensate for window scaling.
2024-05-10 12:10:21 +02:00
return { static_cast<int32_t>(std::ceil(cursorCoords.x / Config::Get().general.WindowScale)),
static_cast<int32_t>(std::ceil(cursorCoords.y / Config::Get().general.WindowScale)) };
2018-02-01 18:49:14 +01:00
}
2017-03-25 18:42:14 +01:00
2022-11-06 21:49:07 +01:00
void ContextSetCursorPosition(const ScreenCoordsXY& cursorPosition)
2018-02-01 18:49:14 +01:00
{
GetContext()->GetUiContext()->SetCursorPosition(cursorPosition);
2018-02-01 18:49:14 +01:00
}
2017-03-25 18:42:14 +01:00
2022-11-06 21:49:07 +01:00
const CursorState* ContextGetCursorState()
2018-02-01 18:49:14 +01:00
{
return GetContext()->GetUiContext()->GetCursorState();
}
2017-03-25 18:42:14 +01:00
2022-11-06 21:49:07 +01:00
const uint8_t* ContextGetKeysState()
2018-02-01 18:49:14 +01:00
{
return GetContext()->GetUiContext()->GetKeysState();
}
2017-03-25 18:42:14 +01:00
2022-11-06 21:49:07 +01:00
const uint8_t* ContextGetKeysPressed()
2018-02-01 18:49:14 +01:00
{
return GetContext()->GetUiContext()->GetKeysPressed();
}
2017-03-25 18:42:14 +01:00
TextInputSession* ContextStartTextInput(u8string& buffer, size_t maxLength)
2018-02-01 18:49:14 +01:00
{
return GetContext()->GetUiContext()->StartTextInput(buffer, maxLength);
}
2017-03-25 18:42:14 +01:00
2022-11-06 21:49:07 +01:00
void ContextStopTextInput()
2018-02-01 18:49:14 +01:00
{
GetContext()->GetUiContext()->StopTextInput();
}
2017-03-25 18:42:14 +01:00
2022-11-06 21:49:07 +01:00
bool ContextIsInputActive()
2018-02-01 18:49:14 +01:00
{
return GetContext()->GetUiContext()->IsTextInputActive();
}
2017-03-26 04:36:22 +02:00
2022-11-06 21:49:07 +01:00
void ContextTriggerResize()
2018-02-01 18:49:14 +01:00
{
return GetContext()->GetUiContext()->TriggerResize();
}
2017-03-26 04:36:22 +02:00
2022-11-06 21:49:07 +01:00
void ContextSetFullscreenMode(int32_t mode)
2018-02-01 18:49:14 +01:00
{
return GetContext()->GetUiContext()->SetFullscreenMode(static_cast<FULLSCREEN_MODE>(mode));
2018-02-01 18:49:14 +01:00
}
2017-03-26 04:36:22 +02:00
2022-11-06 21:49:07 +01:00
void ContextRecreateWindow()
2018-02-01 18:49:14 +01:00
{
GetContext()->GetUiContext()->RecreateWindow();
}
2022-11-06 21:49:07 +01:00
int32_t ContextGetWidth()
2018-02-01 18:49:14 +01:00
{
return GetContext()->GetUiContext()->GetWidth();
}
2022-11-06 21:49:07 +01:00
int32_t ContextGetHeight()
2018-02-01 18:49:14 +01:00
{
return GetContext()->GetUiContext()->GetHeight();
}
2017-04-01 14:38:52 +02:00
2022-11-06 21:49:07 +01:00
bool ContextHasFocus()
2018-02-01 18:49:14 +01:00
{
return GetContext()->GetUiContext()->HasFocus();
}
2017-04-01 14:38:52 +02:00
2022-11-06 21:49:07 +01:00
void ContextSetCursorTrap(bool value)
2018-02-01 18:49:14 +01:00
{
GetContext()->GetUiContext()->SetCursorTrap(value);
}
WindowBase* ContextOpenWindow(WindowClass wc)
2018-02-01 18:49:14 +01:00
{
auto windowManager = GetContext()->GetUiContext()->GetWindowManager();
return windowManager->OpenWindow(wc);
}
WindowBase* ContextOpenWindowView(uint8_t wc)
2018-02-01 18:49:14 +01:00
{
auto windowManager = GetContext()->GetUiContext()->GetWindowManager();
return windowManager->OpenView(wc);
}
2017-09-05 20:55:18 +02:00
WindowBase* ContextOpenDetailWindow(uint8_t type, int32_t id)
2018-02-01 18:49:14 +01:00
{
auto windowManager = GetContext()->GetUiContext()->GetWindowManager();
return windowManager->OpenDetails(type, id);
}
2017-09-06 15:09:18 +02:00
WindowBase* ContextOpenIntent(Intent* intent)
2018-02-01 18:49:14 +01:00
{
auto windowManager = GetContext()->GetUiContext()->GetWindowManager();
return windowManager->OpenIntent(intent);
}
2017-09-10 11:02:16 +02:00
2022-11-06 21:49:07 +01:00
void ContextBroadcastIntent(Intent* intent)
2018-02-01 18:49:14 +01:00
{
auto windowManager = GetContext()->GetUiContext()->GetWindowManager();
windowManager->BroadcastIntent(*intent);
}
2017-10-06 23:03:48 +02:00
2022-11-06 21:49:07 +01:00
void ContextForceCloseWindowByClass(WindowClass windowClass)
2018-02-01 18:49:14 +01:00
{
auto windowManager = GetContext()->GetUiContext()->GetWindowManager();
windowManager->ForceClose(windowClass);
}
WindowBase* ContextShowError(StringId title, StringId message, const Formatter& args, const bool autoClose /* = false */)
2018-02-01 18:49:14 +01:00
{
auto windowManager = GetContext()->GetUiContext()->GetWindowManager();
return windowManager->ShowError(title, message, args, autoClose);
2018-02-01 18:49:14 +01:00
}
2022-11-06 21:49:07 +01:00
void ContextHandleInput()
2018-02-01 18:49:14 +01:00
{
auto windowManager = GetContext()->GetUiContext()->GetWindowManager();
windowManager->HandleInput();
}
2017-12-07 22:16:20 +01:00
2022-11-06 21:49:07 +01:00
void ContextInputHandleKeyboard(bool isTitle)
2018-02-01 18:49:14 +01:00
{
auto windowManager = GetContext()->GetUiContext()->GetWindowManager();
windowManager->HandleKeyboard(isTitle);
}
2022-11-06 21:49:07 +01:00
void ContextQuit()
2018-02-01 18:49:14 +01:00
{
GetContext()->Quit();
}
2017-07-28 19:43:48 +02:00
bool ContextOpenCommonFileDialog(utf8* outFilename, OpenRCT2::Ui::FileDialogDesc& desc, size_t outSize)
2018-02-01 18:49:14 +01:00
{
try
{
2022-01-28 23:50:24 +01:00
std::string result = GetContext()->GetUiContext()->ShowFileDialog(desc);
2018-02-01 18:49:14 +01:00
String::Set(outFilename, outSize, result.c_str());
return !result.empty();
}
2018-06-22 23:25:16 +02:00
catch (const std::exception& ex)
{
LOG_ERROR(ex.what());
2018-02-01 18:49:14 +01:00
outFilename[0] = '\0';
return false;
}
2018-02-01 18:49:14 +01:00
}
2022-03-10 00:12:05 +01:00
u8string ContextOpenCommonFileDialog(OpenRCT2::Ui::FileDialogDesc& desc)
{
try
{
return GetContext()->GetUiContext()->ShowFileDialog(desc);
}
catch (const std::exception& ex)
{
LOG_ERROR(ex.what());
2022-03-10 00:12:05 +01:00
return u8string{};
}
}