Refactor load park result

Use a C++ struct and pass that to C.
This commit is contained in:
Ted John 2017-07-01 01:26:23 +01:00
parent d75295b027
commit ddb96ec267
20 changed files with 257 additions and 219 deletions

View File

@ -21,6 +21,65 @@
#include "object/ObjectRepository.h" #include "object/ObjectRepository.h"
#include "ParkImporter.h" #include "ParkImporter.h"
ParkLoadResult::ParkLoadResult(PARK_LOAD_ERROR error)
: Error(error)
{
}
ParkLoadResult::ParkLoadResult(PARK_LOAD_ERROR error, const std::vector<rct_object_entry> &missingObjects)
: Error(error),
MissingObjects(missingObjects)
{
}
ParkLoadResult ParkLoadResult::CreateOK()
{
return ParkLoadResult(PARK_LOAD_ERROR::PARK_LOAD_ERROR_OK);
}
ParkLoadResult ParkLoadResult::CreateInvalidExtension()
{
return ParkLoadResult(PARK_LOAD_ERROR::PARK_LOAD_ERROR_INVALID_EXTENSION);
}
ParkLoadResult ParkLoadResult::CreateMissingObjects(const std::vector<rct_object_entry> &missingObjects)
{
return ParkLoadResult(PARK_LOAD_ERROR::PARK_LOAD_ERROR_MISSING_OBJECTS, missingObjects);
}
ParkLoadResult ParkLoadResult::CreateUnknown()
{
return ParkLoadResult(PARK_LOAD_ERROR::PARK_LOAD_ERROR_UNKNOWN);
}
extern "C"
{
PARK_LOAD_ERROR ParkLoadResult_GetError(const ParkLoadResult * t)
{
return t->Error;
}
size_t ParkLoadResult_GetMissingObjectsCount(const ParkLoadResult * t)
{
return t->MissingObjects.size();
}
const rct_object_entry * ParkLoadResult_GetMissingObjects(const ParkLoadResult * t)
{
return t->MissingObjects.data();
}
void ParkLoadResult_Delete(ParkLoadResult * t)
{
delete t;
}
ParkLoadResult * ParkLoadResult_CreateInvalidExtension()
{
return new ParkLoadResult(ParkLoadResult::CreateInvalidExtension());
}
}
namespace ParkImporter namespace ParkImporter
{ {
IParkImporter * Create(const std::string &hintPath) IParkImporter * Create(const std::string &hintPath)

View File

@ -22,20 +22,45 @@
extern "C" extern "C"
{ {
#endif #endif
#include "park_load_result_types.h" #include "object.h"
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
typedef enum PARK_LOAD_ERROR
{
PARK_LOAD_ERROR_OK,
PARK_LOAD_ERROR_MISSING_OBJECTS,
PARK_LOAD_ERROR_INVALID_EXTENSION,
PARK_LOAD_ERROR_UNKNOWN = 255
} PARK_LOAD_ERROR;
#ifdef __cplusplus #ifdef __cplusplus
#include <string> #include <string>
#include <vector>
#include "scenario/ScenarioRepository.h" #include "scenario/ScenarioRepository.h"
interface IObjectManager; interface IObjectManager;
interface IObjectRepository; interface IObjectRepository;
interface IStream; interface IStream;
struct ParkLoadResult final
{
public:
const PARK_LOAD_ERROR Error;
const std::vector<rct_object_entry> MissingObjects;
static ParkLoadResult CreateOK();
static ParkLoadResult CreateInvalidExtension();
static ParkLoadResult CreateMissingObjects(const std::vector<rct_object_entry> &missingObjects);
static ParkLoadResult CreateUnknown();
private:
ParkLoadResult(PARK_LOAD_ERROR error);
ParkLoadResult(PARK_LOAD_ERROR error, const std::vector<rct_object_entry> &missingObjects);
};
/** /**
* Interface to import scenarios and saved games. * Interface to import scenarios and saved games.
*/ */
@ -43,10 +68,12 @@ interface IParkImporter
{ {
public: public:
virtual ~IParkImporter() = default; virtual ~IParkImporter() = default;
virtual park_load_result * Load(const utf8 * path) abstract;
virtual park_load_result * LoadSavedGame(const utf8 * path, bool skipObjectCheck = false) abstract; virtual ParkLoadResult Load(const utf8 * path) abstract;
virtual park_load_result * LoadScenario(const utf8 * path, bool skipObjectCheck = false) abstract; virtual ParkLoadResult LoadSavedGame(const utf8 * path, bool skipObjectCheck = false) abstract;
virtual park_load_result * LoadFromStream(IStream * stream, bool isScenario, bool skipObjectCheck = false) abstract; virtual ParkLoadResult LoadScenario(const utf8 * path, bool skipObjectCheck = false) abstract;
virtual ParkLoadResult LoadFromStream(IStream * stream, bool isScenario, bool skipObjectCheck = false) abstract;
virtual void Import() abstract; virtual void Import() abstract;
virtual bool GetDetails(scenario_index_entry * dst) abstract; virtual bool GetDetails(scenario_index_entry * dst) abstract;
}; };
@ -61,6 +88,10 @@ namespace ParkImporter
bool ExtensionIsScenario(const std::string &extension); bool ExtensionIsScenario(const std::string &extension);
} }
#else
typedef struct ParkLoadResult ParkLoadResult;
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
@ -70,6 +101,11 @@ extern "C"
void park_importer_load_from_stream(void * stream, const utf8 * hintPath); void park_importer_load_from_stream(void * stream, const utf8 * hintPath);
bool park_importer_extension_is_scenario(const utf8 * extension); bool park_importer_extension_is_scenario(const utf8 * extension);
PARK_LOAD_ERROR ParkLoadResult_GetError(const ParkLoadResult * t);
size_t ParkLoadResult_GetMissingObjectsCount(const ParkLoadResult * t);
const rct_object_entry * ParkLoadResult_GetMissingObjects(const ParkLoadResult * t);
void ParkLoadResult_Delete(ParkLoadResult * t);
ParkLoadResult * ParkLoadResult_CreateInvalidExtension();
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -31,6 +31,7 @@
#include "platform/platform.h" #include "platform/platform.h"
#include "rct1.h" #include "rct1.h"
#include "ride/ride.h" #include "ride/ride.h"
#include "ParkImporter.h"
#include "scenario/scenario.h" #include "scenario/scenario.h"
#include "util/sawyercoding.h" #include "util/sawyercoding.h"
#include "util/util.h" #include "util/util.h"
@ -261,16 +262,18 @@ static sint32 editor_load_landscape_from_sc4(const char *path)
*/ */
static sint32 editor_read_s6(const char *path) static sint32 editor_read_s6(const char *path)
{ {
park_load_result* loadResult = { 0 }; ParkLoadResult * loadResult = NULL;
const char *extension = path_get_extension(path); const char *extension = path_get_extension(path);
if (_stricmp(extension, ".sc6") == 0) { if (_stricmp(extension, ".sc6") == 0) {
loadResult = scenario_load(path); loadResult = scenario_load(path);
} else if (_stricmp(extension, ".sv6") == 0) { } else if (_stricmp(extension, ".sv6") == 0) {
loadResult = game_load_sv6_path(path); loadResult = game_load_sv6_path(path);
} }
if (loadResult->error != PARK_LOAD_ERROR_NONE) { if (ParkLoadResult_GetError(loadResult) != PARK_LOAD_ERROR_OK) {
ParkLoadResult_Delete(loadResult);
return 0; return 0;
} }
ParkLoadResult_Delete(loadResult);
editor_clear_map_for_editing(true); editor_clear_map_for_editing(true);

View File

@ -33,6 +33,7 @@
#include "network/network.h" #include "network/network.h"
#include "object.h" #include "object.h"
#include "OpenRCT2.h" #include "OpenRCT2.h"
#include "ParkImporter.h"
#include "peep/peep.h" #include "peep/peep.h"
#include "peep/staff.h" #include "peep/staff.h"
#include "platform/platform.h" #include "platform/platform.h"
@ -1094,15 +1095,16 @@ bool game_load_save(const utf8 *path)
safe_strcpy(gScenarioSavePath, path, MAX_PATH); safe_strcpy(gScenarioSavePath, path, MAX_PATH);
uint32 extension_type = get_file_extension_type(path); uint32 extension_type = get_file_extension_type(path);
park_load_result* result = {0}; ParkLoadResult * result = NULL;
bool load_success = false; bool load_success = false;
if (extension_type == FILE_EXTENSION_SV6) { if (extension_type == FILE_EXTENSION_SV6) {
result = game_load_sv6_path(path); result = game_load_sv6_path(path);
load_success = (result->error == PARK_LOAD_ERROR_NONE); load_success = (ParkLoadResult_GetError(result) == PARK_LOAD_ERROR_OK);
if (load_success) if (load_success)
gFirstTimeSaving = false; gFirstTimeSaving = false;
} else if (extension_type == FILE_EXTENSION_SV4) { } else if (extension_type == FILE_EXTENSION_SV4) {
load_success = rct1_load_saved_game(path); result = rct1_load_saved_game(path);
load_success = (ParkLoadResult_GetError(result) == PARK_LOAD_ERROR_OK);
if (load_success) if (load_success)
gFirstTimeSaving = true; gFirstTimeSaving = true;
} }
@ -1126,20 +1128,20 @@ bool game_load_save(const utf8 *path)
} }
} }
void handle_park_load_failure(park_load_result* result, const utf8* path) void handle_park_load_failure(const ParkLoadResult * result, const utf8 * path)
{ {
if (result->error == PARK_LOAD_ERROR_BAD_OBJECTS) if (ParkLoadResult_GetError(result) == PARK_LOAD_ERROR_MISSING_OBJECTS)
{ {
// The path needs to be duplicated as it's a const here // The path needs to be duplicated as it's a const here
// which the window function doesn't like // which the window function doesn't like
window_object_load_error_open(strndup(path, strnlen(path, MAX_PATH)), result->object_validity); window_object_load_error_open(strndup(path, strnlen(path, MAX_PATH)),
} ParkLoadResult_GetMissingObjectsCount(result),
else if (result->error != PARK_LOAD_ERROR_NONE) { ParkLoadResult_GetMissingObjects(result));
} else if (ParkLoadResult_GetError(result) != PARK_LOAD_ERROR_OK) {
// If loading the SV6 or SV4 failed for a reason other than invalid objects // If loading the SV6 or SV4 failed for a reason other than invalid objects
// the current park state will be corrupted so just go back to the title screen. // the current park state will be corrupted so just go back to the title screen.
title_load(); title_load();
} }
SafeFree(result);
} }
void game_load_init() void game_load_init()
@ -1378,7 +1380,6 @@ void rct2_exit()
bool game_load_save_or_scenario(const utf8 * path) bool game_load_save_or_scenario(const utf8 * path)
{ {
park_load_result* result;
uint32 extension = get_file_extension_type(path); uint32 extension = get_file_extension_type(path);
switch (extension) { switch (extension) {
case FILE_EXTENSION_SV4: case FILE_EXTENSION_SV4:
@ -1386,8 +1387,12 @@ bool game_load_save_or_scenario(const utf8 * path)
return game_load_save(path); return game_load_save(path);
case FILE_EXTENSION_SC4: case FILE_EXTENSION_SC4:
case FILE_EXTENSION_SC6: case FILE_EXTENSION_SC6:
result = scenario_load_and_play_from_path(path); {
return (result->error == PARK_LOAD_ERROR_NONE); 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; return false;
} }

View File

@ -20,7 +20,6 @@
#include "rct2/addresses.h" #include "rct2/addresses.h"
#include "common.h" #include "common.h"
#include "scenario/scenario.h" #include "scenario/scenario.h"
#include "park_load_result_types.h"
enum GAME_COMMAND { enum GAME_COMMAND {
GAME_COMMAND_SET_RIDE_APPEARANCE, GAME_COMMAND_SET_RIDE_APPEARANCE,
@ -171,7 +170,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_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(); void game_load_or_quit_no_save_prompt();
park_load_result * game_load_sv6_path(const char * path); ParkLoadResult * game_load_sv6_path(const char * path);
bool game_load_save(const utf8 *path); bool game_load_save(const utf8 *path);
void game_load_init(); void game_load_init();
void game_pause_toggle(sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *edx, sint32 *esi, sint32 *edi, sint32 *ebp); void game_pause_toggle(sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *edx, sint32 *esi, sint32 *edi, sint32 *ebp);
@ -180,7 +179,7 @@ bool game_is_paused();
bool game_is_not_paused(); bool game_is_not_paused();
void save_game(); void save_game();
void save_game_as(); void save_game_as();
void handle_park_load_failure(park_load_result* result, const utf8* path); void handle_park_load_failure(const ParkLoadResult * result, const utf8 * path);
void rct2_exit(); void rct2_exit();
void rct2_exit_reason(rct_string_id title, rct_string_id body); void rct2_exit_reason(rct_string_id title, rct_string_id body);
void game_autosave(); void game_autosave();

View File

@ -767,7 +767,7 @@ rct_window *window_mapgen_open();
rct_window *window_loadsave_open(sint32 type, char *defaultName); rct_window *window_loadsave_open(sint32 type, char *defaultName);
rct_window *window_changelog_open(); rct_window *window_changelog_open();
void window_debug_paint_open(); void window_debug_paint_open();
rct_window *window_object_load_error_open(utf8* path, object_validity_result* result); rct_window * window_object_load_error_open(utf8 * path, size_t numMissingObjects, const rct_object_entry * missingObjects);
rct_window * window_editor_main_open(); rct_window * window_editor_main_open();
void window_editor_bottom_toolbar_open(); void window_editor_bottom_toolbar_open();

View File

@ -447,10 +447,10 @@ private:
return duplicate; return duplicate;
} }
object_validity_result* GetInvalidObjects(const rct_object_entry * entries) override std::vector<rct_object_entry> GetInvalidObjects(const rct_object_entry * entries) override
{ {
uint16 invalidObjectCount = 0; std::vector<rct_object_entry> invalidEntries;
rct_object_entry * * invalidEntries = Memory::AllocateArray<rct_object_entry *>(OBJECT_ENTRY_COUNT); invalidEntries.reserve(OBJECT_ENTRY_COUNT);
for (sint32 i = 0; i < OBJECT_ENTRY_COUNT; i++) for (sint32 i = 0; i < OBJECT_ENTRY_COUNT; i++)
{ {
const rct_object_entry * entry = &entries[i]; const rct_object_entry * entry = &entries[i];
@ -460,7 +460,7 @@ private:
ori = _objectRepository->FindObject(entry); ori = _objectRepository->FindObject(entry);
if (ori == nullptr) if (ori == nullptr)
{ {
invalidEntries[invalidObjectCount++] = DuplicateObjectEntry(entry); invalidEntries.push_back(*entry);
} }
else else
{ {
@ -471,16 +471,14 @@ private:
loadedObject = _objectRepository->LoadObject(ori); loadedObject = _objectRepository->LoadObject(ori);
if (loadedObject == nullptr) if (loadedObject == nullptr)
{ {
invalidEntries[invalidObjectCount++] = DuplicateObjectEntry(entry); invalidEntries.push_back(*entry);
} }
delete loadedObject;
} }
} }
} }
} }
object_validity_result* result = Memory::Allocate<object_validity_result>(sizeof(object_validity_result)); return invalidEntries;
result->invalid_object_count = invalidObjectCount;
result->invalid_objects = invalidEntries;
return result;
} }
bool GetRequiredObjects(const rct_object_entry * entries, bool GetRequiredObjects(const rct_object_entry * entries,

View File

@ -27,7 +27,6 @@ extern "C"
{ {
#endif #endif
#include "../object.h" #include "../object.h"
#include "../park_load_result_types.h"
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
@ -42,10 +41,10 @@ interface IObjectManager
{ {
virtual ~IObjectManager() { } virtual ~IObjectManager() { }
virtual Object * GetLoadedObject(size_t index) abstract; virtual Object * GetLoadedObject(size_t index) abstract;
virtual Object * GetLoadedObject(const rct_object_entry * entry) abstract; virtual Object * GetLoadedObject(const rct_object_entry * entry) abstract;
virtual uint8 GetLoadedObjectEntryIndex(const Object * object) abstract; virtual uint8 GetLoadedObjectEntryIndex(const Object * object) abstract;
virtual object_validity_result* GetInvalidObjects(const rct_object_entry * entries) abstract; virtual std::vector<rct_object_entry> GetInvalidObjects(const rct_object_entry * entries) abstract;
virtual Object * LoadObject(const rct_object_entry * entry) abstract; virtual Object * LoadObject(const rct_object_entry * entry) abstract;
virtual bool LoadObjects(const rct_object_entry * entries, size_t count) abstract; virtual bool LoadObjects(const rct_object_entry * entries, size_t count) abstract;

View File

@ -1,40 +0,0 @@
#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
#ifndef _PARK_LOAD_RESULT_H_
#define _PARK_LOAD_RESULT_H_
#include "object.h"
enum PARK_LOAD_ERROR {
PARK_LOAD_ERROR_NONE,
PARK_LOAD_ERROR_BAD_OBJECTS,
PARK_LOAD_ERROR_INVALID_EXTENSION,
PARK_LOAD_ERROR_UNKNOWN = 255
};
typedef struct object_validity_result
{
uint16 invalid_object_count;
rct_object_entry * * invalid_objects;
} object_validity_result;
typedef struct park_load_result {
uint8 error;
object_validity_result* object_validity;
} park_load_result;
#endif

View File

@ -20,7 +20,6 @@
#include "management/award.h" #include "management/award.h"
#include "management/news_item.h" #include "management/news_item.h"
#include "management/research.h" #include "management/research.h"
#include "park_load_result_types.h"
#include "rct12.h" #include "rct12.h"
#include "rct2.h" #include "rct2.h"
#include "ride/ride.h" #include "ride/ride.h"
@ -35,6 +34,8 @@
#define RCT1_MAX_RIDES_IN_PARK 128 #define RCT1_MAX_RIDES_IN_PARK 128
#define RCT1_RESEARCH_FLAGS_SEPARATOR 0xFF #define RCT1_RESEARCH_FLAGS_SEPARATOR 0xFF
typedef struct ParkLoadResult ParkLoadResult;
#pragma pack(push, 1) #pragma pack(push, 1)
typedef struct rct1_entrance { typedef struct rct1_entrance {
uint16 x; uint16 x;
@ -1210,8 +1211,8 @@ extern const uint8 gRideCategories[RIDE_TYPE_COUNT];
sint32 vehicle_preference_compare(uint8 rideType, const char * a, const char * b); sint32 vehicle_preference_compare(uint8 rideType, const char * a, const char * b);
bool rideTypeShouldLoseSeparateFlag(const rct_ride_entry *rideEntry); bool rideTypeShouldLoseSeparateFlag(const rct_ride_entry *rideEntry);
park_load_result * rct1_load_saved_game(const char *path); ParkLoadResult * rct1_load_saved_game(const char *path);
park_load_result * rct1_load_scenario(const char *path); ParkLoadResult * rct1_load_scenario(const char *path);
colour_t rct1_get_colour(colour_t colour); colour_t rct1_get_colour(colour_t colour);

View File

@ -26,6 +26,7 @@
#include "../core/Path.hpp" #include "../core/Path.hpp"
#include "../core/String.hpp" #include "../core/String.hpp"
#include "../core/Util.hpp" #include "../core/Util.hpp"
#include "../object/Object.h"
#include "../object/ObjectManager.h" #include "../object/ObjectManager.h"
#include "../object/ObjectRepository.h" #include "../object/ObjectRepository.h"
#include "../ParkImporter.h" #include "../ParkImporter.h"
@ -126,7 +127,7 @@ private:
uint8 _researchRideTypeUsed[128]; uint8 _researchRideTypeUsed[128];
public: public:
park_load_result* Load(const utf8 * path) override ParkLoadResult Load(const utf8 * path) override
{ {
const utf8 * extension = Path::GetExtension(path); const utf8 * extension = Path::GetExtension(path);
if (String::Equals(extension, ".sc4", true)) if (String::Equals(extension, ".sc4", true))
@ -143,27 +144,24 @@ public:
} }
} }
park_load_result* LoadSavedGame(const utf8 * path, bool skipObjectCheck = false) override ParkLoadResult LoadSavedGame(const utf8 * path, bool skipObjectCheck = false) override
{ {
auto fs = FileStream(path, FILE_MODE_OPEN); auto fs = FileStream(path, FILE_MODE_OPEN);
park_load_result* result = LoadFromStream(&fs, false, skipObjectCheck); auto result = LoadFromStream(&fs, false, skipObjectCheck);
_s4Path = path; _s4Path = path;
return result; return result;
} }
park_load_result* LoadScenario(const utf8 * path, bool skipObjectCheck = false) override ParkLoadResult LoadScenario(const utf8 * path, bool skipObjectCheck = false) override
{ {
auto fs = FileStream(path, FILE_MODE_OPEN); auto fs = FileStream(path, FILE_MODE_OPEN);
park_load_result* result = LoadFromStream(&fs, true, skipObjectCheck); auto result = LoadFromStream(&fs, true, skipObjectCheck);
_s4Path = path; _s4Path = path;
return result; return result;
} }
park_load_result* LoadFromStream(IStream * stream, bool isScenario, bool skipObjectCheck = false) override ParkLoadResult LoadFromStream(IStream * stream, bool isScenario, bool skipObjectCheck = false) override
{ {
park_load_result* result = Memory::Allocate<park_load_result>(sizeof(park_load_result));
result->error = PARK_LOAD_ERROR_NONE;
size_t dataSize = stream->GetLength() - stream->GetPosition(); size_t dataSize = stream->GetLength() - stream->GetPosition();
std::unique_ptr<uint8> data = std::unique_ptr<uint8>(stream->ReadArray<uint8>(dataSize)); std::unique_ptr<uint8> data = std::unique_ptr<uint8>(stream->ReadArray<uint8>(dataSize));
std::unique_ptr<uint8> decodedData = std::unique_ptr<uint8>(Memory::Allocate<uint8>(sizeof(rct1_s4))); std::unique_ptr<uint8> decodedData = std::unique_ptr<uint8>(Memory::Allocate<uint8>(sizeof(rct1_s4)));
@ -188,12 +186,11 @@ public:
{ {
InitialiseEntryMaps(); InitialiseEntryMaps();
CreateAvailableObjectMappings(); CreateAvailableObjectMappings();
object_validity_result* object_result = GetInvalidObjects();
result->object_validity = object_result; auto missingObjects = GetInvalidObjects();
if (object_result->invalid_object_count > 0) if (missingObjects.size() > 0)
{ {
result->error = PARK_LOAD_ERROR_BAD_OBJECTS; return ParkLoadResult::CreateMissingObjects(missingObjects);
} }
} }
} }
@ -201,7 +198,7 @@ public:
{ {
throw Exception("Unable to decode park."); throw Exception("Unable to decode park.");
} }
return result; return ParkLoadResult::CreateOK();
} }
void Import() override void Import() override
@ -1751,22 +1748,16 @@ private:
} }
} }
object_validity_result* GetInvalidObjects() std::vector<rct_object_entry> GetInvalidObjects()
{ {
object_validity_result* result = Memory::Allocate<object_validity_result>(sizeof(object_validity_result)); std::vector<rct_object_entry> missingObjects;
uint16 invalidObjectCount = 0; GetInvalidObjects(OBJECT_TYPE_RIDE, _rideEntries.GetEntries(), missingObjects);
rct_object_entry * * invalidEntries = Memory::AllocateArray<rct_object_entry *>(OBJECT_ENTRY_COUNT); GetInvalidObjects(OBJECT_TYPE_SMALL_SCENERY, _smallSceneryEntries.GetEntries(), missingObjects);
GetInvalidObjects(OBJECT_TYPE_LARGE_SCENERY, _largeSceneryEntries.GetEntries(), missingObjects);
result->invalid_object_count = invalidObjectCount; GetInvalidObjects(OBJECT_TYPE_WALLS, _wallEntries.GetEntries(), missingObjects);
result->invalid_objects = invalidEntries; GetInvalidObjects(OBJECT_TYPE_PATHS, _pathEntries.GetEntries(), missingObjects);
GetInvalidObjects(OBJECT_TYPE_PATH_BITS, _pathAdditionEntries.GetEntries(), missingObjects);
GetInvalidObjects(OBJECT_TYPE_RIDE, _rideEntries.GetEntries(), *result); GetInvalidObjects(OBJECT_TYPE_SCENERY_SETS, _sceneryGroupEntries.GetEntries(), missingObjects);
GetInvalidObjects(OBJECT_TYPE_SMALL_SCENERY, _smallSceneryEntries.GetEntries(), *result);
GetInvalidObjects(OBJECT_TYPE_LARGE_SCENERY, _largeSceneryEntries.GetEntries(), *result);
GetInvalidObjects(OBJECT_TYPE_WALLS, _wallEntries.GetEntries(), *result);
GetInvalidObjects(OBJECT_TYPE_PATHS, _pathEntries.GetEntries(), *result);
GetInvalidObjects(OBJECT_TYPE_PATH_BITS, _pathAdditionEntries.GetEntries(), *result);
GetInvalidObjects(OBJECT_TYPE_SCENERY_SETS, _sceneryGroupEntries.GetEntries(), *result);
GetInvalidObjects(OBJECT_TYPE_BANNERS, std::vector<const char *>({ GetInvalidObjects(OBJECT_TYPE_BANNERS, std::vector<const char *>({
"BN1 ", "BN1 ",
"BN2 ", "BN2 ",
@ -1777,14 +1768,13 @@ private:
"BN7 ", "BN7 ",
"BN8 ", "BN8 ",
"BN9 " "BN9 "
}), *result); }), missingObjects);
GetInvalidObjects(OBJECT_TYPE_PARK_ENTRANCE, std::vector<const char *>({ "PKENT1 " }), *result); GetInvalidObjects(OBJECT_TYPE_PARK_ENTRANCE, std::vector<const char *>({ "PKENT1 " }), missingObjects);
GetInvalidObjects(OBJECT_TYPE_WATER, _waterEntry.GetEntries(), *result); GetInvalidObjects(OBJECT_TYPE_WATER, _waterEntry.GetEntries(), missingObjects);
return missingObjects;
return result;
} }
void GetInvalidObjects(uint8 objectType, const std::vector<const char *> &entries, object_validity_result &result) void GetInvalidObjects(uint8 objectType, const std::vector<const char *> &entries, std::vector<rct_object_entry> &missingObjects)
{ {
IObjectRepository * objectRepository = GetObjectRepository(); IObjectRepository * objectRepository = GetObjectRepository();
for (const char * objectName : entries) for (const char * objectName : entries)
@ -1794,26 +1784,19 @@ private:
Memory::Copy(entry.name, objectName, 8); Memory::Copy(entry.name, objectName, 8);
entry.checksum = 0; entry.checksum = 0;
const ObjectRepositoryItem * ori = nullptr; const ObjectRepositoryItem * ori = objectRepository->FindObject(&entry);
ori = objectRepository->FindObject(&entry);
if (ori == nullptr) if (ori == nullptr)
{ {
rct_object_entry * invalid_entry = Memory::Allocate<rct_object_entry>(sizeof(rct_object_entry)); missingObjects.push_back(entry);
invalid_entry->flags = entry.flags;
Memory::Copy(invalid_entry->name, objectName, 8);
result.invalid_objects[result.invalid_object_count++] = invalid_entry;
} }
else else
{ {
Object * object = objectRepository->LoadObject(ori); Object * object = objectRepository->LoadObject(ori);
if (object == nullptr && objectType != OBJECT_TYPE_SCENERY_SETS) if (object == nullptr && objectType != OBJECT_TYPE_SCENERY_SETS)
{ {
rct_object_entry * invalid_entry = Memory::Allocate<rct_object_entry>(sizeof(rct_object_entry)); missingObjects.push_back(entry);
invalid_entry->flags = entry.flags;
Memory::Copy(invalid_entry->name, objectName, 8);
result.invalid_objects[result.invalid_object_count++] = invalid_entry;
} }
SafeFree(object); delete object;
} }
} }
} }
@ -2661,46 +2644,43 @@ IParkImporter * ParkImporter::CreateS4()
///////////////////////////////////////// /////////////////////////////////////////
extern "C" extern "C"
{ {
park_load_result* rct1_load_saved_game(const utf8 * path) ParkLoadResult * rct1_load_saved_game(const utf8 * path)
{ {
park_load_result* result = {}; ParkLoadResult * result = nullptr;
auto s4Importer = std::make_unique<S4Importer>();
auto s4Importer = new S4Importer();
try try
{ {
result = s4Importer->LoadSavedGame(path); result = new ParkLoadResult(s4Importer->LoadSavedGame(path));
if (result->error == PARK_LOAD_ERROR_NONE) if (result->Error == PARK_LOAD_ERROR_OK)
{ {
s4Importer->Import(); s4Importer->Import();
} }
} catch (const Exception &)
{
result = {};
result->error = PARK_LOAD_ERROR_UNKNOWN;
} }
delete s4Importer; catch (const Exception &)
{
delete result;
result = new ParkLoadResult(ParkLoadResult::CreateUnknown());
}
return result; return result;
} }
park_load_result* rct1_load_scenario(const utf8 * path) ParkLoadResult * rct1_load_scenario(const utf8 * path)
{ {
park_load_result* result = {}; ParkLoadResult * result = nullptr;
auto s4Importer = std::make_unique<S4Importer>();
auto s4Importer = new S4Importer();
try try
{ {
result = s4Importer->LoadSavedGame(path); result = new ParkLoadResult(s4Importer->LoadSavedGame(path));
if (result->error == PARK_LOAD_ERROR_NONE) if (result->Error == PARK_LOAD_ERROR_OK)
{ {
s4Importer->Import(); s4Importer->Import();
} }
} catch (const Exception &)
{
result = {};
result->error = PARK_LOAD_ERROR_UNKNOWN;
} }
delete s4Importer; catch (const Exception &)
{
delete result;
result = new ParkLoadResult(ParkLoadResult::CreateUnknown());
}
return result; return result;
} }

View File

@ -38,6 +38,7 @@
#include "object.h" #include "object.h"
#include "object/ObjectManager.h" #include "object/ObjectManager.h"
#include "OpenRCT2.h" #include "OpenRCT2.h"
#include "ParkImporter.h"
#include "peep/staff.h" #include "peep/staff.h"
#include "platform/platform.h" #include "platform/platform.h"
#include "rct1.h" #include "rct1.h"
@ -339,12 +340,13 @@ bool rct2_open_file(const char *path)
} }
} else if (_stricmp(extension, "sc6") == 0) { } else if (_stricmp(extension, "sc6") == 0) {
// TODO scenario install // TODO scenario install
park_load_result *result = scenario_load_and_play_from_path(path); ParkLoadResult * result = scenario_load_and_play_from_path(path);
if (result->error == PARK_LOAD_ERROR_NONE) { if (ParkLoadResult_GetError(result) == PARK_LOAD_ERROR_OK) {
ParkLoadResult_Delete(result);
return true; return true;
} } else {
else {
handle_park_load_failure(result, path); handle_park_load_failure(result, path);
ParkLoadResult_Delete(result);
return false; return false;
} }
} else if (_stricmp(extension, "td6") == 0 || _stricmp(extension, "td4") == 0) { } else if (_stricmp(extension, "td6") == 0 || _stricmp(extension, "td4") == 0) {

View File

@ -81,7 +81,7 @@ public:
Memory::Set(&_s6, 0, sizeof(_s6)); Memory::Set(&_s6, 0, sizeof(_s6));
} }
park_load_result* Load(const utf8 * path) override ParkLoadResult Load(const utf8 * path) override
{ {
const utf8 * extension = Path::GetExtension(path); const utf8 * extension = Path::GetExtension(path);
if (String::Equals(extension, ".sc6", true)) if (String::Equals(extension, ".sc6", true))
@ -98,29 +98,24 @@ public:
} }
} }
park_load_result* LoadSavedGame(const utf8 * path, bool skipObjectCheck = false) override ParkLoadResult LoadSavedGame(const utf8 * path, bool skipObjectCheck = false) override
{ {
auto fs = FileStream(path, FILE_MODE_OPEN); auto fs = FileStream(path, FILE_MODE_OPEN);
park_load_result* result = LoadFromStream(&fs, false, skipObjectCheck); auto result = LoadFromStream(&fs, false, skipObjectCheck);
_s6Path = path; _s6Path = path;
return result; return result;
} }
park_load_result* LoadScenario(const utf8 * path, bool skipObjectCheck = false) override ParkLoadResult LoadScenario(const utf8 * path, bool skipObjectCheck = false) override
{ {
auto fs = FileStream(path, FILE_MODE_OPEN); auto fs = FileStream(path, FILE_MODE_OPEN);
park_load_result* result = LoadFromStream(&fs, true, skipObjectCheck); auto result = LoadFromStream(&fs, true, skipObjectCheck);
_s6Path = path; _s6Path = path;
return result; return result;
} }
park_load_result* LoadFromStream(IStream * stream, bool isScenario, bool skipObjectCheck = false) override ParkLoadResult LoadFromStream(IStream * stream, bool isScenario, bool skipObjectCheck = false) override
{ {
park_load_result* result = Memory::Allocate<park_load_result>(sizeof(park_load_result));
result->error = PARK_LOAD_ERROR_UNKNOWN;
if (isScenario && !gConfigGeneral.allow_loading_with_incorrect_checksum && !SawyerEncoding::ValidateChecksum(stream)) if (isScenario && !gConfigGeneral.allow_loading_with_incorrect_checksum && !SawyerEncoding::ValidateChecksum(stream))
{ {
throw IOException("Invalid checksum."); throw IOException("Invalid checksum.");
@ -175,18 +170,12 @@ public:
chunkReader.ReadChunk(&_s6.next_free_map_element_pointer_index, 3048816); chunkReader.ReadChunk(&_s6.next_free_map_element_pointer_index, 3048816);
} }
object_validity_result* object_result = _objectManager->GetInvalidObjects(_s6.objects); auto missingObjects = _objectManager->GetInvalidObjects(_s6.objects);
if (missingObjects.size() > 0)
result->object_validity = object_result;
if (object_result->invalid_object_count > 0)
{ {
result->error = PARK_LOAD_ERROR_BAD_OBJECTS; return ParkLoadResult::CreateMissingObjects(missingObjects);
} }
else return ParkLoadResult::CreateOK();
{
result->error = PARK_LOAD_ERROR_NONE;
}
return result;
} }
bool GetDetails(scenario_index_entry * dst) override bool GetDetails(scenario_index_entry * dst) override
@ -439,17 +428,17 @@ IParkImporter * ParkImporter::CreateS6(IObjectRepository * objectRepository, IOb
extern "C" extern "C"
{ {
park_load_result* game_load_sv6_path(const char * path) ParkLoadResult * game_load_sv6_path(const char * path)
{ {
park_load_result* result = {}; ParkLoadResult * result = nullptr;
auto s6Importer = new S6Importer(GetObjectRepository(), GetObjectManager()); auto s6Importer = new S6Importer(GetObjectRepository(), GetObjectManager());
try try
{ {
result = s6Importer->LoadSavedGame(path); result = new ParkLoadResult(s6Importer->LoadSavedGame(path));
// We mustn't import if there's something // We mustn't import if there's something
// wrong with the park data // wrong with the park data
if (result->error == PARK_LOAD_ERROR_NONE) if (result->Error == PARK_LOAD_ERROR_OK)
{ {
s6Importer->Import(); s6Importer->Import();
@ -474,7 +463,11 @@ extern "C"
} }
delete s6Importer; delete s6Importer;
if (result->error == PARK_LOAD_ERROR_NONE) if (result == nullptr)
{
result = new ParkLoadResult(ParkLoadResult::CreateUnknown());
}
if (result->Error == PARK_LOAD_ERROR_OK)
{ {
gScreenAge = 0; gScreenAge = 0;
gLastAutoSaveUpdate = AUTOSAVE_PAUSE; gLastAutoSaveUpdate = AUTOSAVE_PAUSE;
@ -487,14 +480,14 @@ extern "C"
* rct2: 0x00676053 * rct2: 0x00676053
* scenario (ebx) * scenario (ebx)
*/ */
park_load_result* scenario_load(const char * path) ParkLoadResult * scenario_load(const char * path)
{ {
park_load_result* result = {}; ParkLoadResult * result = nullptr;
auto s6Importer = new S6Importer(GetObjectRepository(), GetObjectManager()); auto s6Importer = new S6Importer(GetObjectRepository(), GetObjectManager());
try try
{ {
result = s6Importer->LoadScenario(path); result = new ParkLoadResult(s6Importer->LoadScenario(path));
if (result->error == PARK_LOAD_ERROR_NONE) if (result->Error == PARK_LOAD_ERROR_OK)
{ {
s6Importer->Import(); s6Importer->Import();
@ -518,7 +511,12 @@ extern "C"
gErrorStringId = STR_FILE_CONTAINS_INVALID_DATA; gErrorStringId = STR_FILE_CONTAINS_INVALID_DATA;
} }
delete s6Importer; delete s6Importer;
if (result->error != PARK_LOAD_ERROR_NONE)
if (result == nullptr)
{
result = new ParkLoadResult(ParkLoadResult::CreateUnknown());
}
if (result->Error != PARK_LOAD_ERROR_OK)
{ {
gScreenAge = 0; gScreenAge = 0;
gLastAutoSaveUpdate = AUTOSAVE_PAUSE; gLastAutoSaveUpdate = AUTOSAVE_PAUSE;

View File

@ -30,6 +30,7 @@
#include "../object.h" #include "../object.h"
#include "../object_list.h" #include "../object_list.h"
#include "../OpenRCT2.h" #include "../OpenRCT2.h"
#include "../ParkImporter.h"
#include "../peep/staff.h" #include "../peep/staff.h"
#include "../platform/platform.h" #include "../platform/platform.h"
#include "../rct1.h" #include "../rct1.h"
@ -88,28 +89,24 @@ money32 gScenarioCompanyValueRecord;
static sint32 scenario_create_ducks(); static sint32 scenario_create_ducks();
static void scenario_objective_check(); static void scenario_objective_check();
park_load_result* scenario_load_and_play_from_path(const char *path) ParkLoadResult * scenario_load_and_play_from_path(const char * path)
{ {
window_close_construction_windows(); window_close_construction_windows();
uint32 extension = get_file_extension_type(path); uint32 extension = get_file_extension_type(path);
park_load_result* result = malloc(sizeof(park_load_result)); ParkLoadResult * result = NULL;
if (extension == FILE_EXTENSION_SC6) { if (extension == FILE_EXTENSION_SC6) {
result = scenario_load(path); result = scenario_load(path);
if (result->error != PARK_LOAD_ERROR_NONE) if (ParkLoadResult_GetError(result) != PARK_LOAD_ERROR_OK) {
{
return result; return result;
} }
} } else if (extension == FILE_EXTENSION_SC4) {
else if (extension == FILE_EXTENSION_SC4) {
result = rct1_load_scenario(path); result = rct1_load_scenario(path);
if (result->error != PARK_LOAD_ERROR_NONE) if (ParkLoadResult_GetError(result) != PARK_LOAD_ERROR_OK) {
{
return result; return result;
} }
} } else {
else { result = ParkLoadResult_CreateInvalidExtension();
result->error = PARK_LOAD_ERROR_INVALID_EXTENSION;
return result; return result;
} }

View File

@ -21,7 +21,6 @@
#include "../management/finance.h" #include "../management/finance.h"
#include "../management/research.h" #include "../management/research.h"
#include "../object.h" #include "../object.h"
#include "../park_load_result_types.h"
#include "../rct12.h" #include "../rct12.h"
#include "../rct2.h" #include "../rct2.h"
#include "../rct2/addresses.h" #include "../rct2/addresses.h"
@ -32,6 +31,8 @@
#include "../world/map_animation.h" #include "../world/map_animation.h"
#include "../world/sprite.h" #include "../world/sprite.h"
typedef struct ParkLoadResult ParkLoadResult;
#pragma pack(push, 1) #pragma pack(push, 1)
/** /**
* SV6/SC6 header chunk * SV6/SC6 header chunk
@ -390,8 +391,8 @@ extern uint32 gLastAutoSaveUpdate;
extern const char *_scenarioFileName; extern const char *_scenarioFileName;
park_load_result *scenario_load(const char *path); ParkLoadResult * scenario_load(const char *path);
park_load_result *scenario_load_and_play_from_path(const char *path); ParkLoadResult * scenario_load_and_play_from_path(const char *path);
void scenario_begin(); void scenario_begin();
void scenario_update(); void scenario_update();

View File

@ -19,7 +19,6 @@
#include <time.h> #include <time.h>
#include "../common.h" #include "../common.h"
#include "../park_load_result_types.h"
sint32 squaredmetres_to_squaredfeet(sint32 squaredMetres); sint32 squaredmetres_to_squaredfeet(sint32 squaredMetres);
sint32 metres_to_feet(sint32 metres); sint32 metres_to_feet(sint32 metres);

View File

@ -21,7 +21,6 @@
#include "../object.h" #include "../object.h"
#include "../platform/platform.h" #include "../platform/platform.h"
#include "../sprites.h" #include "../sprites.h"
#include "../util/util.h"
enum WINDOW_OBJECT_LOAD_ERROR_WIDGET_IDX { enum WINDOW_OBJECT_LOAD_ERROR_WIDGET_IDX {
WIDX_BACKGROUND, WIDX_BACKGROUND,
@ -91,7 +90,7 @@ static rct_window_event_list window_object_load_error_events = {
window_object_load_error_scrollpaint window_object_load_error_scrollpaint
}; };
rct_object_entry * * invalid_entries = NULL; rct_object_entry * invalid_entries = NULL;
sint32 highlighted_index = -1; sint32 highlighted_index = -1;
utf8* file_path = NULL; utf8* file_path = NULL;
@ -168,20 +167,20 @@ static utf8* combine_object_names(rct_window *w)
for (uint16 i = 0; i < w->no_list_items; i++) { for (uint16 i = 0; i < w->no_list_items; i++) {
cur_len += (8 + line_sep_len); cur_len += (8 + line_sep_len);
assert(cur_len < buffer_len); assert(cur_len < buffer_len);
strncat(buffer, invalid_entries[i]->name, 8); strncat(buffer, invalid_entries[i].name, 8);
strncat(buffer, PLATFORM_NEWLINE, line_sep_len); strncat(buffer, PLATFORM_NEWLINE, line_sep_len);
} }
return buffer; return buffer;
} }
rct_window *window_object_load_error_open(utf8* path, object_validity_result* result) rct_window * window_object_load_error_open(utf8 * path, size_t numMissingObjects, const rct_object_entry * missingObjects)
{ {
rct_window* window; size_t missingObjectsSize = numMissingObjects * sizeof(rct_object_entry);
invalid_entries = malloc(missingObjectsSize);
invalid_entries = result->invalid_objects; memcpy(invalid_entries, missingObjects, missingObjectsSize);
// Check if window is already open // Check if window is already open
window = window_bring_to_front_by_class(WC_OBJECT_LOAD_ERROR); rct_window * window = window_bring_to_front_by_class(WC_OBJECT_LOAD_ERROR);
if (window == NULL) { if (window == NULL) {
window = window_create_centred( window = window_create_centred(
WW, WW,
@ -201,7 +200,7 @@ rct_window *window_object_load_error_open(utf8* path, object_validity_result* re
} }
// Refresh list items and path // Refresh list items and path
window->no_list_items = result->invalid_object_count; window->no_list_items = (uint16)numMissingObjects;
file_path = path; file_path = path;
window_invalidate(window); window_invalidate(window);
@ -232,7 +231,7 @@ static void window_object_load_error_mouseup(rct_window *w, rct_widgetindex widg
break; break;
case WIDX_COPY_CURRENT: case WIDX_COPY_CURRENT:
if (w->selected_list_item > -1) { if (w->selected_list_item > -1) {
selected_name = strndup(invalid_entries[w->selected_list_item]->name, 8); selected_name = strndup(invalid_entries[w->selected_list_item].name, 8);
platform_place_string_on_clipboard(selected_name); platform_place_string_on_clipboard(selected_name);
SafeFree(selected_name); SafeFree(selected_name);
} }
@ -296,7 +295,6 @@ static void window_object_load_error_paint(rct_window *w, rct_drawpixelinfo *dpi
static void window_object_load_error_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, sint32 scrollIndex) static void window_object_load_error_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, sint32 scrollIndex)
{ {
gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width - 1, dpi->y + dpi->height - 1, ColourMapA[w->colours[1]].mid_light); gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width - 1, dpi->y + dpi->height - 1, ColourMapA[w->colours[1]].mid_light);
const sint32 list_width = w->widgets[WIDX_SCROLL].right - w->widgets[WIDX_SCROLL].left; const sint32 list_width = w->widgets[WIDX_SCROLL].right - w->widgets[WIDX_SCROLL].left;
@ -317,12 +315,10 @@ static void window_object_load_error_scrollpaint(rct_window *w, rct_drawpixelinf
gfx_fill_rect(dpi, 0, y, list_width, y + LIST_ITEM_HEIGHT - 1, ColourMapA[w->colours[1]].lighter | 0x1000000); gfx_fill_rect(dpi, 0, y, list_width, y + LIST_ITEM_HEIGHT - 1, ColourMapA[w->colours[1]].lighter | 0x1000000);
// Draw the actual object entry's name... // Draw the actual object entry's name...
gfx_draw_string(dpi, strndup(invalid_entries[i]->name, 8), COLOUR_DARK_GREEN, 5, y); gfx_draw_string(dpi, strndup(invalid_entries[i].name, 8), COLOUR_DARK_GREEN, 5, y);
// ... and type // ... and type
rct_string_id type = get_object_type_string(invalid_entries[i]); rct_string_id type = get_object_type_string(&invalid_entries[i]);
gfx_draw_string_left(dpi, type, NULL, COLOUR_DARK_GREEN, (WW - 5) / 3 + 1, y); gfx_draw_string_left(dpi, type, NULL, COLOUR_DARK_GREEN, (WW - 5) / 3 + 1, y);
} }
} }

View File

@ -21,6 +21,7 @@
#include "../interface/window.h" #include "../interface/window.h"
#include "../localisation/localisation.h" #include "../localisation/localisation.h"
#include "../network/network.h" #include "../network/network.h"
#include "../ParkImporter.h"
#include "../platform/platform.h" #include "../platform/platform.h"
#include "../sprites.h" #include "../sprites.h"
#include "../title/TitleScreen.h" #include "../title/TitleScreen.h"
@ -165,14 +166,14 @@ static void window_server_start_close(rct_window *w)
static void window_server_start_scenarioselect_callback(const utf8 *path) static void window_server_start_scenarioselect_callback(const utf8 *path)
{ {
park_load_result* result;
network_set_password(_password); network_set_password(_password);
result = scenario_load_and_play_from_path(path); ParkLoadResult * result = scenario_load_and_play_from_path(path);
if (result->error == PARK_LOAD_ERROR_NONE) { if (ParkLoadResult_GetError(result) == PARK_LOAD_ERROR_OK) {
network_begin_server(gConfigNetwork.default_port, gConfigNetwork.listen_address); network_begin_server(gConfigNetwork.default_port, gConfigNetwork.listen_address);
} else { } else {
handle_park_load_failure(result, path); handle_park_load_failure(result, path);
} }
ParkLoadResult_Delete(result);
} }
static void window_server_start_loadsave_callback(sint32 result, const utf8 * path) static void window_server_start_loadsave_callback(sint32 result, const utf8 * path)

View File

@ -22,6 +22,7 @@
#include "../interface/widget.h" #include "../interface/widget.h"
#include "../interface/window.h" #include "../interface/window.h"
#include "../localisation/localisation.h" #include "../localisation/localisation.h"
#include "../ParkImporter.h"
#include "../sprites.h" #include "../sprites.h"
#include "../title/TitleScreen.h" #include "../title/TitleScreen.h"
#include "../util/util.h" #include "../util/util.h"
@ -129,8 +130,9 @@ void window_title_menu_open()
static void window_title_menu_scenarioselect_callback(const utf8 *path) static void window_title_menu_scenarioselect_callback(const utf8 *path)
{ {
park_load_result *result = scenario_load_and_play_from_path(path); ParkLoadResult * result = scenario_load_and_play_from_path(path);
handle_park_load_failure(result, path); handle_park_load_failure(result, path);
ParkLoadResult_Delete(result);
} }
static void window_title_menu_mouseup(rct_window *w, rct_widgetindex widgetIndex) static void window_title_menu_mouseup(rct_window *w, rct_widgetindex widgetIndex)

View File

@ -30,6 +30,7 @@
#include "../localisation/localisation.h" #include "../localisation/localisation.h"
#include "../network/network.h" #include "../network/network.h"
#include "../network/twitch.h" #include "../network/twitch.h"
#include "../ParkImporter.h"
#include "../peep/staff.h" #include "../peep/staff.h"
#include "../scenario/scenario.h" #include "../scenario/scenario.h"
#include "../sprites.h" #include "../sprites.h"
@ -519,8 +520,9 @@ static void window_top_toolbar_mousedown(rct_widgetindex widgetIndex, rct_window
static void window_top_toolbar_scenarioselect_callback(const utf8 *path) static void window_top_toolbar_scenarioselect_callback(const utf8 *path)
{ {
park_load_result *result = scenario_load_and_play_from_path(path); ParkLoadResult * result = scenario_load_and_play_from_path(path);
handle_park_load_failure(result, path); handle_park_load_failure(result, path);
ParkLoadResult_Delete(result);
} }
/** /**