Upload park recording in case of crash

This commit is contained in:
Michał Janiszewski 2020-03-31 23:12:35 +02:00
parent 08d38f3d24
commit e19eaa6a98
10 changed files with 145 additions and 11 deletions

View File

@ -587,6 +587,12 @@ namespace OpenRCT2
{
network_send_map();
}
#ifdef USE_BREAKPAD
if (network_get_mode() == NETWORK_MODE_NONE)
{
start_silent_record();
}
#endif
return true;
}
catch (const ObjectLoadException& e)

View File

@ -17,11 +17,13 @@
#include "Input.h"
#include "OpenRCT2.h"
#include "ParkImporter.h"
#include "PlatformEnvironment.h"
#include "ReplayManager.h"
#include "actions/LoadOrQuitAction.hpp"
#include "audio/audio.h"
#include "config/Config.h"
#include "core/FileScanner.h"
#include "core/Path.hpp"
#include "interface/Screenshot.h"
#include "interface/Viewport.h"
#include "interface/Window.h"
@ -845,3 +847,45 @@ void game_load_or_quit_no_save_prompt()
break;
}
}
void start_silent_record()
{
std::string name = Path::Combine(
OpenRCT2::GetContext()->GetPlatformEnvironment()->GetDirectoryPath(OpenRCT2::DIRBASE::USER), "debug_replay.sv6r");
auto* replayManager = OpenRCT2::GetContext()->GetReplayManager();
if (replayManager->StartRecording(name, OpenRCT2::k_MaxReplayTicks, OpenRCT2::IReplayManager::RecordType::SILENT))
{
OpenRCT2::ReplayRecordInfo info;
replayManager->GetCurrentReplayInfo(info);
safe_strcpy(gSilentRecordingName, info.FilePath.c_str(), MAX_PATH);
const char* logFmt = "Silent replay recording started: (%s) %s";
printf(logFmt, info.Name.c_str(), info.FilePath.c_str());
}
}
bool stop_silent_record()
{
auto* replayManager = OpenRCT2::GetContext()->GetReplayManager();
if (!replayManager->IsRecording() && !replayManager->IsNormalising())
{
return false;
}
OpenRCT2::ReplayRecordInfo info;
replayManager->GetCurrentReplayInfo(info);
if (replayManager->StopRecording())
{
const char* logFmt = "Replay recording stopped: (%s) %s\n"
" Ticks: %u\n"
" Commands: %u\n"
" Checksums: %u";
printf(logFmt, info.Name.c_str(), info.FilePath.c_str(), info.Ticks, info.NumCommands, info.NumChecksums);
return true;
}
return false;
}

View File

@ -171,3 +171,5 @@ void game_convert_strings_to_rct2(rct_s6_data* s6);
void utf8_to_rct2_self(char* buffer, size_t length);
void rct2_to_utf8_self(char* buffer, size_t length);
void game_fix_save_vars();
void start_silent_record();
bool stop_silent_record();

View File

@ -17,6 +17,7 @@ utf8 gCustomOpenrctDataPath[MAX_PATH] = { 0 };
utf8 gCustomRCT1DataPath[MAX_PATH] = { 0 };
utf8 gCustomRCT2DataPath[MAX_PATH] = { 0 };
utf8 gCustomPassword[MAX_PATH] = { 0 };
utf8 gSilentRecordingName[MAX_PATH] = { 0 };
bool gOpenRCT2Headless = false;
bool gOpenRCT2NoGraphics = false;

View File

@ -46,6 +46,7 @@ extern bool gOpenRCT2Headless;
extern bool gOpenRCT2NoGraphics;
extern bool gOpenRCT2ShowChangelog;
extern bool gOpenRCT2SilentBreakpad;
extern utf8 gSilentRecordingName[MAX_PATH];
#ifndef DISABLE_NETWORK
extern int32_t gNetworkStart;

View File

@ -98,6 +98,8 @@ namespace OpenRCT2
static constexpr uint16_t ReplayVersion = 3;
static constexpr uint32_t ReplayMagic = 0x5243524F; // ORCR.
static constexpr int ReplayCompressionLevel = 9;
static constexpr int NormalRecordingChecksumTicks = 1;
static constexpr int SilentRecordingChecksumTicks = 40; // Same as network server
enum class ReplayMode
{
@ -127,6 +129,11 @@ namespace OpenRCT2
return _mode == ReplayMode::NORMALISATION;
}
virtual bool ShouldDisplayNotice() const override
{
return IsRecording() && _recordType == RecordType::NORMAL;
}
virtual void AddGameAction(uint32_t tick, const GameAction* action) override
{
if (_currentRecording == nullptr)
@ -153,7 +160,7 @@ namespace OpenRCT2
rct_sprite_checksum checksum = sprite_checksum();
AddChecksum(gCurrentTicks, std::move(checksum));
_nextChecksumTick = gCurrentTicks + 1;
_nextChecksumTick = gCurrentTicks + ChecksumTicksDelta();
}
if (_mode == ReplayMode::RECORDING)
@ -197,8 +204,14 @@ namespace OpenRCT2
}
}
virtual bool StartRecording(const std::string& name, uint32_t maxTicks /*= k_MaxReplayTicks*/) override
virtual bool StartRecording(
const std::string& name, uint32_t maxTicks /*= k_MaxReplayTicks*/, RecordType rt /*= RecordType::NORMAL*/) override
{
// If using silent recording, discard whatever recording there is going on, even if a new silent recording is to be
// started.
if (_mode == ReplayMode::RECORDING && _recordType == RecordType::SILENT)
StopRecording(true);
if (_mode != ReplayMode::NONE && _mode != ReplayMode::NORMALISATION)
return false;
@ -213,9 +226,7 @@ namespace OpenRCT2
else
replayData->tickEnd = k_MaxReplayTicks;
std::string replayName = String::StdFormat("%s.sv6r", name.c_str());
std::string outPath = GetContext()->GetPlatformEnvironment()->GetDirectoryPath(DIRBASE::USER, DIRID::REPLAY);
replayData->filePath = Path::Combine(outPath, replayName);
replayData->filePath = name;
auto context = GetContext();
auto& objManager = context->GetObjectManager();
@ -239,18 +250,31 @@ namespace OpenRCT2
_mode = ReplayMode::RECORDING;
_currentRecording = std::move(replayData);
_recordType = rt;
_nextChecksumTick = gCurrentTicks + 1;
return true;
}
virtual bool StopRecording() override
virtual bool StopRecording(bool discard = false) override
{
if (_mode != ReplayMode::RECORDING && _mode != ReplayMode::NORMALISATION)
return false;
if (discard)
{
_currentRecording.reset();
_mode = ReplayMode::NONE;
return true;
}
_currentRecording->tickEnd = gCurrentTicks;
{
rct_sprite_checksum checksum = sprite_checksum();
AddChecksum(gCurrentTicks, std::move(checksum));
}
// Serialise Body.
DataSerialiser recSerialiser(true);
Serialise(recSerialiser, *_currentRecording);
@ -409,7 +433,7 @@ namespace OpenRCT2
return false;
}
if (!StartRecording(outFile, k_MaxReplayTicks))
if (!StartRecording(outFile, k_MaxReplayTicks, RecordType::NORMAL))
{
StopPlayback();
return false;
@ -421,6 +445,18 @@ namespace OpenRCT2
}
private:
int ChecksumTicksDelta() const
{
switch (_recordType)
{
default:
case RecordType::NORMAL:
return NormalRecordingChecksumTicks;
case RecordType::SILENT:
return SilentRecordingChecksumTicks;
}
}
bool LoadReplayDataMap(ReplayRecordData& data)
{
try
@ -787,6 +823,7 @@ namespace OpenRCT2
uint32_t _commandId = 0;
uint32_t _nextChecksumTick = 0;
uint32_t _nextReplayTick = 0;
RecordType _recordType = RecordType::NORMAL;
};
std::unique_ptr<IReplayManager> CreateReplayManager()

View File

@ -35,6 +35,12 @@ namespace OpenRCT2
interface IReplayManager
{
public:
enum class RecordType
{
NORMAL,
SILENT,
};
virtual ~IReplayManager() = default;
virtual void Update() = 0;
@ -42,11 +48,14 @@ namespace OpenRCT2
virtual bool IsReplaying() const = 0;
virtual bool IsRecording() const = 0;
virtual bool IsNormalising() const = 0;
virtual bool ShouldDisplayNotice() const = 0;
virtual void AddGameAction(uint32_t tick, const GameAction* action) = 0;
virtual bool StartRecording(const std::string& name, uint32_t maxTicks = k_MaxReplayTicks) = 0;
virtual bool StopRecording() = 0;
virtual bool StartRecording(
const std::string& name, uint32_t maxTicks = k_MaxReplayTicks, RecordType rt = RecordType::NORMAL)
= 0;
virtual bool StopRecording(bool discard = false) = 0;
virtual bool GetCurrentReplayInfo(ReplayRecordInfo & info) const = 0;
virtual bool StartPlayback(const std::string& file) = 0;

View File

@ -13,6 +13,7 @@
#include "../EditorObjectSelectionSession.h"
#include "../Game.h"
#include "../OpenRCT2.h"
#include "../PlatformEnvironment.h"
#include "../ReplayManager.h"
#include "../Version.h"
#include "../actions/ClimateSetAction.hpp"
@ -22,6 +23,7 @@
#include "../actions/StaffSetCostumeAction.hpp"
#include "../config/Config.h"
#include "../core/Guard.hpp"
#include "../core/Path.hpp"
#include "../core/String.hpp"
#include "../drawing/Drawing.h"
#include "../drawing/Font.h"
@ -1366,6 +1368,14 @@ static int32_t cc_replay_startrecord(InteractiveConsole& console, const argument
std::string name = argv[0];
if (!String::EndsWith(name, ".sv6r", true))
{
name += ".sv6r";
}
std::string outPath = OpenRCT2::GetContext()->GetPlatformEnvironment()->GetDirectoryPath(
OpenRCT2::DIRBASE::USER, OpenRCT2::DIRID::REPLAY);
name = Path::Combine(outPath, name);
// If ticks are specified by user use that otherwise maximum ticks specified by const.
uint32_t maxTicks = OpenRCT2::k_MaxReplayTicks;
if (argv.size() >= 2)

View File

@ -64,7 +64,7 @@ void Painter::Paint(IDrawingEngine& de)
if (replayManager->IsReplaying())
text = "Replaying...";
else if (replayManager->IsRecording())
else if (replayManager->ShouldDisplayNotice())
text = "Recording...";
else if (replayManager->IsNormalising())
text = "Normalising...";

View File

@ -24,6 +24,8 @@
# error Breakpad support not implemented yet for this platform
# endif
# include "../Game.h"
# include "../OpenRCT2.h"
# include "../Version.h"
# include "../config/Config.h"
# include "../core/Console.hpp"
@ -108,10 +110,12 @@ static bool OnCrash(
wchar_t saveFilePath[MAX_PATH];
wchar_t configFilePath[MAX_PATH];
wchar_t saveFilePathGZIP[MAX_PATH];
wchar_t recordFilePathNew[MAX_PATH];
swprintf_s(dumpFilePath, std::size(dumpFilePath), L"%s\\%s.dmp", dumpPath, miniDumpId);
swprintf_s(saveFilePath, std::size(saveFilePath), L"%s\\%s.sv6", dumpPath, miniDumpId);
swprintf_s(configFilePath, std::size(configFilePath), L"%s\\%s.ini", dumpPath, miniDumpId);
swprintf_s(saveFilePathGZIP, std::size(saveFilePathGZIP), L"%s\\%s.sv6.gz", dumpPath, miniDumpId);
swprintf_s(recordFilePathNew, std::size(recordFilePathNew), L"%s\\%s.sv6r", dumpPath, miniDumpId);
wchar_t dumpFilePathNew[MAX_PATH];
swprintf_s(
@ -141,6 +145,8 @@ static bool OnCrash(
fclose(dest);
}
bool with_record = stop_silent_record();
// Try to rename the files
if (_wrename(dumpFilePath, dumpFilePathNew) == 0)
{
@ -201,6 +207,20 @@ static bool OnCrash(
uploadFiles[L"attachment_screenshot.png"] = screenshotPathW;
}
if (with_record)
{
auto sv6rPathW = String::ToWideChar(gSilentRecordingName);
bool record_copied = CopyFileW(sv6rPathW.c_str(), recordFilePathNew, true);
if (record_copied)
{
uploadFiles[L"attachment_replay.sv6r"] = recordFilePathNew;
}
else
{
with_record = false;
}
}
if (gOpenRCT2SilentBreakpad)
{
int error;
@ -243,7 +263,7 @@ static bool OnCrash(
if (SUCCEEDED(coInitializeResult))
{
LPITEMIDLIST pidl = ILCreateFromPathW(dumpPath);
LPITEMIDLIST files[3];
LPITEMIDLIST files[4];
uint32_t numFiles = 0;
files[numFiles++] = ILCreateFromPathW(dumpFilePath);
@ -254,6 +274,10 @@ static bool OnCrash(
{
files[numFiles++] = ILCreateFromPathW(saveFilePath);
}
if (with_record)
{
files[numFiles++] = ILCreateFromPathW(recordFilePathNew);
}
if (pidl != nullptr)
{
SHOpenFolderAndSelectItems(pidl, numFiles, (LPCITEMIDLIST*)files, 0);