From 9edbe8cf2d50bd7c5e597120040160c1fa57b3db Mon Sep 17 00:00:00 2001 From: Kae <80987908+Novaenia@users.noreply.github.com> Date: Tue, 25 Jun 2024 19:56:44 +1000 Subject: [PATCH] Add .patchlist #73 --- source/base/StarAssets.cpp | 52 +++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/source/base/StarAssets.cpp b/source/base/StarAssets.cpp index 68e307a..9fbb66d 100644 --- a/source/base/StarAssets.cpp +++ b/source/base/StarAssets.cpp @@ -104,6 +104,7 @@ Maybe FramesSpecification::getRect(String const& frame) const { Assets::Assets(Settings settings, StringList assetSources) { const char* AssetsPatchSuffix = ".patch"; + const char* AssetsPatchListSuffix = ".patchlist"; const char* AssetsLuaPatchSuffix = ".patch.lua"; m_settings = std::move(settings); @@ -204,6 +205,24 @@ Assets::Assets(Settings settings, StringList assetSources) { auto targetPatchFile = filename.substr(0, filename.size() - strlen(AssetsLuaPatchSuffix)); if (auto p = m_files.ptr(targetPatchFile)) p->patchSources.append({filename, source}); + } else if (filename.endsWith(AssetsPatchListSuffix, String::CaseInsensitive)) { + auto stream = source->read(filename); + size_t patchIndex = 0; + for (auto const& patchPair : inputUtf8Json(stream.begin(), stream.end(), JsonParseType::Top).iterateArray()) { + auto& patches = patchPair.getArray("patches"); + for (auto& path : patchPair.getArray("paths")) { + if (auto p = m_files.ptr(path.toString())) { + for (size_t i = 0; i != patches.size(); ++i) { + auto& patch = patches[i]; + if (patch.isType(Json::Type::String)) + p->patchSources.append({patch.toString(), source}); + else + p->patchSources.append({strf("{}:[{}].patches[{}]", filename, patchIndex, i), source}); + } + } + } + patchIndex++; + } } else { for (int i = 0; i < 10; i++) { if (filename.endsWith(AssetsPatchSuffix + toString(i), String::CaseInsensitive)) { @@ -289,7 +308,7 @@ Assets::Assets(Settings settings, StringList assetSources) { digest.push(assetPath); digest.push(DataStreamBuffer::serialize(descriptor.source->open(descriptor.sourceName)->size())); for (auto const& pair : descriptor.patchSources) - digest.push(DataStreamBuffer::serialize(pair.second->open(pair.first)->size())); + digest.push(DataStreamBuffer::serialize(pair.second->open(AssetPath::removeSubPath(pair.first))->size())); } } @@ -956,32 +975,35 @@ Json Assets::readJson(String const& path) const { try { Json result = inputUtf8Json(streamData.begin(), streamData.end(), JsonParseType::Top); for (auto const& pair : m_files.get(path).patchSources) { - auto& patchPath = pair.first; + auto patchAssetPath = AssetPath::split(pair.first); + auto& patchBasePath = patchAssetPath.basePath; auto& patchSource = pair.second; - auto patchStream = patchSource->read(patchPath); - if (patchPath.endsWith(".lua")) { + auto patchStream = patchSource->read(patchBasePath); + if (patchBasePath.endsWith(".lua")) { RecursiveMutexLocker luaLocker(m_luaMutex); // Kae: i don't like that lock. perhaps have a LuaEngine and patch context cache per worker thread later on? - LuaContextPtr& context = m_patchContexts[patchPath]; + LuaContextPtr& context = m_patchContexts[patchBasePath]; if (!context) { context = make_shared(as(m_luaEngine.get())->createContext()); - context->load(patchStream, patchPath); + context->load(patchStream, patchBasePath); } auto newResult = context->invokePath("patch", result, path); if (newResult) result = std::move(newResult); } else { auto patchJson = inputUtf8Json(patchStream.begin(), patchStream.end(), JsonParseType::Top); + if (patchAssetPath.subPath) + patchJson = patchJson.query(*patchAssetPath.subPath); if (patchJson.isType(Json::Type::Array)) { - auto patchData = patchJson.toArray(); - try { - result = checkPatchArray(patchPath, patchSource, result, patchData, {}); - } catch (JsonPatchTestFail const& e) { - Logger::debug("Patch test failure from file {} in source: '{}' at '{}'. Caused by: {}", patchPath, patchSource->metadata().value("name", ""), m_assetSourcePaths.getLeft(patchSource), e.what()); - } catch (JsonPatchException const& e) { - Logger::error("Could not apply patch from file {} in source: '{}' at '{}'. Caused by: {}", patchPath, patchSource->metadata().value("name", ""), m_assetSourcePaths.getLeft(patchSource), e.what()); - } - } else if (patchJson.isType(Json::Type::Object)) {//Kae: Do a good ol' json merge instead if the .patch file is a Json object + auto patchData = patchJson.toArray(); + try { + result = checkPatchArray(pair.first, patchSource, result, patchData, {}); + } catch (JsonPatchTestFail const& e) { + Logger::debug("Patch test failure from file {} in source: '{}' at '{}'. Caused by: {}", pair.first, patchSource->metadata().value("name", ""), m_assetSourcePaths.getLeft(patchSource), e.what()); + } catch (JsonPatchException const& e) { + Logger::error("Could not apply patch from file {} in source: '{}' at '{}'. Caused by: {}", pair.first, patchSource->metadata().value("name", ""), m_assetSourcePaths.getLeft(patchSource), e.what()); + } + } else if (patchJson.isType(Json::Type::Object)) { result = jsonMergeNulling(result, patchJson.toObject()); } }