mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-02-02 03:35:09 +01:00
@@ -26,11 +26,15 @@ set(TITLE_SEQUENCE_SHA1 "19263f8ca383345959473e64da4785a60f00f420")
|
||||
set(OBJECTS_URL "https://github.com/OpenRCT2/objects/releases/download/v1.0.11/objects.zip")
|
||||
set(OBJECTS_SHA1 "8674120086929f9196560d77cada631fb478d7c0")
|
||||
|
||||
set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v0.0.2/replays.zip")
|
||||
set(REPLAYS_SHA1 "6E034E5299A8EC30A8D0A1B93F6A30A3A6429FEC")
|
||||
|
||||
option(FORCE32 "Force 32-bit build. It will add `-m32` to compiler flags.")
|
||||
option(WITH_TESTS "Build tests")
|
||||
option(PORTABLE "Create a portable build (-rpath=$ORIGIN)" OFF)
|
||||
option(DOWNLOAD_TITLE_SEQUENCES "Download title sequences during installation." ON)
|
||||
option(DOWNLOAD_OBJECTS "Download objects during installation." ON)
|
||||
option(DOWNLOAD_REPLAYS "Download replays during installation." ON)
|
||||
|
||||
# Options
|
||||
option(STATIC "Create a static build.")
|
||||
@@ -287,6 +291,16 @@ if (DOWNLOAD_OBJECTS)
|
||||
file(REMOVE \$ENV{DESTDIR}/${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT}/object/objects.zip)\n\
|
||||
endif ()")
|
||||
endif ()
|
||||
if (DOWNLOAD_REPLAYS)
|
||||
install(CODE
|
||||
"if (EXISTS \$ENV{DESTDIR}${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT}/testdata/replays/)\n\
|
||||
message(\"Using cached replays\")\n\
|
||||
else () \n\
|
||||
file(DOWNLOAD ${REPLAYS_URL} \$ENV{DESTDIR}/${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT}/testdata/replays/replays.zip EXPECTED_HASH SHA1=${REPLAYS_SHA1} SHOW_PROGRESS)\n\
|
||||
execute_process(COMMAND \"${CMAKE_COMMAND}\" -E chdir \$ENV{DESTDIR}/${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT}/testdata/replays/ \"${CMAKE_COMMAND}\" -E tar xf replays.zip)\n\
|
||||
file(REMOVE \$ENV{DESTDIR}/${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT}/testdata/replays/replays.zip)\n\
|
||||
endif ()")
|
||||
endif ()
|
||||
install(TARGETS "libopenrct2" LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
if(NOT DISABLE_GUI)
|
||||
|
||||
@@ -72,6 +72,8 @@
|
||||
<TitleSequencesSha1>19263f8ca383345959473e64da4785a60f00f420</TitleSequencesSha1>
|
||||
<ObjectsUrl>https://github.com/OpenRCT2/objects/releases/download/v1.0.11/objects.zip</ObjectsUrl>
|
||||
<ObjectsSha1>8674120086929f9196560d77cada631fb478d7c0</ObjectsSha1>
|
||||
<ReplaysUrl>https://github.com/OpenRCT2/replays/releases/download/v0.0.2/replays.zip</ReplaysUrl>
|
||||
<ReplaysSha1>6E034E5299A8EC30A8D0A1B93F6A30A3A6429FEC</ReplaysSha1>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -226,6 +228,15 @@
|
||||
OutputDirectory="$(TargetDir)data\object" />
|
||||
</Target>
|
||||
|
||||
<!-- Target to download replays -->
|
||||
<Target Name="DownloadReplays" AfterTargets="Build">
|
||||
<DownloadDependency Name="Replays"
|
||||
Url="$(ReplaysUrl)"
|
||||
Sha1="$(ReplaysSha1)"
|
||||
CheckFile="$(DependenciesCheckFile)"
|
||||
OutputDirectory="$(TargetDir)testdata\replays" />
|
||||
</Target>
|
||||
|
||||
<!-- Target to publish OpenRCT2 as a portable zip -->
|
||||
<Target Name="PublishPortable" DependsOnTargets="Build;g2" Inputs="@(PublishItems)" Outputs="$(PublishZip)"
|
||||
Condition="'$(TestConfig)'!='true'">
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "actions/ParkSetLoanAction.hpp"
|
||||
#include "actions/SetCheatAction.hpp"
|
||||
#include "config/Config.h"
|
||||
#include "core/DataSerialiser.h"
|
||||
#include "localisation/Localisation.h"
|
||||
#include "network/network.h"
|
||||
#include "ride/Ride.h"
|
||||
@@ -28,6 +29,8 @@
|
||||
|
||||
using namespace OpenRCT2;
|
||||
|
||||
// TODO: Refactor this. Cheat variables should contain the cheat type
|
||||
// and a serialisation method.
|
||||
bool gCheatsSandboxMode = false;
|
||||
bool gCheatsDisableClearanceChecks = false;
|
||||
bool gCheatsDisableSupportLimits = false;
|
||||
@@ -80,6 +83,136 @@ void CheatsSet(CheatType cheatType, int32_t param1 /* = 0*/, int32_t param2 /* =
|
||||
GameActions::Execute(&setCheatAction);
|
||||
}
|
||||
|
||||
template<typename T> static void CheatEntrySerialise(DataSerialiser& ds, CheatType type, const T& value, uint16_t& count)
|
||||
{
|
||||
ds << static_cast<int32_t>(type) << value;
|
||||
count++;
|
||||
}
|
||||
|
||||
void CheatsSerialise(DataSerialiser& ds)
|
||||
{
|
||||
uint16_t count = 0;
|
||||
|
||||
if (ds.IsSaving())
|
||||
{
|
||||
IStream& stream = ds.GetStream();
|
||||
|
||||
// Temporarily write 0, will be updated after every cheat is written.
|
||||
uint64_t countOffset = stream.GetPosition();
|
||||
ds << count;
|
||||
|
||||
CheatEntrySerialise(ds, CheatType::SandboxMode, gCheatsSandboxMode, count);
|
||||
CheatEntrySerialise(ds, CheatType::DisableClearanceChecks, gCheatsDisableClearanceChecks, count);
|
||||
CheatEntrySerialise(ds, CheatType::DisableSupportLimits, gCheatsDisableSupportLimits, count);
|
||||
CheatEntrySerialise(ds, CheatType::ShowAllOperatingModes, gCheatsShowAllOperatingModes, count);
|
||||
CheatEntrySerialise(ds, CheatType::ShowVehiclesFromOtherTrackTypes, gCheatsShowVehiclesFromOtherTrackTypes, count);
|
||||
CheatEntrySerialise(ds, CheatType::FastLiftHill, gCheatsFastLiftHill, count);
|
||||
CheatEntrySerialise(ds, CheatType::DisableBrakesFailure, gCheatsDisableBrakesFailure, count);
|
||||
CheatEntrySerialise(ds, CheatType::DisableAllBreakdowns, gCheatsDisableAllBreakdowns, count);
|
||||
CheatEntrySerialise(ds, CheatType::BuildInPauseMode, gCheatsBuildInPauseMode, count);
|
||||
CheatEntrySerialise(ds, CheatType::IgnoreRideIntensity, gCheatsIgnoreRideIntensity, count);
|
||||
CheatEntrySerialise(ds, CheatType::DisableVandalism, gCheatsDisableVandalism, count);
|
||||
CheatEntrySerialise(ds, CheatType::DisableLittering, gCheatsDisableLittering, count);
|
||||
CheatEntrySerialise(ds, CheatType::NeverEndingMarketing, gCheatsNeverendingMarketing, count);
|
||||
CheatEntrySerialise(ds, CheatType::FreezeWeather, gCheatsFreezeWeather, count);
|
||||
CheatEntrySerialise(ds, CheatType::DisableTrainLengthLimit, gCheatsDisableTrainLengthLimit, count);
|
||||
CheatEntrySerialise(ds, CheatType::DisablePlantAging, gCheatsDisablePlantAging, count);
|
||||
CheatEntrySerialise(ds, CheatType::EnableChainLiftOnAllTrack, gCheatsEnableChainLiftOnAllTrack, count);
|
||||
CheatEntrySerialise(ds, CheatType::AllowArbitraryRideTypeChanges, gCheatsAllowArbitraryRideTypeChanges, count);
|
||||
CheatEntrySerialise(ds, CheatType::DisableRideValueAging, gCheatsDisableRideValueAging, count);
|
||||
CheatEntrySerialise(ds, CheatType::IgnoreResearchStatus, gCheatsIgnoreResearchStatus, count);
|
||||
CheatEntrySerialise(ds, CheatType::EnableAllDrawableTrackPieces, gCheatsEnableAllDrawableTrackPieces, count);
|
||||
|
||||
// Remember current position and update count.
|
||||
uint64_t endOffset = stream.GetPosition();
|
||||
|
||||
stream.SetPosition(countOffset);
|
||||
ds << count; // Write correct count.
|
||||
|
||||
// Set position back.
|
||||
stream.SetPosition(endOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
ds << count;
|
||||
|
||||
for (uint16_t i = 0; i < count; i++)
|
||||
{
|
||||
int32_t type = 0;
|
||||
ds << type;
|
||||
|
||||
switch (static_cast<CheatType>(type))
|
||||
{
|
||||
case CheatType::SandboxMode:
|
||||
ds << gCheatsSandboxMode;
|
||||
break;
|
||||
case CheatType::DisableClearanceChecks:
|
||||
ds << gCheatsDisableClearanceChecks;
|
||||
break;
|
||||
case CheatType::DisableSupportLimits:
|
||||
ds << gCheatsDisableSupportLimits;
|
||||
break;
|
||||
case CheatType::ShowAllOperatingModes:
|
||||
ds << gCheatsShowAllOperatingModes;
|
||||
break;
|
||||
case CheatType::ShowVehiclesFromOtherTrackTypes:
|
||||
ds << gCheatsShowVehiclesFromOtherTrackTypes;
|
||||
break;
|
||||
case CheatType::FastLiftHill:
|
||||
ds << gCheatsFastLiftHill;
|
||||
break;
|
||||
case CheatType::DisableBrakesFailure:
|
||||
ds << gCheatsDisableBrakesFailure;
|
||||
break;
|
||||
case CheatType::DisableAllBreakdowns:
|
||||
ds << gCheatsDisableAllBreakdowns;
|
||||
break;
|
||||
case CheatType::BuildInPauseMode:
|
||||
ds << gCheatsBuildInPauseMode;
|
||||
break;
|
||||
case CheatType::IgnoreRideIntensity:
|
||||
ds << gCheatsIgnoreRideIntensity;
|
||||
break;
|
||||
case CheatType::DisableVandalism:
|
||||
ds << gCheatsDisableVandalism;
|
||||
break;
|
||||
case CheatType::DisableLittering:
|
||||
ds << gCheatsDisableLittering;
|
||||
break;
|
||||
case CheatType::NeverEndingMarketing:
|
||||
ds << gCheatsNeverendingMarketing;
|
||||
break;
|
||||
case CheatType::FreezeWeather:
|
||||
ds << gCheatsFreezeWeather;
|
||||
break;
|
||||
case CheatType::DisableTrainLengthLimit:
|
||||
ds << gCheatsDisableTrainLengthLimit;
|
||||
break;
|
||||
case CheatType::DisablePlantAging:
|
||||
ds << gCheatsDisablePlantAging;
|
||||
break;
|
||||
case CheatType::EnableChainLiftOnAllTrack:
|
||||
ds << gCheatsEnableChainLiftOnAllTrack;
|
||||
break;
|
||||
case CheatType::AllowArbitraryRideTypeChanges:
|
||||
ds << gCheatsAllowArbitraryRideTypeChanges;
|
||||
break;
|
||||
case CheatType::DisableRideValueAging:
|
||||
ds << gCheatsDisableRideValueAging;
|
||||
break;
|
||||
case CheatType::IgnoreResearchStatus:
|
||||
ds << gCheatsIgnoreResearchStatus;
|
||||
break;
|
||||
case CheatType::EnableAllDrawableTrackPieces:
|
||||
ds << gCheatsEnableAllDrawableTrackPieces;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char* CheatsGetName(CheatType cheatType)
|
||||
{
|
||||
switch (cheatType)
|
||||
|
||||
@@ -115,5 +115,6 @@ enum
|
||||
void CheatsReset();
|
||||
const char* CheatsGetName(CheatType cheatType);
|
||||
void CheatsSet(CheatType cheatType, int32_t param1 = 0, int32_t param2 = 0);
|
||||
void CheatsSerialise(class DataSerialiser& ds);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -404,24 +404,6 @@ int32_t game_do_command_p(
|
||||
// Second call to actually perform the operation
|
||||
new_game_command_table[command](eax, ebx, ecx, edx, esi, edi, ebp);
|
||||
|
||||
if (replayManager != nullptr)
|
||||
{
|
||||
bool recordCommand = false;
|
||||
bool commandExecutes = (flags & GAME_COMMAND_FLAG_APPLY) && (flags & GAME_COMMAND_FLAG_GHOST) == 0
|
||||
&& (flags & GAME_COMMAND_FLAG_NO_SPEND) == 0;
|
||||
|
||||
if (replayManager->IsRecording() && commandExecutes)
|
||||
recordCommand = true;
|
||||
else if (replayManager->IsNormalising() && commandExecutes && (flags & GAME_COMMAND_FLAG_REPLAY) != 0)
|
||||
recordCommand = true;
|
||||
|
||||
if (recordCommand && gGameCommandNestLevel == 1)
|
||||
{
|
||||
replayManager->AddGameCommand(
|
||||
gCurrentTicks, *eax, original_ebx, *ecx, original_edx, original_esi, original_edi, original_ebp, 0);
|
||||
}
|
||||
}
|
||||
|
||||
*edx = *ebx;
|
||||
|
||||
if (*edx != MONEY32_UNDEFINED && *edx < cost)
|
||||
|
||||
@@ -37,40 +37,21 @@
|
||||
|
||||
namespace OpenRCT2
|
||||
{
|
||||
// NOTE: This is currently very close to what the network version uses.
|
||||
// Should be refactored once the old game commands are gone.
|
||||
struct ReplayCommand
|
||||
{
|
||||
uint32_t tick = 0;
|
||||
GameAction::Ptr action;
|
||||
uint32_t commandIndex = 0;
|
||||
|
||||
ReplayCommand() = default;
|
||||
|
||||
ReplayCommand(uint32_t t, uint32_t* args, uint8_t cb, uint32_t id)
|
||||
{
|
||||
tick = t;
|
||||
eax = args[0];
|
||||
ebx = args[1];
|
||||
ecx = args[2];
|
||||
edx = args[3];
|
||||
esi = args[4];
|
||||
edi = args[5];
|
||||
ebp = args[6];
|
||||
callback = cb;
|
||||
action = nullptr;
|
||||
commandIndex = id;
|
||||
}
|
||||
|
||||
ReplayCommand(uint32_t t, std::unique_ptr<GameAction>&& ga, uint32_t id)
|
||||
{
|
||||
tick = t;
|
||||
action = std::move(ga);
|
||||
commandIndex = id;
|
||||
}
|
||||
: tick(t)
|
||||
, action(std::move(ga))
|
||||
, commandIndex(id)
|
||||
|
||||
uint32_t tick = 0;
|
||||
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0, esi = 0, edi = 0, ebp = 0;
|
||||
GameAction::Ptr action;
|
||||
uint8_t playerid = 0;
|
||||
uint8_t callback = 0;
|
||||
uint32_t commandIndex = 0;
|
||||
{
|
||||
}
|
||||
|
||||
bool operator<(const ReplayCommand& comp) const
|
||||
{
|
||||
@@ -101,6 +82,7 @@ namespace OpenRCT2
|
||||
MemoryStream parkData;
|
||||
MemoryStream spriteSpatialData;
|
||||
MemoryStream parkParams;
|
||||
MemoryStream cheatData;
|
||||
std::string name; // Name of play
|
||||
std::string filePath; // File path of replay.
|
||||
uint64_t timeRecorded; // Posix Time.
|
||||
@@ -113,7 +95,7 @@ namespace OpenRCT2
|
||||
|
||||
class ReplayManager final : public IReplayManager
|
||||
{
|
||||
static constexpr uint16_t ReplayVersion = 2;
|
||||
static constexpr uint16_t ReplayVersion = 3;
|
||||
static constexpr uint32_t ReplayMagic = 0x5243524F; // ORCR.
|
||||
static constexpr int ReplayCompressionLevel = 9;
|
||||
|
||||
@@ -145,25 +127,6 @@ namespace OpenRCT2
|
||||
return _mode == ReplayMode::NORMALISATION;
|
||||
}
|
||||
|
||||
virtual void AddGameCommand(
|
||||
uint32_t tick, uint32_t eax, uint32_t ebx, uint32_t ecx, uint32_t edx, uint32_t esi, uint32_t edi, uint32_t ebp,
|
||||
uint8_t callback) override
|
||||
{
|
||||
if (_currentRecording == nullptr)
|
||||
return;
|
||||
|
||||
uint32_t args[7];
|
||||
args[0] = eax;
|
||||
args[1] = ebx;
|
||||
args[2] = ecx;
|
||||
args[3] = edx;
|
||||
args[4] = esi;
|
||||
args[5] = edi;
|
||||
args[6] = ebp;
|
||||
|
||||
_currentRecording->commands.emplace(gCurrentTicks, args, callback, _commandId++);
|
||||
}
|
||||
|
||||
virtual void AddGameAction(uint32_t tick, const GameAction* action) override
|
||||
{
|
||||
if (_currentRecording == nullptr)
|
||||
@@ -266,8 +229,11 @@ namespace OpenRCT2
|
||||
replayData->spriteSpatialData.Write(gSpriteSpatialIndex, sizeof(gSpriteSpatialIndex));
|
||||
replayData->timeRecorded = std::chrono::seconds(std::time(nullptr)).count();
|
||||
|
||||
DataSerialiser parkParams(true, replayData->parkParams);
|
||||
SerialiseParkParameters(parkParams);
|
||||
DataSerialiser parkParamsDs(true, replayData->parkParams);
|
||||
SerialiseParkParameters(parkParamsDs);
|
||||
|
||||
DataSerialiser cheatDataDs(true, replayData->cheatData);
|
||||
SerialiseCheats(cheatDataDs);
|
||||
|
||||
if (_mode != ReplayMode::NORMALISATION)
|
||||
_mode = ReplayMode::RECORDING;
|
||||
@@ -381,12 +347,6 @@ namespace OpenRCT2
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TranslateDeprecatedGameCommands(*replayData))
|
||||
{
|
||||
log_error("Unable to translate deprecated game commands.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!LoadReplayDataMap(*replayData))
|
||||
{
|
||||
log_error("Unable to load map.");
|
||||
@@ -461,144 +421,6 @@ namespace OpenRCT2
|
||||
}
|
||||
|
||||
private:
|
||||
bool ConvertDeprecatedGameCommand(const ReplayCommand& command, ReplayCommand& result)
|
||||
{
|
||||
// NOTE: If game actions are being ported it is required to implement temporarily
|
||||
// a mapping from game command to game action. This will allow the normalisation
|
||||
// stage to save a new replay file with the game action being used instead of the
|
||||
// old game command. Once normalised the code will be no longer required.
|
||||
|
||||
/* Example case
|
||||
case GAME_COMMAND_RAISE_WATER:
|
||||
{
|
||||
uint32_t param1 = command.ebp;
|
||||
uint32_t param2 = command.edi;
|
||||
result.action = std::make_unique<LandRaiseWaterAction>(param1, param2, ...);
|
||||
}
|
||||
*/
|
||||
|
||||
switch (command.esi)
|
||||
{
|
||||
case GAME_COMMAND_COUNT: // prevent default without case warning.
|
||||
break;
|
||||
case GAME_COMMAND_PLACE_TRACK:
|
||||
{
|
||||
ride_id_t rideId = command.edx & 0xFF;
|
||||
int32_t trackType = (command.edx >> 8) & 0xFF;
|
||||
CoordsXYZD origin = { (int32_t)(command.eax & 0xFFFF), (int32_t)(command.ecx & 0xFFFF),
|
||||
(int32_t)(command.edi & 0xFFFF), (uint8_t)((command.ebx >> 8) & 0xFF) };
|
||||
int32_t brakeSpeed = (command.edi >> 16) & 0xFF;
|
||||
int32_t colour = (command.edi >> 24) & 0x0F;
|
||||
int32_t seatRotation = (command.edi >> 28) & 0x0F;
|
||||
int32_t liftHillAndAlternativeState = (command.edx >> 16);
|
||||
|
||||
result.action = std::make_unique<TrackPlaceAction>(
|
||||
rideId, trackType, origin, brakeSpeed, colour, seatRotation, liftHillAndAlternativeState);
|
||||
result.action->SetFlags(command.ebx & 0xFF);
|
||||
break;
|
||||
}
|
||||
case GAME_COMMAND_SET_RIDE_SETTING:
|
||||
{
|
||||
ride_id_t rideId = command.edx & 0xFF;
|
||||
RideSetSetting setting = static_cast<RideSetSetting>((command.edx >> 8) & 0xFF);
|
||||
uint8_t value = (command.ebx >> 8) & 0xFF;
|
||||
|
||||
result.action = std::make_unique<RideSetSettingAction>(rideId, setting, value);
|
||||
result.action->SetFlags(command.ebx & 0xFF);
|
||||
break;
|
||||
}
|
||||
case GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT:
|
||||
{
|
||||
CoordsXY loc = { (int32_t)(command.eax & 0xFFFF), (int32_t)(command.ecx & 0xFFFF) };
|
||||
Direction direction = (command.ebx >> 8) & 0xFF;
|
||||
ride_id_t rideId = command.edx & 0xFF;
|
||||
uint8_t stationNum = command.edi & 0xFF;
|
||||
bool isExit = ((command.edx >> 8) & 0xFF) != 0;
|
||||
result.action = std::make_unique<RideEntranceExitPlaceAction>(loc, direction, rideId, stationNum, isExit);
|
||||
result.action->SetFlags(command.ebx & 0xFF);
|
||||
break;
|
||||
}
|
||||
case GAME_COMMAND_PLACE_PATH:
|
||||
{
|
||||
CoordsXYZ loc = { (int32_t)(command.eax & 0xFFFF), (int32_t)(command.ecx & 0xFFFF),
|
||||
(int32_t)(command.edx & 0xFF) * 8 };
|
||||
uint8_t slope = (command.ebx >> 8) & 0xFF;
|
||||
uint8_t type = (command.edx >> 8) & 0xFF;
|
||||
result.action = std::make_unique<FootpathPlaceAction>(loc, slope, type);
|
||||
result.action->SetFlags(command.ebx & 0xFF);
|
||||
break;
|
||||
}
|
||||
case GAME_COMMAND_CHEAT:
|
||||
{
|
||||
int32_t param1 = command.edx;
|
||||
int32_t param2 = command.edi;
|
||||
CheatType cheatType = static_cast<CheatType>(command.ecx);
|
||||
|
||||
result.action = std::make_unique<SetCheatAction>(cheatType, param1, param2);
|
||||
result.action->SetFlags(command.ebx & 0xFF);
|
||||
break;
|
||||
}
|
||||
case GAME_COMMAND_MODIFY_TILE:
|
||||
{
|
||||
int32_t param1 = command.edx;
|
||||
int32_t param2 = command.edi;
|
||||
CoordsXY loc = { static_cast<int16_t>((command.ecx & 0xFF) * 32),
|
||||
static_cast<int16_t>(((command.ecx >> 8) & 0xFF) * 32) };
|
||||
TileModifyType type = static_cast<TileModifyType>(command.eax & 0xFF);
|
||||
|
||||
if (type == TileModifyType::AnyPaste)
|
||||
{
|
||||
TileElement copiedElement{};
|
||||
uint32_t data[2] = { command.edx, command.edi };
|
||||
std::memcpy(&copiedElement, &data[0], 8);
|
||||
result.action = std::make_unique<TileModifyAction>(loc, type, 0, 0, copiedElement);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.action = std::make_unique<TileModifyAction>(loc, type, param1, param2);
|
||||
}
|
||||
result.action->SetFlags(command.ebx & 0xFF);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Deprecated game command requires replay translation.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TranslateDeprecatedGameCommands(ReplayRecordData& data)
|
||||
{
|
||||
for (auto it = data.commands.begin(); it != data.commands.end(); it++)
|
||||
{
|
||||
const ReplayCommand& replayCommand = *it;
|
||||
|
||||
if (replayCommand.action == nullptr)
|
||||
{
|
||||
// Check if we can create a game action with the command id.
|
||||
uint32_t commandId = replayCommand.esi;
|
||||
if (GameActions::IsValidId(commandId))
|
||||
{
|
||||
// Convert
|
||||
ReplayCommand converted;
|
||||
converted.commandIndex = replayCommand.commandIndex;
|
||||
|
||||
if (!ConvertDeprecatedGameCommand(replayCommand, converted))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove deprecated command.
|
||||
data.commands.erase(it);
|
||||
|
||||
// Insert new game action, iterator points to the replaced element.
|
||||
it = data.commands.emplace(std::move(converted));
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadReplayDataMap(ReplayRecordData& data)
|
||||
{
|
||||
try
|
||||
@@ -623,8 +445,14 @@ namespace OpenRCT2
|
||||
std::memcpy(gSpriteSpatialIndex, data.spriteSpatialData.GetData(), data.spriteSpatialData.GetLength());
|
||||
|
||||
// Load all map global variables.
|
||||
DataSerialiser parkParams(false, data.parkParams);
|
||||
SerialiseParkParameters(parkParams);
|
||||
DataSerialiser parkParamsDs(false, data.parkParams);
|
||||
SerialiseParkParameters(parkParamsDs);
|
||||
|
||||
// New cheats might not be serialised, make sure they are using their defaults.
|
||||
CheatsReset();
|
||||
|
||||
DataSerialiser cheatDataDs(false, data.cheatData);
|
||||
SerialiseCheats(cheatDataDs);
|
||||
|
||||
game_load_init();
|
||||
fix_invalid_vehicle_sprite_sizes();
|
||||
@@ -729,36 +557,39 @@ namespace OpenRCT2
|
||||
// Reset position of all streams.
|
||||
data.parkData.SetPosition(0);
|
||||
data.parkParams.SetPosition(0);
|
||||
data.cheatData.SetPosition(0);
|
||||
data.spriteSpatialData.SetPosition(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialiseCheats(DataSerialiser& serialiser)
|
||||
{
|
||||
CheatsSerialise(serialiser);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialiseParkParameters(DataSerialiser& serialiser)
|
||||
{
|
||||
serialiser << _guestGenerationProbability;
|
||||
serialiser << _suggestedGuestMaximum;
|
||||
serialiser << gCheatsSandboxMode;
|
||||
serialiser << gCheatsDisableClearanceChecks;
|
||||
serialiser << gCheatsDisableSupportLimits;
|
||||
serialiser << gCheatsDisableTrainLengthLimit;
|
||||
serialiser << gCheatsEnableChainLiftOnAllTrack;
|
||||
serialiser << gCheatsShowAllOperatingModes;
|
||||
serialiser << gCheatsShowVehiclesFromOtherTrackTypes;
|
||||
serialiser << gCheatsFastLiftHill;
|
||||
serialiser << gCheatsDisableBrakesFailure;
|
||||
serialiser << gCheatsDisableAllBreakdowns;
|
||||
serialiser << gCheatsBuildInPauseMode;
|
||||
serialiser << gCheatsIgnoreRideIntensity;
|
||||
serialiser << gCheatsDisableVandalism;
|
||||
serialiser << gCheatsDisableLittering;
|
||||
serialiser << gCheatsNeverendingMarketing;
|
||||
serialiser << gCheatsFreezeWeather;
|
||||
serialiser << gCheatsDisablePlantAging;
|
||||
serialiser << gCheatsAllowArbitraryRideTypeChanges;
|
||||
serialiser << gCheatsDisableRideValueAging;
|
||||
serialiser << gConfigGeneral.show_real_names_of_guests;
|
||||
serialiser << gCheatsIgnoreResearchStatus;
|
||||
|
||||
// To make this a little bit less volatile against updates
|
||||
// we reserve some space for future additions.
|
||||
uint64_t tempStorage = 0;
|
||||
|
||||
// If another park parameter has to be added simply swap tempStorage.
|
||||
// and ensure the length read/write will stay uint64_t
|
||||
serialiser << tempStorage;
|
||||
serialiser << tempStorage;
|
||||
serialiser << tempStorage;
|
||||
serialiser << tempStorage;
|
||||
serialiser << tempStorage;
|
||||
serialiser << tempStorage;
|
||||
serialiser << tempStorage;
|
||||
serialiser << tempStorage;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -768,47 +599,27 @@ namespace OpenRCT2
|
||||
serialiser << command.tick;
|
||||
serialiser << command.commandIndex;
|
||||
|
||||
bool isGameAction = false;
|
||||
uint32_t actionType = 0;
|
||||
if (serialiser.IsSaving())
|
||||
{
|
||||
isGameAction = command.action != nullptr;
|
||||
actionType = command.action->GetType();
|
||||
}
|
||||
serialiser << isGameAction;
|
||||
serialiser << actionType;
|
||||
|
||||
if (isGameAction)
|
||||
if (serialiser.IsLoading())
|
||||
{
|
||||
uint32_t actionType = 0;
|
||||
if (serialiser.IsSaving())
|
||||
{
|
||||
actionType = command.action->GetType();
|
||||
}
|
||||
serialiser << actionType;
|
||||
|
||||
if (serialiser.IsLoading())
|
||||
{
|
||||
command.action = GameActions::Create(actionType);
|
||||
Guard::Assert(command.action != nullptr);
|
||||
}
|
||||
|
||||
command.action->Serialise(serialiser);
|
||||
}
|
||||
else
|
||||
{
|
||||
serialiser << command.eax;
|
||||
serialiser << command.ebx;
|
||||
serialiser << command.ecx;
|
||||
serialiser << command.edx;
|
||||
serialiser << command.esi;
|
||||
serialiser << command.edi;
|
||||
serialiser << command.ebp;
|
||||
serialiser << command.callback;
|
||||
command.action = GameActions::Create(actionType);
|
||||
Guard::Assert(command.action != nullptr);
|
||||
}
|
||||
|
||||
command.action->Serialise(serialiser);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Compatible(ReplayRecordData& data)
|
||||
{
|
||||
return data.version == 1 && ReplayVersion == 2;
|
||||
return data.version == ReplayVersion;
|
||||
}
|
||||
|
||||
bool Serialise(DataSerialiser& serialiser, ReplayRecordData& data)
|
||||
@@ -841,6 +652,7 @@ namespace OpenRCT2
|
||||
serialiser << data.timeRecorded;
|
||||
serialiser << data.parkData;
|
||||
serialiser << data.parkParams;
|
||||
serialiser << data.cheatData;
|
||||
serialiser << data.spriteSpatialData;
|
||||
serialiser << data.tickStart;
|
||||
serialiser << data.tickEnd;
|
||||
@@ -946,26 +758,13 @@ namespace OpenRCT2
|
||||
|
||||
bool isPositionValid = false;
|
||||
|
||||
if (command.action != nullptr)
|
||||
{
|
||||
GameAction* action = command.action.get();
|
||||
action->SetFlags(action->GetFlags() | GAME_COMMAND_FLAG_REPLAY);
|
||||
GameAction* action = command.action.get();
|
||||
action->SetFlags(action->GetFlags() | GAME_COMMAND_FLAG_REPLAY);
|
||||
|
||||
GameActionResult::Ptr result = GameActions::Execute(action);
|
||||
if (result->Error == GA_ERROR::OK)
|
||||
{
|
||||
isPositionValid = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
GameActionResult::Ptr result = GameActions::Execute(action);
|
||||
if (result->Error == GA_ERROR::OK)
|
||||
{
|
||||
uint32_t flags = command.ebx | GAME_COMMAND_FLAG_REPLAY;
|
||||
int32_t res = game_do_command(
|
||||
command.eax, flags, command.ecx, command.edx, command.esi, command.edi, command.ebp);
|
||||
if (res != MONEY32_UNDEFINED)
|
||||
{
|
||||
isPositionValid = true;
|
||||
}
|
||||
isPositionValid = true;
|
||||
}
|
||||
|
||||
// Focus camera on event.
|
||||
|
||||
@@ -43,11 +43,6 @@ namespace OpenRCT2
|
||||
virtual bool IsRecording() const = 0;
|
||||
virtual bool IsNormalising() const = 0;
|
||||
|
||||
// NOTE: Will become obsolete eventually once all game actions are done.
|
||||
virtual void AddGameCommand(
|
||||
uint32_t tick, uint32_t eax, uint32_t ebx, uint32_t ecx, uint32_t edx, uint32_t esi, uint32_t edi, uint32_t ebp,
|
||||
uint8_t callback)
|
||||
= 0;
|
||||
virtual void AddGameAction(uint32_t tick, const GameAction* action) = 0;
|
||||
|
||||
virtual bool StartRecording(const std::string& name, uint32_t maxTicks = k_MaxReplayTicks) = 0;
|
||||
|
||||
@@ -106,7 +106,7 @@ namespace GameActions
|
||||
action->Serialise(dsOut);
|
||||
|
||||
// Serialise into new action.
|
||||
MemoryStream& stream = dsOut.GetStream();
|
||||
IStream& stream = dsOut.GetStream();
|
||||
stream.SetPosition(0);
|
||||
|
||||
DataSerialiser dsIn(false, stream);
|
||||
|
||||
@@ -17,23 +17,23 @@ class DataSerialiser
|
||||
{
|
||||
private:
|
||||
MemoryStream _stream;
|
||||
IStream* _activeStream = nullptr;
|
||||
IStream& _activeStream;
|
||||
bool _isSaving = false;
|
||||
bool _isLogging = false;
|
||||
|
||||
public:
|
||||
DataSerialiser(bool isSaving)
|
||||
: _isSaving(isSaving)
|
||||
: _activeStream(_stream)
|
||||
, _isSaving(isSaving)
|
||||
, _isLogging(false)
|
||||
{
|
||||
_activeStream = &_stream;
|
||||
}
|
||||
|
||||
DataSerialiser(bool isSaving, IStream& stream, bool isLogging = false)
|
||||
: _isSaving(isSaving)
|
||||
: _activeStream(stream)
|
||||
, _isSaving(isSaving)
|
||||
, _isLogging(isLogging)
|
||||
{
|
||||
_activeStream = &stream;
|
||||
}
|
||||
|
||||
bool IsSaving() const
|
||||
@@ -46,9 +46,9 @@ public:
|
||||
return !_isSaving;
|
||||
}
|
||||
|
||||
MemoryStream& GetStream()
|
||||
IStream& GetStream()
|
||||
{
|
||||
return _stream;
|
||||
return _activeStream;
|
||||
}
|
||||
|
||||
template<typename T> DataSerialiser& operator<<(const T& data)
|
||||
@@ -56,13 +56,13 @@ public:
|
||||
if (!_isLogging)
|
||||
{
|
||||
if (_isSaving)
|
||||
DataSerializerTraits<T>::encode(_activeStream, data);
|
||||
DataSerializerTraits<T>::encode(&_activeStream, data);
|
||||
else
|
||||
DataSerializerTraits<T>::decode(_activeStream, const_cast<T&>(data));
|
||||
DataSerializerTraits<T>::decode(&_activeStream, const_cast<T&>(data));
|
||||
}
|
||||
else
|
||||
{
|
||||
DataSerializerTraits<T>::log(_activeStream, data);
|
||||
DataSerializerTraits<T>::log(&_activeStream, data);
|
||||
}
|
||||
|
||||
return *this;
|
||||
@@ -73,13 +73,13 @@ public:
|
||||
if (!_isLogging)
|
||||
{
|
||||
if (_isSaving)
|
||||
DataSerializerTraits<DataSerialiserTag<T>>::encode(_activeStream, data);
|
||||
DataSerializerTraits<DataSerialiserTag<T>>::encode(&_activeStream, data);
|
||||
else
|
||||
DataSerializerTraits<DataSerialiserTag<T>>::decode(_activeStream, data);
|
||||
DataSerializerTraits<DataSerialiserTag<T>>::decode(&_activeStream, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
DataSerializerTraits<DataSerialiserTag<T>>::log(_activeStream, data);
|
||||
DataSerializerTraits<DataSerialiserTag<T>>::log(&_activeStream, data);
|
||||
}
|
||||
|
||||
return *this;
|
||||
|
||||
@@ -214,4 +214,9 @@ public:
|
||||
size_t readBytes = fread(buffer, 1, (size_t)length, _file);
|
||||
return readBytes;
|
||||
}
|
||||
|
||||
const void* GetData() const override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -49,6 +49,8 @@ interface IStream
|
||||
|
||||
virtual uint64_t TryRead(void* buffer, uint64_t length) abstract;
|
||||
|
||||
virtual const void* GetData() const abstract;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Helper methods
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
|
||||
MemoryStream& operator=(MemoryStream&& mv);
|
||||
|
||||
const void* GetData() const;
|
||||
const void* GetData() const override;
|
||||
void* GetDataCopy() const;
|
||||
void* TakeData();
|
||||
|
||||
|
||||
BIN
test/tests/testdata/replays/bpb.sv6r
vendored
BIN
test/tests/testdata/replays/bpb.sv6r
vendored
Binary file not shown.
BIN
test/tests/testdata/replays/issue5953.sv6r
vendored
BIN
test/tests/testdata/replays/issue5953.sv6r
vendored
Binary file not shown.
BIN
test/tests/testdata/replays/issue6807.sv6r
vendored
BIN
test/tests/testdata/replays/issue6807.sv6r
vendored
Binary file not shown.
BIN
test/tests/testdata/replays/issue7828.sv6r
vendored
BIN
test/tests/testdata/replays/issue7828.sv6r
vendored
Binary file not shown.
BIN
test/tests/testdata/replays/issue7867.sv6r
vendored
BIN
test/tests/testdata/replays/issue7867.sv6r
vendored
Binary file not shown.
BIN
test/tests/testdata/replays/issue8203.sv6r
vendored
BIN
test/tests/testdata/replays/issue8203.sv6r
vendored
Binary file not shown.
BIN
test/tests/testdata/replays/issue8216.sv6r
vendored
BIN
test/tests/testdata/replays/issue8216.sv6r
vendored
Binary file not shown.
BIN
test/tests/testdata/replays/issue8345.sv6r
vendored
BIN
test/tests/testdata/replays/issue8345.sv6r
vendored
Binary file not shown.
BIN
test/tests/testdata/replays/issue8426.sv6r
vendored
BIN
test/tests/testdata/replays/issue8426.sv6r
vendored
Binary file not shown.
Reference in New Issue
Block a user