This commit is contained in:
bryanthaboi
2026-08-18 09:51:22 -04:00
parent 55616fc03d
commit 8240205254
13 changed files with 137 additions and 47 deletions
+10 -7
View File
@@ -3,8 +3,9 @@
-- instead of teaching every call site about versioned caches, this module
-- wraps EVERY read-side love entry point that accepts a filesystem path
-- once at boot: any string path under assets/generated/ or data/generated/
-- that does not resolve falls back to the active version's prefixed copy
-- (yellow|blue|gold/... ). Covering the whole read surface --
-- prefers the active version's prefixed copy (yellow|blue|gold/...) when
-- that file exists, so leftover unprefixed Red cache cannot shadow it.
-- Covering the whole read surface --
-- not just the loaders we happened to need -- is what keeps future states
-- and mods inside the fallback without anyone updating this file.
--
@@ -35,10 +36,13 @@ local NxAssetOverlay = {}
local originals -- raw love functions, non-nil while installed
-- Resolve `path` to the versioned copy when the un-prefixed file is missing
-- and the active version (Blue/Yellow/Gold) carries it. Returns nil when the
-- caller's path should be used untouched (non-generated path, the real
-- file exists, or no versioned copy).
-- Resolve `path` to the active version's prefixed copy when that file
-- exists (gold|yellow|blue|red/{assets,data}/generated/...). The versioned
-- tree wins over a leftover un-prefixed file so a pre-#899 Red root cache
-- (assets/generated/font.png in the save dir) cannot shadow Gold/Blue/
-- Yellow art that shares a name. Returns nil when the caller's path
-- should be used untouched (non-generated path, empty prefix, or no
-- versioned copy).
local function versioned(path)
if type(path) ~= "string" then return nil end
local generated = false
@@ -52,7 +56,6 @@ local function versioned(path)
if not generated then return nil end
local prefix = GameVersion.cachePrefix()
if prefix == "" then return nil end
if originals.getInfo(path) then return nil end
local candidate = prefix .. path
if originals.getInfo(candidate) then return candidate end
return nil
+1 -1
View File
@@ -34,7 +34,7 @@ local SEP = package.config:sub(1, 1)
-- Cache-relative paths are prefixed with this before every read/write, so a
-- version's import lands under its GameVersion.cachePrefix (red/, blue/,
-- yellow/). The launcher sets it per import / per readiness check; it stays
-- yellow/, gold/). The launcher sets it per import / per readiness check; it stays
-- "" outside those flows. Runtime *reads* (require / newImage) do NOT go
-- through here -- CacheFs.mountVersion overlays the active version's subtree
-- onto the un-prefixed paths instead.
+23 -12
View File
@@ -192,20 +192,28 @@ local PAL = {
chipInkGold = { 58, 44, 0 }, -- #3a2c00 dark "Y" on the gold chip
}
-- Per-version required cache files. Gold replaces the Gen 1 list entirely
-- (VERSION_REQUIRED_FILES_OVERRIDE); Yellow adds a few extra markers.
local function requiredFilesFor(version)
local override = VERSION_REQUIRED_FILES_OVERRIDE[version]
if override then return override, true end
return REQUIRED_FILES, false
end
-- CacheFs.exists checks the game folder directly for a portable install,
-- otherwise the save directory through love.filesystem. It honors
-- CacheFs.prefix, so we point it at the version's cache subtree (red/,
-- blue/, yellow/).
-- blue/, yellow/, gold/).
local function allRequiredFilesExist(version)
local CacheFs = require("src.import.CacheFs")
local saved = CacheFs.prefix
CacheFs.prefix = GameVersion.cachePrefix(version)
local ok = true
local required = VERSION_REQUIRED_FILES_OVERRIDE[version] or REQUIRED_FILES
local required, isOverride = requiredFilesFor(version)
for _, path in ipairs(required) do
if not CacheFs.exists(path) then ok = false; break end
end
if ok and not VERSION_REQUIRED_FILES_OVERRIDE[version] then
if ok and not isOverride then
for _, path in ipairs(VERSION_REQUIRED_FILES[version] or {}) do
if not CacheFs.exists(path) then ok = false; break end
end
@@ -215,20 +223,23 @@ local function allRequiredFilesExist(version)
end
-- A developer checkout / Python build leaves generated data in the physfs
-- source: Red at the historical root, Blue/Yellow in their versioned trees.
-- Imported Red caches still live under red/. Check source paths directly so
-- that cache prefix cannot hide Red's source tree, and keep save-dir caches
-- from counting as current source data.
-- source: Red at the historical root, Blue/Yellow/Gold in their versioned
-- trees. Imported Red caches still live under red/. Check source paths
-- directly so that cache prefix cannot hide Red's source tree, and keep
-- save-dir caches from counting as current source data.
local function sourceTreeHasData(version)
if not love.filesystem.getRealDirectory then return false end
local prefix = version == "red" and "" or GameVersion.cachePrefix(version)
for _, path in ipairs(REQUIRED_FILES) do
local required, isOverride = requiredFilesFor(version)
for _, path in ipairs(required) do
if love.filesystem.getInfo(prefix .. path, "file") == nil then return false end
end
for _, path in ipairs(VERSION_REQUIRED_FILES[version] or {}) do
if love.filesystem.getInfo(prefix .. path, "file") == nil then return false end
if not isOverride then
for _, path in ipairs(VERSION_REQUIRED_FILES[version] or {}) do
if love.filesystem.getInfo(prefix .. path, "file") == nil then return false end
end
end
local path = prefix .. REQUIRED_FILES[1]
local path = prefix .. required[1]
local real = love.filesystem.getRealDirectory(path)
return real == love.filesystem.getSource()
end
@@ -285,7 +296,7 @@ local function purgeSaveDirCache()
return true
end
-- Purge each version's stale save-directory copy (under its red/ / blue/
-- / yellow/ prefix) so it cannot shadow the portable game-folder cache.
-- / yellow/ / gold/ prefix) so it cannot shadow the portable game-folder cache.
for _, version in ipairs(GameVersion.ORDER) do
local prefix = GameVersion.cachePrefix(version)
if saveDirHas(prefix .. MARKER_PATH) or saveDirHas(prefix .. REQUIRED_FILES[1]) then
+1 -1
View File
@@ -141,7 +141,7 @@ function SaveFileIO.exportActiveSlot(version)
fs.createDirectory("exports")
fs.createDirectory("exports/" .. version)
end
-- Per-game folder so MTP browsing matches inbox layout (red/blue/yellow).
-- Per-game folder so MTP browsing matches inbox layout (red/blue/yellow/gold).
local rel = ("exports/%s/gen1recomp-%s-%s.sav"):format(version, version, slotId)
local ok, writeErr = fs.write(rel, bytes)
if not ok then return false, "could not write the export: " .. tostring(writeErr) end