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>
14 ASSERT(m_currentGhostFileName);
15 ASSERT(m_currentRawGhost);
16 ASSERT(m_currentGhost);
21 System::RaceConfig::RegisterInitCallback(
OnInit,
nullptr);
22 Abstract::File::Remove(
"results.txt");
24 m_sceneMgr->changeScene(0);
49 PANIC(
"Expected ghost argument!");
52 for (
int i = 0; i < argc; ++i) {
53 std::optional<Host::EOption> flag = Host::Option::CheckFlag(argv[i]);
54 if (!flag || *flag == Host::EOption::Invalid) {
55 WARN(
"Expected a flag! Got: %s", argv[i]);
60 case Host::EOption::Ghost: {
63 m_currentGhostFileName = argv[++i];
64 m_currentRawGhost = Abstract::File::Load(m_currentGhostFileName, m_currentRawGhostSize);
66 if (m_currentRawGhostSize < System::RKG_HEADER_SIZE ||
68 PANIC(
"File cannot be a ghost! Check the file size.");
75 ASSERT(m_currentGhost);
77 case Host::EOption::Invalid:
79 PANIC(
"Invalid flag!");
91void KReplaySystem::DestroyInstance() {
93 auto *instance = s_instance;
98KReplaySystem::KReplaySystem()
99 : m_currentGhostFileName(nullptr), m_currentGhost(nullptr), m_currentRawGhost(nullptr),
100 m_currentRawGhostSize(0) {}
102KReplaySystem::~KReplaySystem() {
104 s_instance =
nullptr;
105 WARN(
"KReplaySystem instance not explicitly handled!");
109 delete m_currentGhost;
110 delete m_currentRawGhost;
116 constexpr u16 MAX_MINUTE_COUNT = 10;
118 const auto *raceManager = System::RaceManager::Instance();
119 if (raceManager->stage() == System::RaceManager::Stage::FinishGlobal) {
123 if (raceManager->timerManager().currentTimer().min >= MAX_MINUTE_COUNT) {
133 std::string report(m_currentGhostFileName);
134 report +=
"\n" + std::string(msg);
135 Abstract::File::Append(
"results.txt", report.c_str(), report.size());
142 std::ostringstream oss;
143 oss << std::setw(2) << std::setfill(
'0') << timer.min <<
":" << std::setw(2)
144 << std::setfill(
'0') << timer.sec <<
"." << std::setw(3) << std::setfill(
'0')
149 const auto *raceManager = System::RaceManager::Instance();
150 if (raceManager->stage() != System::RaceManager::Stage::FinishGlobal) {
151 m_sceneMgr->currentScene()->heap()->enableAllocation();
157 if (desyncingTimerIdx != -1) {
158 m_sceneMgr->currentScene()->heap()->enableAllocation();
162 if (desyncingTimerIdx == 0) {
163 msg =
"Final timer desync!";
165 msg =
"Lap " + std::to_string(desyncingTimerIdx) +
" timer desync!";
168 msg +=
" Expected " + format(correct) +
", got " + format(incorrect);
179 const auto &player = System::RaceManager::Instance()->player();
180 if (m_currentGhost->raceTimer() != player.raceTimer()) {
184 for (
size_t i = 0; i < 3; ++i) {
185 if (m_currentGhost->lapTimer(i) != player.getLapSplit(i + 1)) {
198 ASSERT(cond != std::strong_ordering::less);
200 if (cond == std::strong_ordering::equal) {
201 const auto &correct = m_currentGhost->raceTimer();
202 const auto &incorrect = System::RaceManager::Instance()->player().raceTimer();
203 ASSERT(correct != incorrect);
204 return DesyncingTimerPair(correct, incorrect);
205 }
else if (cond == std::strong_ordering::greater) {
206 const auto &correct = m_currentGhost->lapTimer(i - 1);
207 const auto &incorrect = System::RaceManager::Instance()->player().lapTimer(i - 1);
208 ASSERT(correct != incorrect);
209 return DesyncingTimerPair(correct, incorrect);
220 config->setGhost(Instance()->m_currentRawGhost);
221 config->raceScenario().players[0].type = System::RaceConfig::Player::Type::Ghost;
Manages the scene stack and transitions between scenes.
Kinoko system designed to execute replays.
bool success() const
Determines whether the simulation was a success or not.
bool calcEnd() const
Determines whether or not the ghost simulation should end.
void reportFail(const std::string &msg) const
Reports failure to file.
void parseOptions(int argc, char **argv) override
Parses non-generic command line options.
static void OnInit(System::RaceConfig *config, void *arg)
Initializes the race configuration as needed for replays.
void init() override
Initializes the system.
s32 getDesyncingTimerIdx() const
Finds the desyncing timer index, if one exists.
DesyncingTimerPair getDesyncingTimer(s32 i) const
Gets the desyncing timer according to the index.
bool run() override
Executes a run.
void calc() override
Executes a frame.
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.