mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-20 12:40:21 +02:00
ingested
This commit is contained in:
+13
-9
@@ -3,7 +3,7 @@
|
|||||||
Every GitHub Release that includes Switch support ships an SD-ready zip:
|
Every GitHub Release that includes Switch support ships an SD-ready zip:
|
||||||
`gen1recomp-*-switch.zip`. Extract it at the root of your microSD (install
|
`gen1recomp-*-switch.zip`. Extract it at the root of your microSD (install
|
||||||
or update, same steps), launch with **title override**, then import your
|
or update, same steps), launch with **title override**, then import your
|
||||||
own legal `.gb` ROM.
|
own legal `.gb` / `.gbc` ROM.
|
||||||
|
|
||||||
> You need a console that can run Switch homebrew (custom firmware / hbmenu).
|
> You need a console that can run Switch homebrew (custom firmware / hbmenu).
|
||||||
> This project does not help you set that up.
|
> This project does not help you set that up.
|
||||||
@@ -91,13 +91,14 @@ Do **not** launch from the Album applet path for normal play.
|
|||||||
|
|
||||||
This project ships **no** game data. On first launch:
|
This project ships **no** game data. On first launch:
|
||||||
|
|
||||||
1. Put your own legally obtained Pokémon Red, Blue (`.gb`), or Yellow
|
1. Put your own legally obtained Pokémon Red, Blue (`.gb`), Yellow, or
|
||||||
(`.gbc`) dump into `switch/gen1recomp/pokemon-love2d/imports/` (the
|
Gold (`.gbc`) dump into `switch/gen1recomp/pokemon-love2d/imports/` (the
|
||||||
launcher also shows the live save-dir path). All three can sit in the
|
launcher also shows the live save-dir path). All four can sit in the
|
||||||
same folder.
|
same folder.
|
||||||
2. Use **Scan again** on that game's tab (Red / Blue / Yellow). Rescan
|
2. Use **Scan again** on that game's tab (Red / Blue / Yellow / Gold).
|
||||||
matches by ROM SHA-1 for the open tab only. A Red dump never imports
|
Rescan matches by ROM SHA-1 for the open tab only. A Red dump never
|
||||||
from the Yellow tab (and vice versa).
|
imports from the Yellow tab (and vice versa). Gold is Beta in the
|
||||||
|
launcher; a clean US Gold dump is enough to Play.
|
||||||
|
|
||||||
## 5. Import / Export a raw `.sav`
|
## 5. Import / Export a raw `.sav`
|
||||||
|
|
||||||
@@ -109,10 +110,13 @@ SD / FTP, same transfer methods as ROMs. Paths are **per game**:
|
|||||||
| Red | `imports/saves/red/` | `exports/red/` |
|
| Red | `imports/saves/red/` | `exports/red/` |
|
||||||
| Blue | `imports/saves/blue/` | `exports/blue/` |
|
| Blue | `imports/saves/blue/` | `exports/blue/` |
|
||||||
| Yellow | `imports/saves/yellow/` | `exports/yellow/` |
|
| Yellow | `imports/saves/yellow/` | `exports/yellow/` |
|
||||||
|
| Gold | `imports/saves/gold/` | `exports/gold/` |
|
||||||
|
|
||||||
(Under the save dir `pokemon-love2d/`. The zip already creates these folders.)
|
(Under the save dir `pokemon-love2d/`. The zip already creates these folders.
|
||||||
|
Gold cart `.sav` import/export is not supported yet -- the folders exist so
|
||||||
|
MTP browsing matches the other games. Gold progress still saves in-engine.)
|
||||||
|
|
||||||
1. Copy a Gen1 `.sav` (32 KB) into that game's inbox under the save dir
|
1. Copy a Gen 1 `.sav` (32 KB) into that game's inbox under the save dir
|
||||||
([switch-transfer.md](switch-transfer.md)).
|
([switch-transfer.md](switch-transfer.md)).
|
||||||
2. With the game's ROM already imported, open **that game's tab** →
|
2. With the game's ROM already imported, open **that game's tab** →
|
||||||
**SAVE FILES** → **Import save**. Only that folder is scanned.
|
**SAVE FILES** → **Import save**. Only that folder is scanned.
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ Player install (what to download, title override) stays in
|
|||||||
| Loose iteration pair | `sdmc:/switch/gen1recomp/gen1recomp.nro` **and** `game.love` beside it |
|
| Loose iteration pair | `sdmc:/switch/gen1recomp/gen1recomp.nro` **and** `game.love` beside it |
|
||||||
| ROM inbox | LÖVE save dir → `imports/` (launcher shows the live `getSaveDirectory()` path; under MTP often `1: SD Card/<save identity>/imports/`) |
|
| ROM inbox | LÖVE save dir → `imports/` (launcher shows the live `getSaveDirectory()` path; under MTP often `1: SD Card/<save identity>/imports/`) |
|
||||||
| Mod zip inbox | Same save dir → `imports/mods/` then MODS → **Scan again** |
|
| Mod zip inbox | Same save dir → `imports/mods/` then MODS → **Scan again** |
|
||||||
| Save `.sav` inbox | Same save dir → `imports/saves/red\|blue\|yellow/` then that game's SAVE FILES → **Import save** |
|
| Save `.sav` inbox | Same save dir → `imports/saves/red\|blue\|yellow\|gold/` then that game's SAVE FILES → **Import save** (Gold cart `.sav` not supported yet) |
|
||||||
| Save exports | Same save dir → `exports/red\|blue\|yellow/` (pull after **Export save**; MTP / SD / FTP) |
|
| Save exports | Same save dir → `exports/red\|blue\|yellow\|gold/` (pull after **Export save**; Gold cart `.sav` not supported yet) |
|
||||||
| Opt-in diagnostics | Empty `switch-debug.txt` in the save dir → `switch.log` |
|
| Opt-in diagnostics | Empty `switch-debug.txt` in the save dir → `switch.log` |
|
||||||
| Lua error log | `lua-error.log` in the save dir |
|
| Lua error log | `lua-error.log` in the save dir |
|
||||||
|
|
||||||
@@ -54,8 +54,8 @@ macOS, not a Mac-only requirement.
|
|||||||
3. Create `switch/gen1recomp/` if needed; extract the release zip at SD root
|
3. Create `switch/gen1recomp/` if needed; extract the release zip at SD root
|
||||||
(or copy NRO / `game.love` for loose).
|
(or copy NRO / `game.love` for loose).
|
||||||
4. For ROMs/mods/saves, open the save-dir `imports/`, `imports/mods/`,
|
4. For ROMs/mods/saves, open the save-dir `imports/`, `imports/mods/`,
|
||||||
`imports/saves/<red|blue|yellow>/`, or `exports/<red|blue|yellow>/` path the
|
`imports/saves/<red|blue|yellow|gold>/`, or `exports/<red|blue|yellow|gold>/`
|
||||||
launcher prints.
|
path the launcher prints.
|
||||||
5. Wait for the queue; refresh; exit MTP responder; title-override launch.
|
5. Wait for the queue; refresh; exit MTP responder; title-override launch.
|
||||||
|
|
||||||
macOS clients often create AppleDouble sidecars (`._Something.zip`,
|
macOS clients often create AppleDouble sidecars (`._Something.zip`,
|
||||||
|
|||||||
@@ -71,15 +71,15 @@ First install or update (same steps):
|
|||||||
your saves, imported ROMs, mods, and options. Re-extracting only
|
your saves, imported ROMs, mods, and options. Re-extracting only
|
||||||
replaces the NRO(s) and these help files.
|
replaces the NRO(s) and these help files.
|
||||||
3. Launch with title override (hold R on HOME, open any title → hbmenu).
|
3. Launch with title override (hold R on HOME, open any title → hbmenu).
|
||||||
4. Copy a legal Pokemon Red/Blue .gb into:
|
4. Copy a legal Pokemon Red/Blue .gb or Yellow/Gold .gbc into:
|
||||||
switch/gen1recomp/pokemon-love2d/imports/
|
switch/gen1recomp/pokemon-love2d/imports/
|
||||||
then use Scan again in the launcher if needed.
|
then use Scan again in the launcher if needed.
|
||||||
|
|
||||||
Inboxes (drop files here via MTP / SD / FTP):
|
Inboxes (drop files here via MTP / SD / FTP):
|
||||||
imports/ — ROM .gb / .gbc
|
imports/ — ROM .gb / .gbc
|
||||||
imports/mods/ — community mod .zip
|
imports/mods/ — community mod .zip
|
||||||
imports/saves/red|blue|yellow/ — raw .sav import
|
imports/saves/red|blue|yellow|gold/ — raw .sav import (Gold cart .sav not yet)
|
||||||
exports/red|blue|yellow/ — pull after Export save
|
exports/red|blue|yellow|gold/ — pull after Export save (Gold not yet)
|
||||||
|
|
||||||
Full guide: https://github.com/bryanthaboi/gen1recomp/blob/main/docs/switch-install.md
|
Full guide: https://github.com/bryanthaboi/gen1recomp/blob/main/docs/switch-install.md
|
||||||
EOF
|
EOF
|
||||||
@@ -92,7 +92,7 @@ write_readme() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
write_readme "$SAVE_ROOT/imports/README.txt" \
|
write_readme "$SAVE_ROOT/imports/README.txt" \
|
||||||
"Put a legal Pokemon Red or Blue .gb / .gbc here, then Scan again in the launcher."
|
"Put a legal Pokemon Red/Blue .gb or Yellow/Gold .gbc here, then Scan again in the launcher."
|
||||||
write_readme "$SAVE_ROOT/imports/mods/README.txt" \
|
write_readme "$SAVE_ROOT/imports/mods/README.txt" \
|
||||||
"Put community mod .zip files here, then MODS → Scan again."
|
"Put community mod .zip files here, then MODS → Scan again."
|
||||||
write_readme "$SAVE_ROOT/imports/saves/red/README.txt" \
|
write_readme "$SAVE_ROOT/imports/saves/red/README.txt" \
|
||||||
@@ -101,12 +101,16 @@ write_readme "$SAVE_ROOT/imports/saves/blue/README.txt" \
|
|||||||
"Put a Blue .sav (32 KB) here, then Blue tab → SAVE FILES → Import save."
|
"Put a Blue .sav (32 KB) here, then Blue tab → SAVE FILES → Import save."
|
||||||
write_readme "$SAVE_ROOT/imports/saves/yellow/README.txt" \
|
write_readme "$SAVE_ROOT/imports/saves/yellow/README.txt" \
|
||||||
"Put a Yellow .sav (32 KB) here, then Yellow tab → SAVE FILES → Import save."
|
"Put a Yellow .sav (32 KB) here, then Yellow tab → SAVE FILES → Import save."
|
||||||
|
write_readme "$SAVE_ROOT/imports/saves/gold/README.txt" \
|
||||||
|
"Gold cart .sav import is not supported yet. Folder reserved so MTP matches the other games."
|
||||||
write_readme "$SAVE_ROOT/exports/red/README.txt" \
|
write_readme "$SAVE_ROOT/exports/red/README.txt" \
|
||||||
"After Export save (Red), copy the .sav out of this folder via MTP / SD / FTP."
|
"After Export save (Red), copy the .sav out of this folder via MTP / SD / FTP."
|
||||||
write_readme "$SAVE_ROOT/exports/blue/README.txt" \
|
write_readme "$SAVE_ROOT/exports/blue/README.txt" \
|
||||||
"After Export save (Blue), copy the .sav out of this folder via MTP / SD / FTP."
|
"After Export save (Blue), copy the .sav out of this folder via MTP / SD / FTP."
|
||||||
write_readme "$SAVE_ROOT/exports/yellow/README.txt" \
|
write_readme "$SAVE_ROOT/exports/yellow/README.txt" \
|
||||||
"After Export save (Yellow), copy the .sav out of this folder via MTP / SD / FTP."
|
"After Export save (Yellow), copy the .sav out of this folder via MTP / SD / FTP."
|
||||||
|
write_readme "$SAVE_ROOT/exports/gold/README.txt" \
|
||||||
|
"Gold cart .sav export is not supported yet. Folder reserved so MTP matches the other games."
|
||||||
|
|
||||||
rm -f "$OUT_ZIP"
|
rm -f "$OUT_ZIP"
|
||||||
(
|
(
|
||||||
@@ -135,9 +139,11 @@ REQUIRED=(
|
|||||||
"switch/gen1recomp/pokemon-love2d/imports/saves/red/README.txt"
|
"switch/gen1recomp/pokemon-love2d/imports/saves/red/README.txt"
|
||||||
"switch/gen1recomp/pokemon-love2d/imports/saves/blue/README.txt"
|
"switch/gen1recomp/pokemon-love2d/imports/saves/blue/README.txt"
|
||||||
"switch/gen1recomp/pokemon-love2d/imports/saves/yellow/README.txt"
|
"switch/gen1recomp/pokemon-love2d/imports/saves/yellow/README.txt"
|
||||||
|
"switch/gen1recomp/pokemon-love2d/imports/saves/gold/README.txt"
|
||||||
"switch/gen1recomp/pokemon-love2d/exports/red/README.txt"
|
"switch/gen1recomp/pokemon-love2d/exports/red/README.txt"
|
||||||
"switch/gen1recomp/pokemon-love2d/exports/blue/README.txt"
|
"switch/gen1recomp/pokemon-love2d/exports/blue/README.txt"
|
||||||
"switch/gen1recomp/pokemon-love2d/exports/yellow/README.txt"
|
"switch/gen1recomp/pokemon-love2d/exports/yellow/README.txt"
|
||||||
|
"switch/gen1recomp/pokemon-love2d/exports/gold/README.txt"
|
||||||
)
|
)
|
||||||
for rel in "${REQUIRED[@]}"; do
|
for rel in "${REQUIRED[@]}"; do
|
||||||
printf '%s\n' "$LISTING" | grep -Fq "$rel" || fail "zip missing $rel"
|
printf '%s\n' "$LISTING" | grep -Fq "$rel" || fail "zip missing $rel"
|
||||||
|
|||||||
@@ -270,9 +270,11 @@ for rel in \
|
|||||||
"switch/gen1recomp/pokemon-love2d/imports/saves/red/README.txt" \
|
"switch/gen1recomp/pokemon-love2d/imports/saves/red/README.txt" \
|
||||||
"switch/gen1recomp/pokemon-love2d/imports/saves/blue/README.txt" \
|
"switch/gen1recomp/pokemon-love2d/imports/saves/blue/README.txt" \
|
||||||
"switch/gen1recomp/pokemon-love2d/imports/saves/yellow/README.txt" \
|
"switch/gen1recomp/pokemon-love2d/imports/saves/yellow/README.txt" \
|
||||||
|
"switch/gen1recomp/pokemon-love2d/imports/saves/gold/README.txt" \
|
||||||
"switch/gen1recomp/pokemon-love2d/exports/red/README.txt" \
|
"switch/gen1recomp/pokemon-love2d/exports/red/README.txt" \
|
||||||
"switch/gen1recomp/pokemon-love2d/exports/blue/README.txt" \
|
"switch/gen1recomp/pokemon-love2d/exports/blue/README.txt" \
|
||||||
"switch/gen1recomp/pokemon-love2d/exports/yellow/README.txt"
|
"switch/gen1recomp/pokemon-love2d/exports/yellow/README.txt" \
|
||||||
|
"switch/gen1recomp/pokemon-love2d/exports/gold/README.txt"
|
||||||
do
|
do
|
||||||
printf '%s\n' "$ZIP_LIST" | grep -Fq "$rel" || PACK_MISSING="${PACK_MISSING} ${rel}"
|
printf '%s\n' "$ZIP_LIST" | grep -Fq "$rel" || PACK_MISSING="${PACK_MISSING} ${rel}"
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -3,8 +3,9 @@
|
|||||||
-- instead of teaching every call site about versioned caches, this module
|
-- instead of teaching every call site about versioned caches, this module
|
||||||
-- wraps EVERY read-side love entry point that accepts a filesystem path
|
-- wraps EVERY read-side love entry point that accepts a filesystem path
|
||||||
-- once at boot: any string path under assets/generated/ or data/generated/
|
-- 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
|
-- prefers the active version's prefixed copy (yellow|blue|gold/...) when
|
||||||
-- (yellow|blue|gold/... ). Covering the whole read surface --
|
-- 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
|
-- not just the loaders we happened to need -- is what keeps future states
|
||||||
-- and mods inside the fallback without anyone updating this file.
|
-- 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
|
local originals -- raw love functions, non-nil while installed
|
||||||
|
|
||||||
-- Resolve `path` to the versioned copy when the un-prefixed file is missing
|
-- Resolve `path` to the active version's prefixed copy when that file
|
||||||
-- and the active version (Blue/Yellow/Gold) carries it. Returns nil when the
|
-- exists (gold|yellow|blue|red/{assets,data}/generated/...). The versioned
|
||||||
-- caller's path should be used untouched (non-generated path, the real
|
-- tree wins over a leftover un-prefixed file so a pre-#899 Red root cache
|
||||||
-- file exists, or no versioned copy).
|
-- (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)
|
local function versioned(path)
|
||||||
if type(path) ~= "string" then return nil end
|
if type(path) ~= "string" then return nil end
|
||||||
local generated = false
|
local generated = false
|
||||||
@@ -52,7 +56,6 @@ local function versioned(path)
|
|||||||
if not generated then return nil end
|
if not generated then return nil end
|
||||||
local prefix = GameVersion.cachePrefix()
|
local prefix = GameVersion.cachePrefix()
|
||||||
if prefix == "" then return nil end
|
if prefix == "" then return nil end
|
||||||
if originals.getInfo(path) then return nil end
|
|
||||||
local candidate = prefix .. path
|
local candidate = prefix .. path
|
||||||
if originals.getInfo(candidate) then return candidate end
|
if originals.getInfo(candidate) then return candidate end
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ local SEP = package.config:sub(1, 1)
|
|||||||
|
|
||||||
-- Cache-relative paths are prefixed with this before every read/write, so a
|
-- Cache-relative paths are prefixed with this before every read/write, so a
|
||||||
-- version's import lands under its GameVersion.cachePrefix (red/, blue/,
|
-- 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
|
-- "" outside those flows. Runtime *reads* (require / newImage) do NOT go
|
||||||
-- through here -- CacheFs.mountVersion overlays the active version's subtree
|
-- through here -- CacheFs.mountVersion overlays the active version's subtree
|
||||||
-- onto the un-prefixed paths instead.
|
-- onto the un-prefixed paths instead.
|
||||||
|
|||||||
+23
-12
@@ -192,20 +192,28 @@ local PAL = {
|
|||||||
chipInkGold = { 58, 44, 0 }, -- #3a2c00 dark "Y" on the gold chip
|
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,
|
-- CacheFs.exists checks the game folder directly for a portable install,
|
||||||
-- otherwise the save directory through love.filesystem. It honors
|
-- otherwise the save directory through love.filesystem. It honors
|
||||||
-- CacheFs.prefix, so we point it at the version's cache subtree (red/,
|
-- CacheFs.prefix, so we point it at the version's cache subtree (red/,
|
||||||
-- blue/, yellow/).
|
-- blue/, yellow/, gold/).
|
||||||
local function allRequiredFilesExist(version)
|
local function allRequiredFilesExist(version)
|
||||||
local CacheFs = require("src.import.CacheFs")
|
local CacheFs = require("src.import.CacheFs")
|
||||||
local saved = CacheFs.prefix
|
local saved = CacheFs.prefix
|
||||||
CacheFs.prefix = GameVersion.cachePrefix(version)
|
CacheFs.prefix = GameVersion.cachePrefix(version)
|
||||||
local ok = true
|
local ok = true
|
||||||
local required = VERSION_REQUIRED_FILES_OVERRIDE[version] or REQUIRED_FILES
|
local required, isOverride = requiredFilesFor(version)
|
||||||
for _, path in ipairs(required) do
|
for _, path in ipairs(required) do
|
||||||
if not CacheFs.exists(path) then ok = false; break end
|
if not CacheFs.exists(path) then ok = false; break end
|
||||||
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
|
for _, path in ipairs(VERSION_REQUIRED_FILES[version] or {}) do
|
||||||
if not CacheFs.exists(path) then ok = false; break end
|
if not CacheFs.exists(path) then ok = false; break end
|
||||||
end
|
end
|
||||||
@@ -215,20 +223,23 @@ local function allRequiredFilesExist(version)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- A developer checkout / Python build leaves generated data in the physfs
|
-- A developer checkout / Python build leaves generated data in the physfs
|
||||||
-- source: Red at the historical root, Blue/Yellow in their versioned trees.
|
-- source: Red at the historical root, Blue/Yellow/Gold in their versioned
|
||||||
-- Imported Red caches still live under red/. Check source paths directly so
|
-- trees. Imported Red caches still live under red/. Check source paths
|
||||||
-- that cache prefix cannot hide Red's source tree, and keep save-dir caches
|
-- directly so that cache prefix cannot hide Red's source tree, and keep
|
||||||
-- from counting as current source data.
|
-- save-dir caches from counting as current source data.
|
||||||
local function sourceTreeHasData(version)
|
local function sourceTreeHasData(version)
|
||||||
if not love.filesystem.getRealDirectory then return false end
|
if not love.filesystem.getRealDirectory then return false end
|
||||||
local prefix = version == "red" and "" or GameVersion.cachePrefix(version)
|
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
|
if love.filesystem.getInfo(prefix .. path, "file") == nil then return false end
|
||||||
end
|
end
|
||||||
for _, path in ipairs(VERSION_REQUIRED_FILES[version] or {}) do
|
if not isOverride then
|
||||||
if love.filesystem.getInfo(prefix .. path, "file") == nil then return false end
|
for _, path in ipairs(VERSION_REQUIRED_FILES[version] or {}) do
|
||||||
|
if love.filesystem.getInfo(prefix .. path, "file") == nil then return false end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
local path = prefix .. REQUIRED_FILES[1]
|
local path = prefix .. required[1]
|
||||||
local real = love.filesystem.getRealDirectory(path)
|
local real = love.filesystem.getRealDirectory(path)
|
||||||
return real == love.filesystem.getSource()
|
return real == love.filesystem.getSource()
|
||||||
end
|
end
|
||||||
@@ -285,7 +296,7 @@ local function purgeSaveDirCache()
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
-- Purge each version's stale save-directory copy (under its red/ / blue/
|
-- 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
|
for _, version in ipairs(GameVersion.ORDER) do
|
||||||
local prefix = GameVersion.cachePrefix(version)
|
local prefix = GameVersion.cachePrefix(version)
|
||||||
if saveDirHas(prefix .. MARKER_PATH) or saveDirHas(prefix .. REQUIRED_FILES[1]) then
|
if saveDirHas(prefix .. MARKER_PATH) or saveDirHas(prefix .. REQUIRED_FILES[1]) then
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ function SaveFileIO.exportActiveSlot(version)
|
|||||||
fs.createDirectory("exports")
|
fs.createDirectory("exports")
|
||||||
fs.createDirectory("exports/" .. version)
|
fs.createDirectory("exports/" .. version)
|
||||||
end
|
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 rel = ("exports/%s/gen1recomp-%s-%s.sav"):format(version, version, slotId)
|
||||||
local ok, writeErr = fs.write(rel, bytes)
|
local ok, writeErr = fs.write(rel, bytes)
|
||||||
if not ok then return false, "could not write the export: " .. tostring(writeErr) end
|
if not ok then return false, "could not write the export: " .. tostring(writeErr) end
|
||||||
|
|||||||
@@ -97,10 +97,11 @@ local launcher = love.graphics.newImage("assets/launcher/gear.png")
|
|||||||
eq(launcher.path, "assets/launcher/gear.png",
|
eq(launcher.path, "assets/launcher/gear.png",
|
||||||
"overlay leaves non-generated paths alone")
|
"overlay leaves non-generated paths alone")
|
||||||
|
|
||||||
-- The real un-prefixed file wins when it exists
|
-- Leftover un-prefixed Red cache must not shadow the versioned copy
|
||||||
|
-- (pre-#899 assets/generated at the save-dir root).
|
||||||
love.filesystem.write(PNG, "root-png-bytes")
|
love.filesystem.write(PNG, "root-png-bytes")
|
||||||
eq(love.filesystem.read(PNG), "root-png-bytes",
|
eq(love.filesystem.read(PNG), "yellow-png-bytes",
|
||||||
"overlay prefers the real un-prefixed file over the versioned copy")
|
"overlay prefers the versioned copy over leftover unprefixed")
|
||||||
clearPath(PNG)
|
clearPath(PNG)
|
||||||
|
|
||||||
-- Blue gets the same treatment
|
-- Blue gets the same treatment
|
||||||
@@ -110,9 +111,18 @@ clearPath("yellow/" .. PNG)
|
|||||||
eq(love.filesystem.read(PNG), "blue-png-bytes",
|
eq(love.filesystem.read(PNG), "blue-png-bytes",
|
||||||
"overlay maps generated reads to blue/ for Blue")
|
"overlay maps generated reads to blue/ for Blue")
|
||||||
|
|
||||||
|
-- Leftover unprefixed font (old Red root) must not beat Gold's copy.
|
||||||
|
GameVersion.set("gold")
|
||||||
|
local FONT = "assets/generated/fonts/font.png"
|
||||||
|
love.filesystem.write(FONT, "stale-red-font")
|
||||||
|
love.filesystem.write("gold/" .. FONT, "gold-font")
|
||||||
|
eq(love.filesystem.read(FONT), "gold-font",
|
||||||
|
"Gold versioned font wins over leftover unprefixed Red font")
|
||||||
|
clearPath(FONT)
|
||||||
|
clearPath("gold/" .. FONT)
|
||||||
|
|
||||||
-- Gold data/generated: fused NX hides gold/maps.lua at the unprefixed path,
|
-- Gold data/generated: fused NX hides gold/maps.lua at the unprefixed path,
|
||||||
-- which is the "Gold cache incomplete / maps.lua Does not exist" crash.
|
-- which is the "Gold cache incomplete / maps.lua Does not exist" crash.
|
||||||
GameVersion.set("gold")
|
|
||||||
local MAPS = "data/generated/maps.lua"
|
local MAPS = "data/generated/maps.lua"
|
||||||
love.filesystem.write("gold/" .. MAPS, "return { NEW_BARK_TOWN = true }")
|
love.filesystem.write("gold/" .. MAPS, "return { NEW_BARK_TOWN = true }")
|
||||||
local mapsChunk = love.filesystem.load(MAPS)
|
local mapsChunk = love.filesystem.load(MAPS)
|
||||||
@@ -122,7 +132,8 @@ eq(love.filesystem.read(MAPS), "return { NEW_BARK_TOWN = true }",
|
|||||||
"wrapped filesystem.read returns gold maps.lua bytes")
|
"wrapped filesystem.read returns gold maps.lua bytes")
|
||||||
clearPath("gold/" .. MAPS)
|
clearPath("gold/" .. MAPS)
|
||||||
|
|
||||||
-- Red has no prefix: nothing is rewritten
|
-- Red has no empty prefix anymore (cachePrefix is red/), but with no
|
||||||
|
-- red/ copy the unprefixed miss stays a miss.
|
||||||
GameVersion.set("red")
|
GameVersion.set("red")
|
||||||
clearPath("blue/" .. PNG)
|
clearPath("blue/" .. PNG)
|
||||||
eq(love.filesystem.read(PNG), nil, "Red keeps the stock miss behavior")
|
eq(love.filesystem.read(PNG), nil, "Red keeps the stock miss behavior")
|
||||||
|
|||||||
@@ -66,4 +66,21 @@ check(mainSrc:find("isNX", 1, true) ~= nil
|
|||||||
and mainSrc:find('require("src.core.NxAssetOverlay").install()', 1, true) ~= nil,
|
and mainSrc:find('require("src.core.NxAssetOverlay").install()', 1, true) ~= nil,
|
||||||
"the overlay install stays gated on Platform.isNX()")
|
"the overlay install stays gated on Platform.isNX()")
|
||||||
|
|
||||||
|
-- Gold Game2 / World must compile data/generated via CacheFs.loadActive so
|
||||||
|
-- a fused NX boot does not depend on mounting gold/ onto data/generated.
|
||||||
|
local function readSrc(path)
|
||||||
|
local fh = io.open(path, "r")
|
||||||
|
local body = fh and fh:read("*a") or ""
|
||||||
|
if fh then fh:close() end
|
||||||
|
return body
|
||||||
|
end
|
||||||
|
local game2Src = readSrc("src/core/Game2.lua")
|
||||||
|
check(game2Src:find("loadActive", 1, true) ~= nil,
|
||||||
|
"Game2 compiles generated modules through CacheFs.loadActive")
|
||||||
|
check(game2Src:find("loadActive(path)", 1, true) ~= nil,
|
||||||
|
"Game2.loadGenerated calls loadActive")
|
||||||
|
local worldSrc = readSrc("src/world/gen2/World.lua")
|
||||||
|
check(worldSrc:find("loadActive", 1, true) ~= nil,
|
||||||
|
"World's on-disk fallback also uses CacheFs.loadActive")
|
||||||
|
|
||||||
T.finish()
|
T.finish()
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ package.loaded["src.import.RomImporter"] = nil
|
|||||||
RomImporter = require("src.import.RomImporter")
|
RomImporter = require("src.import.RomImporter")
|
||||||
|
|
||||||
local function clearSavesInbox()
|
local function clearSavesInbox()
|
||||||
for _, ver in ipairs({ "red", "blue", "yellow" }) do
|
for _, ver in ipairs({ "red", "blue", "yellow", "gold" }) do
|
||||||
local dir = "imports/saves/" .. ver
|
local dir = "imports/saves/" .. ver
|
||||||
for _, name in ipairs(love.filesystem.getDirectoryItems(dir) or {}) do
|
for _, name in ipairs(love.filesystem.getDirectoryItems(dir) or {}) do
|
||||||
love.filesystem.remove(dir .. "/" .. name)
|
love.filesystem.remove(dir .. "/" .. name)
|
||||||
@@ -135,6 +135,8 @@ check(createdDirs["imports/saves/blue"] == true,
|
|||||||
"RES-01: ensureSavesInboxDir creates imports/saves/blue/")
|
"RES-01: ensureSavesInboxDir creates imports/saves/blue/")
|
||||||
check(createdDirs["imports/saves/yellow"] == true,
|
check(createdDirs["imports/saves/yellow"] == true,
|
||||||
"RES-01: ensureSavesInboxDir creates imports/saves/yellow/")
|
"RES-01: ensureSavesInboxDir creates imports/saves/yellow/")
|
||||||
|
check(createdDirs["imports/saves/gold"] == true,
|
||||||
|
"RES-01: ensureSavesInboxDir creates imports/saves/gold/")
|
||||||
|
|
||||||
-- NXSAV-02: notice/hint includes save dir + per-game imports/saves/<version>/ MTP path
|
-- NXSAV-02: notice/hint includes save dir + per-game imports/saves/<version>/ MTP path
|
||||||
ri = freshImporter()
|
ri = freshImporter()
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
-- sourceTreeHasData must use each version's required-file list. Gold's
|
||||||
|
-- cache has no Gen 1 trade art / pikachu.png; validating it against
|
||||||
|
-- REQUIRED_FILES made a Gold source tree look incomplete forever.
|
||||||
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
||||||
|
|
||||||
|
local T = require("tests.harness")
|
||||||
|
local check = T.check
|
||||||
|
|
||||||
|
local f = assert(io.open("src/import/RomImporter.lua", "r"))
|
||||||
|
local src = f:read("*a")
|
||||||
|
f:close()
|
||||||
|
|
||||||
|
local start = src:find("local function sourceTreeHasData", 1, true)
|
||||||
|
check(start ~= nil, "sourceTreeHasData is defined")
|
||||||
|
local finish = src:find("\nfunction RomImporter.isReady", start, true)
|
||||||
|
check(finish ~= nil, "sourceTreeHasData ends before isReady")
|
||||||
|
local body = src:sub(start, finish)
|
||||||
|
|
||||||
|
check(body:find("requiredFilesFor", 1, true) ~= nil,
|
||||||
|
"sourceTreeHasData uses requiredFilesFor (Gold override, not Gen 1 only)")
|
||||||
|
check(body:find("ipairs(REQUIRED_FILES)", 1, true) == nil,
|
||||||
|
"sourceTreeHasData does not iterate the Gen 1 REQUIRED_FILES list raw")
|
||||||
|
|
||||||
|
local helperStart = src:find("local function requiredFilesFor", 1, true)
|
||||||
|
check(helperStart ~= nil, "requiredFilesFor helper exists")
|
||||||
|
local helper = src:sub(helperStart, start)
|
||||||
|
check(helper:find("VERSION_REQUIRED_FILES_OVERRIDE", 1, true) ~= nil,
|
||||||
|
"requiredFilesFor consults VERSION_REQUIRED_FILES_OVERRIDE")
|
||||||
|
|
||||||
|
T.finish()
|
||||||
@@ -30,6 +30,7 @@ mustContain(transfer, "FTP", "transfer")
|
|||||||
mustContain(transfer, "sdmc:/switch/gen1recomp/", "transfer")
|
mustContain(transfer, "sdmc:/switch/gen1recomp/", "transfer")
|
||||||
mustContain(transfer, "imports/", "transfer")
|
mustContain(transfer, "imports/", "transfer")
|
||||||
mustContain(transfer, "imports/mods/", "transfer")
|
mustContain(transfer, "imports/mods/", "transfer")
|
||||||
|
mustContain(transfer, "gold", "transfer")
|
||||||
mustContain(transfer, "1: SD Card", "transfer")
|
mustContain(transfer, "1: SD Card", "transfer")
|
||||||
mustContain(transfer, "Scan again", "transfer")
|
mustContain(transfer, "Scan again", "transfer")
|
||||||
mustContain(transfer, "documented example", "transfer")
|
mustContain(transfer, "documented example", "transfer")
|
||||||
@@ -70,6 +71,9 @@ mustContain(install, "PERFORMANCE", "install")
|
|||||||
mustContain(install, "Stock engine effect", "install")
|
mustContain(install, "Stock engine effect", "install")
|
||||||
mustContain(install, "## Limitations", "install")
|
mustContain(install, "## Limitations", "install")
|
||||||
mustContain(install, "Launch with title override", "install")
|
mustContain(install, "Launch with title override", "install")
|
||||||
|
mustContain(install, "Gold", "install")
|
||||||
|
mustContain(install, "imports/saves/gold/", "install")
|
||||||
|
mustContain(install, "exports/gold/", "install")
|
||||||
mustNotContain(install, "VoxelMod", "install")
|
mustNotContain(install, "VoxelMod", "install")
|
||||||
mustNotContain(install, "switch-development", "install")
|
mustNotContain(install, "switch-development", "install")
|
||||||
mustContain(build, "switch-transfer.md", "build")
|
mustContain(build, "switch-transfer.md", "build")
|
||||||
|
|||||||
Reference in New Issue
Block a user