1#include "KReplaySystem.hh"
3#include "host/Option.hh"
4#include "host/SceneCreatorDynamic.hh"
6#include <abstract/File.hh>
8#include <game/system/RaceManager.hh>
16 ASSERT(m_currentGhostFileName);
17 ASSERT(m_currentRawGhost);
18 ASSERT(m_currentGhost);
23 System::RaceConfig::RegisterInitCallback(
OnInit,
nullptr);
24 Abstract::File::Remove(
"results.txt");
26 m_sceneMgr->changeScene(0);
51 PANIC(
"Expected ghost argument!");
54 for (
int i = 0; i < argc; ++i) {
55 std::optional<Host::EOption> flag = Host::Option::CheckFlag(argv[i]);
56 if (!flag || *flag == Host::EOption::Invalid) {
57 WARN(
"Expected a flag! Got: %s", argv[i]);
62 case Host::EOption::Ghost: {
65 m_currentGhostFileName = argv[++i];
66 m_currentRawGhost = Abstract::File::Load(m_currentGhostFileName, m_currentRawGhostSize);
68 if (m_currentRawGhostSize < System::RKG_HEADER_SIZE ||
70 PANIC(
"File cannot be a ghost! Check the file size.");
77 ASSERT(m_currentGhost);
79 case Host::EOption::Invalid:
81 PANIC(
"Invalid flag!");
93void KReplaySystem::DestroyInstance() {
95 auto *instance = s_instance;
100KReplaySystem::KReplaySystem()
101 : m_currentGhostFileName(nullptr), m_currentGhost(nullptr), m_currentRawGhost(nullptr),
102 m_currentRawGhostSize(0) {}
104KReplaySystem::~KReplaySystem() {
106 s_instance =
nullptr;
107 WARN(
"KReplaySystem instance not explicitly handled!");
111 delete m_currentGhost;
112 delete m_currentRawGhost;
118 constexpr u16 MAX_MINUTE_COUNT = 10;
120 const auto *raceManager = System::RaceManager::Instance();
121 if (raceManager->stage() == System::RaceManager::Stage::FinishGlobal) {
125 if (raceManager->timerManager().currentTimer().min >= MAX_MINUTE_COUNT) {
135 std::string report(m_currentGhostFileName);
136 report +=
"\n" + std::string(msg);
137 Abstract::File::Append(
"results.txt", report.c_str(), report.size());
144 std::ostringstream oss;
145 oss << std::setw(2) << std::setfill(
'0') << timer.min <<
":" << std::setw(2)
146 << std::setfill(
'0') << timer.sec <<
"." << std::setw(3) << std::setfill(
'0')
151 const auto *raceManager = System::RaceManager::Instance();
152 if (raceManager->stage() != System::RaceManager::Stage::FinishGlobal) {
153 m_sceneMgr->currentScene()->heap()->enableAllocation();
159 if (desyncingTimerIdx != -1) {
160 m_sceneMgr->currentScene()->heap()->enableAllocation();
164 if (desyncingTimerIdx == 0) {
165 msg =
"Final timer desync!";
167 msg =
"Lap " + std::to_string(desyncingTimerIdx) +
" timer desync!";
170 msg +=
" Expected " + format(correct) +
", got " + format(incorrect);
181 const auto &player = System::RaceManager::Instance()->player();
182 if (m_currentGhost->raceTimer() != player.raceTimer()) {
186 for (
size_t i = 0; i < 3; ++i) {
187 if (m_currentGhost->lapTimer(i) != player.getLapSplit(i + 1)) {
200 ASSERT(cond != std::strong_ordering::less);
202 if (cond == std::strong_ordering::equal) {
203 const auto &correct = m_currentGhost->raceTimer();
204 const auto &incorrect = System::RaceManager::Instance()->player().raceTimer();
205 ASSERT(correct != incorrect);
206 return DesyncingTimerPair(correct, incorrect);
207 }
else if (cond == std::strong_ordering::greater) {
208 const auto &correct = m_currentGhost->lapTimer(i - 1);
209 const auto &incorrect = System::RaceManager::Instance()->player().lapTimer(i - 1);
210 ASSERT(correct != incorrect);
211 return DesyncingTimerPair(correct, incorrect);
222 config->setGhost(Instance()->m_currentRawGhost);
223 config->raceScenario().players[0].type = System::RaceConfig::Player::Type::Ghost;
Manages the scene stack and transitions between scenes.
Kinoko system designed to execute replays.
s32 getDesyncingTimerIdx() const
Finds the desyncing timer index, if one exists.
void parseOptions(int argc, char **argv) override
Parses non-generic command line options.
void reportFail(const std::string &msg) const
Reports failure to file.
bool calcEnd() const
Determines whether or not the ghost simulation should end.
bool run() override
Executes a run.
static void OnInit(System::RaceConfig *config, void *arg)
Initializes the race configuration as needed for replays.
DesyncingTimerPair getDesyncingTimer(s32 i) const
Gets the desyncing timer according to the index.
bool success() const
Determines whether the simulation was a success or not.
void calc() override
Executes a frame.
void init() override
Initializes the system.
Parsed representation of a binary ghost file.
Initializes the player with parameters specified in the provided ghost file.
The binary data of a ghost saved to a file.
A simple struct to represent a lap or race finish time.