1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-06 06:32:56 +01:00
This commit is contained in:
Matt
2018-12-28 20:31:07 +01:00
parent 0ba42d6899
commit c7ab757a86
7 changed files with 123 additions and 117 deletions

View File

@@ -389,7 +389,7 @@ int32_t game_do_command_p(
flags = *ebx;
auto* replayManager = GetContext()->GetReplayManager();
if (replayManager != nullptr && replayManager->IsReplaying())
if (replayManager->IsReplaying())
{
// We only accept replay commands as long the replay is active.
if ((flags & GAME_COMMAND_FLAG_REPLAY) == 0)

View File

@@ -23,6 +23,7 @@
#include "rct2/S6Exporter.h"
#include "world/Park.h"
#include <chrono>
#include <vector>
namespace OpenRCT2
@@ -146,16 +147,7 @@ namespace OpenRCT2
if (_currentRecording == nullptr)
return;
MemoryStream stream;
DataSerialiser dsOut(true, stream);
action->Serialise(dsOut);
std::unique_ptr<GameAction> ga = GameActions::Create(action->GetType());
ga->SetCallback(action->GetCallback());
stream.SetPosition(0);
DataSerialiser dsIn(false, stream);
ga->Serialise(dsIn);
auto ga = GameActions::Clone(action);
_currentRecording->commands.emplace(gCurrentTicks, std::move(ga), _commandId++);
@@ -202,6 +194,8 @@ namespace OpenRCT2
else if (_mode == ReplayMode::PLAYING)
{
#ifndef DISABLE_NETWORK
// If the network is disabled we will only get a dummy hash which will cause
// false positives during replay.
CheckState();
#endif
ReplayCommands();
@@ -230,7 +224,7 @@ namespace OpenRCT2
}
}
virtual bool StartRecording(const std::string& name, uint32_t maxTicks /*= 0xFFFFFFFF*/) override
virtual bool StartRecording(const std::string& name, uint32_t maxTicks /*= k_MaxReplayTicks*/) override
{
if (_mode != ReplayMode::NONE && _mode != ReplayMode::NORMALISATION)
return false;
@@ -238,10 +232,10 @@ namespace OpenRCT2
auto replayData = std::make_unique<ReplayRecordData>();
replayData->name = name;
replayData->tickStart = gCurrentTicks;
if (maxTicks != 0xFFFFFFFF)
if (maxTicks != k_MaxReplayTicks)
replayData->tickEnd = gCurrentTicks + maxTicks;
else
replayData->tickEnd = 0xFFFFFFFF;
replayData->tickEnd = k_MaxReplayTicks;
auto context = GetContext();
auto& objManager = context->GetObjectManager();
@@ -253,31 +247,10 @@ namespace OpenRCT2
s6exporter->SaveGame(&replayData->parkData);
replayData->spriteSpatialData.Write(gSpriteSpatialIndex, sizeof(gSpriteSpatialIndex));
replayData->timeRecorded = std::chrono::seconds(std::time(nullptr)).count();
DataSerialiser parkParams(true, replayData->parkParams);
parkParams << _guestGenerationProbability;
parkParams << _suggestedGuestMaximum;
parkParams << gCheatsSandboxMode;
parkParams << gCheatsDisableClearanceChecks;
parkParams << gCheatsDisableSupportLimits;
parkParams << gCheatsDisableTrainLengthLimit;
parkParams << gCheatsEnableChainLiftOnAllTrack;
parkParams << gCheatsShowAllOperatingModes;
parkParams << gCheatsShowVehiclesFromOtherTrackTypes;
parkParams << gCheatsFastLiftHill;
parkParams << gCheatsDisableBrakesFailure;
parkParams << gCheatsDisableAllBreakdowns;
parkParams << gCheatsBuildInPauseMode;
parkParams << gCheatsIgnoreRideIntensity;
parkParams << gCheatsDisableVandalism;
parkParams << gCheatsDisableLittering;
parkParams << gCheatsNeverendingMarketing;
parkParams << gCheatsFreezeWeather;
parkParams << gCheatsDisablePlantAging;
parkParams << gCheatsAllowArbitraryRideTypeChanges;
parkParams << gCheatsDisableRideValueAging;
parkParams << gConfigGeneral.show_real_names_of_guests;
parkParams << gCheatsIgnoreResearchStatus;
SerialiseParkParameters(parkParams);
if (_mode != ReplayMode::NORMALISATION)
_mode = ReplayMode::RECORDING;
@@ -304,6 +277,8 @@ namespace OpenRCT2
std::string outPath = GetContext()->GetPlatformEnvironment()->GetDirectoryPath(DIRBASE::USER, DIRID::REPLAY);
std::string outFile = Path::Combine(outPath, replayName);
bool result = true;
FILE* fp = fopen(outFile.c_str(), "wb");
if (fp)
{
@@ -311,6 +286,13 @@ namespace OpenRCT2
fwrite(stream.GetData(), 1, stream.GetLength(), fp);
fclose(fp);
result = true;
}
else
{
log_error("Unable to write to file '%s'", outFile.c_str());
result = false;
}
// When normalizing the output we don't touch the mode.
@@ -319,7 +301,7 @@ namespace OpenRCT2
_currentRecording.reset();
return true;
return result;
}
virtual bool StartPlayback(const std::string& file) override
@@ -393,7 +375,7 @@ namespace OpenRCT2
return false;
}
if (StartRecording(outFile, 0xFFFFFFFF) == false)
if (StartRecording(outFile, k_MaxReplayTicks) == false)
{
StopPlayback();
return false;
@@ -434,8 +416,10 @@ namespace OpenRCT2
bool TranslateDeprecatedGameCommands(ReplayRecordData& data)
{
for (auto&& replayCommand : data.commands)
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.
@@ -444,13 +428,18 @@ namespace OpenRCT2
{
// Convert
ReplayCommand converted;
converted.commandIndex = replayCommand.commandIndex;
if (!ConvertDeprecatedGameCommand(replayCommand, converted))
{
return false;
}
data.commands.erase(replayCommand);
data.commands.emplace(std::move(converted));
// Remove deprecated command.
data.commands.erase(it);
// Insert new game action, iterator points to the replaced element.
it = data.commands.emplace(std::move(converted));
}
}
}
@@ -474,38 +463,22 @@ namespace OpenRCT2
sprite_position_tween_reset();
Guard::Assert(sizeof(gSpriteSpatialIndex) >= data.spriteSpatialData.GetLength());
// In case the sprite limit will be increased we keep the unused fields cleared.
std::fill_n(gSpriteSpatialIndex, std::size(gSpriteSpatialIndex), SPRITE_INDEX_NULL);
std::memcpy(gSpriteSpatialIndex, data.spriteSpatialData.GetData(), data.spriteSpatialData.GetLength());
// Load all map global variables.
DataSerialiser parkParams(false, data.parkParams);
parkParams << _guestGenerationProbability;
parkParams << _suggestedGuestMaximum;
parkParams << gCheatsSandboxMode;
parkParams << gCheatsDisableClearanceChecks;
parkParams << gCheatsDisableSupportLimits;
parkParams << gCheatsDisableTrainLengthLimit;
parkParams << gCheatsEnableChainLiftOnAllTrack;
parkParams << gCheatsShowAllOperatingModes;
parkParams << gCheatsShowVehiclesFromOtherTrackTypes;
parkParams << gCheatsFastLiftHill;
parkParams << gCheatsDisableBrakesFailure;
parkParams << gCheatsDisableAllBreakdowns;
parkParams << gCheatsBuildInPauseMode;
parkParams << gCheatsIgnoreRideIntensity;
parkParams << gCheatsDisableVandalism;
parkParams << gCheatsDisableLittering;
parkParams << gCheatsNeverendingMarketing;
parkParams << gCheatsFreezeWeather;
parkParams << gCheatsDisablePlantAging;
parkParams << gCheatsAllowArbitraryRideTypeChanges;
parkParams << gCheatsDisableRideValueAging;
parkParams << gConfigGeneral.show_real_names_of_guests;
parkParams << gCheatsIgnoreResearchStatus;
SerialiseParkParameters(parkParams);
game_load_init();
fix_invalid_vehicle_sprite_sizes();
}
catch (const std::exception&)
catch (const std::exception& ex)
{
log_error("Exception: %s", ex.what());
return false;
}
return true;
@@ -520,10 +493,10 @@ namespace OpenRCT2
char buffer[128];
while (feof(fp) == false)
{
size_t read = fread(buffer, 1, 128, fp);
if (read == 0)
size_t numBytesRead = fread(buffer, 1, 128, fp);
if (numBytesRead == 0)
break;
stream.Write(buffer, read);
stream.Write(buffer, numBytesRead);
}
fclose(fp);
@@ -571,6 +544,35 @@ namespace OpenRCT2
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;
return true;
}
bool SerialiseCommand(DataSerialiser& serialiser, ReplayCommand& command)
{
serialiser << command.tick;
@@ -673,7 +675,7 @@ namespace OpenRCT2
if (_currentReplay->checksums[checksumIndex].first == gCurrentTicks)
{
rct_sprite_checksum checksum = sprite_checksum();
if (savedChecksum.second.ToString() != checksum.ToString())
if (savedChecksum.second.raw != checksum.raw)
{
// Detected different game state.
log_verbose(
@@ -724,8 +726,6 @@ namespace OpenRCT2
GameAction* action = command.action.get();
action->SetFlags(action->GetFlags() | GAME_COMMAND_FLAG_REPLAY);
Guard::Assert(action != nullptr);
GameActionResult::Ptr result = GameActions::Execute(action);
if (result->Error == GA_ERROR::OK)
{
@@ -744,7 +744,7 @@ namespace OpenRCT2
}
// Focus camera on event.
if (isPositionValid && static_cast<uint16_t>(gCommandPosition.x) != 0x8000)
if (isPositionValid && gCommandPosition.x != LOCATION_NULL)
{
auto* mainWindow = window_get_main();
if (mainWindow != nullptr)

View File

@@ -19,6 +19,8 @@ struct GameAction;
namespace OpenRCT2
{
static constexpr uint32_t k_MaxReplayTicks = 0xFFFFFFFF;
interface IReplayManager
{
public:
@@ -37,7 +39,7 @@ namespace OpenRCT2
= 0;
virtual void AddGameAction(uint32_t tick, const GameAction* action) = 0;
virtual bool StartRecording(const std::string& name, uint32_t maxTicks = 0xFFFFFFFF) = 0;
virtual bool StartRecording(const std::string& name, uint32_t maxTicks = k_MaxReplayTicks) = 0;
virtual bool StopRecording() = 0;
virtual bool StartPlayback(const std::string& file) = 0;

View File

@@ -94,6 +94,25 @@ namespace GameActions
return std::unique_ptr<GameAction>(result);
}
GameAction::Ptr Clone(const GameAction* action)
{
std::unique_ptr<GameAction> ga = GameActions::Create(action->GetType());
ga->SetCallback(action->GetCallback());
// Serialise action data into stream.
DataSerialiser dsOut(true);
action->Serialise(dsOut);
// Serialise into new action.
MemoryStream& stream = dsOut.GetStream();
stream.SetPosition(0);
DataSerialiser dsIn(false, stream);
ga->Serialise(dsIn);
return ga;
}
static bool CheckActionInPausedMode(uint32_t actionFlags)
{
if (gGamePaused == 0)

View File

@@ -243,6 +243,7 @@ namespace GameActions
void Register();
bool IsValidId(uint32_t id);
GameAction::Ptr Create(uint32_t id);
GameAction::Ptr Clone(const GameAction* action);
GameActionResult::Ptr Query(const GameAction* action);
GameActionResult::Ptr Execute(const GameAction* action);
GameActionFactory Register(uint32_t id, GameActionFactory action);

View File

@@ -1348,20 +1348,19 @@ static int32_t cc_replay_startrecord(InteractiveConsole& console, const utf8** a
}
std::string name = argv[0];
uint32_t maxTicks = 0xFFFFFFFF;
// If ticks are specified by user use that otherwise maximum ticks specified by const.
uint32_t maxTicks = OpenRCT2::k_MaxReplayTicks;
if (argc >= 2)
{
maxTicks = atol(argv[1]);
}
auto* replayManager = OpenRCT2::GetContext()->GetReplayManager();
if (replayManager != nullptr)
if (replayManager->StartRecording(name, maxTicks))
{
if (replayManager->StartRecording(name, maxTicks))
{
console.WriteFormatLine("Replay recording start");
return 1;
}
console.WriteFormatLine("Replay recording start");
return 1;
}
return 0;
@@ -1376,13 +1375,10 @@ static int32_t cc_replay_stoprecord(InteractiveConsole& console, const utf8** ar
}
auto* replayManager = OpenRCT2::GetContext()->GetReplayManager();
if (replayManager != nullptr)
if (replayManager->StopRecording())
{
if (replayManager->StopRecording())
{
console.WriteFormatLine("Replay recording stopped");
return 1;
}
console.WriteFormatLine("Replay recording stopped");
return 1;
}
return 0;
@@ -1405,13 +1401,10 @@ static int32_t cc_replay_start(InteractiveConsole& console, const utf8** argv, i
std::string name = argv[0];
auto* replayManager = OpenRCT2::GetContext()->GetReplayManager();
if (replayManager != nullptr)
if (replayManager->StartPlayback(name))
{
if (replayManager->StartPlayback(name))
{
console.WriteFormatLine("Started replay");
return 1;
}
console.WriteFormatLine("Started replay");
return 1;
}
return 0;
@@ -1426,13 +1419,10 @@ static int32_t cc_replay_stop(InteractiveConsole& console, const utf8** argv, in
}
auto* replayManager = OpenRCT2::GetContext()->GetReplayManager();
if (replayManager != nullptr)
if (replayManager->StopPlayback())
{
if (replayManager->StopPlayback())
{
console.WriteFormatLine("Stopped replay");
return 1;
}
console.WriteFormatLine("Stopped replay");
return 1;
}
return 0;
@@ -1456,13 +1446,10 @@ static int32_t cc_replay_normalise(InteractiveConsole& console, const utf8** arg
std::string outputFile = argv[1];
auto* replayManager = OpenRCT2::GetContext()->GetReplayManager();
if (replayManager != nullptr)
if (replayManager->NormaliseReplay(inputFile, outputFile))
{
if (replayManager->NormaliseReplay(inputFile, outputFile))
{
console.WriteFormatLine("Stopped replay");
return 1;
}
console.WriteFormatLine("Stopped replay");
return 1;
}
return 0;

View File

@@ -59,20 +59,17 @@ void Painter::Paint(IDrawingEngine& de)
}
auto* replayManager = GetContext()->GetReplayManager();
if (replayManager != nullptr)
{
const char* text = nullptr;
const char* text = nullptr;
if (replayManager->IsReplaying())
text = "Replaying...";
else if (replayManager->IsRecording())
text = "Recording...";
else if (replayManager->IsNormalising())
text = "Normalising...";
if (replayManager->IsReplaying())
text = "Replaying...";
else if (replayManager->IsRecording())
text = "Recording...";
else if (replayManager->IsNormalising())
text = "Normalising...";
if (text != nullptr)
PaintReplayNotice(dpi, text);
}
if (text != nullptr)
PaintReplayNotice(dpi, text);
if (gConfigGeneral.show_fps)
{