1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-10 09:32:29 +01:00

Show error message when issuing replay_start with a nonexistent file

This commit is contained in:
Kirill Gusev
2025-12-09 10:56:08 +03:00
committed by GitHub
parent cc1e217a90
commit b1103708ea
6 changed files with 88 additions and 41 deletions

View File

@@ -3839,3 +3839,5 @@ STR_7006 :Draw border around image buttons
STR_7007 :Ride Type STR_7007 :Ride Type
STR_7008 :Unknown ride type ({INT32}) STR_7008 :Unknown ride type ({INT32})
STR_7009 :Receiving scripts… STR_7009 :Receiving scripts…
STR_7010 :Could not start replay, file {STRING} doesnt exist or isnt valid
STR_7011 :Could not start replay

View File

@@ -27,12 +27,16 @@
#include "config/Config.h" #include "config/Config.h"
#include "core/Compression.h" #include "core/Compression.h"
#include "core/DataSerialiser.h" #include "core/DataSerialiser.h"
#include "core/EnumUtils.hpp"
#include "core/FileStream.h" #include "core/FileStream.h"
#include "core/FileSystem.hpp" #include "core/FileSystem.hpp"
#include "core/Path.hpp" #include "core/Path.hpp"
#include "core/String.hpp"
#include "entity/EntityRegistry.h" #include "entity/EntityRegistry.h"
#include "entity/EntityTweener.h" #include "entity/EntityTweener.h"
#include "interface/Window.h" #include "interface/Window.h"
#include "localisation/Formatting.h"
#include "localisation/StringIds.h"
#include "management/NewsItem.h" #include "management/NewsItem.h"
#include "object/ObjectManager.h" #include "object/ObjectManager.h"
#include "object/ObjectRepository.h" #include "object/ObjectRepository.h"
@@ -41,7 +45,10 @@
#include "world/Park.h" #include "world/Park.h"
#include <chrono> #include <chrono>
#include <exception>
#include <memory> #include <memory>
#include <stdexcept>
#include <string>
#include <vector> #include <vector>
namespace OpenRCT2 namespace OpenRCT2
@@ -121,6 +128,13 @@ namespace OpenRCT2
NORMALISATION, NORMALISATION,
}; };
static constexpr std::array modeToName = {
"NONE",
"RECORDING",
"PLAYING",
"NORMALISATION",
};
public: public:
virtual ~ReplayManager() virtual ~ReplayManager()
{ {
@@ -415,23 +429,25 @@ namespace OpenRCT2
} }
} }
virtual bool StartPlayback(const std::string& file) override void StartPlayback(const std::string& file) override
{ {
if (_mode != ReplayMode::NONE && _mode != ReplayMode::NORMALISATION) if (_mode != ReplayMode::NONE && _mode != ReplayMode::NORMALISATION)
return false; throw std::invalid_argument(std::string("Unexpected mode ") + modeToName[EnumValue(_mode)]);
auto replayData = std::make_unique<ReplayRecordData>(); auto replayData = std::make_unique<ReplayRecordData>();
if (!ReadReplayData(file, *replayData)) try
{ {
LOG_ERROR("Unable to read replay data."); ReadReplayData(file, *replayData);
return false; }
catch (const std::exception&)
{
throw;
} }
if (!LoadReplayDataMap(*replayData)) if (!LoadReplayDataMap(*replayData))
{ {
LOG_ERROR("Unable to load map."); throw std::runtime_error("Unable to load map.");
return false;
} }
getGameState().currentTicks = replayData->tickStart; getGameState().currentTicks = replayData->tickStart;
@@ -447,8 +463,6 @@ namespace OpenRCT2
if (_mode != ReplayMode::NORMALISATION) if (_mode != ReplayMode::NORMALISATION)
_mode = ReplayMode::PLAYING; _mode = ReplayMode::PLAYING;
return true;
} }
virtual bool IsPlaybackStateMismatching() const override virtual bool IsPlaybackStateMismatching() const override
@@ -485,7 +499,11 @@ namespace OpenRCT2
{ {
_mode = ReplayMode::NORMALISATION; _mode = ReplayMode::NORMALISATION;
if (!StartPlayback(file)) try
{
StartPlayback(file);
}
catch (const std::invalid_argument&)
{ {
return false; return false;
} }
@@ -595,23 +613,31 @@ namespace OpenRCT2
return recFile.data; return recFile.data;
} }
bool ReadReplayData(const std::string& file, ReplayRecordData& data) void ReadReplayData(const std::string& file, ReplayRecordData& data)
{ {
fs::path filePath = file; fs::path filePath = file;
if (filePath.is_absolute())
{
if (!fs::exists(filePath))
{
throw std::runtime_error(FormatStringID(STR_REPLAY_FILE_NOT_FOUND, filePath.u8string().c_str()));
}
}
else if (filePath.is_relative())
{
if (filePath.extension() != ".parkrep") if (filePath.extension() != ".parkrep")
filePath += ".parkrep"; filePath += ".parkrep";
if (filePath.is_relative())
{
fs::path replayPath = GetContext()->GetPlatformEnvironment().GetDirectoryPath( fs::path replayPath = GetContext()->GetPlatformEnvironment().GetDirectoryPath(
DirBase::user, DirId::replayRecordings) DirBase::user, DirId::replayRecordings)
/ filePath; / filePath;
if (fs::is_regular_file(replayPath))
filePath = replayPath; filePath = replayPath;
} }
if (!fs::is_regular_file(filePath)) if (!fs::is_regular_file(filePath))
return false; {
throw std::runtime_error(FormatStringID(STR_REPLAY_FILE_NOT_FOUND, filePath.u8string().c_str()));
}
FileStream fileStream(filePath, FileMode::open); FileStream fileStream(filePath, FileMode::open);
MemoryStream stream = DecompressFile(fileStream); MemoryStream stream = DecompressFile(fileStream);
@@ -620,7 +646,7 @@ namespace OpenRCT2
DataSerialiser serialiser(false, stream); DataSerialiser serialiser(false, stream);
if (!Serialise(serialiser, data)) if (!Serialise(serialiser, data))
{ {
return false; throw std::runtime_error(LanguageGetString(STR_REPLAY_NOT_STARTED));
} }
// Reset position of all streams. // Reset position of all streams.
@@ -628,8 +654,6 @@ namespace OpenRCT2
data.parkParams.SetPosition(0); data.parkParams.SetPosition(0);
data.cheatData.SetPosition(0); data.cheatData.SetPosition(0);
data.gameStateSnapshots.SetPosition(0); data.gameStateSnapshots.SetPosition(0);
return true;
} }
bool SerialiseCheats(DataSerialiser& serialiser) bool SerialiseCheats(DataSerialiser& serialiser)

View File

@@ -60,7 +60,7 @@ namespace OpenRCT2
virtual bool StopRecording(bool discard = false) = 0; virtual bool StopRecording(bool discard = false) = 0;
virtual bool GetCurrentReplayInfo(ReplayRecordInfo& info) const = 0; virtual bool GetCurrentReplayInfo(ReplayRecordInfo& info) const = 0;
virtual bool StartPlayback(const std::string& file) = 0; virtual void StartPlayback(const std::string& file) = 0;
virtual bool IsPlaybackStateMismatching() const = 0; virtual bool IsPlaybackStateMismatching() const = 0;
virtual bool StopPlayback() = 0; virtual bool StopPlayback() = 0;

View File

@@ -1485,8 +1485,17 @@ static void ConsoleCommandReplayStart(InteractiveConsole& console, const argumen
std::string name = argv[0]; std::string name = argv[0];
auto* replayManager = OpenRCT2::GetContext()->GetReplayManager(); auto* replayManager = OpenRCT2::GetContext()->GetReplayManager();
if (replayManager->StartPlayback(name))
try
{ {
replayManager->StartPlayback(name);
}
catch (const std::exception& e)
{
console.WriteLine(e.what());
return;
}
OpenRCT2::ReplayRecordInfo info; OpenRCT2::ReplayRecordInfo info;
replayManager->GetCurrentReplayInfo(info); replayManager->GetCurrentReplayInfo(info);
@@ -1504,7 +1513,6 @@ static void ConsoleCommandReplayStart(InteractiveConsole& console, const argumen
console.WriteFormatLine(logFmt, info.FilePath.c_str(), recordingDate, info.Ticks, info.NumCommands, info.NumChecksums); console.WriteFormatLine(logFmt, info.FilePath.c_str(), recordingDate, info.Ticks, info.NumCommands, info.NumChecksums);
Console::WriteLine(logFmt, info.FilePath.c_str(), recordingDate, info.Ticks, info.NumCommands, info.NumChecksums); Console::WriteLine(logFmt, info.FilePath.c_str(), recordingDate, info.Ticks, info.NumCommands, info.NumChecksums);
} }
}
static void ConsoleCommandReplayStop(InteractiveConsole& console, const arguments_t& argv) static void ConsoleCommandReplayStop(InteractiveConsole& console, const arguments_t& argv)
{ {

View File

@@ -1758,6 +1758,9 @@ enum : StringId
// Window: Error // Window: Error
STR_AUDIO_FILE_TRUNCATED = 7003, STR_AUDIO_FILE_TRUNCATED = 7003,
STR_REPLAY_FILE_NOT_FOUND = 7010,
STR_REPLAY_NOT_STARTED = 7011,
// Have to include resource strings (from scenarios and objects) for the time being now that language is partially working // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working
/* MAX_STR_COUNT = 32768 */ // MAX_STR_COUNT - upper limit for number of strings, not the current count strings /* MAX_STR_COUNT = 32768 */ // MAX_STR_COUNT - upper limit for number of strings, not the current count strings
}; };

View File

@@ -9,8 +9,10 @@
#include "TestData.h" #include "TestData.h"
#include <exception>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <openrct2/Context.h> #include <openrct2/Context.h>
#include <openrct2/Diagnostic.h>
#include <openrct2/Game.h> #include <openrct2/Game.h>
#include <openrct2/GameState.h> #include <openrct2/GameState.h>
#include <openrct2/OpenRCT2.h> #include <openrct2/OpenRCT2.h>
@@ -22,6 +24,7 @@
#include <openrct2/core/String.hpp> #include <openrct2/core/String.hpp>
#include <openrct2/platform/Platform.h> #include <openrct2/platform/Platform.h>
#include <openrct2/ride/Ride.h> #include <openrct2/ride/Ride.h>
#include <stdexcept>
#include <string> #include <string>
using namespace OpenRCT2; using namespace OpenRCT2;
@@ -58,7 +61,7 @@ static std::vector<ReplayTestData> GetReplayFiles()
{ {
ReplayTestData test; ReplayTestData test;
test.name = sanitizeTestName(scanner->GetFileInfo().Name); test.name = sanitizeTestName(scanner->GetFileInfo().Name);
test.filePath = scanner->GetPath(); test.filePath = Path::GetAbsolute(scanner->GetPath());
res.push_back(std::move(test)); res.push_back(std::move(test));
} }
return res; return res;
@@ -84,8 +87,15 @@ TEST_P(ReplayTests, RunReplay)
IReplayManager* replayManager = context->GetReplayManager(); IReplayManager* replayManager = context->GetReplayManager();
ASSERT_NE(replayManager, nullptr); ASSERT_NE(replayManager, nullptr);
bool startedReplay = replayManager->StartPlayback(replayFile); try
ASSERT_TRUE(startedReplay); {
replayManager->StartPlayback(replayFile);
}
catch (const std::exception& e)
{
LOG_WARNING("Can't start replay!. %s", e.what());
FAIL();
}
while (replayManager->IsReplaying()) while (replayManager->IsReplaying())
{ {