A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
KReplaySystem.cc
Go to the documentation of this file.
1#include "KReplaySystem.hh"
2
3#include "host/Option.hh"
5
6#include <abstract/File.hh>
7#include <egg/core/Heap.hh>
8
10
11#include <iomanip>
12
13namespace Kinoko {
14
29
34
39 while (!calcEnd()) {
40 calc();
41 }
42
43 return success();
44}
45
50void KReplaySystem::parseOptions(int argc, char **argv) {
51 if (argc < 2) {
52 PANIC("Expected ghost argument!");
53 }
54
55 for (int i = 0; i < argc; ++i) {
56 std::optional<Host::EOption> flag = Host::Option::CheckFlag(argv[i]);
57 if (!flag || *flag == Host::EOption::Invalid) {
58 WARN("Expected a flag! Got: %s", argv[i]);
59 continue;
60 }
61
62 switch (*flag) {
64 ASSERT(i + 1 < argc);
65
66 m_currentGhostFileName = argv[++i];
69
70 if (m_currentRawGhostSize < System::RKG_HEADER_SIZE ||
72 PANIC("File cannot be a ghost! Check the file size.");
73 }
74
75 // Creating the raw ghost file validates it
77
80 } break;
82 default:
83 PANIC("Invalid flag!");
84 break;
85 }
86 }
87}
88
94
97 auto *instance = s_instance;
98 s_instance = nullptr;
99 EGG::egg_delete(instance);
100}
101
105
107 if (s_instance) {
108 s_instance = nullptr;
109 WARN("KReplaySystem instance not explicitly handled!");
110 }
111
114 delete[] m_currentRawGhost;
115}
116
120 constexpr u32 MAX_FRAME_COUNT = 10 * 60 * 60; // 10 minutes
121
122 const auto *raceManager = System::RaceManager::Instance();
123 if (raceManager->stage() == System::RaceManager::Stage::FinishGlobal) {
124 return true;
125 }
126
127 if (raceManager->timerManager().frameCounter() > MAX_FRAME_COUNT) {
128 return true;
129 }
130
131 return false;
132}
133
136void KReplaySystem::reportFail(const std::string &msg) const {
137 std::string report(m_currentGhostFileName);
138 report += "\n" + std::string(msg);
139 Abstract::File::Append("results.txt", report.c_str(), report.size());
140}
141
145 auto format = [](const System::Timer &timer) {
146 std::ostringstream oss;
147 oss << std::setw(2) << std::setfill('0') << timer.min << ":" << std::setw(2)
148 << std::setfill('0') << timer.sec << "." << std::setw(3) << std::setfill('0')
149 << timer.mil;
150 return oss.str();
151 };
152
153 const auto *raceManager = System::RaceManager::Instance();
154 if (raceManager->stage() != System::RaceManager::Stage::FinishGlobal) {
156 reportFail("Race didn't finish");
157 return false;
158 }
159
160 s32 desyncingTimerIdx = getDesyncingTimerIdx();
161 if (desyncingTimerIdx != -1) {
163 std::string msg;
164
165 const auto [correct, incorrect] = getDesyncingTimer(desyncingTimerIdx);
166 if (desyncingTimerIdx == 0) {
167 msg = "Final timer desync!";
168 } else {
169 msg = "Lap " + std::to_string(desyncingTimerIdx) + " timer desync!";
170 }
171
172 msg += " Expected " + format(correct) + ", got " + format(incorrect);
173 reportFail(msg);
174 return false;
175 }
176
177 return true;
178}
179
183 const auto &player = System::RaceManager::Instance()->player();
184 if (m_currentGhost->raceTimer() != player.raceTimer()) {
185 return 0;
186 }
187
188 for (size_t i = 0; i < 3; ++i) {
189 if (m_currentGhost->lapTimer(i) != player.getLapSplit(i + 1)) {
190 return i + 1;
191 }
192 }
193
194 return -1;
195}
196
201 auto cond = i <=> 0;
202 ASSERT(cond != std::strong_ordering::less);
203
204 if (cond == std::strong_ordering::equal) {
205 const auto &correct = m_currentGhost->raceTimer();
206 const auto &incorrect = System::RaceManager::Instance()->player().raceTimer();
207 ASSERT(correct != incorrect);
208 return DesyncingTimerPair(correct, incorrect);
209 } else if (cond == std::strong_ordering::greater) {
210 const auto &correct = m_currentGhost->lapTimer(i - 1);
211 const auto &incorrect = System::RaceManager::Instance()->player().lapTimer(i - 1);
212 ASSERT(correct != incorrect);
213 return DesyncingTimerPair(correct, incorrect);
214 }
215
216 // This is unreachable
218}
219
227
228} // namespace Kinoko
#define ASSERT(e)
Definition Logger.hh:25
#define PANIC(m,...)
Definition Logger.hh:27
#define WARN(m,...)
Definition Logger.hh:33
void enableAllocation()
Definition Heap.hh:52
Scene * currentScene() const
void changeScene(int nextSceneId)
Heap * heap() const
Definition Scene.hh:55
static KReplaySystem * Instance()
const char * m_currentGhostFileName
bool run() override
Executes a run.
void parseOptions(int argc, char **argv) override
Parses non-generic command line options.
const System::GhostFile * m_currentGhost
static void OnInit(System::RaceConfig *config, void *arg)
Initializes the race configuration as needed for replays.
EGG::SceneManager * m_sceneMgr
static KReplaySystem * CreateInstance()
std::pair< const System::Timer &, const System::Timer & > DesyncingTimerPair
DesyncingTimerPair getDesyncingTimer(s32 i) const
Gets the desyncing timer according to the index.
static void DestroyInstance()
bool calcEnd() const
Determines whether or not the ghost simulation should end.
void calc() override
Executes a frame.
void reportFail(const std::string &msg) const
Reports failure to file.
s32 getDesyncingTimerIdx() const
Finds the desyncing timer index, if one exists.
void init() override
Initializes the system.
bool success() const
Determines whether the simulation was a success or not.
static KSystem * s_instance
Definition KSystem.hh:33
const Timer & lapTimer(size_t i) const
Definition GhostFile.hh:85
const Timer & raceTimer() const
Definition GhostFile.hh:90
Initializes the player with parameters specified in the provided ghost file.
Definition RaceConfig.hh:23
const Scenario & raceScenario() const
Definition RaceConfig.hh:62
void setGhost(const u8 *rkg)
Definition RaceConfig.hh:70
static void RegisterInitCallback(const InitCallback &callback, void *arg)
Definition RaceConfig.hh:74
const Timer & lapTimer(size_t idx) const
const Timer & raceTimer() const
static RaceManager * Instance()
const Player & player() const
The binary data of a ghost saved to a file.
Definition GhostFile.hh:45
int Remove(const char *path)
Definition File.cc:83
void Append(const char *path, const char *data, size_t size)
Definition File.cc:77
u8 * LoadHost(const char *path, size_t &size)
Loads files from host system.
Definition File.cc:57
void egg_delete(const T *ptr)
Definition Heap.hh:154
T * egg_new(Args &&...args)
Definition Heap.hh:148
std::optional< EOption > CheckFlag(const char *arg)
Definition Option.cc:7
int32_t s32
Definition Memory.hh:13
uint32_t u32
Definition Memory.hh:18
std::array< Player, 12 > players
Definition RaceConfig.hh:50
A simple struct to represent a lap or race finish time.