mirror of https://github.com/OpenRCT2/OpenRCT2.git
Upload park recording in case of crash
This commit is contained in:
parent
08d38f3d24
commit
e19eaa6a98
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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...";
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue