#pragma once #include "ResourceType.h" #include "n64/Cartridge.h" #include #include #include #include #include #include #include #include #include #include #include #include "lib/binarytools/BinaryWriter.h" #include "lib/binarytools/BinaryReader.h" #ifdef BUILD_UI #define IMGUI_DEFINE_MATH_OPERATORS #include "imgui.h" #endif namespace fs = std::filesystem; struct ParseResultData; #define REGISTER(type, c) { ExportType::type, std::make_shared() }, #define SEGMENT_OFFSET(a) ((uint32_t)(a) & 0x00FFFFFF) #define SEGMENT_NUMBER(x) (((uint32_t)(x) >> 24) & 0xFF) // I would love to use 0x01000000, but the stupid compiler takes it as 0x01 #define IS_SEGMENTED(x) ((SEGMENT_NUMBER(x) > 0) && (SEGMENT_NUMBER(x) < 0x20)) #define IS_VIRTUAL_SEGMENT(x) (SEGMENT_NUMBER(x) >= 0x80) #define ASSET_PTR(x) ((IS_SEGMENTED(x) || IS_VIRTUAL_SEGMENT(x)) ? SEGMENT_OFFSET(x) : (x)) #define tab_t "\t" #define fourSpaceTab " " struct OffsetEntry { uint32_t start; uint32_t end; }; typedef std::optional> ExportResult; enum class ExportType { Header, Code, Binary, Modding, XML }; template std::optional GetNode(YAML::Node& node, const std::string& key) { if(!node[key]) { return std::nullopt; } return std::optional(node[key].as()); } template T GetSafeNode(YAML::Node& node, const std::string& key) { if(!node[key]) { auto dump = YAML::Dump(node); if (node["symbol"]) { throw std::runtime_error("Yaml asset missing the '" + key + "' node for '" + node["symbol"].as() + "'\nProblematic YAML:\n" + dump); } else { throw std::runtime_error("Yaml asset missing the '" + key + "' node\nProblematic YAML:\n" + dump); } } return node[key].as(); } template T GetSafeNode(YAML::Node& node, const std::string& key, const T& def) { if(!node[key]) { return def; } return node[key].as(); } class IParsedData{}; template class GenericData : public IParsedData { public: T mData; }; class BaseExporter { public: virtual ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) = 0; static void WriteHeader(LUS::BinaryWriter& write, Torch::ResourceType resType, int32_t version); }; class BaseFactory { public: virtual std::optional> parse(std::vector& buffer, YAML::Node& data) = 0; virtual std::optional> parse_modding(std::vector& buffer, YAML::Node& data) { return std::nullopt; } std::optional> GetExporter(ExportType type) { auto exporters = this->GetExporters(); if (exporters.find(type) != exporters.end()) { return exporters[type]; } return std::nullopt; } virtual bool SupportModdedAssets() { return false; } virtual bool HasModdedDependencies() { return false; } virtual uint32_t GetAlignment() { return 4; } virtual bool IsDialogPackRoot() const { return false; } virtual void PreprocessConfig(YAML::Node& cfg, N64::Cartridge* cart) {} virtual std::optional> CreateDataPointer() { return std::nullopt; } // When true, the viewer's default preview renders this factory's Code // exporter output as read-only text. Only enable for exporters that just // format to the stream (no file writes or other side effects). virtual bool CanPreviewCode() { return false; } private: virtual std::unordered_map> GetExporters() { return {}; } }; #ifdef BUILD_UI // Base preview renderer. The default implementation (see BaseFactory.cpp) shows // the asset's Code-exporter text when the factory opts in via CanPreviewCode(), // otherwise its YAML config. Subclasses override DrawUI for richer visuals. class BaseFactoryUI { public: virtual ~BaseFactoryUI() = default; virtual float GetItemHeight(const ParseResultData& data); virtual void DrawUI(const ParseResultData& data); }; #endif