From b56eefab94bc7ee42f18b2b943f65af5859c0518 Mon Sep 17 00:00:00 2001 From: KiritoDv Date: Tue, 12 Mar 2024 21:43:59 -0600 Subject: Implemented ObjectInit factory and added an enum system --- src/Companion.cpp | 66 +++++++++++++++++++++++++++++++++ src/Companion.h | 5 ++- src/factories/ResourceType.h | 1 + src/factories/sf64/ObjInitFactory.cpp | 69 +++++++++++++++++++++++++++++++++++ src/factories/sf64/ObjInitFactory.h | 50 +++++++++++++++++++++++++ 5 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 src/factories/sf64/ObjInitFactory.cpp create mode 100644 src/factories/sf64/ObjInitFactory.h diff --git a/src/Companion.cpp b/src/Companion.cpp index 754a92e..806e6a1 100644 --- a/src/Companion.cpp +++ b/src/Companion.cpp @@ -34,6 +34,8 @@ #include "factories/sf64/AnimFactory.h" #include "factories/sf64/ScriptFactory.h" #include "factories/sf64/HitboxFactory.h" +#include "factories/sf64/ObjInitFactory.h" +#include using namespace std::chrono; namespace fs = std::filesystem; @@ -77,11 +79,56 @@ void Companion::Init(const ExportType type) { this->RegisterFactory("SF64:MSG_TABLE", std::make_shared()); this->RegisterFactory("SF64:SCRIPT", std::make_shared()); this->RegisterFactory("SF64:HITBOX", std::make_shared()); + this->RegisterFactory("SF64:OBJECT_INIT", std::make_shared()); this->Process(); } +void Companion::ParseEnums(std::string& header) { + std::ifstream file(header); + + if (!file.is_open()) { + throw std::runtime_error("Failed to open file"); + } + + std::regex enumRegex(R"(enum\s+(\w+)\s*(?:\s*:\s*(\w+))?[\s\n\r]*\{)"); + + std::string line; + std::smatch match; + std::string enumName; + + bool inEnum = false; + + while (std::getline(file, line)) { + if (!inEnum && std::regex_search(line, match, enumRegex) && match.size() > 1) { + enumName = match.str(1); + inEnum = true; + continue; + } + + if(!inEnum) { + continue; + } + + if(line.find("}") != std::string::npos) { + inEnum = false; + continue; + } + + // Remove any comments and non-alphanumeric characters + line = std::regex_replace(line, std::regex(R"((/\*.*?\*/)|([^a-zA-Z0-9=_\-\.]))"), ""); + + if(line.find("=") != std::string::npos) { + auto name = line.substr(0, line.find("=")); + auto value = line.substr(line.find("=") + 1); + this->gEnums[enumName][value.starts_with("-") ? -std::stoi(value.substr(1)) : std::stoi(value)] = name; + } else { + this->gEnums[enumName][this->gEnums[enumName].size()] = line; + } + } +} + void Companion::ExtractNode(YAML::Node& node, std::string& name, SWrapper* binary) { std::ostringstream stream; @@ -409,6 +456,13 @@ void Companion::Process() { } } + if(cfg["enums"]) { + auto enums = GetSafeNode>(cfg, "enums"); + for (auto& file : enums) { + this->ParseEnums(file); + } + } + SPDLOG_INFO("------------------------------------------------"); spdlog::set_pattern(line); @@ -806,6 +860,18 @@ std::optional Companion::SearchTable(uint32_t addr){ return std::nullopt; } +std::optional Companion::GetEnumFromValue(const std::string& key, int32_t id) { + if(!this->gEnums.contains(key)){ + return std::nullopt; + } + + if(!this->gEnums[key].contains(id)){ + return std::nullopt; + } + + return this->gEnums[key][id]; +} + std::optional Companion::GetFileOffsetFromSegmentedAddr(const uint8_t segment) const { auto segments = this->gConfig.segment; diff --git a/src/Companion.h b/src/Companion.h index 1ed5470..754befa 100644 --- a/src/Companion.h +++ b/src/Companion.h @@ -89,6 +89,7 @@ public: GBIVersion GetGBIVersion() const { return this->gConfig.gbi.version; } GBIMinorVersion GetGBIMinorVersion() const { return this->gConfig.gbi.subversion; } + std::optional GetEnumFromValue(const std::string& key, int id); std::optional GetFileOffsetFromSegmentedAddr(uint8_t segment) const; std::optional> GetNodeByAddr(uint32_t addr); @@ -116,6 +117,7 @@ private: std::vector gRomData; std::filesystem::path gRomPath; std::shared_ptr gCartridge; + std::unordered_map> gEnums; // Temporal Variables std::string gCurrentFile; @@ -133,8 +135,9 @@ private: std::unordered_map>>> gWriteMap; std::unordered_map>> gAddrMap; - void ParseCurrentFileConfig(YAML::Node node); + void ParseEnums(std::string& file); void ParseModdingConfig(); + void ParseCurrentFileConfig(YAML::Node node); void RegisterFactory(const std::string& type, const std::shared_ptr& factory); void ExtractNode(YAML::Node& node, std::string& name, SWrapper* binary); }; diff --git a/src/factories/ResourceType.h b/src/factories/ResourceType.h index c8d9257..85acd48 100644 --- a/src/factories/ResourceType.h +++ b/src/factories/ResourceType.h @@ -39,5 +39,6 @@ enum class ResourceType { Skeleton = 0x534B454C, // SKEL Script = 0x53435250, // SCRP Hitbox = 0x48544258, // HTBX + ObjectInit = 0x4F42494E, // OBIN }; } // namespace LUS diff --git a/src/factories/sf64/ObjInitFactory.cpp b/src/factories/sf64/ObjInitFactory.cpp new file mode 100644 index 0000000..4b5c21a --- /dev/null +++ b/src/factories/sf64/ObjInitFactory.cpp @@ -0,0 +1,69 @@ +#include "ObjInitFactory.h" +#include "utils/Decompressor.h" +#include "Companion.h" + +#define NUM(x, w) std::dec << std::setfill(' ') << std::setw(w) << x + +void SF64::ObjInitCodeExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto symbol = GetSafeNode(node, "symbol", entryName); + auto objs = std::static_pointer_cast(raw)->mObjInit; + + write << "ObjectInit " << symbol << "[] = {\n"; + for(auto& obj : objs) { + auto enumName = Companion::Instance->GetEnumFromValue("ObjectId", obj.id).value_or(std::to_string(obj.id)); + write << fourSpaceTab << "{ "; + write << NUM(obj.zPos1, 8) << "f, "; + write << NUM(obj.zPos2, 7) << ", "; + write << NUM(obj.xPos, 7) << ", "; + write << NUM(obj.yPos, 7) << ", "; + write << "{ " << NUM(obj.rot.x, 3) << ", " << NUM(obj.rot.y, 3) << ", " << NUM(obj.rot.z, 3) << " }, "; + write << enumName << " },\n"; + } + write << "};\n\n"; +} + +void SF64::ObjInitBinaryExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto writer = LUS::BinaryWriter(); + auto data = std::static_pointer_cast(raw)->mObjInit; + + WriteHeader(writer, LUS::ResourceType::ObjectInit, 0); + writer.Write((uint32_t) data.size()); + for(auto& obj : data) { + writer.Write(obj.zPos1); + writer.Write(obj.zPos2); + writer.Write(obj.xPos); + writer.Write(obj.yPos); + writer.Write(obj.rot.x); + writer.Write(obj.rot.y); + writer.Write(obj.rot.z); + writer.Write(obj.id); + } + writer.Finish(write); +} + +std::optional> SF64::ObjInitFactory::parse(std::vector& buffer, YAML::Node& node) { + auto [_, segment] = Decompressor::AutoDecode(node, buffer); + + LUS::BinaryReader reader(segment.data, segment.size); + reader.SetEndianness(LUS::Endianness::Big); + std::vector objects; + + bool processing = true; + while(processing) { + float zPos1 = reader.ReadFloat(); + int16_t zPos2 = reader.ReadInt16(); + int16_t xPos = reader.ReadInt16(); + int16_t yPos = reader.ReadInt16(); + int16_t rotX = reader.ReadInt16(); + int16_t rotY = reader.ReadInt16(); + int16_t rotZ = reader.ReadInt16(); + int16_t id = reader.ReadInt16(); + reader.ReadInt16(); + + processing = id != -1; + + objects.push_back({ zPos1, zPos2, xPos, yPos, {rotX, rotY, rotZ}, id}); + } + + return std::make_shared(objects); +} \ No newline at end of file diff --git a/src/factories/sf64/ObjInitFactory.h b/src/factories/sf64/ObjInitFactory.h new file mode 100644 index 0000000..a6aba31 --- /dev/null +++ b/src/factories/sf64/ObjInitFactory.h @@ -0,0 +1,50 @@ +#pragma once + +#include "../BaseFactory.h" + +namespace SF64 { +struct Vec3s { + /* 0x0 */ int16_t x; + /* 0x2 */ int16_t y; + /* 0x4 */ int16_t z; +}; // size = 0x6; + +struct ObjectInit { + /* 0x00 */ float zPos1; + /* 0x04 */ int16_t zPos2; + /* 0x06 */ int16_t xPos; + /* 0x08 */ int16_t yPos; + /* 0x0A */ Vec3s rot; + /* 0x10 */ int16_t id; +}; + +class ObjInitData : public IParsedData { +public: + std::vector mObjInit; + + explicit ObjInitData(std::vector objInit) : mObjInit(objInit) {} +}; + +class ObjInitBinaryExporter : public BaseExporter { + void Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class ObjInitCodeExporter : public BaseExporter { + void Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class ObjInitFactory : public BaseFactory { +public: + std::optional> parse(std::vector& buffer, YAML::Node& data) override; + std::optional> parse_modding(std::vector& buffer, YAML::Node& data) override { + return std::nullopt; + } + inline std::unordered_map> GetExporters() override { + return { + REGISTER(Binary, ObjInitBinaryExporter) + REGISTER(Code, ObjInitCodeExporter) + }; + } + bool SupportModdedAssets() override { return false; } +}; +} \ No newline at end of file -- cgit v1.2.3