Make start on loading objects only once

This commit is contained in:
Ted John 2018-05-21 00:11:42 +01:00
parent 633b3e5b92
commit 96a0a22cd1
11 changed files with 365 additions and 330 deletions

View File

@ -36,8 +36,8 @@
#include "core/String.hpp"
#include "core/Util.hpp"
#include "drawing/IDrawingEngine.h"
#include "localisation/Localisation.h"
#include "FileClassifier.h"
#include "HandleParkLoad.h"
#include "network/network.h"
#include "object/ObjectManager.h"
#include "object/ObjectRepository.h"
@ -559,52 +559,80 @@ namespace OpenRCT2
try
{
auto result = parkImporter->LoadFromStream(stream, info.Type == FILE_TYPE::SCENARIO, false, path.c_str());
if (result.Error == PARK_LOAD_ERROR_OK)
// _objectManager->LoadObjects(result.RequiredObjects.data(), result.RequiredObjects.size());
parkImporter->Import();
String::Set(gScenarioSavePath, Util::CountOf(gScenarioSavePath), path.c_str());
String::Set(gCurrentLoadedPath, Util::CountOf(gCurrentLoadedPath), path.c_str());
gFirstTimeSaving = true;
game_fix_save_vars();
sprite_position_tween_reset();
gScreenAge = 0;
gLastAutoSaveUpdate = AUTOSAVE_PAUSE;
if (info.Type == FILE_TYPE::SAVED_GAME)
{
parkImporter->Import();
String::Set(gScenarioSavePath, Util::CountOf(gScenarioSavePath), path.c_str());
String::Set(gCurrentLoadedPath, Util::CountOf(gCurrentLoadedPath), path.c_str());
gFirstTimeSaving = true;
game_fix_save_vars();
sprite_position_tween_reset();
gScreenAge = 0;
gLastAutoSaveUpdate = AUTOSAVE_PAUSE;
if (info.Type == FILE_TYPE::SAVED_GAME)
if (network_get_mode() == NETWORK_MODE_CLIENT)
{
if (network_get_mode() == NETWORK_MODE_CLIENT)
{
network_close();
}
game_load_init();
if (network_get_mode() == NETWORK_MODE_SERVER)
{
network_send_map();
}
network_close();
}
else
game_load_init();
if (network_get_mode() == NETWORK_MODE_SERVER)
{
scenario_begin();
if (network_get_mode() == NETWORK_MODE_SERVER)
{
network_send_map();
}
if (network_get_mode() == NETWORK_MODE_CLIENT)
{
network_close();
}
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_with_title_opt(&result, path, loadTitleScreenFirstOnFail);
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;
}
catch (const std::exception &e)
catch (const ObjectLoadException& e)
{
// This option is used when loading parks from the command line
// to ensure that the title sequence loads before the window
if (loadTitleScreenFirstOnFail)
{
title_load();
}
// The path needs to be duplicated as it's a const here
// which the window function doesn't like
auto intent = Intent(WC_OBJECT_LOAD_ERROR);
intent.putExtra(INTENT_EXTRA_PATH, path);
intent.putExtra(INTENT_EXTRA_LIST, (void *)e.MissingObjects.data());
intent.putExtra(INTENT_EXTRA_LIST_COUNT, (uint32)e.MissingObjects.size());
auto windowManager = _uiContext->GetWindowManager();
windowManager->OpenIntent(&intent);
}
catch (const UnsupportedRCTCFlagException& e)
{
// This option is used when loading parks from the command line
// to ensure that the title sequence loads before the window
if (loadTitleScreenFirstOnFail)
{
title_load();
}
auto windowManager = _uiContext->GetWindowManager();
set_format_arg(0, uint16, e.Flag);
windowManager->ShowError(STR_FAILED_TO_LOAD_IMCOMPATIBLE_RCTC_FLAG, STR_NONE);
}
catch (const std::exception& e)
{
// 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.
title_load();
Console::Error::WriteLine(e.what());
}
}

View File

@ -245,22 +245,15 @@ namespace Editor
*/
static bool ReadS6(const char * path)
{
ParkLoadResult * loadResult = nullptr;
const char * extension = path_get_extension(path);
auto extension = path_get_extension(path);
if (_stricmp(extension, ".sc6") == 0)
{
loadResult = load_from_sc6(path);
load_from_sc6(path);
}
else if (_stricmp(extension, ".sv6") == 0)
{
loadResult = load_from_sv6(path);
load_from_sv6(path);
}
if (ParkLoadResult_GetError(loadResult) != PARK_LOAD_ERROR_OK)
{
ParkLoadResult_Delete(loadResult);
return false;
}
ParkLoadResult_Delete(loadResult);
ClearMapForEditing(true);

View File

@ -25,7 +25,6 @@
#include "Editor.h"
#include "FileClassifier.h"
#include "Game.h"
#include "HandleParkLoad.h"
#include "Input.h"
#include "interface/Screenshot.h"
#include "interface/Viewport.h"
@ -1324,50 +1323,6 @@ void game_fix_save_vars()
fix_park_entrance_locations();
}
void handle_park_load_failure_with_title_opt(const ParkLoadResult * result, const std::string & path, bool loadTitleFirst)
{
if (ParkLoadResult_GetError(result) == PARK_LOAD_ERROR_MISSING_OBJECTS)
{
// This option is used when loading parks from the command line
// to ensure that the title sequence loads before the window
if (loadTitleFirst)
{
title_load();
}
// The path needs to be duplicated as it's a const here
// which the window function doesn't like
auto intent = Intent(WC_OBJECT_LOAD_ERROR);
intent.putExtra(INTENT_EXTRA_PATH, path);
intent.putExtra(INTENT_EXTRA_LIST, (void *) ParkLoadResult_GetMissingObjects(result));
intent.putExtra(INTENT_EXTRA_LIST_COUNT, (uint32) ParkLoadResult_GetMissingObjectsCount(result));
context_open_intent(&intent);
}
else if (ParkLoadResult_GetError(result) == PARK_LOAD_ERROR_UNSUPPORTED_RCTC_FLAG)
{
// This option is used when loading parks from the command line
// to ensure that the title sequence loads before the window
if (loadTitleFirst)
{
title_load();
}
set_format_arg(0, uint16, ParkLoadResult_GetFlag(result));
context_show_error(STR_FAILED_TO_LOAD_IMCOMPATIBLE_RCTC_FLAG, STR_NONE);
}
else if (ParkLoadResult_GetError(result) != PARK_LOAD_ERROR_OK)
{
// 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.
title_load();
}
}
void handle_park_load_failure(const ParkLoadResult * result, const std::string & path)
{
handle_park_load_failure_with_title_opt(result, path, false);
}
void game_load_init()
{
rct_window * mainWindow;

View File

@ -172,7 +172,7 @@ sint32 game_do_command_p(uint32 command, sint32 * eax, sint32 * ebx, sint32 * ec
void game_log_multiplayer_command(int command, const int * eax, const int * ebx, const int * ecx, int * edx, int * edi, int * ebp);
void game_load_or_quit_no_save_prompt();
ParkLoadResult * load_from_sv6(const char * path);
void 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();

View File

@ -1,26 +0,0 @@
#pragma region Copyright (c) 2014-2018 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
#pragma once
#include <string>
#include "common.h"
struct ParkLoadResult;
void handle_park_load_failure_with_title_opt(const ParkLoadResult * result, const std::string & path, bool loadTitleFirst);
void handle_park_load_failure(const ParkLoadResult * result, const std::string & path);

View File

@ -22,81 +22,6 @@
#include "object/ObjectRepository.h"
#include "ParkImporter.h"
ParkLoadResult::ParkLoadResult(PARK_LOAD_ERROR error)
: Error(error),
Flag(0)
{
}
ParkLoadResult::ParkLoadResult(PARK_LOAD_ERROR error, const std::vector<rct_object_entry> &missingObjects)
: Error(error),
MissingObjects(missingObjects),
Flag(0)
{
}
ParkLoadResult::ParkLoadResult(PARK_LOAD_ERROR error, const uint8 flag)
: Error(error),
Flag(flag)
{
}
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);
}
ParkLoadResult ParkLoadResult::CreateUnsupportedRCTCflag(uint8 classic_flag)
{
return ParkLoadResult(PARK_LOAD_ERROR::PARK_LOAD_ERROR_UNSUPPORTED_RCTC_FLAG, classic_flag);
}
PARK_LOAD_ERROR ParkLoadResult_GetError(const ParkLoadResult * t)
{
return t->Error;
}
size_t ParkLoadResult_GetMissingObjectsCount(const ParkLoadResult * t)
{
return t->MissingObjects.size();
}
uint8 ParkLoadResult_GetFlag(const ParkLoadResult * t)
{
return t->Flag;
}
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
{
std::unique_ptr<IParkImporter> Create(const std::string &hintPath)

View File

@ -42,20 +42,12 @@ struct scenario_index_entry;
struct ParkLoadResult final
{
public:
const PARK_LOAD_ERROR Error;
const std::vector<rct_object_entry> MissingObjects;
const uint8 Flag;
std::vector<rct_object_entry> const RequiredObjects;
static ParkLoadResult CreateOK();
static ParkLoadResult CreateInvalidExtension();
static ParkLoadResult CreateMissingObjects(const std::vector<rct_object_entry> &missingObjects);
static ParkLoadResult CreateUnknown();
static ParkLoadResult CreateUnsupportedRCTCflag(uint8 classic_flag);
private:
explicit ParkLoadResult(PARK_LOAD_ERROR error);
ParkLoadResult(PARK_LOAD_ERROR error, const std::vector<rct_object_entry> &missingObjects);
ParkLoadResult(PARK_LOAD_ERROR error, const uint8 flag);
explicit ParkLoadResult(std::vector<rct_object_entry>&& requiredObjects)
: RequiredObjects(requiredObjects)
{
}
};
/**
@ -88,6 +80,28 @@ namespace ParkImporter
bool ExtensionIsScenario(const std::string &extension);
}
class ObjectLoadException : std::exception
{
public:
std::vector<rct_object_entry> const MissingObjects;
explicit ObjectLoadException(std::vector<rct_object_entry>&& missingObjects)
: MissingObjects(missingObjects)
{
}
};
class UnsupportedRCTCFlagException : std::exception
{
public:
uint8 const Flag;
explicit UnsupportedRCTCFlagException(uint8 flag)
: Flag(flag)
{
}
};
void park_importer_load_from_stream(void * stream, const utf8 * hintPath);
bool park_importer_extension_is_scenario(const utf8 * extension);

View File

@ -57,7 +57,183 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\resources\resource.h" />
<ClInclude Include="**\*.h" />
<ClInclude Include="actions\GameAction.h" />
<ClInclude Include="audio\audio.h" />
<ClInclude Include="audio\AudioChannel.h" />
<ClInclude Include="audio\AudioContext.h" />
<ClInclude Include="audio\AudioMixer.h" />
<ClInclude Include="audio\AudioSource.h" />
<ClInclude Include="Cheats.h" />
<ClInclude Include="CmdlineSprite.h" />
<ClInclude Include="common.h" />
<ClInclude Include="config\Config.h" />
<ClInclude Include="Context.h" />
<ClInclude Include="core\DataSerialiser.h" />
<ClInclude Include="core\DataSerialiserTraits.h" />
<ClInclude Include="core\Endianness.h" />
<ClInclude Include="core\File.h" />
<ClInclude Include="core\FileScanner.h" />
<ClInclude Include="core\Imaging.h" />
<ClInclude Include="core\MemoryStream.h" />
<ClInclude Include="core\Zip.h" />
<ClInclude Include="Date.h" />
<ClInclude Include="Diagnostic.h" />
<ClInclude Include="drawing\Drawing.h" />
<ClInclude Include="drawing\Font.h" />
<ClInclude Include="drawing\IDrawingContext.h" />
<ClInclude Include="drawing\IDrawingEngine.h" />
<ClInclude Include="drawing\ImageImporter.h" />
<ClInclude Include="drawing\LightFX.h" />
<ClInclude Include="drawing\NewDrawing.h" />
<ClInclude Include="drawing\Rain.h" />
<ClInclude Include="drawing\Text.h" />
<ClInclude Include="drawing\TTF.h" />
<ClInclude Include="drawing\X8DrawingEngine.h" />
<ClInclude Include="Editor.h" />
<ClInclude Include="EditorObjectSelectionSession.h" />
<ClInclude Include="FileClassifier.h" />
<ClInclude Include="Game.h" />
<ClInclude Include="Input.h" />
<ClInclude Include="interface\Chat.h" />
<ClInclude Include="interface\Colour.h" />
<ClInclude Include="interface\Console.h" />
<ClInclude Include="interface\Cursors.h" />
<ClInclude Include="interface\FontFamilies.h" />
<ClInclude Include="interface\Fonts.h" />
<ClInclude Include="interface\Screenshot.h" />
<ClInclude Include="interface\themes.h" />
<ClInclude Include="interface\Viewport.h" />
<ClInclude Include="interface\Widget.h" />
<ClInclude Include="interface\Window.h" />
<ClInclude Include="interface\Window_internal.h" />
<ClInclude Include="Intro.h" />
<ClInclude Include="localisation\Currency.h" />
<ClInclude Include="localisation\Date.h" />
<ClInclude Include="localisation\FormatCodes.h" />
<ClInclude Include="localisation\Language.h" />
<ClInclude Include="localisation\LanguagePack.h" />
<ClInclude Include="localisation\Localisation.h" />
<ClInclude Include="localisation\LocalisationService.h" />
<ClInclude Include="localisation\StringIds.h" />
<ClInclude Include="localisation\User.h" />
<ClInclude Include="management\Award.h" />
<ClInclude Include="management\Finance.h" />
<ClInclude Include="management\Marketing.h" />
<ClInclude Include="management\NewsItem.h" />
<ClInclude Include="management\Research.h" />
<ClInclude Include="network\DiscordService.h" />
<ClInclude Include="network\http.h" />
<ClInclude Include="network\network.h" />
<ClInclude Include="network\NetworkAction.h" />
<ClInclude Include="network\NetworkConnection.h" />
<ClInclude Include="network\NetworkGroup.h" />
<ClInclude Include="network\NetworkKey.h" />
<ClInclude Include="network\NetworkPacket.h" />
<ClInclude Include="network\NetworkPlayer.h" />
<ClInclude Include="network\NetworkServerAdvertiser.h" />
<ClInclude Include="network\NetworkTypes.h" />
<ClInclude Include="network\NetworkUser.h" />
<ClInclude Include="network\ServerList.h" />
<ClInclude Include="network\TcpSocket.h" />
<ClInclude Include="network\twitch.h" />
<ClInclude Include="object\BannerObject.h" />
<ClInclude Include="object\DefaultObjects.h" />
<ClInclude Include="object\EntranceObject.h" />
<ClInclude Include="object\FootpathItemObject.h" />
<ClInclude Include="object\FootpathObject.h" />
<ClInclude Include="object\ImageTable.h" />
<ClInclude Include="object\LargeSceneryObject.h" />
<ClInclude Include="object\Object.h" />
<ClInclude Include="object\ObjectFactory.h" />
<ClInclude Include="object\ObjectJsonHelpers.h" />
<ClInclude Include="object\ObjectLimits.h" />
<ClInclude Include="object\ObjectList.h" />
<ClInclude Include="object\ObjectManager.h" />
<ClInclude Include="object\ObjectRepository.h" />
<ClInclude Include="object\RideObject.h" />
<ClInclude Include="object\SceneryGroupObject.h" />
<ClInclude Include="object\SceneryObject.h" />
<ClInclude Include="object\SmallSceneryObject.h" />
<ClInclude Include="object\StexObject.h" />
<ClInclude Include="object\StringTable.h" />
<ClInclude Include="object\WallObject.h" />
<ClInclude Include="object\WaterObject.h" />
<ClInclude Include="OpenRCT2.h" />
<ClInclude Include="paint\Paint.h" />
<ClInclude Include="paint\Painter.h" />
<ClInclude Include="paint\sprite\Sprite.h" />
<ClInclude Include="paint\Supports.h" />
<ClInclude Include="paint\tile_element\Surface.h" />
<ClInclude Include="paint\tile_element\TileElement.h" />
<ClInclude Include="paint\VirtualFloor.h" />
<ClInclude Include="ParkImporter.h" />
<ClInclude Include="peep\Peep.h" />
<ClInclude Include="peep\Staff.h" />
<ClInclude Include="PlatformEnvironment.h" />
<ClInclude Include="platform\Crash.h" />
<ClInclude Include="platform\platform.h" />
<ClInclude Include="platform\Platform2.h" />
<ClInclude Include="rct12\RCT12.h" />
<ClInclude Include="rct12\SawyerChunk.h" />
<ClInclude Include="rct12\SawyerChunkReader.h" />
<ClInclude Include="rct12\SawyerChunkWriter.h" />
<ClInclude Include="rct12\SawyerEncoding.h" />
<ClInclude Include="rct1\RCT1.h" />
<ClInclude Include="rct1\Tables.h" />
<ClInclude Include="rct2\RCT2.h" />
<ClInclude Include="rct2\S6Exporter.h" />
<ClInclude Include="ride\CableLift.h" />
<ClInclude Include="ride\coaster\BolligerMabillardTrack.h" />
<ClInclude Include="ride\coaster\JuniorRollerCoaster.h" />
<ClInclude Include="ride\MusicList.h" />
<ClInclude Include="ride\Ride.h" />
<ClInclude Include="ride\RideData.h" />
<ClInclude Include="ride\RideGroupManager.h" />
<ClInclude Include="ride\RideRatings.h" />
<ClInclude Include="ride\ShopItem.h" />
<ClInclude Include="ride\Station.h" />
<ClInclude Include="ride\Track.h" />
<ClInclude Include="ride\TrackData.h" />
<ClInclude Include="ride\TrackDesign.h" />
<ClInclude Include="ride\TrackDesignRepository.h" />
<ClInclude Include="ride\TrackPaint.h" />
<ClInclude Include="ride\Vehicle.h" />
<ClInclude Include="ride\VehicleData.h" />
<ClInclude Include="ride\VehiclePaint.h" />
<ClInclude Include="scenario\Scenario.h" />
<ClInclude Include="scenario\ScenarioRepository.h" />
<ClInclude Include="scenario\ScenarioSources.h" />
<ClInclude Include="sprites.h" />
<ClInclude Include="title\TitleScreen.h" />
<ClInclude Include="title\TitleSequence.h" />
<ClInclude Include="title\TitleSequenceManager.h" />
<ClInclude Include="title\TitleSequencePlayer.h" />
<ClInclude Include="ui\UiContext.h" />
<ClInclude Include="ui\WindowManager.h" />
<ClInclude Include="util\SawyerCoding.h" />
<ClInclude Include="util\Util.h" />
<ClInclude Include="Version.h" />
<ClInclude Include="windows\Intent.h" />
<ClInclude Include="windows\tile_inspector.h" />
<ClInclude Include="world\Banner.h" />
<ClInclude Include="world\Climate.h" />
<ClInclude Include="world\Entrance.h" />
<ClInclude Include="world\Footpath.h" />
<ClInclude Include="world\Fountain.h" />
<ClInclude Include="world\LargeScenery.h" />
<ClInclude Include="world\Map.h" />
<ClInclude Include="world\MapAnimation.h" />
<ClInclude Include="world\MapGen.h" />
<ClInclude Include="world\MapHelpers.h" />
<ClInclude Include="world\Park.h" />
<ClInclude Include="world\Scenery.h" />
<ClInclude Include="world\SmallScenery.h" />
<ClInclude Include="world\Sprite.h" />
<ClInclude Include="world\Surface.h" />
<ClInclude Include="world\TileElement.h" />
<ClInclude Include="world\TileInspector.h" />
<ClInclude Include="world\Wall.h" />
<ClInclude Include="world\Water.h" />
<ClInclude Include="**\*.hpp" />
</ItemGroup>
<ItemGroup>
@ -67,4 +243,4 @@
<Image Include="..\..\resources\logo\icon.ico" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
</Project>

View File

@ -1238,7 +1238,7 @@ enum {
RCT1_LANDSCAPE_DOOR_OPEN = 3,
};
ParkLoadResult * load_from_sv4(const char *path);
ParkLoadResult * load_from_sc4(const char *path);
void load_from_sv4(const char *path);
void load_from_sc4(const char *path);
#endif

View File

@ -108,7 +108,7 @@ public:
class S4Importer final : public IParkImporter
{
private:
const utf8 * _s4Path = nullptr;
std::string _s4Path;
rct1_s4 _s4 = { 0 };
uint8 _gameVersion = 0;
uint8 _parkValueConversionFactor = 0;
@ -174,51 +174,16 @@ public:
ParkLoadResult LoadFromStream(IStream * stream,
bool isScenario,
bool skipObjectCheck = false,
const utf8 * path = String::Empty) override
bool skipObjectCheck,
const utf8 * path) override
{
size_t dataSize = stream->GetLength() - stream->GetPosition();
auto deleter_lambda = [dataSize](uint8 * ptr) { Memory::FreeArray(ptr, dataSize); };
auto data = std::unique_ptr<uint8, decltype(deleter_lambda)>(stream->ReadArray<uint8>(dataSize), deleter_lambda);
auto decodedData = std::unique_ptr<uint8, decltype(&Memory::Free<uint8>)>(Memory::Allocate<uint8>(sizeof(rct1_s4)), &Memory::Free<uint8>);
_s4 = ReadAndDecodeS4(stream, isScenario);
_s4Path = path;
size_t decodedSize;
sint32 fileType = sawyercoding_detect_file_type(data.get(), dataSize);
if (isScenario && (fileType & FILE_VERSION_MASK) != FILE_VERSION_RCT1)
{
decodedSize = sawyercoding_decode_sc4(data.get(), decodedData.get(), dataSize, sizeof(rct1_s4));
}
else
{
decodedSize = sawyercoding_decode_sv4(data.get(), decodedData.get(), dataSize, sizeof(rct1_s4));
}
if (decodedSize == sizeof(rct1_s4))
{
std::memcpy(&_s4, decodedData.get(), sizeof(rct1_s4));
if (_s4Path)
{
Memory::Free(_s4Path);
}
_s4Path = String::Duplicate(path);
if (!skipObjectCheck)
{
InitialiseEntryMaps();
CreateAvailableObjectMappings();
auto missingObjects = GetInvalidObjects();
if (!missingObjects.empty())
{
return ParkLoadResult::CreateMissingObjects(missingObjects);
}
}
}
else
{
throw std::runtime_error("Unable to decode park.");
}
return ParkLoadResult::CreateOK();
// Only determine what objects we required to import this saved game
InitialiseEntryMaps();
CreateAvailableObjectMappings();
return ParkLoadResult(GetRequiredObjects());
}
void Import() override
@ -333,6 +298,36 @@ public:
}
private:
rct1_s4 ReadAndDecodeS4(IStream * stream, bool isScenario)
{
rct1_s4 s4;
size_t dataSize = stream->GetLength() - stream->GetPosition();
auto deleter_lambda = [dataSize](uint8 * ptr) { Memory::FreeArray(ptr, dataSize); };
auto data = std::unique_ptr<uint8, decltype(deleter_lambda)>(stream->ReadArray<uint8>(dataSize), deleter_lambda);
auto decodedData = std::unique_ptr<uint8, decltype(&Memory::Free<uint8>)>(Memory::Allocate<uint8>(sizeof(rct1_s4)), &Memory::Free<uint8>);
size_t decodedSize;
sint32 fileType = sawyercoding_detect_file_type(data.get(), dataSize);
if (isScenario && (fileType & FILE_VERSION_MASK) != FILE_VERSION_RCT1)
{
decodedSize = sawyercoding_decode_sc4(data.get(), decodedData.get(), dataSize, sizeof(rct1_s4));
}
else
{
decodedSize = sawyercoding_decode_sv4(data.get(), decodedData.get(), dataSize, sizeof(rct1_s4));
}
if (decodedSize == sizeof(rct1_s4))
{
std::memcpy(&s4, decodedData.get(), sizeof(rct1_s4));
return s4;
}
else
{
throw std::runtime_error("Unable to decode park.");
}
}
void Initialise()
{
_gameVersion = sawyercoding_detect_rct1_version(_s4.game_version) & FILE_VERSION_MASK;
@ -1890,17 +1885,34 @@ private:
}
}
std::vector<rct_object_entry> GetInvalidObjects()
void AppendRequiredObjects(std::vector<rct_object_entry>& entries, uint8 objectType, const EntryList& entryList)
{
std::vector<rct_object_entry> missingObjects;
GetInvalidObjects(OBJECT_TYPE_RIDE, _rideEntries.GetEntries(), missingObjects);
GetInvalidObjects(OBJECT_TYPE_SMALL_SCENERY, _smallSceneryEntries.GetEntries(), missingObjects);
GetInvalidObjects(OBJECT_TYPE_LARGE_SCENERY, _largeSceneryEntries.GetEntries(), missingObjects);
GetInvalidObjects(OBJECT_TYPE_WALLS, _wallEntries.GetEntries(), missingObjects);
GetInvalidObjects(OBJECT_TYPE_PATHS, _pathEntries.GetEntries(), missingObjects);
GetInvalidObjects(OBJECT_TYPE_PATH_BITS, _pathAdditionEntries.GetEntries(), missingObjects);
GetInvalidObjects(OBJECT_TYPE_SCENERY_GROUP, _sceneryGroupEntries.GetEntries(), missingObjects);
GetInvalidObjects(OBJECT_TYPE_BANNERS, std::vector<const char *>({
AppendRequiredObjects(entries, objectType, entryList.GetEntries());
}
void AppendRequiredObjects(std::vector<rct_object_entry>& entries, uint8 objectType, const std::vector<const char *>& objectNames)
{
for (const auto objectName : objectNames)
{
rct_object_entry entry{};
entry.flags = ((OBJECT_SOURCE_RCT2 << 4) & 0xF0) | (objectType & 0x0F);
std::memset(entry.name, ' ', sizeof(entry.name));
std::strncpy(entry.name, objectName, sizeof(entry.name));
entries.push_back(entry);
}
}
std::vector<rct_object_entry> GetRequiredObjects()
{
std::vector<rct_object_entry> result;
AppendRequiredObjects(result, OBJECT_TYPE_RIDE, _rideEntries);
AppendRequiredObjects(result, OBJECT_TYPE_SMALL_SCENERY, _smallSceneryEntries);
AppendRequiredObjects(result, OBJECT_TYPE_LARGE_SCENERY, _largeSceneryEntries);
AppendRequiredObjects(result, OBJECT_TYPE_WALLS, _wallEntries);
AppendRequiredObjects(result, OBJECT_TYPE_PATHS, _pathEntries);
AppendRequiredObjects(result, OBJECT_TYPE_PATH_BITS, _pathAdditionEntries);
AppendRequiredObjects(result, OBJECT_TYPE_SCENERY_GROUP, _sceneryGroupEntries);
AppendRequiredObjects(result, OBJECT_TYPE_BANNERS, std::vector<const char *>({
"BN1 ",
"BN2 ",
"BN3 ",
@ -1909,11 +1921,10 @@ private:
"BN6 ",
"BN7 ",
"BN8 ",
"BN9 "
}), missingObjects);
GetInvalidObjects(OBJECT_TYPE_PARK_ENTRANCE, std::vector<const char *>({ "PKENT1 " }), missingObjects);
GetInvalidObjects(OBJECT_TYPE_WATER, _waterEntry.GetEntries(), missingObjects);
return missingObjects;
"BN9 " }));
AppendRequiredObjects(result, OBJECT_TYPE_PARK_ENTRANCE, std::vector<const char *>({ "PKENT1 " }));
AppendRequiredObjects(result, OBJECT_TYPE_WATER, _waterEntry);
return result;
}
void GetInvalidObjects(uint8 objectType, const std::vector<const char *> &entries, std::vector<rct_object_entry> &missingObjects)
@ -2843,44 +2854,20 @@ std::unique_ptr<IParkImporter> ParkImporter::CreateS4()
return std::make_unique<S4Importer>();
}
ParkLoadResult * load_from_sv4(const utf8 * path)
void load_from_sv4(const utf8 * path)
{
ParkLoadResult * result = nullptr;
auto s4Importer = std::make_unique<S4Importer>();
try
{
result = new ParkLoadResult(s4Importer->LoadSavedGame(path));
if (result->Error == PARK_LOAD_ERROR_OK)
{
s4Importer->Import();
}
}
catch (const std::exception &)
{
delete result;
result = new ParkLoadResult(ParkLoadResult::CreateUnknown());
}
return result;
auto result = s4Importer->LoadSavedGame(path);
// TODO load objects
s4Importer->Import();
}
ParkLoadResult * load_from_sc4(const utf8 * path)
void load_from_sc4(const utf8 * path)
{
ParkLoadResult * result = nullptr;
auto s4Importer = std::make_unique<S4Importer>();
try
{
result = new ParkLoadResult(s4Importer->LoadScenario(path));
if (result->Error == PARK_LOAD_ERROR_OK)
{
s4Importer->Import();
}
}
catch (const std::exception &)
{
delete result;
result = new ParkLoadResult(ParkLoadResult::CreateUnknown());
}
return result;
auto result = s4Importer->LoadScenario(path);
// TODO load objects
s4Importer->Import();
}
static uint8 GetPathType(rct_tile_element * tileElement)

View File

@ -857,52 +857,35 @@ std::unique_ptr<IParkImporter> ParkImporter::CreateS6(std::shared_ptr<IObjectRep
return std::make_unique<S6Importer>(objectRepository, objectManager);
}
ParkLoadResult * load_from_sv6(const char * path)
void load_from_sv6(const char * path)
{
ParkLoadResult * result = nullptr;
auto context = OpenRCT2::GetContext();
auto s6Importer = new S6Importer(context->GetObjectRepository(), context->GetObjectManager());
auto s6Importer = std::make_unique<S6Importer>(context->GetObjectRepository(), context->GetObjectManager());
try
{
result = new ParkLoadResult(s6Importer->LoadSavedGame(path));
// We mustn't import if there's something
// wrong with the park data
if (result->Error == PARK_LOAD_ERROR_OK)
{
s6Importer->Import();
game_fix_save_vars();
sprite_position_tween_reset();
}
auto result = s6Importer->LoadSavedGame(path);
// TODO load objects
s6Importer->Import();
game_fix_save_vars();
sprite_position_tween_reset();
gScreenAge = 0;
gLastAutoSaveUpdate = AUTOSAVE_PAUSE;
}
catch (const ObjectLoadException &)
catch (const ObjectLoadException&)
{
gErrorType = ERROR_TYPE_FILE_LOAD;
gErrorStringId = STR_FILE_CONTAINS_INVALID_DATA;
}
catch (const IOException &)
catch (const IOException&)
{
gErrorType = ERROR_TYPE_FILE_LOAD;
gErrorStringId = STR_GAME_SAVE_FAILED;
}
catch (const std::exception &)
catch (const std::exception&)
{
gErrorType = ERROR_TYPE_FILE_LOAD;
gErrorStringId = STR_FILE_CONTAINS_INVALID_DATA;
}
delete s6Importer;
if (result == nullptr)
{
result = new ParkLoadResult(ParkLoadResult::CreateUnknown());
}
if (result->Error == PARK_LOAD_ERROR_OK)
{
gScreenAge = 0;
gLastAutoSaveUpdate = AUTOSAVE_PAUSE;
}
return result;
}
/**