diff options
| author | inspectredc <inspectredc@gmail.com> | 2025-04-03 16:39:23 +0100 |
|---|---|---|
| committer | Lywx <kiritodev01@gmail.com> | 2025-04-23 07:54:00 -0600 |
| commit | dfaad4b3eac5c532b4dea999c484d5f43689bcae (patch) | |
| tree | 0bfc98955acc8922032ae73e1590f80cc803ce20 /src | |
| parent | 5c3ff9a40132d3d98211b2d37ad4cb7b6e208bd2 (diff) | |
Ghost Testing
Diffstat (limited to 'src')
| -rw-r--r-- | src/Companion.cpp | 2 | ||||
| -rw-r--r-- | src/factories/fzerox/GhostRecordFactory.cpp | 245 | ||||
| -rw-r--r-- | src/factories/fzerox/GhostRecordFactory.h | 28 | ||||
| -rw-r--r-- | src/factories/fzerox/ghost/Ghost.h | 385 |
4 files changed, 650 insertions, 10 deletions
diff --git a/src/Companion.cpp b/src/Companion.cpp index a70f715..1864236 100644 --- a/src/Companion.cpp +++ b/src/Companion.cpp @@ -72,6 +72,7 @@ #ifdef FZERO_SUPPORT #include "factories/fzerox/CourseFactory.h" +#include "factories/fzerox/GhostRecordFactory.h" #endif #ifdef NAUDIO_SUPPORT @@ -165,6 +166,7 @@ void Companion::Init(const ExportType type) { #ifdef FZERO_SUPPORT this->RegisterFactory("FZX:COURSE", std::make_shared<FZX::CourseFactory>()); + this->RegisterFactory("FZX:GHOST", std::make_shared<FZX::GhostRecordFactory>()); #endif #ifdef NAUDIO_SUPPORT diff --git a/src/factories/fzerox/GhostRecordFactory.cpp b/src/factories/fzerox/GhostRecordFactory.cpp index 9536d80..a72a6ed 100644 --- a/src/factories/fzerox/GhostRecordFactory.cpp +++ b/src/factories/fzerox/GhostRecordFactory.cpp @@ -1,9 +1,69 @@ #include "GhostRecordFactory.h" +#include "ghost/Ghost.h" #include "utils/Decompressor.h" #include "spdlog/spdlog.h" #include "Companion.h" +#define ARRAY_COUNT(arr) (int32_t)(sizeof(arr) / sizeof(arr[0])) +#define ALIGN16(val) (((val) + 0xF) & ~0xF) + +uint16_t FZX::GhostRecordData::Save_CalculateChecksum(void* data, int32_t size) { + uint8_t* dataPtr = (uint8_t*)data; + uint16_t checksum = 0; + int32_t i; + + for (i = 0; i < size; i++) { + checksum += *dataPtr++; + } + + return checksum; +} + +uint16_t FZX::GhostRecordData::CalculateRecordChecksum(void) { + uint16_t checksum = 0; + int32_t recordChecksum = CalculateReplayChecksum(); + + checksum += Save_CalculateChecksum(&mGhostType, sizeof(mGhostType)); + checksum += Save_CalculateChecksum(&recordChecksum, sizeof(recordChecksum)); + checksum += Save_CalculateChecksum(&mCourseEncoding, sizeof(mCourseEncoding)); + checksum += Save_CalculateChecksum(&mRaceTime, sizeof(mRaceTime)); + checksum += Save_CalculateChecksum(&mUnk10, sizeof(mUnk10)); + checksum += Save_CalculateChecksum((void*)mTrackName.c_str(), mTrackName.length()); + checksum += Save_CalculateChecksum(&mGhostMachineInfo, sizeof(mGhostMachineInfo)); + + return checksum; +} + +uint16_t FZX::GhostRecordData::CalculateDataChecksum(void) { + uint16_t checksum = 0; + + checksum += Save_CalculateChecksum(&mReplayEnd, sizeof(mReplayEnd)); + checksum += Save_CalculateChecksum(&mReplaySize, sizeof(mReplaySize)); + + for (auto lapTime : mLapTimes) { + checksum += Save_CalculateChecksum(&lapTime, sizeof(lapTime)); + } + + checksum += Save_CalculateChecksum(mReplayData.data(), mReplayData.size()); + + return checksum; +} + +int32_t FZX::GhostRecordData::CalculateReplayChecksum(void) { + int32_t checksum = 0; + int32_t i = 0; + + for (auto dataByte : mReplayData) { + checksum += ((uint32_t)(uint8_t)dataByte) << ((3 - i) * 8); + + i++; + i %= 4; + } + + return checksum; +} + ExportResult FZX::GhostRecordHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) { const auto symbol = GetSafeNode(node, "symbol", entryName); @@ -12,7 +72,9 @@ ExportResult FZX::GhostRecordHeaderExporter::Export(std::ostream &write, std::sh return std::nullopt; } - write << "extern GhostRecord " << symbol << ";\n"; + write << "extern GhostRecord " << symbol << "Record;\n"; + write << "extern GhostReplayInfo " << symbol << "ReplayInfo;\n"; + write << "extern s8 " << symbol << "Data[];\n"; return std::nullopt; } @@ -22,9 +84,111 @@ ExportResult FZX::GhostRecordCodeExporter::Export(std::ostream &write, std::shar const auto offset = GetSafeNode<uint32_t>(node, "offset"); const auto record = std::static_pointer_cast<GhostRecordData>(raw); - write << "GhostRecord " << symbol << " = {\n"; + write << "GhostRecord " << symbol << "Record = {\n"; + + write << fourSpaceTab << "0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << record->CalculateRecordChecksum() << std::dec << ", /* Checksum */\n"; + + write << fourSpaceTab << static_cast<GhostType>(record->mGhostType) << ",\n"; + + write << fourSpaceTab << "0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(8) << record->CalculateReplayChecksum() << std::dec << ", /* Replay Checksum */\n"; + + write << fourSpaceTab << "0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(8) << record->mCourseEncoding << std::dec << ", /* Course Encoding */\n"; + + write << fourSpaceTab << record->mRaceTime << ", /* Race Time */ \n"; + + write << fourSpaceTab << record->mUnk10 << ", { 0 },\n"; + + write << fourSpaceTab << "\"" << record->mTrackName << "\",\n"; + + write << fourSpaceTab << " {\n"; + write << fourSpaceTab << fourSpaceTab << static_cast<Character>(record->mGhostMachineInfo.character) << ", "; + write << static_cast<CustomType>(record->mGhostMachineInfo.customType) << ",\n"; + + write << fourSpaceTab << fourSpaceTab << static_cast<FrontType>(record->mGhostMachineInfo.frontType) << ", "; + write << static_cast<RearType>(record->mGhostMachineInfo.rearType) << ", "; + write << static_cast<WingType>(record->mGhostMachineInfo.wingType) << ",\n"; + + write << fourSpaceTab << fourSpaceTab << static_cast<Logo>(record->mGhostMachineInfo.frontType) << ", "; + write << "MACHINE_NUMBER(" << (uint32_t)record->mGhostMachineInfo.number + 1 << "), "; + write << static_cast<Decal>(record->mGhostMachineInfo.decal) << ",\n"; + + write << fourSpaceTab << fourSpaceTab << (uint32_t)record->mGhostMachineInfo.bodyR << ", "; + write << (uint32_t)record->mGhostMachineInfo.bodyG << ", "; + write << (uint32_t)record->mGhostMachineInfo.bodyB << ", /* Body Color */\n"; + write << fourSpaceTab << fourSpaceTab << (uint32_t)record->mGhostMachineInfo.numberR << ", "; + write << (uint32_t)record->mGhostMachineInfo.numberG << ", "; + write << (uint32_t)record->mGhostMachineInfo.numberB << ", /* Number Color */\n"; + write << fourSpaceTab << fourSpaceTab << (uint32_t)record->mGhostMachineInfo.decalR << ", "; + write << (uint32_t)record->mGhostMachineInfo.decalG << ", "; + write << (uint32_t)record->mGhostMachineInfo.decalB << ", /* Decal Color */\n"; + write << fourSpaceTab << fourSpaceTab << (uint32_t)record->mGhostMachineInfo.cockpitR << ", "; + write << (uint32_t)record->mGhostMachineInfo.cockpitG << ", "; + write << (uint32_t)record->mGhostMachineInfo.cockpitB << " /* Cockpit Color */\n"; + write << fourSpaceTab << "}\n"; + + write << "};\n\n"; + + + write << "GhostReplayInfo " << symbol << "ReplayInfo = {\n"; + + write << fourSpaceTab << "0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << record->CalculateDataChecksum() << std::dec << ", /* Checksum */\n"; + + write << fourSpaceTab << "0,\n"; + + write << fourSpaceTab << "{ "; - return offset; + for (int32_t i = 0; i < 3; i++) { + write << record->mLapTimes.at(i); + if (i != 2) { + write << ", "; + } + } + + write << " },\n"; + + write << fourSpaceTab << record->mReplayEnd << ", "; + + write << record->mReplaySize << ",\n"; + + write << fourSpaceTab << "0, 0\n"; + + write << "};\n\n"; + + + write << "u8 " << symbol << "Data[] = {\n"; + + write << fourSpaceTab; + + int32_t counter = 0; + for (uint32_t i = 0; i < record->mReplaySize; i++) { + int32_t replayData = (int32_t)record->mReplayData.at(i); + + if (replayData == -0x80) { + write << ""; + + replayData = ((int32_t)record->mReplayData.at(i + 1) << 8) | (int32_t)record->mReplayData.at(i + 2); + write << "REPLAY_DATA_LARGE(" << replayData << ")"; + + i += 2; + } else { + write << replayData; + } + + if (i != record->mReplaySize - 1) { + write << ", "; + } else { + write << "\n"; + break; + } + + if ((++counter % 3) == 0) { + write << "\n" << fourSpaceTab; + } + } + + write << "};\n\n"; + + return offset + 0x20 + 0x40 + ALIGN16(record->mReplaySize); } ExportResult FZX::GhostRecordBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) { @@ -63,12 +227,78 @@ std::optional<std::shared_ptr<IParsedData>> FZX::GhostRecordFactory::parse(std:: reader.SetEndianness(Torch::Endianness::Big); - return std::make_shared<GhostRecordData>(); + // Record + uint16_t recordChecksum = reader.ReadInt16(); + uint16_t ghostType = reader.ReadUInt16(); + int32_t replayChecksum = reader.ReadInt32(); + int32_t courseEncoding = reader.ReadInt32(); + int32_t raceTime = reader.ReadInt32(); + + uint16_t unk_10 = reader.ReadInt16(); + for (int32_t i = 0; i < 5; i++) { + reader.ReadInt8(); + } + + char trackNameBuffer[9]; + for (int32_t i = 0; i < ARRAY_COUNT(trackNameBuffer); i++) { + trackNameBuffer[i] = reader.ReadChar(); + } + std::string trackName(trackNameBuffer); + + GhostMachineInfo ghostMachineInfo; + + ghostMachineInfo.character = reader.ReadUByte(); + ghostMachineInfo.customType = reader.ReadUByte(); + ghostMachineInfo.frontType = reader.ReadUByte(); + ghostMachineInfo.rearType = reader.ReadUByte(); + ghostMachineInfo.wingType = reader.ReadUByte(); + ghostMachineInfo.logo = reader.ReadUByte(); + ghostMachineInfo.number = reader.ReadUByte(); + ghostMachineInfo.decal = reader.ReadUByte(); + ghostMachineInfo.bodyR = reader.ReadUByte(); + ghostMachineInfo.bodyG = reader.ReadUByte(); + ghostMachineInfo.bodyB = reader.ReadUByte(); + ghostMachineInfo.numberR = reader.ReadUByte(); + ghostMachineInfo.numberG = reader.ReadUByte(); + ghostMachineInfo.numberB = reader.ReadUByte(); + ghostMachineInfo.decalR = reader.ReadUByte(); + ghostMachineInfo.decalG = reader.ReadUByte(); + ghostMachineInfo.decalB = reader.ReadUByte(); + ghostMachineInfo.cockpitR = reader.ReadUByte(); + ghostMachineInfo.cockpitG = reader.ReadUByte(); + ghostMachineInfo.cockpitB = reader.ReadUByte(); + + // Data + reader.Seek(0x40, LUS::SeekOffsetType::Start); + + uint16_t dataChecksum = reader.ReadInt16(); + + reader.ReadInt16(); + + std::vector<int32_t> lapTimes; + + for (int32_t i = 0; i < 3; i++) { + lapTimes.push_back(reader.ReadInt32()); + } + + int32_t replayEnd = reader.ReadInt32(); + uint32_t replaySize = reader.ReadUInt32(); + + reader.ReadInt32(); + reader.ReadInt32(); + + std::vector<int8_t> replayData; + for (uint32_t i = 0; i < replaySize; i++) { + replayData.push_back(reader.ReadInt8()); + } + + return std::make_shared<GhostRecordData>(ghostType, courseEncoding, raceTime, unk_10, trackName, ghostMachineInfo, lapTimes, replayEnd, replaySize, replayData); } +/* std::optional<std::shared_ptr<IParsedData>> FZX::GhostRecordFactory::parse_modding(std::vector<uint8_t>& buffer, YAML::Node& node) { YAML::Node assetNode; - + try { std::string text((char*) buffer.data(), buffer.size()); assetNode = YAML::Load(text.c_str()); @@ -77,8 +307,9 @@ std::optional<std::shared_ptr<IParsedData>> FZX::GhostRecordFactory::parse_moddi SPDLOG_ERROR("{}", (char*) buffer.data()); return std::nullopt; } - + const auto info = assetNode.begin()->second; - + return std::make_shared<GhostRecordData>(); } +*/ diff --git a/src/factories/fzerox/GhostRecordFactory.h b/src/factories/fzerox/GhostRecordFactory.h index aaf8ae1..3497629 100644 --- a/src/factories/fzerox/GhostRecordFactory.h +++ b/src/factories/fzerox/GhostRecordFactory.h @@ -29,14 +29,36 @@ typedef struct GhostMachineInfo { class GhostRecordData : public IParsedData { public: + // Records uint16_t mGhostType; - int32_t mReplayChecksum; int32_t mCourseEncoding; int32_t mRaceTime; + uint16_t mUnk10; std::string mTrackName; // empty for normal tracks GhostMachineInfo mGhostMachineInfo; + + // Data + std::vector<int32_t> mLapTimes; + int32_t mReplayEnd; + uint32_t mReplaySize; + std::vector<int8_t> mReplayData; - GhostRecordData(uint16_t ghostType, int32_t replayChecksum, int32_t courseEncoding, int32_t raceTime, std::string trackName, GhostMachineInfo& ghostMachineInfo) : mGhostType(ghostType), mReplayChecksum(replayChecksum), mCourseEncoding(courseEncoding), mRaceTime(raceTime), mTrackName(trackName), mGhostMachineInfo(ghostMachineInfo) {} + GhostRecordData(uint16_t ghostType, int32_t courseEncoding, int32_t raceTime, uint16_t unk_10, std::string trackName, GhostMachineInfo& ghostMachineInfo, std::vector<int32_t> lapTimes, int32_t replayEnd, uint32_t replaySize, std::vector<int8_t> replayData) : + mGhostType(ghostType), + mCourseEncoding(courseEncoding), + mRaceTime(raceTime), + mUnk10(unk_10), + mTrackName(trackName), + mGhostMachineInfo(ghostMachineInfo), + mLapTimes(std::move(lapTimes)), + mReplayEnd(replayEnd), + mReplaySize(replaySize), + mReplayData(std::move(replayData)) {} + + uint16_t Save_CalculateChecksum(void* data, int32_t size); + uint16_t CalculateRecordChecksum(void); + uint16_t CalculateDataChecksum(void); + int32_t CalculateReplayChecksum(void); }; class GhostRecordHeaderExporter : public BaseExporter { @@ -58,7 +80,7 @@ class GhostRecordModdingExporter : public BaseExporter { class GhostRecordFactory : public BaseFactory { public: std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override; - std::optional<std::shared_ptr<IParsedData>> parse_modding(std::vector<uint8_t>& buffer, YAML::Node& data) override; + // std::optional<std::shared_ptr<IParsedData>> parse_modding(std::vector<uint8_t>& buffer, YAML::Node& data) override; inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override { return { REGISTER(Code, GhostRecordCodeExporter) diff --git a/src/factories/fzerox/ghost/Ghost.h b/src/factories/fzerox/ghost/Ghost.h new file mode 100644 index 0000000..efaf923 --- /dev/null +++ b/src/factories/fzerox/ghost/Ghost.h @@ -0,0 +1,385 @@ +#pragma once + +#include <string> +#include <spdlog/spdlog.h> +#include <spdlog/fmt/ostr.h> + +namespace FZX { +enum class GhostType { + /* 0 */ GHOST_NONE, + /* 1 */ GHOST_PLAYER, + /* 2 */ GHOST_STAFF, + /* 3 */ GHOST_CELEBRITY, + /* 4 */ GHOST_CHAMP, +}; + +enum class Character { + /* 00 */ CAPTAIN_FALCON, + /* 01 */ DR_STEWART, + /* 02 */ PICO, + /* 03 */ SAMURAI_GOROH, + /* 04 */ JODY_SUMMER, + /* 05 */ MIGHTY_GAZELLE, + /* 06 */ MR_EAD, + /* 07 */ BABA, + /* 08 */ OCTOMAN, + /* 09 */ GOMAR_AND_SHIOH, + /* 10 */ KATE_ALEN, + /* 11 */ ROGER_BUSTER, + /* 12 */ JAMES_MCCLOUD, + /* 13 */ LEON, + /* 14 */ ANTONIO_GUSTER, + /* 15 */ BLACK_SHADOW, + /* 16 */ MICHAEL_CHAIN, + /* 17 */ JACK_LEVIN, + /* 18 */ SUPER_ARROW, + /* 19 */ MRS_ARROW, + /* 20 */ JOHN_TANAKA, + /* 21 */ BEASTMAN, + /* 22 */ ZODA, + /* 23 */ DR_CLASH, + /* 24 */ SILVER_NEELSEN, + /* 25 */ BIO_REX, + /* 26 */ DRAQ, + /* 27 */ BILLY, + /* 28 */ THE_SKULL, + /* 29 */ BLOOD_FALCON, +}; + +enum class CustomType { + /* 0 */ CUSTOM_MACHINE_DEFAULT, + /* 1 */ CUSTOM_MACHINE_EDITED, + /* 2 */ CUSTOM_MACHINE_SUPER_FALCON, + /* 3 */ CUSTOM_MACHINE_SUPER_STINGRAY, + /* 4 */ CUSTOM_MACHINE_SUPER_CAT, +}; + +enum class FrontType { + /* 0 */ FRONT_0, + /* 1 */ FRONT_1, + /* 2 */ FRONT_2, + /* 3 */ FRONT_3, + /* 4 */ FRONT_4, + /* 5 */ FRONT_5, + /* 6 */ FRONT_6, +}; + +enum class RearType { + /* 0 */ REAR_0, + /* 1 */ REAR_1, + /* 2 */ REAR_2, + /* 3 */ REAR_3, + /* 4 */ REAR_4, + /* 5 */ REAR_5, + /* 6 */ REAR_6, +}; + +enum class WingType { + /* 0 */ WING_NONE, + /* 1 */ WING_1, + /* 2 */ WING_2, + /* 3 */ WING_3, + /* 4 */ WING_4, + /* 5 */ WING_5, + /* 6 */ WING_6, +}; + +enum class Logo { + /* 0 */ LOGO_SHIELD, + /* 1 */ LOGO_ARROW_PLANE, + /* 2 */ LOGO_CIRCLE, + /* 3 */ LOGO_SKULL, + /* 4 */ LOGO_YELLOW_GREEN, + /* 5 */ LOGO_KANJI, + /* 6 */ LOGO_X, + /* 7 */ LOGO_N64, +}; + +enum class Decal { + /* 0 */ DECAL_STRIPE, + /* 1 */ DECAL_THIN_STRIPE, + /* 2 */ DECAL_DOUBLE_STRIPE, + /* 3 */ DECAL_TRIPLE_STRIPE_UNEVEN, + /* 4 */ DECAL_BLOCK, +}; + + +inline std::ostream& operator<<(std::ostream& out, const GhostType& ghostType) { + std::string output; + switch (ghostType) { + case GhostType::GHOST_NONE: + output = "GHOST_NONE"; + break; + case GhostType::GHOST_PLAYER: + output = "GHOST_PLAYER"; + break; + case GhostType::GHOST_STAFF: + output = "GHOST_STAFF"; + break; + case GhostType::GHOST_CELEBRITY: + output = "GHOST_CELEBRITY"; + break; + case GhostType::GHOST_CHAMP: + output = "GHOST_CHAMP"; + break; + } + return out << output; +} + +inline std::ostream& operator<<(std::ostream& out, const Character& character) { + std::string output; + switch (character) { + case Character::CAPTAIN_FALCON: + output = "CAPTAIN_FALCON"; + break; + case Character::DR_STEWART: + output = "DR_STEWART"; + break; + case Character::PICO: + output = "PICO"; + break; + case Character::SAMURAI_GOROH: + output = "SAMURAI_GOROH"; + break; + case Character::JODY_SUMMER: + output = "JODY_SUMMER"; + break; + case Character::MIGHTY_GAZELLE: + output = "MIGHTY_GAZELLE"; + break; + case Character::MR_EAD: + output = "MR_EAD"; + break; + case Character::BABA: + output = "BABA"; + break; + case Character::OCTOMAN: + output = "OCTOMAN"; + break; + case Character::GOMAR_AND_SHIOH: + output = "GOMAR_AND_SHIOH"; + break; + case Character::KATE_ALEN: + output = "KATE_ALEN"; + break; + case Character::ROGER_BUSTER: + output = "ROGER_BUSTER"; + break; + case Character::JAMES_MCCLOUD: + output = "JAMES_MCCLOUD"; + break; + case Character::LEON: + output = "LEON"; + break; + case Character::ANTONIO_GUSTER: + output = "ANTONIO_GUSTER"; + break; + case Character::BLACK_SHADOW: + output = "BLACK_SHADOW"; + break; + case Character::MICHAEL_CHAIN: + output = "MICHAEL_CHAIN"; + break; + case Character::JACK_LEVIN: + output = "JACK_LEVIN"; + break; + case Character::SUPER_ARROW: + output = "SUPER_ARROW"; + break; + case Character::MRS_ARROW: + output = "MRS_ARROW"; + break; + case Character::JOHN_TANAKA: + output = "JOHN_TANAKA"; + break; + case Character::BEASTMAN: + output = "BEASTMAN"; + break; + case Character::ZODA: + output = "ZODA"; + break; + case Character::DR_CLASH: + output = "DR_CLASH"; + break; + case Character::SILVER_NEELSEN: + output = "SILVER_NEELSEN"; + break; + case Character::BIO_REX: + output = "BIO_REX"; + break; + case Character::DRAQ: + output = "DRAQ"; + break; + case Character::BILLY: + output = "BILLY"; + break; + case Character::THE_SKULL: + output = "THE_SKULL"; + break; + case Character::BLOOD_FALCON: + output = "BLOOD_FALCON"; + break; + } + return out << output; +} + +inline std::ostream& operator<<(std::ostream& out, const CustomType& customType) { + std::string output; + switch (customType) { + case CustomType::CUSTOM_MACHINE_DEFAULT: + output = "CUSTOM_MACHINE_DEFAULT"; + break; + case CustomType::CUSTOM_MACHINE_EDITED: + output = "CUSTOM_MACHINE_EDITED"; + break; + case CustomType::CUSTOM_MACHINE_SUPER_FALCON: + output = "CUSTOM_MACHINE_SUPER_FALCON"; + break; + case CustomType::CUSTOM_MACHINE_SUPER_STINGRAY: + output = "CUSTOM_MACHINE_SUPER_STINGRAY"; + break; + case CustomType::CUSTOM_MACHINE_SUPER_CAT: + output = "CUSTOM_MACHINE_SUPER_CAT"; + break; + } + return out << output; +} + +inline std::ostream& operator<<(std::ostream& out, const FrontType& frontType) { + std::string output; + switch (frontType) { + case FrontType::FRONT_0: + output = "FRONT_0"; + break; + case FrontType::FRONT_1: + output = "FRONT_1"; + break; + case FrontType::FRONT_2: + output = "FRONT_2"; + break; + case FrontType::FRONT_3: + output = "FRONT_3"; + break; + case FrontType::FRONT_4: + output = "FRONT_4"; + break; + case FrontType::FRONT_5: + output = "FRONT_5"; + break; + case FrontType::FRONT_6: + output = "FRONT_6"; + break; + } + return out << output; +} + +inline std::ostream& operator<<(std::ostream& out, const RearType rearType) { + std::string output; + switch (rearType) { + case RearType::REAR_0: + output = "REAR_0"; + break; + case RearType::REAR_1: + output = "REAR_1"; + break; + case RearType::REAR_2: + output = "REAR_2"; + break; + case RearType::REAR_3: + output = "REAR_3"; + break; + case RearType::REAR_4: + output = "REAR_4"; + break; + case RearType::REAR_5: + output = "REAR_5"; + break; + case RearType::REAR_6: + output = "REAR_6"; + break; + } + return out << output; +} + +inline std::ostream& operator<<(std::ostream& out, const WingType& wingType) { + std::string output; + switch (wingType) { + case WingType::WING_NONE: + output = "WING_NONE"; + break; + case WingType::WING_1: + output = "WING_1"; + break; + case WingType::WING_2: + output = "WING_2"; + break; + case WingType::WING_3: + output = "WING_3"; + break; + case WingType::WING_4: + output = "WING_4"; + break; + case WingType::WING_5: + output = "WING_5"; + break; + case WingType::WING_6: + output = "WING_6"; + break; + } + return out << output; +} + +inline std::ostream& operator<<(std::ostream& out, const Logo& logo) { + std::string output; + switch (logo) { + case Logo::LOGO_SHIELD: + output = "LOGO_SHIELD"; + break; + case Logo::LOGO_ARROW_PLANE: + output = "LOGO_ARROW_PLANE"; + break; + case Logo::LOGO_CIRCLE: + output = "LOGO_CIRCLE"; + break; + case Logo::LOGO_SKULL: + output = "LOGO_SKULL"; + break; + case Logo::LOGO_YELLOW_GREEN: + output = "LOGO_YELLOW_GREEN"; + break; + case Logo::LOGO_KANJI: + output = "LOGO_KANJI"; + break; + case Logo::LOGO_X: + output = "LOGO_X"; + break; + case Logo::LOGO_N64: + output = "LOGO_N64"; + break; + } + return out << output; +} + +inline std::ostream& operator<<(std::ostream& out, const Decal& decal) { + std::string output; + switch (decal) { + case Decal::DECAL_STRIPE: + output = "DECAL_STRIPE"; + break; + case Decal::DECAL_THIN_STRIPE: + output = "DECAL_THIN_STRIPE"; + break; + case Decal::DECAL_DOUBLE_STRIPE: + output = "DECAL_DOUBLE_STRIPE"; + break; + case Decal::DECAL_TRIPLE_STRIPE_UNEVEN: + output = "DECAL_TRIPLE_STRIPE_UNEVEN"; + break; + case Decal::DECAL_BLOCK: + output = "DECAL_BLOCK"; + break; + } + return out << output; +} + +} |
