mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-24 00:03:11 +01:00
Refactor OpenRCT2.cpp
This commit is contained in:
687
src/OpenRCT2.cpp
687
src/OpenRCT2.cpp
@@ -14,348 +14,411 @@
|
||||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#include "audio/audio.h"
|
||||
#include "audio/mixer.h"
|
||||
#include "config.h"
|
||||
#include "editor.h"
|
||||
#include "game.h"
|
||||
#include "interface/chat.h"
|
||||
#include "interface/themes.h"
|
||||
#include "interface/window.h"
|
||||
#include "interface/viewport.h"
|
||||
#include "intro.h"
|
||||
#include "localisation/localisation.h"
|
||||
#include "network/http.h"
|
||||
#include <string>
|
||||
#include "core/Guard.hpp"
|
||||
#include "core/String.hpp"
|
||||
#include "network/network.h"
|
||||
#include "object_list.h"
|
||||
#include "OpenRCT2.h"
|
||||
#include "platform/crash.h"
|
||||
#include "platform/platform.h"
|
||||
#include "rct2/interop.h"
|
||||
#include "ride/ride.h"
|
||||
#include "title.h"
|
||||
#include "util/util.h"
|
||||
#include "version.h"
|
||||
#include "world/mapgen.h"
|
||||
#include "OpenRCT2.h"
|
||||
|
||||
#define UPDATE_TIME_MS 25 // (1000 / 40fps) = 25ms
|
||||
extern "C"
|
||||
{
|
||||
#include "audio/audio.h"
|
||||
#include "config.h"
|
||||
#include "editor.h"
|
||||
#include "game.h"
|
||||
#include "interface/chat.h"
|
||||
#include "interface/themes.h"
|
||||
#include "intro.h"
|
||||
#include "localisation/localisation.h"
|
||||
#include "network/http.h"
|
||||
#include "object_list.h"
|
||||
#include "platform/platform.h"
|
||||
#include "rct2/interop.h"
|
||||
#include "title.h"
|
||||
#include "version.h"
|
||||
}
|
||||
|
||||
int gExitCode;
|
||||
// The game update inverval in milliseconds, (1000 / 40fps) = 25ms
|
||||
constexpr uint32 UPDATE_TIME_MS = 25;
|
||||
|
||||
int gOpenRCT2StartupAction = STARTUP_ACTION_TITLE;
|
||||
utf8 gOpenRCT2StartupActionPath[512] = { 0 };
|
||||
utf8 gExePath[MAX_PATH];
|
||||
utf8 gCustomUserDataPath[MAX_PATH] = { 0 };
|
||||
utf8 gCustomOpenrctDataPath[MAX_PATH] = { 0 };
|
||||
utf8 gCustomRCT2DataPath[MAX_PATH] = { 0 };
|
||||
utf8 gCustomPassword[MAX_PATH] = { 0 };
|
||||
extern "C"
|
||||
{
|
||||
int gExitCode;
|
||||
int gOpenRCT2StartupAction = STARTUP_ACTION_TITLE;
|
||||
utf8 gOpenRCT2StartupActionPath[512] = { 0 };
|
||||
utf8 gExePath[MAX_PATH];
|
||||
utf8 gCustomUserDataPath[MAX_PATH] = { 0 };
|
||||
utf8 gCustomOpenrctDataPath[MAX_PATH] = { 0 };
|
||||
utf8 gCustomRCT2DataPath[MAX_PATH] = { 0 };
|
||||
utf8 gCustomPassword[MAX_PATH] = { 0 };
|
||||
|
||||
// This should probably be changed later and allow a custom selection of things to initialise like SDL_INIT
|
||||
bool gOpenRCT2Headless = false;
|
||||
// This should probably be changed later and allow a custom selection of things to initialise like SDL_INIT
|
||||
bool gOpenRCT2Headless = false;
|
||||
|
||||
bool gOpenRCT2ShowChangelog;
|
||||
bool gOpenRCT2SilentBreakpad;
|
||||
bool gOpenRCT2ShowChangelog;
|
||||
bool gOpenRCT2SilentBreakpad;
|
||||
|
||||
#ifndef DISABLE_NETWORK
|
||||
// OpenSSL's message digest context used for calculating sprite checksums
|
||||
EVP_MD_CTX *gHashCTX = NULL;
|
||||
// OpenSSL's message digest context used for calculating sprite checksums
|
||||
EVP_MD_CTX * gHashCTX = nullptr;
|
||||
#endif // DISABLE_NETWORK
|
||||
}
|
||||
|
||||
namespace OpenRCT2
|
||||
{
|
||||
static std::string _versionInfo;
|
||||
static bool _isWindowMinimised;
|
||||
static uint32 _isWindowMinimisedLastCheckTick;
|
||||
static uint32 _lastTick;
|
||||
static uint32 _uncapTick;
|
||||
|
||||
/** If set, will end the OpenRCT2 game loop. Intentially private to this module so that the flag can not be set back to false. */
|
||||
static bool _finished;
|
||||
|
||||
static void SetVersionInfoString();
|
||||
static bool ShouldRunVariableFrame();
|
||||
static void RunGameLoop();
|
||||
static void RunFixedFrame();
|
||||
static void RunVariableFrame();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void openrct2_write_full_version_info(utf8 * buffer, size_t bufferSize)
|
||||
{
|
||||
if (OpenRCT2::_versionInfo.empty())
|
||||
{
|
||||
OpenRCT2::SetVersionInfoString();
|
||||
}
|
||||
String::Set(buffer, bufferSize, OpenRCT2::_versionInfo.c_str());
|
||||
}
|
||||
|
||||
static void openrct2_set_exe_path()
|
||||
{
|
||||
platform_get_exe_path(gExePath, sizeof(gExePath));
|
||||
log_verbose("Setting exe path to %s", gExePath);
|
||||
}
|
||||
|
||||
bool openrct2_initialise()
|
||||
{
|
||||
#ifndef DISABLE_NETWORK
|
||||
gHashCTX = EVP_MD_CTX_create();
|
||||
Guard::Assert(gHashCTX != nullptr, "EVP_MD_CTX_create failed");
|
||||
#endif // DISABLE_NETWORK
|
||||
|
||||
/** If set, will end the OpenRCT2 game loop. Intentially private to this module so that the flag can not be set back to 0. */
|
||||
int _finished;
|
||||
utf8 userPath[MAX_PATH];
|
||||
platform_resolve_openrct_data_path();
|
||||
platform_resolve_user_data_path();
|
||||
platform_get_user_directory(userPath, NULL, sizeof(userPath));
|
||||
if (!platform_ensure_directory_exists(userPath))
|
||||
{
|
||||
log_fatal("Could not create user directory (do you have write access to your documents folder?)");
|
||||
return false;
|
||||
}
|
||||
|
||||
static void openrct2_loop();
|
||||
crash_init();
|
||||
|
||||
void openrct2_write_full_version_info(utf8 *buffer, size_t bufferSize)
|
||||
{
|
||||
utf8 *ch = buffer;
|
||||
if (!rct2_interop_setup_segment()) {
|
||||
log_fatal("Unable to load RCT2 data sector");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Name and version
|
||||
safe_strcpy(ch, OPENRCT2_NAME ", v" OPENRCT2_VERSION, bufferSize - (ch - buffer));
|
||||
ch = strchr(ch, '\0');
|
||||
openrct2_set_exe_path();
|
||||
|
||||
// Build information
|
||||
if (!str_is_null_or_empty(gGitBranch)) {
|
||||
snprintf(ch, bufferSize - (ch - buffer), "-%s", gGitBranch);
|
||||
ch = strchr(ch, '\0');
|
||||
}
|
||||
if (!str_is_null_or_empty(gCommitSha1Short)) {
|
||||
snprintf(ch, bufferSize - (ch - buffer), " build %s", gCommitSha1Short);
|
||||
ch = strchr(ch, '\0');
|
||||
}
|
||||
if (!str_is_null_or_empty(gBuildServer)) {
|
||||
snprintf(ch, bufferSize - (ch - buffer), " provided by %s", gBuildServer);
|
||||
ch = strchr(ch, '\0');
|
||||
}
|
||||
config_set_defaults();
|
||||
if (!config_open_default())
|
||||
{
|
||||
if (!config_find_or_browse_install_directory())
|
||||
{
|
||||
gConfigGeneral.last_run_version = String::Duplicate(OPENRCT2_VERSION);
|
||||
config_save_default();
|
||||
utf8 path[MAX_PATH];
|
||||
config_get_default_path(path, sizeof(path));
|
||||
log_fatal("An RCT2 install directory must be specified! Please edit \"game_path\" in %s.", path);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
snprintf(ch, bufferSize - (ch - buffer), " (DEBUG)");
|
||||
#endif
|
||||
}
|
||||
gOpenRCT2ShowChangelog = true;
|
||||
if (gConfigGeneral.last_run_version != NULL && (strcmp(gConfigGeneral.last_run_version, OPENRCT2_VERSION) == 0))
|
||||
{
|
||||
gOpenRCT2ShowChangelog = false;
|
||||
}
|
||||
gConfigGeneral.last_run_version = String::Duplicate(OPENRCT2_VERSION);
|
||||
config_save_default();
|
||||
|
||||
static void openrct2_set_exe_path()
|
||||
{
|
||||
platform_get_exe_path(gExePath, sizeof(gExePath));
|
||||
log_verbose("Setting exe path to %s", gExePath);
|
||||
}
|
||||
// TODO add configuration option to allow multiple instances
|
||||
// if (!gOpenRCT2Headless && !platform_lock_single_instance()) {
|
||||
// log_fatal("OpenRCT2 is already running.");
|
||||
// return false;
|
||||
// }
|
||||
|
||||
bool openrct2_initialise()
|
||||
{
|
||||
utf8 userPath[MAX_PATH];
|
||||
if (!rct2_init_directories())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!rct2_startup_checks())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!gOpenRCT2Headless) {
|
||||
audio_init();
|
||||
audio_populate_devices();
|
||||
}
|
||||
|
||||
if (!language_open(gConfigGeneral.language))
|
||||
{
|
||||
log_error("Failed to open configured language...");
|
||||
if (!language_open(LANGUAGE_ENGLISH_UK))
|
||||
{
|
||||
log_fatal("Failed to open fallback language...");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
http_init();
|
||||
theme_manager_initialise();
|
||||
title_sequences_set_default();
|
||||
title_sequences_load_presets();
|
||||
|
||||
rct2_interop_setup_hooks();
|
||||
|
||||
if (!rct2_init())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
chat_init();
|
||||
|
||||
rct2_copy_original_user_files_over();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches the game, after command line arguments have been parsed and processed.
|
||||
*/
|
||||
void openrct2_launch()
|
||||
{
|
||||
if (openrct2_initialise())
|
||||
{
|
||||
gIntroState = INTRO_STATE_NONE;
|
||||
if ((gOpenRCT2StartupAction == STARTUP_ACTION_TITLE) && gConfigGeneral.play_intro)
|
||||
gOpenRCT2StartupAction = STARTUP_ACTION_INTRO;
|
||||
|
||||
switch (gOpenRCT2StartupAction) {
|
||||
case STARTUP_ACTION_INTRO:
|
||||
gIntroState = INTRO_STATE_PUBLISHER_BEGIN;
|
||||
title_load();
|
||||
break;
|
||||
case STARTUP_ACTION_TITLE:
|
||||
title_load();
|
||||
break;
|
||||
case STARTUP_ACTION_OPEN:
|
||||
assert(gOpenRCT2StartupActionPath != NULL);
|
||||
if (!rct2_open_file(gOpenRCT2StartupActionPath)) {
|
||||
fprintf(stderr, "Failed to load '%s'", gOpenRCT2StartupActionPath);
|
||||
title_load();
|
||||
break;
|
||||
}
|
||||
|
||||
gScreenFlags = SCREEN_FLAGS_PLAYING;
|
||||
|
||||
#ifndef DISABLE_NETWORK
|
||||
gHashCTX = EVP_MD_CTX_create();
|
||||
assert(gHashCTX != NULL);
|
||||
if (gNetworkStart == NETWORK_MODE_SERVER) {
|
||||
if (gNetworkStartPort == 0) {
|
||||
gNetworkStartPort = gConfigNetwork.default_port;
|
||||
}
|
||||
|
||||
if (String::IsNullOrEmpty(gCustomPassword)) {
|
||||
network_set_password(gConfigNetwork.default_password);
|
||||
} else {
|
||||
network_set_password(gCustomPassword);
|
||||
}
|
||||
network_begin_server(gNetworkStartPort);
|
||||
}
|
||||
#endif // DISABLE_NETWORK
|
||||
|
||||
platform_resolve_openrct_data_path();
|
||||
platform_resolve_user_data_path();
|
||||
platform_get_user_directory(userPath, NULL, sizeof(userPath));
|
||||
if (!platform_ensure_directory_exists(userPath)) {
|
||||
log_fatal("Could not create user directory (do you have write access to your documents folder?)");
|
||||
return false;
|
||||
}
|
||||
|
||||
crash_init();
|
||||
|
||||
if (!rct2_interop_setup_segment()) {
|
||||
log_fatal("Unable to load RCT2 data sector");
|
||||
return false;
|
||||
}
|
||||
|
||||
openrct2_set_exe_path();
|
||||
|
||||
config_set_defaults();
|
||||
if (!config_open_default()) {
|
||||
if (!config_find_or_browse_install_directory()) {
|
||||
gConfigGeneral.last_run_version = strndup(OPENRCT2_VERSION, strlen(OPENRCT2_VERSION));
|
||||
config_save_default();
|
||||
utf8 path[MAX_PATH];
|
||||
config_get_default_path(path, sizeof(path));
|
||||
log_fatal("An RCT2 install directory must be specified! Please edit \"game_path\" in %s.", path);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
gOpenRCT2ShowChangelog = true;
|
||||
if (gConfigGeneral.last_run_version != NULL && (strcmp(gConfigGeneral.last_run_version, OPENRCT2_VERSION) == 0))
|
||||
gOpenRCT2ShowChangelog = false;
|
||||
gConfigGeneral.last_run_version = strndup(OPENRCT2_VERSION, strlen(OPENRCT2_VERSION));
|
||||
config_save_default();
|
||||
|
||||
// TODO add configuration option to allow multiple instances
|
||||
// if (!gOpenRCT2Headless && !platform_lock_single_instance()) {
|
||||
// log_fatal("OpenRCT2 is already running.");
|
||||
// return false;
|
||||
// }
|
||||
|
||||
if (!rct2_init_directories()) {
|
||||
return false;
|
||||
}
|
||||
if (!rct2_startup_checks()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!gOpenRCT2Headless) {
|
||||
audio_init();
|
||||
audio_populate_devices();
|
||||
}
|
||||
|
||||
if (!language_open(gConfigGeneral.language)) {
|
||||
log_error("Failed to open configured language...");
|
||||
|
||||
if (!language_open(LANGUAGE_ENGLISH_UK)) {
|
||||
log_fatal("Failed to open fallback language...");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
http_init();
|
||||
|
||||
theme_manager_initialise();
|
||||
title_sequences_set_default();
|
||||
title_sequences_load_presets();
|
||||
|
||||
rct2_interop_setup_hooks();
|
||||
|
||||
if (!rct2_init())
|
||||
return false;
|
||||
|
||||
chat_init();
|
||||
|
||||
rct2_copy_original_user_files_over();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches the game, after command line arguments have been parsed and processed.
|
||||
*/
|
||||
void openrct2_launch()
|
||||
{
|
||||
if (openrct2_initialise()) {
|
||||
gIntroState = INTRO_STATE_NONE;
|
||||
if((gOpenRCT2StartupAction == STARTUP_ACTION_TITLE) && gConfigGeneral.play_intro)
|
||||
gOpenRCT2StartupAction = STARTUP_ACTION_INTRO;
|
||||
|
||||
switch (gOpenRCT2StartupAction) {
|
||||
case STARTUP_ACTION_INTRO:
|
||||
gIntroState = INTRO_STATE_PUBLISHER_BEGIN;
|
||||
title_load();
|
||||
break;
|
||||
case STARTUP_ACTION_TITLE:
|
||||
title_load();
|
||||
break;
|
||||
case STARTUP_ACTION_OPEN:
|
||||
assert(gOpenRCT2StartupActionPath != NULL);
|
||||
if (!rct2_open_file(gOpenRCT2StartupActionPath)) {
|
||||
fprintf(stderr, "Failed to load '%s'", gOpenRCT2StartupActionPath);
|
||||
title_load();
|
||||
break;
|
||||
}
|
||||
|
||||
gScreenFlags = SCREEN_FLAGS_PLAYING;
|
||||
break;
|
||||
case STARTUP_ACTION_EDIT:
|
||||
if (strlen(gOpenRCT2StartupActionPath) == 0) {
|
||||
editor_load();
|
||||
} else {
|
||||
if (!editor_load_landscape(gOpenRCT2StartupActionPath)) {
|
||||
title_load();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_NETWORK
|
||||
if (gNetworkStart == NETWORK_MODE_SERVER) {
|
||||
if (gNetworkStartPort == 0) {
|
||||
gNetworkStartPort = gConfigNetwork.default_port;
|
||||
}
|
||||
if (gNetworkStart == NETWORK_MODE_CLIENT) {
|
||||
if (gNetworkStartPort == 0) {
|
||||
gNetworkStartPort = gConfigNetwork.default_port;
|
||||
}
|
||||
|
||||
if (str_is_null_or_empty(gCustomPassword)) {
|
||||
network_set_password(gConfigNetwork.default_password);
|
||||
}
|
||||
else {
|
||||
network_set_password(gCustomPassword);
|
||||
}
|
||||
network_begin_server(gNetworkStartPort);
|
||||
}
|
||||
network_begin_client(gNetworkStartHost, gNetworkStartPort);
|
||||
}
|
||||
#endif // DISABLE_NETWORK
|
||||
break;
|
||||
case STARTUP_ACTION_EDIT:
|
||||
if (strlen(gOpenRCT2StartupActionPath) == 0) {
|
||||
editor_load();
|
||||
} else {
|
||||
if (!editor_load_landscape(gOpenRCT2StartupActionPath)) {
|
||||
title_load();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
OpenRCT2::RunGameLoop();
|
||||
}
|
||||
openrct2_dispose();
|
||||
|
||||
// HACK Some threads are still running which causes the game to not terminate. Investigation required!
|
||||
exit(gExitCode);
|
||||
}
|
||||
|
||||
void openrct2_dispose()
|
||||
{
|
||||
network_close();
|
||||
http_dispose();
|
||||
language_close_all();
|
||||
rct2_dispose();
|
||||
config_release();
|
||||
#ifndef DISABLE_NETWORK
|
||||
if (gNetworkStart == NETWORK_MODE_CLIENT) {
|
||||
if (gNetworkStartPort == 0) {
|
||||
gNetworkStartPort = gConfigNetwork.default_port;
|
||||
}
|
||||
|
||||
network_begin_client(gNetworkStartHost, gNetworkStartPort);
|
||||
}
|
||||
EVP_MD_CTX_destroy(gHashCTX);
|
||||
#endif // DISABLE_NETWORK
|
||||
rct2_interop_dispose();
|
||||
platform_free();
|
||||
}
|
||||
|
||||
openrct2_loop();
|
||||
}
|
||||
openrct2_dispose();
|
||||
|
||||
// HACK Some threads are still running which causes the game to not terminate. Investigation required!
|
||||
exit(gExitCode);
|
||||
/**
|
||||
* Causes the OpenRCT2 game loop to finish.
|
||||
*/
|
||||
void openrct2_finish()
|
||||
{
|
||||
OpenRCT2::_finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
void openrct2_dispose()
|
||||
namespace OpenRCT2
|
||||
{
|
||||
network_close();
|
||||
http_dispose();
|
||||
language_close_all();
|
||||
rct2_dispose();
|
||||
config_release();
|
||||
#ifndef DISABLE_NETWORK
|
||||
EVP_MD_CTX_destroy(gHashCTX);
|
||||
#endif // DISABLE_NETWORK
|
||||
rct2_interop_dispose();
|
||||
platform_free();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the main game loop until the finished flag is set at 40fps (25ms interval).
|
||||
*/
|
||||
static void openrct2_loop()
|
||||
{
|
||||
uint32 currentTick, ticksElapsed, lastTick = 0;
|
||||
static uint32 uncapTick = 0;
|
||||
static int fps = 0;
|
||||
static uint32 secondTick = 0;
|
||||
|
||||
log_verbose("begin openrct2 loop");
|
||||
|
||||
_finished = 0;
|
||||
do {
|
||||
bool is_minimised = (SDL_GetWindowFlags(gWindow) & (SDL_WINDOW_MINIMIZED | SDL_WINDOW_HIDDEN)) != 0;
|
||||
if (gConfigGeneral.uncap_fps && gGameSpeed <= 4 && !gOpenRCT2Headless && !is_minimised) {
|
||||
currentTick = SDL_GetTicks();
|
||||
if (uncapTick == 0) {
|
||||
// Reset sprite locations
|
||||
uncapTick = SDL_GetTicks();
|
||||
sprite_position_tween_reset();
|
||||
}
|
||||
|
||||
// Limit number of updates per loop (any long pauses or debugging can make this update for a very long time)
|
||||
if (currentTick - uncapTick > UPDATE_TIME_MS * 60) {
|
||||
uncapTick = currentTick - UPDATE_TIME_MS - 1;
|
||||
}
|
||||
|
||||
platform_process_messages();
|
||||
|
||||
while (uncapTick <= currentTick && currentTick - uncapTick > UPDATE_TIME_MS) {
|
||||
// Get the original position of each sprite
|
||||
sprite_position_tween_store_a();
|
||||
|
||||
// Update the game so the sprite positions update
|
||||
rct2_update();
|
||||
|
||||
// Get the next position of each sprite
|
||||
sprite_position_tween_store_b();
|
||||
|
||||
uncapTick += UPDATE_TIME_MS;
|
||||
}
|
||||
|
||||
// Tween the position of each sprite from the last position to the new position based on the time between the last
|
||||
// tick and the next tick.
|
||||
float nudge = 1 - ((float)(currentTick - uncapTick) / UPDATE_TIME_MS);
|
||||
sprite_position_tween_all(nudge);
|
||||
|
||||
platform_draw();
|
||||
|
||||
fps++;
|
||||
if (SDL_GetTicks() - secondTick >= 1000) {
|
||||
fps = 0;
|
||||
secondTick = SDL_GetTicks();
|
||||
}
|
||||
|
||||
sprite_position_tween_restore();
|
||||
} else {
|
||||
uncapTick = 0;
|
||||
currentTick = SDL_GetTicks();
|
||||
ticksElapsed = currentTick - lastTick;
|
||||
if (ticksElapsed < UPDATE_TIME_MS) {
|
||||
SDL_Delay(UPDATE_TIME_MS - ticksElapsed);
|
||||
lastTick += UPDATE_TIME_MS;
|
||||
} else {
|
||||
lastTick = currentTick;
|
||||
}
|
||||
|
||||
platform_process_messages();
|
||||
|
||||
rct2_update();
|
||||
|
||||
if (!is_minimised) {
|
||||
platform_draw();
|
||||
}
|
||||
}
|
||||
} while (!_finished);
|
||||
}
|
||||
|
||||
/**
|
||||
* Causes the OpenRCT2 game loop to finish.
|
||||
*/
|
||||
void openrct2_finish()
|
||||
{
|
||||
_finished = 1;
|
||||
static void SetVersionInfoString()
|
||||
{
|
||||
utf8 buffer[256];
|
||||
size_t bufferSize = sizeof(buffer);
|
||||
String::Set(buffer, bufferSize, OPENRCT2_NAME ", v" OPENRCT2_VERSION);
|
||||
if (!String::IsNullOrEmpty(gGitBranch))
|
||||
{
|
||||
String::AppendFormat(buffer, bufferSize, "-%s", gGitBranch);
|
||||
}
|
||||
if (!String::IsNullOrEmpty(gCommitSha1Short))
|
||||
{
|
||||
String::AppendFormat(buffer, bufferSize, " build %s", gCommitSha1Short);
|
||||
}
|
||||
if (!String::IsNullOrEmpty(gBuildServer))
|
||||
{
|
||||
String::AppendFormat(buffer, bufferSize, " provided by %s", gBuildServer);
|
||||
}
|
||||
#if DEBUG
|
||||
String::AppendFormat(buffer, bufferSize, " (DEBUG)", gBuildServer);
|
||||
#endif
|
||||
_versionInfo = buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the main game loop until the finished flag is set.
|
||||
*/
|
||||
static void RunGameLoop()
|
||||
{
|
||||
log_verbose("begin openrct2 loop");
|
||||
_finished = false;
|
||||
do
|
||||
{
|
||||
if (ShouldRunVariableFrame())
|
||||
{
|
||||
RunVariableFrame();
|
||||
}
|
||||
else
|
||||
{
|
||||
RunFixedFrame();
|
||||
}
|
||||
}
|
||||
while (!_finished);
|
||||
log_verbose("finish openrct2 loop");
|
||||
}
|
||||
|
||||
static bool IsMinimised()
|
||||
{
|
||||
// Don't check if window is minimised too frequently (every second is fine)
|
||||
if (_lastTick > _isWindowMinimisedLastCheckTick + 1000)
|
||||
{
|
||||
uint32 windowFlags = SDL_GetWindowFlags(gWindow);
|
||||
_isWindowMinimised = (windowFlags & SDL_WINDOW_MINIMIZED) ||
|
||||
(windowFlags & SDL_WINDOW_HIDDEN);
|
||||
}
|
||||
return _isWindowMinimised;
|
||||
}
|
||||
|
||||
static bool ShouldRunVariableFrame()
|
||||
{
|
||||
if (!gConfigGeneral.uncap_fps) return false;
|
||||
if (gGameSpeed > 4) return false;
|
||||
if (gOpenRCT2Headless) return false;
|
||||
if (IsMinimised()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void RunFixedFrame()
|
||||
{
|
||||
_uncapTick = 0;
|
||||
uint32 currentTick = SDL_GetTicks();
|
||||
uint32 ticksElapsed = currentTick - _lastTick;
|
||||
if (ticksElapsed < UPDATE_TIME_MS)
|
||||
{
|
||||
SDL_Delay(UPDATE_TIME_MS - ticksElapsed);
|
||||
_lastTick += UPDATE_TIME_MS;
|
||||
} else
|
||||
{
|
||||
_lastTick = currentTick;
|
||||
}
|
||||
platform_process_messages();
|
||||
rct2_update();
|
||||
if (!_isWindowMinimised)
|
||||
{
|
||||
platform_draw();
|
||||
}
|
||||
}
|
||||
|
||||
static void RunVariableFrame()
|
||||
{
|
||||
uint32 currentTick = SDL_GetTicks();
|
||||
if (_uncapTick == 0)
|
||||
{
|
||||
_uncapTick = currentTick;
|
||||
sprite_position_tween_reset();
|
||||
}
|
||||
|
||||
// Limit number of updates per loop (any long pauses or debugging can make this update for a very long time)
|
||||
if (currentTick - _uncapTick > UPDATE_TIME_MS * 60)
|
||||
{
|
||||
_uncapTick = currentTick - UPDATE_TIME_MS - 1;
|
||||
}
|
||||
|
||||
platform_process_messages();
|
||||
|
||||
while (_uncapTick <= currentTick && currentTick - _uncapTick > UPDATE_TIME_MS)
|
||||
{
|
||||
// Get the original position of each sprite
|
||||
sprite_position_tween_store_a();
|
||||
|
||||
// Update the game so the sprite positions update
|
||||
rct2_update();
|
||||
|
||||
// Get the next position of each sprite
|
||||
sprite_position_tween_store_b();
|
||||
|
||||
_uncapTick += UPDATE_TIME_MS;
|
||||
}
|
||||
|
||||
// Tween the position of each sprite from the last position to the new position based on the time between the last
|
||||
// tick and the next tick.
|
||||
float nudge = 1 - ((float)(currentTick - _uncapTick) / UPDATE_TIME_MS);
|
||||
sprite_position_tween_all(nudge);
|
||||
|
||||
platform_draw();
|
||||
|
||||
sprite_position_tween_restore();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,53 +14,60 @@
|
||||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#ifndef _OPENRCT2_H_
|
||||
#define _OPENRCT2_H_
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "core/Guard.hpp"
|
||||
#include "platform/platform.h"
|
||||
|
||||
#ifndef DISABLE_NETWORK
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/evp.h>
|
||||
#endif // DISABLE_NETWORK
|
||||
|
||||
enum {
|
||||
STARTUP_ACTION_INTRO,
|
||||
STARTUP_ACTION_TITLE,
|
||||
STARTUP_ACTION_OPEN,
|
||||
STARTUP_ACTION_EDIT
|
||||
enum STARTUP_ACTION
|
||||
{
|
||||
STARTUP_ACTION_INTRO,
|
||||
STARTUP_ACTION_TITLE,
|
||||
STARTUP_ACTION_OPEN,
|
||||
STARTUP_ACTION_EDIT
|
||||
};
|
||||
|
||||
/** The exit code for OpenRCT2 when it exits. */
|
||||
extern int gExitCode;
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern int gOpenRCT2StartupAction;
|
||||
extern utf8 gOpenRCT2StartupActionPath[512];
|
||||
extern utf8 gExePath[MAX_PATH];
|
||||
extern utf8 gCustomUserDataPath[MAX_PATH];
|
||||
extern utf8 gCustomOpenrctDataPath[MAX_PATH];
|
||||
extern utf8 gCustomRCT2DataPath[MAX_PATH];
|
||||
extern utf8 gCustomPassword[MAX_PATH];
|
||||
extern bool gOpenRCT2Headless;
|
||||
extern bool gOpenRCT2ShowChangelog;
|
||||
/** The exit code for OpenRCT2 when it exits. */
|
||||
extern int gExitCode;
|
||||
|
||||
extern int gOpenRCT2StartupAction;
|
||||
extern utf8 gOpenRCT2StartupActionPath[512];
|
||||
extern utf8 gExePath[MAX_PATH];
|
||||
extern utf8 gCustomUserDataPath[MAX_PATH];
|
||||
extern utf8 gCustomOpenrctDataPath[MAX_PATH];
|
||||
extern utf8 gCustomRCT2DataPath[MAX_PATH];
|
||||
extern utf8 gCustomPassword[MAX_PATH];
|
||||
extern bool gOpenRCT2Headless;
|
||||
extern bool gOpenRCT2ShowChangelog;
|
||||
|
||||
#ifndef DISABLE_NETWORK
|
||||
extern EVP_MD_CTX *gHashCTX;
|
||||
extern EVP_MD_CTX * gHashCTX;
|
||||
#endif // DISABLE_NETWORK
|
||||
|
||||
#ifndef DISABLE_NETWORK
|
||||
extern int gNetworkStart;
|
||||
extern char gNetworkStartHost[128];
|
||||
extern int gNetworkStartPort;
|
||||
extern int gNetworkStart;
|
||||
extern char gNetworkStartHost[128];
|
||||
extern int gNetworkStartPort;
|
||||
#endif
|
||||
|
||||
void openrct2_write_full_version_info(utf8 *buffer, size_t bufferSize);
|
||||
bool openrct2_initialise();
|
||||
void openrct2_launch();
|
||||
void openrct2_dispose();
|
||||
void openrct2_finish();
|
||||
void openrct2_write_full_version_info(utf8 * buffer, size_t bufferSize);
|
||||
bool openrct2_initialise();
|
||||
void openrct2_launch();
|
||||
void openrct2_dispose();
|
||||
void openrct2_finish();
|
||||
|
||||
int cmdline_run(const char **argv, int argc);
|
||||
int cmdline_run(const char * * argv, int argc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -54,11 +54,18 @@
|
||||
|
||||
#define OPENRCT2_TIMESTAMP __DATE__ " " __TIME__
|
||||
|
||||
// The following constants are for automated build servers
|
||||
extern const char *gBuildNumber;
|
||||
extern const char *gBuildServer;
|
||||
extern const char *gGitBranch;
|
||||
extern const char *gCommitSha1;
|
||||
extern const char *gCommitSha1Short;
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
// The following constants are for automated build servers
|
||||
extern const char *gBuildNumber;
|
||||
extern const char *gBuildServer;
|
||||
extern const char *gGitBranch;
|
||||
extern const char *gCommitSha1;
|
||||
extern const char *gCommitSha1Short;
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user