diff --git a/src/Companion.cpp b/src/Companion.cpp index b6d26052..886f1522 100644 --- a/src/Companion.cpp +++ b/src/Companion.cpp @@ -185,26 +185,35 @@ void Companion::ExtractNode(YAML::Node& node, std::string& name, SWrapper* binar } std::optional> result; - if(this->gConfig.modding) { - if(impl->SupportModdedAssets() && this->gModdedAssetPaths.contains(name)) { - - auto path = fs::path(this->gConfig.moddingPath) / this->gModdedAssetPaths[name]; - if(!fs::exists(path)) { - SPDLOG_ERROR("Modded asset {} not found", this->gModdedAssetPaths[name]); - return; - } + if(this->gConfig.modding && impl->SupportModdedAssets() && this->gModdedAssetPaths.contains(name)) { + auto path = fs::path(this->gConfig.moddingPath) / this->gModdedAssetPaths[name]; + if(!fs::exists(path)) { + SPDLOG_ERROR("Modded asset {} not found", this->gModdedAssetPaths[name]); + return; + } - std::ifstream input(path, std::ios::binary); - std::vector data = std::vector( std::istreambuf_iterator( input ), {}); - input.close(); + std::ifstream input(path, std::ios::binary); + std::vector data = std::vector( std::istreambuf_iterator( input ), {}); + input.close(); - result = factory->get()->parse_modding(data, node); + result = impl->parse_modding(data, node); + } else if(this->gNodeIsCacheable && impl->IsCacheable()) { + if(this->gCacheData.contains(name)) { + result = std::make_shared(); + result->get()->FromCacheBuffer(this->gCacheData[name]); } else { - result = factory->get()->parse(this->gRomData, node); + result = impl->parse(this->gRomData, node); + if(result.has_value()) { + auto cache = result.value()->ToCacheBuffer(); + if(cache.has_value()) { + this->StoreCache(cache.value()); + } + } } } else { - result = factory->get()->parse(this->gRomData, node); + result = impl->parse(this->gRomData, node); } + if(!result.has_value()){ SPDLOG_ERROR("Failed to process {}", name); return; @@ -394,6 +403,46 @@ void Companion::ParseCurrentFileConfig(YAML::Node node) { } this->gEnablePadGen = GetSafeNode(node, "autopads", true); + this->gNodeIsCacheable = GetSafeNode(node, "cacheable", true); +} + +void Companion::PrepareCache(const std::string& path) { + std::ifstream yaml(path); + const std::vector data = std::vector(std::istreambuf_iterator( yaml ), {}); + this->gCurrentCacheHash = CalculateHash(data); + + const std::string out = "torch.cache.yml"; + YAML::Node root; + + if(fs::exists(out)) { + root = YAML::LoadFile(out); + } else { + root = YAML::Node(); + } + + if(root[this->gCurrentCacheHash]) { + const auto cache = GetSafeNode(root, this->gCurrentCacheHash); + if(cache == this->gCurrentCacheHash) { + std::ifstream file("cache/" + cache, std::ios::binary); + this->gCacheData[cache] = std::vector(std::istreambuf_iterator( file ), {}); + file.close(); + } else { + root[path] = this->gCurrentCacheHash; + fs::remove("cache/" + cache); + } + } else { + root[path] = this->gCurrentCacheHash; + } + + std::ofstream file(out, std::ios::binary); + file << root; + file.close(); +} + +void Companion::StoreCache(const std::vector& value) { + std::ofstream file("cache/" + this->gCurrentCacheHash, std::ios::binary); + file.write(reinterpret_cast(value.data()), value.size()); + file.close(); } void Companion::Process() { @@ -570,6 +619,8 @@ void Companion::Process() { this->gCurrentDirectory = relative(entry.path(), path).replace_extension(""); this->gCurrentFile = yamlPath; + this->PrepareCache(yamlPath); + // Set compressed file offsets and compression type if (auto segments = root[":config"]["segments"]) { if (segments.IsSequence() && segments.size() > 0) { @@ -656,6 +707,10 @@ void Companion::Process() { this->ParseCurrentFileConfig(root[":config"]); } + if(this->gNodeIsCacheable) { + this->PrepareCache(yamlPath); + } + spdlog::set_pattern(regular); SPDLOG_INFO("------------------------------------------------"); spdlog::set_pattern(line); @@ -669,7 +724,6 @@ void Companion::Process() { continue; } - // Parse horizontal assets if(assetNode["files"]){ auto segment = assetNode["segment"] ? assetNode["segment"].as() : -1; @@ -1079,11 +1133,14 @@ std::optional Companion::AddAsset(YAML::Node asset) { } auto rom = this->GetRomData(); - auto factory = this->GetFactory(type)->get(); + auto factory = this->GetFactory(type); + + if(!factory.has_value()) { + return std::nullopt; + } std::string output; std::string typeId = ConvertType(type); - int index; if(symbol != "") { output = symbol; @@ -1095,10 +1152,10 @@ std::optional Companion::AddAsset(YAML::Node asset) { asset["autogen"] = true; asset["symbol"] = output; - auto result = factory->parse(rom, asset); + auto result = this->RegisterAsset(output, asset); if(result.has_value()){ - return std::get<1>(this->RegisterAsset(output, asset).value()); + return std::get<1>(result.value()); } return std::nullopt; diff --git a/src/Companion.h b/src/Companion.h index 748efbbf..8fcde4ae 100644 --- a/src/Companion.h +++ b/src/Companion.h @@ -85,6 +85,9 @@ class Companion { } void Init(ExportType type); + + void PrepareCache(const std::string& string); + void Process(); bool IsOTRMode() const { return this->gConfig.otrMode; } @@ -122,8 +125,10 @@ class Companion { TorchConfig gConfig; YAML::Node gModdingConfig; fs::path gCurrentDirectory; + std::string gCurrentCacheHash; std::vector gRomData; std::filesystem::path gRomPath; + bool gNodeIsCacheable; std::shared_ptr gCartridge; std::unordered_map> gEnums; @@ -140,6 +145,7 @@ class Companion { std::variant, std::string> gWriteOrder; std::unordered_map> gFactories; std::unordered_map gModdedAssetPaths; + std::unordered_map> gCacheData; std::unordered_map>> gWriteMap; std::unordered_map>> gAssetDependencies; std::unordered_map>> gAddrMap; @@ -148,5 +154,8 @@ class Companion { void ParseModdingConfig(); void ParseCurrentFileConfig(YAML::Node node); void RegisterFactory(const std::string& type, const std::shared_ptr& factory); + + void StoreCache(const std::vector& value); + void ExtractNode(YAML::Node& node, std::string& name, SWrapper* binary); }; diff --git a/src/factories/BaseFactory.h b/src/factories/BaseFactory.h index 18c03ef2..5dc8b819 100644 --- a/src/factories/BaseFactory.h +++ b/src/factories/BaseFactory.h @@ -71,7 +71,16 @@ T GetSafeNode(YAML::Node& node, const std::string& key, const T& def) { return node[key].as(); } -class IParsedData {}; +class IParsedData { +public: + virtual std::optional> ToCacheBuffer() { + return std::nullopt; + } + + virtual void FromCacheBuffer(std::vector& buffer) { + + } +}; template class GenericData : public IParsedData { @@ -103,7 +112,10 @@ class BaseFactory { } virtual uint32_t GetAlignment() { return 4; - }; + } + virtual bool IsCacheable() { + return false; + } private: virtual std::unordered_map> GetExporters() = 0; }; \ No newline at end of file