1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-10 17:42:29 +01:00

Refactor game load functions, resolves #6011

This commit is contained in:
Richard Jenkins
2017-08-23 07:04:36 +01:00
committed by Michael Steenbeek
parent 9aeca18026
commit 71e580a58f
18 changed files with 81 additions and 201 deletions

View File

@@ -14,6 +14,7 @@
*****************************************************************************/
#pragma endregion
#include <openrct2/Context.h>
#include <openrct2/config/Config.h>
#include <openrct2/ParkImporter.h>
#include <openrct2/network/network.h>
@@ -169,18 +170,14 @@ static void window_server_start_close(rct_window *w)
static void window_server_start_scenarioselect_callback(const utf8 *path)
{
network_set_password(_password);
ParkLoadResult * result = scenario_load_and_play_from_path(path);
if (ParkLoadResult_GetError(result) == PARK_LOAD_ERROR_OK) {
if (context_load_park_from_file(path)) {
network_begin_server(gConfigNetwork.default_port, gConfigNetwork.listen_address);
} else {
handle_park_load_failure(result, path);
}
ParkLoadResult_Delete(result);
}
static void window_server_start_loadsave_callback(sint32 result, const utf8 * path)
{
if (result == MODAL_RESULT_OK && game_load_save_or_scenario(path)) {
if (result == MODAL_RESULT_OK && context_load_park_from_file(path)) {
network_begin_server(gConfigNetwork.default_port, gConfigNetwork.listen_address);
}
}

View File

@@ -134,9 +134,7 @@ rct_window * window_title_menu_open()
static void window_title_menu_scenarioselect_callback(const utf8 *path)
{
ParkLoadResult * result = scenario_load_and_play_from_path(path);
handle_park_load_failure(result, path);
ParkLoadResult_Delete(result);
context_load_park_from_file(path);
}
static void window_title_menu_mouseup(rct_window *w, rct_widgetindex widgetIndex)

View File

@@ -370,10 +370,10 @@ namespace OpenRCT2
return true;
}
void Open(const std::string &path) final override
bool LoadParkFromFile(const std::string &path, bool loadTitleScreenOnFail = false) final override
{
auto fs = FileStream(path, FILE_MODE_OPEN);
OpenParkAutoDetectFormat(&fs, path);
return LoadParkFromStream(&fs, path, loadTitleScreenOnFail);
}
private:
@@ -454,7 +454,7 @@ namespace OpenRCT2
}
auto ms = MemoryStream(data, dataSize, MEMORY_ACCESS::OWNER);
if (!OpenParkAutoDetectFormat(&ms, gOpenRCT2StartupActionPath))
if (!LoadParkFromStream(&ms, gOpenRCT2StartupActionPath, true))
{
Console::Error::WriteLine("Failed to load '%s'", gOpenRCT2StartupActionPath);
title_load();
@@ -466,7 +466,10 @@ namespace OpenRCT2
{
try
{
Open(gOpenRCT2StartupActionPath);
if (!LoadParkFromFile(gOpenRCT2StartupActionPath, true))
{
break;
}
}
catch (const std::exception &ex)
{
@@ -679,21 +682,23 @@ namespace OpenRCT2
console_update();
}
bool OpenParkAutoDetectFormat(IStream * stream, const std::string &path)
bool LoadParkFromStream(IStream * stream, const std::string &path, bool loadTitleScreenFirstOnFail)
{
ClassifiedFile info;
ClassifiedFileInfo info;
if (TryClassifyFile(stream, &info))
{
if (info.Type == FILE_TYPE::SAVED_GAME ||
info.Type == FILE_TYPE::SCENARIO)
{
std::unique_ptr<IParkImporter> parkImporter;
if (info.Version <= 2)
if (info.Version <= FILE_TYPE_S4_CUTOFF)
{
// Save is an S4 (RCT1 format)
parkImporter.reset(ParkImporter::CreateS4());
}
else
{
// Save is an S6 (RCT2 format)
parkImporter.reset(ParkImporter::CreateS6(_objectRepository, _objectManager));
}
@@ -707,20 +712,38 @@ namespace OpenRCT2
gLastAutoSaveUpdate = AUTOSAVE_PAUSE;
if (info.Type == FILE_TYPE::SAVED_GAME)
{
if (network_get_mode() == NETWORK_MODE_CLIENT)
{
network_close();
}
game_load_init();
if (network_get_mode() == NETWORK_MODE_SERVER)
{
network_send_map();
}
}
else
{
reset_sprite_spatial_index();
reset_all_sprite_quadrant_placements();
scenario_begin();
if (network_get_mode() == NETWORK_MODE_SERVER)
{
network_send_map();
}
if (network_get_mode() == NETWORK_MODE_CLIENT)
{
network_close();
}
}
// This ensures that the newly loaded save reflects the user's
// 'show real names of guests' option, now that it's a global setting
peep_update_names(gConfigGeneral.show_real_names_of_guests);
return true;
}
else
{
handle_park_load_failure_with_title_opt(&result, path.c_str(), true);
handle_park_load_failure_with_title_opt(&result, path.c_str(), loadTitleScreenFirstOnFail);
}
}
else
{
@@ -828,6 +851,11 @@ namespace OpenRCT2
extern "C"
{
bool context_load_park_from_file(const utf8 * path)
{
return GetContext()->LoadParkFromFile(path);
}
void openrct2_write_full_version_info(utf8 * buffer, size_t bufferSize)
{
String::Set(buffer, bufferSize, gVersionInfoFull);

View File

@@ -96,7 +96,7 @@ namespace OpenRCT2
virtual sint32 RunOpenRCT2(int argc, char * * argv) abstract;
virtual bool Initialise() abstract;
virtual void Open(const std::string &path) abstract;
virtual bool LoadParkFromFile(const std::string &path, bool loadTitleScreenOnFail = false) abstract;
virtual void Finish() abstract;
virtual void Quit() abstract;
@@ -214,6 +214,7 @@ extern "C"
bool context_read_bmp(void * * outPixels, uint32 * outWidth, uint32 * outHeight, const utf8 * path);
void context_quit();
const utf8 * context_get_path_legacy(sint32 pathId);
bool context_load_park_from_file(const utf8 * path);
#ifdef __cplusplus
}
#endif

View File

@@ -25,11 +25,11 @@ extern "C"
#include "util/sawyercoding.h"
}
static bool TryClassifyAsS6(IStream * stream, ClassifiedFile * result);
static bool TryClassifyAsS4(IStream * stream, ClassifiedFile * result);
static bool TryClassifyAsTD4_TD6(IStream * stream, ClassifiedFile * result);
static bool TryClassifyAsS6(IStream * stream, ClassifiedFileInfo * result);
static bool TryClassifyAsS4(IStream * stream, ClassifiedFileInfo * result);
static bool TryClassifyAsTD4_TD6(IStream * stream, ClassifiedFileInfo * result);
bool TryClassifyFile(const std::string &path, ClassifiedFile * result)
bool TryClassifyFile(const std::string &path, ClassifiedFileInfo * result)
{
try
{
@@ -42,7 +42,7 @@ bool TryClassifyFile(const std::string &path, ClassifiedFile * result)
}
}
bool TryClassifyFile(IStream * stream, ClassifiedFile * result)
bool TryClassifyFile(IStream * stream, ClassifiedFileInfo * result)
{
// TODO Currently track designs get classified as SC4s because they use the
// same checksum algorithm. The only way after to tell the difference
@@ -70,7 +70,7 @@ bool TryClassifyFile(IStream * stream, ClassifiedFile * result)
return false;
}
static bool TryClassifyAsS6(IStream * stream, ClassifiedFile * result)
static bool TryClassifyAsS6(IStream * stream, ClassifiedFileInfo * result)
{
bool success = false;
uint64 originalPosition = stream->GetPosition();
@@ -96,7 +96,7 @@ static bool TryClassifyAsS6(IStream * stream, ClassifiedFile * result)
return success;
}
static bool TryClassifyAsS4(IStream * stream, ClassifiedFile * result)
static bool TryClassifyAsS4(IStream * stream, ClassifiedFileInfo * result)
{
uint64 originalPosition = stream->GetPosition();
size_t dataLength = (size_t)stream->GetLength();
@@ -124,7 +124,7 @@ static bool TryClassifyAsS4(IStream * stream, ClassifiedFile * result)
return false;
}
static bool TryClassifyAsTD4_TD6(IStream * stream, ClassifiedFile * result)
static bool TryClassifyAsTD4_TD6(IStream * stream, ClassifiedFileInfo * result)
{
bool success = false;
uint64 originalPosition = stream->GetPosition();

View File

@@ -45,14 +45,15 @@ enum class FILE_TYPE
TRACK_DESIGN,
};
struct ClassifiedFile
struct ClassifiedFileInfo
{
FILE_TYPE Type;
uint32 Version;
};
bool TryClassifyFile(const std::string &path, ClassifiedFile * result);
bool TryClassifyFile(IStream * stream, ClassifiedFile * result);
#define FILE_TYPE_S4_CUTOFF 2
bool TryClassifyFile(const std::string &path, ClassifiedFileInfo * result);
bool TryClassifyFile(IStream * stream, ClassifiedFileInfo * result);
#endif // __cplusplus

View File

@@ -15,6 +15,7 @@
#pragma endregion
#include "audio/audio.h"
#include "Context.h"
#include "drawing/drawing.h"
#include "editor.h"
#include "FileClassifier.h"
@@ -122,7 +123,7 @@ static void editor_convert_save_to_scenario_callback(sint32 result, const utf8 *
return;
}
if (!game_load_save_or_scenario(path)) {
if (!context_load_park_from_file(path)) {
return;
}
@@ -233,7 +234,7 @@ bool editor_load_landscape(const utf8 *path)
*/
static sint32 editor_load_landscape_from_sv4(const char *path)
{
rct1_load_saved_game(path);
load_from_sv4(path);
editor_clear_map_for_editing(true);
gS6Info.editor_step = EDITOR_STEP_LANDSCAPE_EDITOR;
@@ -247,7 +248,7 @@ static sint32 editor_load_landscape_from_sv4(const char *path)
static sint32 editor_load_landscape_from_sc4(const char *path)
{
rct1_load_scenario(path);
load_from_sc4(path);
editor_clear_map_for_editing(false);
gS6Info.editor_step = EDITOR_STEP_LANDSCAPE_EDITOR;
@@ -268,9 +269,9 @@ static sint32 editor_read_s6(const char *path)
ParkLoadResult * loadResult = NULL;
const char *extension = path_get_extension(path);
if (_stricmp(extension, ".sc6") == 0) {
loadResult = scenario_load(path);
loadResult = load_from_sc6(path);
} else if (_stricmp(extension, ".sv6") == 0) {
loadResult = game_load_sv6_path(path);
loadResult = load_from_sv6(path);
}
if (ParkLoadResult_GetError(loadResult) != PARK_LOAD_ERROR_OK) {
ParkLoadResult_Delete(loadResult);

View File

@@ -1106,52 +1106,6 @@ void game_fix_save_vars()
fix_invalid_vehicle_sprite_sizes();
}
/**
*
* rct2: 0x00675E1B
*/
bool game_load_save(const utf8 *path)
{
log_verbose("loading saved game, %s", path);
safe_strcpy(gScenarioSavePath, path, MAX_PATH);
uint32 extension_type = get_file_extension_type(path);
ParkLoadResult * result = NULL;
bool load_success = false;
if (extension_type == FILE_EXTENSION_SV6) {
result = game_load_sv6_path(path);
load_success = (ParkLoadResult_GetError(result) == PARK_LOAD_ERROR_OK);
if (load_success)
gFirstTimeSaving = false;
} else if (extension_type == FILE_EXTENSION_SV4) {
result = rct1_load_saved_game(path);
load_success = (ParkLoadResult_GetError(result) == PARK_LOAD_ERROR_OK);
if (load_success)
gFirstTimeSaving = true;
}
if (load_success) {
ParkLoadResult_Delete(result);
if (network_get_mode() == NETWORK_MODE_CLIENT) {
network_close();
}
game_load_init();
if (network_get_mode() == NETWORK_MODE_SERVER) {
network_send_map();
}
// This ensures that the newly loaded save reflects the user's
// 'show real names of guests' option, now that it's a global setting
peep_update_names(gConfigGeneral.show_real_names_of_guests);
return true;
} else {
handle_park_load_failure(result, path);
ParkLoadResult_Delete(result);
return false;
}
}
void handle_park_load_failure_with_title_opt(const ParkLoadResult * result, const utf8 * path, bool loadTitleFirst)
{
if (ParkLoadResult_GetError(result) == PARK_LOAD_ERROR_MISSING_OBJECTS)
@@ -1224,6 +1178,7 @@ void game_load_init()
window_update_all();
}
audio_stop_title_music();
gGameSpeed = 1;
}
@@ -1417,29 +1372,10 @@ void rct2_exit()
openrct2_finish();
}
bool game_load_save_or_scenario(const utf8 * path)
{
uint32 extension = get_file_extension_type(path);
switch (extension) {
case FILE_EXTENSION_SV4:
case FILE_EXTENSION_SV6:
return game_load_save(path);
case FILE_EXTENSION_SC4:
case FILE_EXTENSION_SC6:
{
ParkLoadResult * result = scenario_load_and_play_from_path(path);
bool success = (ParkLoadResult_GetError(result) == PARK_LOAD_ERROR_OK);
ParkLoadResult_Delete(result);
return success;
}
}
return false;
}
static void game_load_or_quit_no_save_prompt_callback(sint32 result, const utf8 * path)
{
if (result == MODAL_RESULT_OK) {
game_load_save_or_scenario(path);
context_load_park_from_file(path);
}
}

View File

@@ -169,8 +169,7 @@ sint32 game_do_command_p(sint32 command, sint32 *eax, sint32 *ebx, sint32 *ecx,
void game_log_multiplayer_command(int command, int *eax, int* ebx, int* ecx, int* edx, int* edi, int* ebp);
void game_load_or_quit_no_save_prompt();
ParkLoadResult * game_load_sv6_path(const char * path);
bool game_load_save(const utf8 *path);
ParkLoadResult * load_from_sv6(const char * path);
void game_load_init();
void game_pause_toggle(sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *edx, sint32 *esi, sint32 *edi, sint32 *ebp);
void pause_toggle();
@@ -187,7 +186,6 @@ void game_convert_strings_to_utf8();
void game_convert_news_items_to_utf8();
void game_convert_strings_to_rct2(rct_s6_data *s6);
void game_fix_save_vars();
bool game_load_save_or_scenario(const utf8 * path);
void game_init_all(sint32 mapSize);
#endif

View File

@@ -268,7 +268,7 @@ sint32 cmdline_for_gfxbench(const char **argv, sint32 argc)
if (context->Initialise())
{
drawing_engine_init();
context->Open(inputPath);
context->LoadParkFromFile(inputPath);
gIntroState = INTRO_STATE_NONE;
gScreenFlags = SCREEN_FLAGS_PLAYING;
@@ -387,7 +387,7 @@ sint32 cmdline_for_screenshot(const char **argv, sint32 argc)
if (context->Initialise())
{
drawing_engine_init();
context->Open(inputPath);
context->LoadParkFromFile(inputPath);
gIntroState = INTRO_STATE_NONE;
gScreenFlags = SCREEN_FLAGS_PLAYING;

View File

@@ -1217,8 +1217,8 @@ extern const uint8 gRideCategories[RIDE_TYPE_COUNT];
bool rideTypeShouldLoseSeparateFlag(const rct_ride_entry *rideEntry);
ParkLoadResult * rct1_load_saved_game(const char *path);
ParkLoadResult * rct1_load_scenario(const char *path);
ParkLoadResult * load_from_sv4(const char *path);
ParkLoadResult * load_from_sc4(const char *path);
colour_t rct1_get_colour(colour_t colour);

View File

@@ -2642,7 +2642,7 @@ IParkImporter * ParkImporter::CreateS4()
/////////////////////////////////////////
extern "C"
{
ParkLoadResult * rct1_load_saved_game(const utf8 * path)
ParkLoadResult * load_from_sv4(const utf8 * path)
{
ParkLoadResult * result = nullptr;
auto s4Importer = std::make_unique<S4Importer>();
@@ -2662,7 +2662,7 @@ extern "C"
return result;
}
ParkLoadResult * rct1_load_scenario(const utf8 * path)
ParkLoadResult * load_from_sc4(const utf8 * path)
{
ParkLoadResult * result = nullptr;
auto s4Importer = std::make_unique<S4Importer>();

View File

@@ -671,7 +671,7 @@ IParkImporter * ParkImporter::CreateS6(IObjectRepository * objectRepository, IOb
extern "C"
{
ParkLoadResult * game_load_sv6_path(const char * path)
ParkLoadResult * load_from_sv6(const char * path)
{
ParkLoadResult * result = nullptr;
auto s6Importer = new S6Importer(GetObjectRepository(), GetObjectManager());
@@ -723,7 +723,7 @@ extern "C"
* rct2: 0x00676053
* scenario (ebx)
*/
ParkLoadResult * scenario_load(const char * path)
ParkLoadResult * load_from_sc6(const char * path)
{
ParkLoadResult * result = nullptr;
auto s6Importer = new S6Importer(GetObjectRepository(), GetObjectManager());

View File

@@ -89,90 +89,15 @@ char gScenarioFileName[MAX_PATH];
static sint32 scenario_create_ducks();
static void scenario_objective_check();
ParkLoadResult * scenario_load_and_play_from_path(const char * path)
{
window_close_construction_windows();
uint32 extension = get_file_extension_type(path);
ParkLoadResult * result = NULL;
if (extension == FILE_EXTENSION_SC6) {
result = scenario_load(path);
if (ParkLoadResult_GetError(result) != PARK_LOAD_ERROR_OK) {
return result;
}
} else if (extension == FILE_EXTENSION_SC4) {
result = rct1_load_scenario(path);
if (ParkLoadResult_GetError(result) != PARK_LOAD_ERROR_OK) {
return result;
}
} else {
result = ParkLoadResult_CreateInvalidExtension();
return result;
}
reset_sprite_spatial_index();
reset_all_sprite_quadrant_placements();
safe_strcpy(gScenarioFileName, path_get_filename(path), sizeof(gScenarioFileName));
gFirstTimeSaving = true;
log_verbose("starting scenario, %s", path);
scenario_begin();
if (network_get_mode() == NETWORK_MODE_SERVER) {
network_send_map();
}
if (network_get_mode() == NETWORK_MODE_CLIENT) {
network_close();
}
// This ensures that the newly loaded scenario reflects the user's
// 'show real names of guests' option, now that it's a global setting
peep_update_names(gConfigGeneral.show_real_names_of_guests);
return result;
}
void scenario_begin()
{
rct_window *mainWindow;
audio_stop_title_music();
gScreenFlags = SCREEN_FLAGS_PLAYING;
audio_stop_all_music_and_sounds();
viewport_init_all();
game_create_windows();
mainWindow = window_get_main();
mainWindow->viewport_target_sprite = SPRITE_INDEX_NULL;
mainWindow->saved_view_x = gSavedViewX;
mainWindow->saved_view_y = gSavedViewY;
uint8 zoomDifference = gSavedViewZoom - mainWindow->viewport->zoom;
mainWindow->viewport->zoom = gSavedViewZoom;
gCurrentRotation = gSavedViewRotation;
if (zoomDifference != 0) {
if (zoomDifference < 0) {
zoomDifference = -zoomDifference;
mainWindow->viewport->view_width >>= zoomDifference;
mainWindow->viewport->view_height >>= zoomDifference;
} else {
mainWindow->viewport->view_width <<= zoomDifference;
mainWindow->viewport->view_height <<= zoomDifference;
}
}
mainWindow->saved_view_x -= mainWindow->viewport->view_width >> 1;
mainWindow->saved_view_y -= mainWindow->viewport->view_height >> 1;
window_invalidate(mainWindow);
reset_all_sprite_quadrant_placements();
window_new_ride_init_vars();
game_load_init();
// Set the scenario pseudo-random seeds
gScenarioSrand0 ^= platform_get_ticks();
gScenarioSrand1 ^= platform_get_ticks();
gWindowUpdateTicks = 0;
gParkFlags &= ~PARK_FLAGS_NO_MONEY;
if (gParkFlags & PARK_FLAGS_NO_MONEY_SCENARIO)
gParkFlags |= PARK_FLAGS_NO_MONEY;
@@ -206,7 +131,8 @@ void scenario_begin()
if (localisedStringIds[2] != STR_NONE) {
safe_strcpy(gScenarioDetails, language_get_string(localisedStringIds[2]), 256);
}
} else {
}
else {
rct_stex_entry* stex = g_stexEntries[0];
if ((intptr_t)stex != -1) {
char *buffer = gCommonStringFormatBuffer;
@@ -263,10 +189,7 @@ void scenario_begin()
gParkFlags |= PARK_FLAGS_SPRITES_INITIALISED;
load_palette();
window_tile_inspector_clear_clipboard();
gScreenAge = 0;
gGameSpeed = 1;
}
static void scenario_end()

View File

@@ -391,8 +391,7 @@ extern uint32 gLastAutoSaveUpdate;
extern char gScenarioFileName[260];
ParkLoadResult * scenario_load(const char *path);
ParkLoadResult * scenario_load_and_play_from_path(const char *path);
ParkLoadResult * load_from_sc6(const char *path);
void scenario_begin();
void scenario_update();

View File

@@ -520,9 +520,7 @@ static void window_top_toolbar_mousedown(rct_window *w, rct_widgetindex widgetIn
static void window_top_toolbar_scenarioselect_callback(const utf8 *path)
{
ParkLoadResult * result = scenario_load_and_play_from_path(path);
handle_park_load_failure(result, path);
ParkLoadResult_Delete(result);
context_load_park_from_file(path);
}
/**

View File

@@ -30,7 +30,7 @@ TEST(MultiLaunchTest, all)
bool initialised = context->Initialise();
ASSERT_TRUE(initialised);
ParkLoadResult * plr = game_load_sv6_path(path.c_str());
ParkLoadResult * plr = load_from_sv6(path.c_str());
ASSERT_EQ(ParkLoadResult_GetError(plr), PARK_LOAD_ERROR_OK);
ParkLoadResult_Delete(plr);

View File

@@ -67,7 +67,7 @@ TEST_F(RideRatings, all)
bool initialised = context->Initialise();
ASSERT_TRUE(initialised);
game_load_sv6_path(path.c_str());
load_from_sv6(path.c_str());
// Check ride count to check load was successful
ASSERT_EQ(gRideCount, 134);