Store Gen 3 cache pixel data deflated and write compressed PNGs

Same decoded pixels, about 60 percent smaller caches. Bumps the FireRed/LeafGreen, Emerald and Ruby/Sapphire cache versions.
This commit is contained in:
bryanthaboi
2026-10-05 08:00:07 -04:00
parent 5bee513600
commit b305652fdb
77 changed files with 319 additions and 213 deletions
+4 -2
View File
@@ -2,6 +2,7 @@
local Pack = require("src.import.gba.native_pack")
local Palette = require("src.core.game3.palette")
local OwExtract = require("src.import.gba.ow_extract")
local CacheBlob = require("src.import.CacheBlob")
local D = {}
function D.imageData(rgba, w, h)
@@ -111,12 +112,13 @@ function D.cache(spec, cancelSignal)
if spec.directory then
local f = io.open(spec.directory .. "/" .. path(rel), "rb")
if not f then return nil end
local bytes = f:read("*a"); f:close(); return bytes
local bytes = f:read("*a"); f:close(); return CacheBlob.decode(rel, bytes)
end
return love.filesystem.read(path(rel))
return CacheBlob.readFs(path(rel))
end
function cache:write(rel, bytes)
checkCancel()
bytes = CacheBlob.encode(rel, bytes)
-- No directory creation or mounting in a worker; derived caches are optional.
if spec.directory then
local f = io.open(spec.directory .. "/" .. path(rel), "wb")
+9 -4
View File
@@ -5,10 +5,11 @@ local Versions = require("src.import.gba.versions")
local Extract = require("src.import.gba.extract_island1")
local MapIds = require("src.core.game3.map_ids")
local Profile = require("src.core.game3.profile")
local CacheBlob = require("src.import.CacheBlob")
local Dataset = {}
local function diskFallback(rel)
local function diskFallbackRaw(rel)
local override = Dataset.cacheRootOverride
if override then
local f = io.open(override .. "/" .. rel:gsub("^data/generated/gba/", ""), "rb")
@@ -63,6 +64,10 @@ local function diskFallback(rel)
return nil
end
local function diskFallback(rel)
return CacheBlob.decode(rel, diskFallbackRaw(rel))
end
local function loveCache()
return {
assetWorkerSpec = function(_, root, kind, key)
@@ -82,7 +87,7 @@ local function loveCache()
if type(bytes) == "string" then return bytes end
end
if love and love.filesystem then
local bytes = love.filesystem.read(rel)
local bytes = CacheBlob.readFs(rel)
if type(bytes) == "string" then return bytes end
end
return diskFallback(rel)
@@ -93,7 +98,7 @@ local function loveCache()
return CacheFs.write(rel, bytes)
end
if not love or not love.filesystem then return false end
return love.filesystem.write(rel, bytes)
return love.filesystem.write(rel, CacheBlob.encode(rel, bytes))
end,
exists = function(_, rel)
local ok, CacheFs = pcall(require, "src.import.CacheFs")
@@ -108,7 +113,7 @@ local function loveCache()
and love.filesystem.getInfo(rel, "file") then
return true
end
return diskFallback(rel) ~= nil
return diskFallbackRaw(rel) ~= nil
end,
}
end
+3 -2
View File
@@ -8,6 +8,7 @@
local SE = require("src.core.game3.se_ids")
local MB = require("src.core.game3.mb")
local CacheBlob = require("src.import.CacheBlob")
local Doors = {}
@@ -619,13 +620,13 @@ local function loadSheet(tileName, sheetFile)
end
if not bytes and love and love.filesystem and love.filesystem.read then
bytes = love.filesystem.read(relPath) or love.filesystem.read("doors/" .. file)
bytes = CacheBlob.readFs(relPath) or CacheBlob.readFs("doors/" .. file)
end
if not bytes then
local f = io.open(relPath, "rb")
if f then
bytes = f:read("*a")
bytes = CacheBlob.decode(relPath, f:read("*a"))
f:close()
end
end
+2 -1
View File
@@ -5,6 +5,7 @@ local Extract = require("src.import.gba.extract_island1")
local Dex = require("src.core.game3.dex")
local Pokemon = require("src.core.game3.pokemon")
local RomText = require("src.core.game3.rom_text")
local CacheBlob = require("src.import.CacheBlob")
local PokedexData = {}
@@ -40,7 +41,7 @@ local function read_bytes(rel)
for _, p in ipairs(candidates) do
local f = io.open(p, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(p, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+2 -1
View File
@@ -3,6 +3,7 @@ local CachePaths = require("src.core.game3.cache_paths")
local PokemonExtract = require("src.import.gba.pokemon_extract")
local Versions = require("src.import.gba.versions")
local ModRuntime = require("src.mods.Runtime")
local CacheBlob = require("src.import.CacheBlob")
local Pokemon = {}
@@ -56,7 +57,7 @@ local function resolve_cache(cache)
end
local f = io.open(rel, "rb") or io.open("data/generated/gba/" .. rel, "rb")
if f then
local data = f:read("*a")
local data = CacheBlob.decode(rel, f:read("*a"))
f:close()
return data
end
+2 -1
View File
@@ -4,6 +4,7 @@ local band, rshift = bit.band, bit.rshift
local Tasks = require("src.core.game3.gba_tasks")
local RsPolicy = require("src.core.game3.rs.berry_blender_policy")
local CacheBlob = require("src.import.CacheBlob")
local Blender = {}
Blender.__index = Blender
@@ -71,7 +72,7 @@ local function readCache(path)
if okR and s then return s end
end
if love and love.filesystem and love.filesystem.getInfo and love.filesystem.getInfo(path) then
return love.filesystem.read(path)
return CacheBlob.readFs(path)
end
return nil
end
+3 -2
View File
@@ -1,3 +1,4 @@
local CacheBlob = require("src.import.CacheBlob")
local Tower = {}
-- pokefirered/include/constants/trainer_tower.h:30
@@ -152,12 +153,12 @@ local function read_bytes(rel)
if okR and type(d) == "string" and #d > 0 then return d end
end
if type(love) == "table" and love.filesystem and love.filesystem.read then
local okR, d = pcall(love.filesystem.read, rel)
local okR, d = pcall(CacheBlob.readFs, rel)
if okR and type(d) == "string" and #d > 0 then return d end
end
local f = io.open(rel, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(rel, f:read("*a"))
f:close()
if type(d) == "string" and #d > 0 then return d end
end
+96
View File
@@ -0,0 +1,96 @@
local CacheBlob = {}
CacheBlob.LEVEL = 6
CacheBlob.DERIVED_LEVEL = 1
local PACKED = { rgba = true, idx = true }
local function extension(rel)
return type(rel) == "string" and rel:match("%.([^./\\]+)$") or nil
end
function CacheBlob.packs(rel)
local ext = extension(rel)
return ext ~= nil and PACKED[ext] == true
end
local loveData
local function loveBackend()
if loveData ~= nil then return loveData end
loveData = false
local L = rawget(_G, "love")
if L and not (L.data and L.data.compress) then pcall(require, "love.data") end
if L and L.data and L.data.compress and L.data.decompress then loveData = L.data end
return loveData
end
local zlib
local function ffiBackend()
if zlib ~= nil then return zlib end
zlib = false
local okF, ffi = pcall(require, "ffi")
if not okF then return zlib end
pcall(ffi.cdef, [[
unsigned long compressBound(unsigned long sourceLen);
int compress2(uint8_t *dest, unsigned long *destLen, const uint8_t *source, unsigned long sourceLen, int level);
int uncompress(uint8_t *dest, unsigned long *destLen, const uint8_t *source, unsigned long sourceLen);
]])
for _, name in ipairs(ffi.os == "Windows" and { "zlib1", "z" } or { "z", "libz.so.1" }) do
local okL, lib = pcall(ffi.load, name)
if okL and lib and pcall(function() return lib.uncompress end) then
zlib = { ffi = ffi, lib = lib }
break
end
end
return zlib
end
function CacheBlob.deflate(raw, level)
level = level or CacheBlob.LEVEL
local L = loveBackend()
if L then return L.compress("string", "zlib", raw, level) end
local Z = assert(ffiBackend(), "CacheBlob: no zlib backend (love.data or libz)")
local ffi = Z.ffi
local cap = tonumber(Z.lib.compressBound(#raw))
local out = ffi.new("uint8_t[?]", cap)
local len = ffi.new("unsigned long[1]", cap)
local rc = Z.lib.compress2(out, len, raw, #raw, level)
assert(rc == 0, "CacheBlob: compress2 failed (" .. tostring(rc) .. ")")
return ffi.string(out, tonumber(len[0]))
end
function CacheBlob.inflate(z)
local L = loveBackend()
if L then return L.decompress("string", "zlib", z) end
local Z = assert(ffiBackend(), "CacheBlob: no zlib backend (love.data or libz)")
local ffi = Z.ffi
local cap = math.max(4096, #z * 16)
while true do
local out = ffi.new("uint8_t[?]", cap)
local len = ffi.new("unsigned long[1]", cap)
local rc = Z.lib.uncompress(out, len, z, #z)
if rc == 0 then return ffi.string(out, tonumber(len[0])) end
assert(rc == -5, "CacheBlob: uncompress failed (" .. tostring(rc) .. ")")
cap = cap * 4
end
end
function CacheBlob.encode(rel, bytes)
if type(bytes) ~= "string" or not CacheBlob.packs(rel) then return bytes end
return CacheBlob.deflate(bytes, rel:find("/atlas_", 1, true) and CacheBlob.DERIVED_LEVEL or CacheBlob.LEVEL)
end
function CacheBlob.decode(rel, bytes)
if type(bytes) ~= "string" or not CacheBlob.packs(rel) then return bytes end
local ok, raw = pcall(CacheBlob.inflate, bytes)
if not ok then error("cache blob " .. tostring(rel) .. " is not deflated (stale cache, reimport): " .. tostring(raw), 2) end
return raw
end
function CacheBlob.readFs(rel)
if not (love and love.filesystem and love.filesystem.read) then return nil end
local bytes = love.filesystem.read(rel)
return CacheBlob.decode(rel, bytes)
end
return CacheBlob
+6 -6
View File
@@ -22,12 +22,12 @@ CacheContract.VERSION_FORMAT = {
-- data/pikachu/pikachu_pic_animation.asm:340
yellow = "rom-cache-v12-yellow2:",
-- v8: M4A tracks retain reachable patterns and explicit entry offsets.
firered = "rom-cache-v24-firered:",
leafgreen = "rom-cache-v9-leafgreen:",
emerald = "rom-cache-v4-emerald:",
firered = "rom-cache-v25-firered:",
leafgreen = "rom-cache-v10-leafgreen:",
emerald = "rom-cache-v5-emerald:",
-- pokeruby/src/string_util.c:408
ruby = "rom-cache-v6-ruby:",
sapphire = "rom-cache-v6-sapphire:",
ruby = "rom-cache-v7-ruby:",
sapphire = "rom-cache-v7-sapphire:",
}
CacheContract.MARKER_PATH = "rom-cache.complete"
@@ -1009,7 +1009,7 @@ function CacheContract.sourceTreeHasData(version)
local exact = {
read = function(path)
local full = prefix .. path
if love.filesystem.getRealDirectory(full) == source then return love.filesystem.read(full) end
if love.filesystem.getRealDirectory(full) == source then return require("src.import.CacheBlob").readFs(full) end
end,
exists = function(path)
local full = prefix .. path
+4 -2
View File
@@ -29,6 +29,7 @@
local CacheFs = {}
local Platform = require("src.core.Platform")
local CacheBlob = require("src.import.CacheBlob")
local SaveData = setmetatable({}, {
__index = function(_, k) return require("src.core.SaveData")[k] end,
})
@@ -324,6 +325,7 @@ end
function CacheFs.write(rel, data)
rel = withPrefix(rel)
if unsafe_rel(rel) then return false, "unsafe cache path" end
data = CacheBlob.encode(rel, data)
local root, rootErr = resolveWriteRoot()
if not root and rootErr then return false, rootErr end
if root then
@@ -389,12 +391,12 @@ function CacheFs.readAt(rel)
if not f then return nil end
local data = f:read("*a")
f:close()
return data
return CacheBlob.decode(rel, data)
end
-- headless (plain luajit, e.g. the modkit validate/pack driver): there is
-- no save directory to read from, so a cache miss is nil, not a crash
if not (love and love.filesystem and love.filesystem.read) then return nil end
return love.filesystem.read(rel)
return (CacheBlob.readFs(rel))
end
-- read cache-relative `rel`; returns the bytes or nil
+2 -39
View File
@@ -6,6 +6,7 @@
local Versions = require("src.import.gba.versions")
local Lz77 = require("src.import.gba.lz77")
local CacheBlob = require("src.import.CacheBlob")
local BattleAnimExtract = {}
@@ -504,16 +505,6 @@ local function crc32(str)
return bxor(c, 0xFFFFFFFF)
end
local function adler32(str)
local s1 = 1
local s2 = 0
for i = 1, #str do
s1 = (s1 + str:byte(i)) % 65521
s2 = (s2 + s1) % 65521
end
return s2 * 65536 + s1
end
local function u32be(n)
n = band(n, 0xFFFFFFFF)
return string.char(
@@ -524,10 +515,6 @@ local function u32be(n)
)
end
local function u16le(n)
return string.char(band(n, 0xFF), band(rshift(n, 8), 0xFF))
end
local function make_chunk(type_str, data)
local crc = crc32(type_str .. data)
return u32be(#data) .. type_str .. data .. u32be(crc)
@@ -607,31 +594,7 @@ local function encode_png(pixels, w, h)
raw_data = table.concat(raw_lines)
end
local idat_data
if love and love.data and love.data.compress then
local ok, comp = pcall(love.data.compress, "string", "zlib", raw_data)
if ok and comp then
idat_data = comp
end
end
if not idat_data then
-- Deflate uncompressed blocks (max 65535 per block)
local zlib_blocks = { string.char(0x78, 0x01) } -- ZLIB header
local pos = 1
local total_len = #raw_data
while pos <= total_len do
local chunk_len = math.min(total_len - pos + 1, 65535)
local is_final = (pos + chunk_len > total_len) and 1 or 0
zlib_blocks[#zlib_blocks + 1] = string.char(is_final)
zlib_blocks[#zlib_blocks + 1] = u16le(chunk_len)
zlib_blocks[#zlib_blocks + 1] = u16le(bxor(chunk_len, 0xFFFF))
zlib_blocks[#zlib_blocks + 1] = raw_data:sub(pos, pos + chunk_len - 1)
pos = pos + chunk_len
end
zlib_blocks[#zlib_blocks + 1] = u32be(adler32(raw_data))
idat_data = table.concat(zlib_blocks)
end
local idat_data = CacheBlob.deflate(raw_data, 9)
-- PNG Signature + IHDR + IDAT + IEND
local sig = "\137PNG\r\n\026\n"
+4 -3
View File
@@ -4,6 +4,7 @@
local Versions = require("src.import.gba.versions")
local Lz77 = require("src.import.gba.lz77")
local CacheBlob = require("src.import.CacheBlob")
local BattleChromeExtract = {}
@@ -725,11 +726,11 @@ function BattleChromeExtract.ready(cache, cacheRoot)
local CacheFs = require("src.import.CacheFs")
local bytes = CacheFs.readActive and CacheFs.readActive(rel)
if bytes then return bytes end
if love and love.filesystem then bytes = love.filesystem.read(rel) end
if love and love.filesystem then bytes = CacheBlob.readFs(rel) end
if bytes then return bytes end
local file = io.open(rel, "rb")
if not file then return nil end
bytes = file:read("*a"); file:close(); return bytes
bytes = CacheBlob.decode(rel, file:read("*a")); file:close(); return bytes
end
local body = read_file(root .. "/manifest.lua")
local chunk = type(body) == "string" and load(body, "@battle/manifest.lua", "t", {})
@@ -767,7 +768,7 @@ function BattleChromeExtract.ready(cache, cacheRoot)
if data and #data >= minSize then return true end
end
if love and love.filesystem and love.filesystem.read then
local ok, data = pcall(love.filesystem.read, rel)
local ok, data = pcall(CacheBlob.readFs, rel)
if ok and data and #data >= minSize then return true end
end
local f = io.open(rel, "rb")
+3 -2
View File
@@ -1,6 +1,7 @@
-- File-backed mod.imports / mod.cache shim for offline extract (dev CLI).
local FileIO = {}
local CacheBlob = require("src.import.CacheBlob")
function FileIO.makeImports(path, md5, id)
id = id or "firered"
@@ -45,7 +46,7 @@ function FileIO.makeCache(root)
local parent = path:match("^(.*)/[^/]+$")
if parent then mkdir_p(parent) end
local f = assert(io.open(path, "wb"))
f:write(bytes)
f:write(CacheBlob.encode(rel, bytes))
f:close()
return true
end
@@ -54,7 +55,7 @@ function FileIO.makeCache(root)
if not f then return nil end
local d = f:read("*a")
f:close()
return d
return CacheBlob.decode(rel, d)
end
function cache:exists(rel)
local f = io.open(root .. "/" .. rel, "rb")
+1 -1
View File
@@ -3,7 +3,7 @@ local VersionsRse = require("src.import.gba.versions_rse")
local V = VersionsRse.new("emerald")
local sym, count = V.sym, V.count
V.CACHE_VERSION = 14
V.CACHE_VERSION = 15
V.NATIVE_VERSION = 2
V.OW_VERSION = 1
V.ANIM_VERSION = 1
+1 -1
View File
@@ -6,7 +6,7 @@ local Rs = {}
local function tables(game, revision)
local V = VersionsRse.new(game, revision.build)
local sym, count = V.sym, V.count
V.CACHE_VERSION = 2
V.CACHE_VERSION = 3
V.NATIVE_VERSION = 2
V.OW_VERSION = 1
V.ANIM_VERSION = 1
+3 -2
View File
@@ -3,6 +3,7 @@
local Versions = require("src.import.gba.versions")
local Lz77 = require("src.import.gba.lz77")
local CacheBlob = require("src.import.CacheBlob")
local PartyChromeExtract = {}
@@ -488,12 +489,12 @@ function PartyChromeExtract.ready(cache, cacheRoot)
if d and #d >= 80 * 56 * 4 then return true end
end
if love and love.filesystem and love.filesystem.read then
local d = love.filesystem.read(need)
local d = CacheBlob.readFs(need)
if d and #d >= 80 * 56 * 4 then return true end
end
local f = io.open(need, "rb") or io.open("data/generated/gba/" .. PartyChromeExtract.CACHE_SUB .. "/slot_main.rgba", "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(need, f:read("*a"))
f:close()
if d and #d >= 80 * 56 * 4 then return true end
end
+2 -1
View File
@@ -8,6 +8,7 @@
local Versions = require("src.import.gba.versions")
local TextIR = require("src.core.game3.scripting.text_ir")
local Lz77 = require("src.import.gba.lz77")
local CacheBlob = require("src.import.CacheBlob")
local PokedexChromeExtract = {}
@@ -873,7 +874,7 @@ function PokedexChromeExtract.ready(cache, cacheRoot)
if data and #data >= minSize then return true end
end
if love and love.filesystem and love.filesystem.read then
local ok, data = pcall(love.filesystem.read, rel)
local ok, data = pcall(CacheBlob.readFs, rel)
if ok and data and #data >= minSize then return true end
end
local f = io.open(rel, "rb")
+4 -2
View File
@@ -1,3 +1,5 @@
local CacheBlob = require("src.import.CacheBlob")
-- src/region_map.c:393-427
local RegionMapExtract = {}
@@ -553,12 +555,12 @@ local function baked(cache, rel)
if d and #d > 8 then return true end
end
if love and love.filesystem and love.filesystem.read then
local d = love.filesystem.read(rel)
local d = CacheBlob.readFs(rel)
if d and #d > 8 then return true end
end
local f = io.open(rel, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(rel, f:read("*a"))
f:close()
if d and #d > 8 then return true end
end
+2 -32
View File
@@ -1,5 +1,6 @@
local Lz77 = require("src.import.gba.lz77")
local LuaWriter = require("src.import.LuaWriter")
local CacheBlob = require("src.import.CacheBlob")
local bit = rawget(_G, "bit") or require("bit")
local band, bxor, rshift = bit.band, bit.bxor, bit.rshift
@@ -51,40 +52,9 @@ local function chunk(kind, data)
return be32(#data) .. kind .. data .. be32(crc32(kind .. data))
end
local function adler32(s)
local a, b = 1, 0
for i = 1, #s do
a = (a + s:byte(i)) % 65521
b = (b + a) % 65521
end
return b * 65536 + a
end
local function zlibStored(raw)
local parts = { "\120\1" }
local n = #raw
local pos = 1
repeat
local len = math.min(65535, n - pos + 1)
local final = (pos + len > n) and 1 or 0
parts[#parts + 1] = string.char(final, len % 256, math.floor(len / 256),
(65535 - len) % 256, math.floor((65535 - len) / 256))
parts[#parts + 1] = raw:sub(pos, pos + len - 1)
pos = pos + len
until pos > n
parts[#parts + 1] = be32(adler32(raw))
return table.concat(parts)
end
local function zlib(raw)
local love = rawget(_G, "love")
if love and love.data and love.data.compress then
local ok, out = pcall(love.data.compress, "string", "zlib", raw)
if ok and type(out) == "string" then return out end
end
return zlibStored(raw)
return CacheBlob.deflate(raw, 9)
end
K.zlibStored = zlibStored
local function scanlines(w, h, idx)
local rows = {}
+5 -4
View File
@@ -3,6 +3,7 @@
local Versions = require("src.import.gba.versions")
local Lz77 = require("src.import.gba.lz77")
local CacheBlob = require("src.import.CacheBlob")
local SummaryChromeExtract = {}
@@ -82,12 +83,12 @@ local function read_bin(candidates)
if d and #d > 0 then return d end
end
if love and love.filesystem and love.filesystem.read then
local ok, d = pcall(love.filesystem.read, p)
local ok, d = pcall(CacheBlob.readFs, p)
if ok and d and #d > 0 then return d end
end
local f = io.open(p, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(p, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
@@ -709,12 +710,12 @@ function SummaryChromeExtract.ready(cache, cacheRoot)
if d and #d >= 240 * 160 * 4 then return true end
end
if love and love.filesystem and love.filesystem.read then
local d = love.filesystem.read(need)
local d = CacheBlob.readFs(need)
if d and #d >= 240 * 160 * 4 then return true end
end
local f = io.open(need, "rb") or io.open("data/generated/gba/" .. SummaryChromeExtract.CACHE_SUB .. "/page_info.rgba", "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(need, f:read("*a"))
f:close()
if d and #d >= 240 * 160 * 4 then return true end
end
+3 -2
View File
@@ -3,6 +3,7 @@
local Versions = require("src.import.gba.versions")
local Lz77 = require("src.import.gba.lz77")
local CacheBlob = require("src.import.CacheBlob")
local TrainerCardExtract = {}
@@ -406,12 +407,12 @@ function TrainerCardExtract.ready(cache, cacheRoot)
if d and #d >= 240 * 160 * 4 then return true end
end
if love and love.filesystem and love.filesystem.read then
local d = love.filesystem.read(need)
local d = CacheBlob.readFs(need)
if d and #d >= 240 * 160 * 4 then return true end
end
local f = io.open(need, "rb") or io.open("data/generated/gba/" .. TrainerCardExtract.CACHE_SUB .. "/bg.rgba", "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(need, f:read("*a"))
f:close()
if d and #d >= 240 * 160 * 4 then return true end
end
+1 -1
View File
@@ -43,7 +43,7 @@ Versions.ROM_SIZE = 16777216
-- v115: LeafGreen profiles, edition-specific title assets and Deoxys stats.
-- v121: chrome/fonts/japanese_{normal,small}_* and japanese_widths.lua, the
-- cart's Japanese fonts, for text a Japanese translation mod prints.
Versions.CACHE_VERSION = 129
Versions.CACHE_VERSION = 130
Versions.NATIVE_VERSION = 6
Versions.OW_VERSION = 3
Versions.ANIM_VERSION = 1
+4 -3
View File
@@ -2,6 +2,7 @@
local Extract = require("src.import.gba.extract_island1")
local BagChromeExtract = require("src.import.gba.bag_chrome_extract")
local CacheBlob = require("src.import.CacheBlob")
local BagChrome = {}
@@ -48,10 +49,10 @@ local function read_bytes(rel)
if type(d) == "string" and #d > 0 then return d end
end
if love and love.filesystem and love.filesystem.read then
local d = love.filesystem.read(rel)
local d = CacheBlob.readFs(rel)
if type(d) == "string" and #d > 0 then return d end
local alt = "data/generated/gba/" .. (rel:gsub("^data/generated/gba/", ""))
d = love.filesystem.read(alt)
d = CacheBlob.readFs(alt)
if type(d) == "string" and #d > 0 then return d end
end
local candidates = {
@@ -61,7 +62,7 @@ local function read_bytes(rel)
for _, p in ipairs(candidates) do
local f = io.open(p, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(p, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+4 -3
View File
@@ -2,6 +2,7 @@
local Extract = require("src.import.gba.extract_island1")
local BattleChromeExtract = require("src.import.gba.battle_chrome_extract")
local CacheBlob = require("src.import.CacheBlob")
local BattleChrome = {}
@@ -68,10 +69,10 @@ local function read_bytes(rel)
if type(d) == "string" and #d > 0 then return d end
end
if love and love.filesystem and love.filesystem.read then
local d = love.filesystem.read(rel)
local d = CacheBlob.readFs(rel)
if type(d) == "string" and #d > 0 then return d end
local alt = "data/generated/gba/" .. (rel:gsub("^data/generated/gba/", ""))
d = love.filesystem.read(alt)
d = CacheBlob.readFs(alt)
if type(d) == "string" and #d > 0 then return d end
end
local candidates = {
@@ -81,7 +82,7 @@ local function read_bytes(rel)
for _, p in ipairs(candidates) do
local f = io.open(p, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(p, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+4 -3
View File
@@ -2,6 +2,7 @@
local Extract = require("src.import.gba.extract_island1")
local BerryPouchExtract = require("src.import.gba.berry_pouch_extract")
local CacheBlob = require("src.import.CacheBlob")
local BerryPouchChrome = {}
@@ -37,10 +38,10 @@ local function read_bytes(rel)
if type(d) == "string" and #d > 0 then return d end
end
if love and love.filesystem and love.filesystem.read then
local d = love.filesystem.read(rel)
local d = CacheBlob.readFs(rel)
if type(d) == "string" and #d > 0 then return d end
local alt = "data/generated/gba/" .. (rel:gsub("^data/generated/gba/", ""))
d = love.filesystem.read(alt)
d = CacheBlob.readFs(alt)
if type(d) == "string" and #d > 0 then return d end
end
local candidates = {
@@ -50,7 +51,7 @@ local function read_bytes(rel)
for _, p in ipairs(candidates) do
local f = io.open(p, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(p, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+4 -3
View File
@@ -2,6 +2,7 @@
local FrlgFont = require("src.ui.game3.frlg_font")
local TextIR = require("src.core.game3.scripting.text_ir")
local CacheBlob = require("src.import.CacheBlob")
local Braille = {}
@@ -109,17 +110,17 @@ local function read_bytes(rel)
if okR and type(d) == "string" and #d > 0 then return d end
end
if love and love.filesystem and love.filesystem.read then
local okR, d = pcall(love.filesystem.read, rel)
local okR, d = pcall(CacheBlob.readFs, rel)
if okR and type(d) == "string" and #d > 0 then return d end
local alt = "data/generated/gba/" .. (rel:gsub("^data/generated/gba/", ""))
okR, d = pcall(love.filesystem.read, alt)
okR, d = pcall(CacheBlob.readFs, alt)
if okR and type(d) == "string" and #d > 0 then return d end
end
local candidates = { rel, "data/generated/gba/" .. (rel:gsub("^data/generated/gba/", "")) }
for _, path in ipairs(candidates) do
local f = io.open(path, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(path, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+3 -2
View File
@@ -9,6 +9,7 @@ local Oam = require("src.core.game3.oam")
local SE = require("src.core.game3.se_ids")
local RomText = require("src.core.game3.rom_text")
local BattleChrome = require("src.ui.game3.battle_chrome")
local CacheBlob = require("src.import.CacheBlob")
local EggHatch = {}
@@ -70,13 +71,13 @@ local function read_bytes(path)
if love and love.filesystem and love.filesystem.getInfo then
local info = love.filesystem.getInfo(path)
if info then
local data = love.filesystem.read(path)
local data = CacheBlob.readFs(path)
if data and #data > 0 then return data end
end
end
local f = io.open(path, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(path, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+3 -2
View File
@@ -6,6 +6,7 @@ local FrlgFont = require("src.ui.game3.frlg_font")
local FameChecker = require("src.core.game3.fame_checker")
local TextIR = require("src.core.game3.scripting.text_ir")
local RomText = require("src.core.game3.rom_text")
local CacheBlob = require("src.import.CacheBlob")
local FameCheckerUi = { isMenu = true }
@@ -105,12 +106,12 @@ local function read_bytes(rel)
if ok and type(d) == "string" and #d > 0 then return d end
end
if love and love.filesystem and love.filesystem.read then
local ok, d = pcall(love.filesystem.read, rel)
local ok, d = pcall(CacheBlob.readFs, rel)
if ok and type(d) == "string" and #d > 0 then return d end
end
local f = io.open(rel, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(rel, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+4 -3
View File
@@ -2,6 +2,7 @@
-- Field dialogue must use this — Gen2 Font.lua is fixed 8px and overflows the 208px box.
local TextIR = require("src.core.game3.scripting.text_ir")
local CacheBlob = require("src.import.CacheBlob")
local FrlgFont = {}
@@ -246,15 +247,15 @@ local function loadImage(candidates)
end
end
if not data and love and love.filesystem and love.filesystem.read then
data = love.filesystem.read(path)
data = CacheBlob.readFs(path)
if not data then
data = love.filesystem.read("data/generated/gba/" .. (path:gsub("^data/generated/gba/", "")))
data = CacheBlob.readFs("data/generated/gba/" .. (path:gsub("^data/generated/gba/", "")))
end
end
if not data then
local f = io.open(path, "rb") or io.open("data/generated/gba/" .. (path:gsub("^data/generated/gba/", "")), "rb")
if f then
data = f:read("*a")
data = CacheBlob.decode(path, f:read("*a"))
f:close()
end
end
+3 -2
View File
@@ -2,6 +2,7 @@ local Stack = require("src.ui.game3.stack")
local Window = require("src.ui.game3.window")
local FrlgFont = require("src.ui.game3.frlg_font")
local Status = require("src.core.game3.link.status")
local CacheBlob = require("src.import.CacheBlob")
local LinkMenu = {}
@@ -53,12 +54,12 @@ local function read_bytes(rel)
if okR and type(d) == "string" and #d > 0 then return d end
end
if love and love.filesystem and love.filesystem.read then
local okR, d = pcall(love.filesystem.read, "data/generated/gba/" .. rel)
local okR, d = pcall(CacheBlob.readFs, "data/generated/gba/" .. rel)
if okR and type(d) == "string" and #d > 0 then return d end
end
local f = io.open("data/generated/gba/" .. rel, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode("data/generated/gba/" .. rel, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+4 -3
View File
@@ -5,6 +5,7 @@ local CaveTransition = require("src.ui.game3.cave_transition")
local Extract = require("src.import.gba.extract_island1")
local MapPreviewExtract = require("src.import.gba.map_preview_extract")
local Strings = require("src.core.Strings")
local CacheBlob = require("src.import.CacheBlob")
local MapPreviewScreen = {}
@@ -87,10 +88,10 @@ local function read_bytes(rel)
if type(d) == "string" and #d > 0 then return d end
end
if love and love.filesystem and love.filesystem.read then
local d = love.filesystem.read(rel)
local d = CacheBlob.readFs(rel)
if type(d) == "string" and #d > 0 then return d end
local alt = "data/generated/gba/" .. (rel:gsub("^data/generated/gba/", ""))
d = love.filesystem.read(alt)
d = CacheBlob.readFs(alt)
if type(d) == "string" and #d > 0 then return d end
end
local candidates = {
@@ -100,7 +101,7 @@ local function read_bytes(rel)
for _, p in ipairs(candidates) do
local f = io.open(p, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(p, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+3 -2
View File
@@ -37,6 +37,7 @@ local WIN_PROMPT = Window.template(2, 15, 26, 4)
-- pokefirered/src/learn_move.c:329 sMoveRelearnerYesNoMenuTemplate
local WIN_YESNO = Window.template(21, 8, 6, 4)
local SE = require("src.core.game3.se_ids")
local CacheBlob = require("src.import.CacheBlob")
local function se(id)
pcall(function()
@@ -57,12 +58,12 @@ local function read_bytes(rel)
if ok and type(d) == "string" and #d > 0 then return d end
end
if love and love.filesystem and love.filesystem.read then
local ok, d = pcall(love.filesystem.read, rel)
local ok, d = pcall(CacheBlob.readFs, rel)
if ok and type(d) == "string" and #d > 0 then return d end
end
local f = io.open(rel, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(rel, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+4 -3
View File
@@ -5,6 +5,7 @@ local Extract = require("src.import.gba.extract_island1")
local PartyChromeExtract = require("src.import.gba.party_chrome_extract")
local FrlgFont = require("src.ui.game3.frlg_font")
local RomText = require("src.core.game3.rom_text")
local CacheBlob = require("src.import.CacheBlob")
local PartyChrome = {}
@@ -54,10 +55,10 @@ local function read_bytes(rel)
if type(d) == "string" and #d > 0 then return d end
end
if love and love.filesystem and love.filesystem.read then
local d = love.filesystem.read(rel)
local d = CacheBlob.readFs(rel)
if type(d) == "string" and #d > 0 then return d end
local alt = "data/generated/gba/" .. (rel:gsub("^data/generated/gba/", ""))
d = love.filesystem.read(alt)
d = CacheBlob.readFs(alt)
if type(d) == "string" and #d > 0 then return d end
end
local candidates = {
@@ -67,7 +68,7 @@ local function read_bytes(rel)
for _, p in ipairs(candidates) do
local f = io.open(p, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(p, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+3 -2
View File
@@ -7,6 +7,7 @@ local Pokemon = require("src.core.game3.pokemon")
local ItemsData = require("src.core.game3.items_data")
local Strings = require("src.core.Strings")
local Presentation = require("src.ui.game3.storage_presentation")
local CacheBlob = require("src.import.CacheBlob")
local PcChrome = {}
@@ -62,12 +63,12 @@ local function read_bytes(rel)
if type(d) == "string" and #d > 0 then return d end
end
if love and love.filesystem and love.filesystem.read then
local ok, d = pcall(love.filesystem.read, rel)
local ok, d = pcall(CacheBlob.readFs, rel)
if ok and type(d) == "string" and #d > 0 then return d end
end
local f = io.open(rel, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(rel, f:read("*a"))
f:close()
if type(d) == "string" and #d > 0 then return d end
end
+4 -3
View File
@@ -5,6 +5,7 @@
local Display = require("src.core.game3.display")
local Extract = require("src.import.gba.extract_island1")
local PokedexData = require("src.core.game3.pokedex_data")
local CacheBlob = require("src.import.CacheBlob")
local PokedexChrome = {}
@@ -38,10 +39,10 @@ local function read_bytes(rel)
if type(d) == "string" and #d > 0 then return d end
end
if love and love.filesystem and love.filesystem.read then
local d = love.filesystem.read(rel)
local d = CacheBlob.readFs(rel)
if type(d) == "string" and #d > 0 then return d end
local alt = "data/generated/gba/" .. (rel:gsub("^data/generated/gba/", ""))
d = love.filesystem.read(alt)
d = CacheBlob.readFs(alt)
if type(d) == "string" and #d > 0 then return d end
end
local candidates = {
@@ -51,7 +52,7 @@ local function read_bytes(rel)
for _, p in ipairs(candidates) do
local f = io.open(p, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(p, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+2 -1
View File
@@ -7,6 +7,7 @@ local SummaryData = require("src.core.game3.summary_data")
local Policy = require("src.ui.game3.rs.summary_policy")
local Pal = require("src.core.game3.pal_fade")
local Audio = require("src.core.game3.audio")
local CacheBlob = require("src.import.CacheBlob")
local S = {isMenu = true, open = false, PAGE = Policy.PAGE, MODE = Policy.MODE, policy = Policy}
local layers, tiles, quads = {}, {}, {}
local function rawMon() return S._party and S._party[S._cursor] end
@@ -275,7 +276,7 @@ local function frame(entry, index, x, y)
if not quads[key] then quads[key] = love.graphics.newQuad(0, index * entry.h, entry.w, entry.h, image:getDimensions()) end
love.graphics.setColor(1, 1, 1, 1); love.graphics.draw(image, quads[key], x, y)
end
local function read(path) return assert(love.filesystem.read(path), path) end
local function read(path) return assert(CacheBlob.readFs(path), path) end
local function shiny() return not Pokemon.isEgg(mon()) and Pokemon.isShiny(mon()) end
local function nativeImage(key, tile, bank, sourceOverride)
local palette = S._man.palettes.bg
+2 -1
View File
@@ -7,6 +7,7 @@ local Sprites = require("src.core.game3.gba_sprites")
local Machine = require("src.ui.game3.rse.gba_machine")
local Affine = require("src.core.game3.bg_affine")
local B = require("src.core.game3.rse.berry_blender")
local CacheBlob = require("src.import.CacheBlob")
local UI = {}
UI.__index = UI
@@ -102,7 +103,7 @@ function UI:readCache(path)
if ok and Dataset and Dataset.cache then data = Dataset.cache():read(path) end
end
if not data and love and love.filesystem and love.filesystem.getInfo and love.filesystem.getInfo(path) then
data = love.filesystem.read(path)
data = CacheBlob.readFs(path)
end
return assert(data, "berry_blender: missing " .. tostring(path))
end
+2 -1
View File
@@ -5,6 +5,7 @@ local Palette = require("src.core.game3.gba_palette")
local Sprites = require("src.core.game3.gba_sprites")
local TileLayer = require("src.ui.game3.rse.tile_layer")
local OwSheet = require("src.ui.game3.rse.ow_sheet")
local CacheBlob = require("src.import.CacheBlob")
local band = bit.band
@@ -406,7 +407,7 @@ function CableCar:loadCb()
ppu.sprites:freeAllPalettes()
ppu.palette:resetFade()
self:startWeather()
local tiles = assert(love.filesystem.read(self.man.bgTiles), "cable_car: bg tiles missing from cache")
local tiles = assert(CacheBlob.readFs(self.man.bgTiles), "cable_car: bg tiles missing from cache")
self.bg = {}
for i = 0, 3 do self.bg[i] = TileLayer.new(tiles) end
-- pokeemerald/src/cable_car.c:95
+2 -1
View File
@@ -1,4 +1,5 @@
local Kit = require("src.ui.game3.rse.scene_kit")
local CacheBlob = require("src.import.CacheBlob")
local Gfx = {}
Gfx.__index = Gfx
@@ -16,7 +17,7 @@ local function readCache(path)
end
end
if not data and love and love.filesystem and love.filesystem.getInfo(path) then
data = love.filesystem.read(path)
data = CacheBlob.readFs(path)
end
return data
end
+2 -1
View File
@@ -1,4 +1,5 @@
local Kit = require("src.ui.game3.rse.scene_kit")
local CacheBlob = require("src.import.CacheBlob")
local Gfx = {}
@@ -11,7 +12,7 @@ local function readCache(path)
local okC, CacheFs = pcall(require, "src.import.CacheFs")
local data = okC and CacheFs and CacheFs.read and CacheFs.read(path) or nil
if not data and love and love.filesystem and love.filesystem.getInfo(path) then
data = love.filesystem.read(path)
data = CacheBlob.readFs(path)
end
return data
end
+2 -1
View File
@@ -4,6 +4,7 @@ local RomText = require("src.core.game3.rom_text")
local FrlgFont = require("src.ui.game3.frlg_font")
local Chrome = require("src.ui.game3.chrome")
local Pal = require("src.core.game3.pal_fade")
local CacheBlob = require("src.import.CacheBlob")
local Kit = {}
@@ -60,7 +61,7 @@ function Kit.rgbaImage(path, w, h)
local okC, CacheFs = pcall(require, "src.import.CacheFs")
if okC and CacheFs and CacheFs.read then data = CacheFs.read(path) end
if (not data) and love and love.filesystem and love.filesystem.getInfo(path) then
data = love.filesystem.read(path)
data = CacheBlob.readFs(path)
end
if type(data) == "string" and #data == w * h * 4 and love and love.image then
local ok, id = pcall(love.image.newImageData, w, h, "rgba8", data)
+4 -3
View File
@@ -7,6 +7,7 @@ local Seagallop = {}
local W, H = 240, 160
local SE = require("src.core.game3.se_ids") -- pokefirered/include/constants/songs.h:23
local CacheBlob = require("src.import.CacheBlob")
local CROSSING_FRAMES = 140
local MUSIC_FADE_FRAMES = 64
@@ -54,10 +55,10 @@ local function read_bytes(rel)
if type(d) == "string" and #d > 0 then return d end
end
if love and love.filesystem and love.filesystem.read then
local d = love.filesystem.read(rel)
local d = CacheBlob.readFs(rel)
if type(d) == "string" and #d > 0 then return d end
local alt = "data/generated/gba/" .. (rel:gsub("^data/generated/gba/", ""))
d = love.filesystem.read(alt)
d = CacheBlob.readFs(alt)
if type(d) == "string" and #d > 0 then return d end
end
local home = os.getenv("HOME") or ""
@@ -71,7 +72,7 @@ local function read_bytes(rel)
for _, p in ipairs(candidates) do
local f = io.open(p, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(p, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+4 -3
View File
@@ -2,6 +2,7 @@
local Extract = require("src.import.gba.extract_island1")
local ShopChromeExtract = require("src.import.gba.shop_chrome_extract")
local CacheBlob = require("src.import.CacheBlob")
local ShopChrome = {}
@@ -59,10 +60,10 @@ local function read_bytes(rel)
if type(d) == "string" and #d > 0 then return d end
end
if love and love.filesystem and love.filesystem.read then
local d = love.filesystem.read(rel)
local d = CacheBlob.readFs(rel)
if type(d) == "string" and #d > 0 then return d end
local alt = "data/generated/gba/" .. (rel:gsub("^data/generated/gba/", ""))
d = love.filesystem.read(alt)
d = CacheBlob.readFs(alt)
if type(d) == "string" and #d > 0 then return d end
end
local candidates = {
@@ -72,7 +73,7 @@ local function read_bytes(rel)
for _, p in ipairs(candidates) do
local f = io.open(p, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(p, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+3 -2
View File
@@ -6,6 +6,7 @@ local FrlgFont = require("src.ui.game3.frlg_font")
local Strings = require("src.core.Strings")
local RomText = require("src.core.game3.rom_text")
local Model = require("src.core.game3.slot_machine")
local CacheBlob = require("src.import.CacheBlob")
local SlotMachineUi = {}
@@ -119,12 +120,12 @@ local function read_bytes(rel)
if okR and type(d) == "string" and #d > 0 then return d end
end
if love and love.filesystem and love.filesystem.read then
local okR, d = pcall(love.filesystem.read, rel)
local okR, d = pcall(CacheBlob.readFs, rel)
if okR and type(d) == "string" and #d > 0 then return d end
end
local f = io.open(rel, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(rel, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+4 -3
View File
@@ -4,6 +4,7 @@
local Display = require("src.core.game3.display")
local Extract = require("src.import.gba.extract_island1")
local SummaryChromeExtract = require("src.import.gba.summary_chrome_extract")
local CacheBlob = require("src.import.CacheBlob")
local SummaryChrome = {}
@@ -56,10 +57,10 @@ local function read_bytes(rel)
if type(d) == "string" and #d > 0 then return d end
end
if love and love.filesystem and love.filesystem.read then
local d = love.filesystem.read(rel)
local d = CacheBlob.readFs(rel)
if type(d) == "string" and #d > 0 then return d end
local alt = "data/generated/gba/" .. (rel:gsub("^data/generated/gba/", ""))
d = love.filesystem.read(alt)
d = CacheBlob.readFs(alt)
if type(d) == "string" and #d > 0 then return d end
end
local candidates = {
@@ -69,7 +70,7 @@ local function read_bytes(rel)
for _, p in ipairs(candidates) do
local f = io.open(p, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(p, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+3 -2
View File
@@ -6,6 +6,7 @@ local Chrome = require("src.ui.game3.chrome")
local FrlgFont = require("src.ui.game3.frlg_font")
local TeachyTv = require("src.core.game3.teachy_tv")
local SeIds = require("src.core.game3.se_ids")
local CacheBlob = require("src.import.CacheBlob")
local Ui = {}
@@ -129,12 +130,12 @@ local function read_bytes(rel)
if ok and type(d) == "string" and #d > 0 then return d end
end
if love and love.filesystem and love.filesystem.read then
local ok, d = pcall(love.filesystem.read, rel)
local ok, d = pcall(CacheBlob.readFs, rel)
if ok and type(d) == "string" and #d > 0 then return d end
end
local f = io.open(rel, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(rel, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+4 -3
View File
@@ -2,6 +2,7 @@
local Extract = require("src.import.gba.extract_island1")
local TmCaseExtract = require("src.import.gba.tm_case_extract")
local CacheBlob = require("src.import.CacheBlob")
local TmCaseChrome = {}
@@ -41,10 +42,10 @@ local function read_bytes(rel)
if type(d) == "string" and #d > 0 then return d end
end
if love and love.filesystem and love.filesystem.read then
local d = love.filesystem.read(rel)
local d = CacheBlob.readFs(rel)
if type(d) == "string" and #d > 0 then return d end
local alt = "data/generated/gba/" .. (rel:gsub("^data/generated/gba/", ""))
d = love.filesystem.read(alt)
d = CacheBlob.readFs(alt)
if type(d) == "string" and #d > 0 then return d end
end
local candidates = {
@@ -54,7 +55,7 @@ local function read_bytes(rel)
for _, p in ipairs(candidates) do
local f = io.open(p, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(p, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+4 -3
View File
@@ -6,6 +6,7 @@ local Pokemon = require("src.core.game3.pokemon")
local Extract = require("src.import.gba.extract_island1")
local Profile = require("src.core.game3.profile")
local RsTrade = require("src.ui.game3.rs.trade_policy")
local CacheBlob = require("src.import.CacheBlob")
local TradeSceneUi = {}
@@ -45,16 +46,16 @@ local function read_bytes(rel)
if type(d) == "string" and #d > 0 then return d end
end
if love and love.filesystem and love.filesystem.read then
local d = love.filesystem.read(rel)
local d = CacheBlob.readFs(rel)
if type(d) == "string" and #d > 0 then return d end
local alt = "data/generated/gba/" .. (rel:gsub("^data/generated/gba/", ""))
d = love.filesystem.read(alt)
d = CacheBlob.readFs(alt)
if type(d) == "string" and #d > 0 then return d end
end
for _, p in ipairs({ rel, "data/generated/gba/" .. (rel:gsub("^data/generated/gba/", "")) }) do
local f = io.open(p, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(p, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+4 -3
View File
@@ -3,6 +3,7 @@
local Stack = require("src.ui.game3.stack")
local FrlgFont = require("src.ui.game3.frlg_font")
local RomText = require("src.core.game3.rom_text")
local CacheBlob = require("src.import.CacheBlob")
local TrainerCard = { isMenu = true }
@@ -47,15 +48,15 @@ local function read_cache_file(path)
end
end
if love and love.filesystem and love.filesystem.read then
local d = love.filesystem.read(path)
local d = CacheBlob.readFs(path)
if d and #d > 0 then return d end
local alt = "data/generated/gba/" .. (path:gsub("^data/generated/gba/", ""))
d = love.filesystem.read(alt)
d = CacheBlob.readFs(alt)
if d and #d > 0 then return d end
end
local f = io.open(path, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(path, f:read("*a"))
f:close()
if d and #d > 0 then return d end
end
+3 -2
View File
@@ -22,6 +22,7 @@ Records.BOARD_WINDOW_ID = 1
Records.LINK_ROWS = 5
-- pokefirered/include/constants/songs.h:9
local SE = require("src.core.game3.se_ids")
local CacheBlob = require("src.import.CacheBlob")
Records.CACHE_BG = "data/generated/gba/trainer_tower/records_bg.rgba"
Records.CACHE_MANIFEST = "data/generated/gba/trainer_tower/manifest.lua"
@@ -78,12 +79,12 @@ local function read_bytes(rel)
if okR and type(d) == "string" and #d > 0 then return d end
end
if type(love) == "table" and love.filesystem and love.filesystem.read then
local okR, d = pcall(love.filesystem.read, rel)
local okR, d = pcall(CacheBlob.readFs, rel)
if okR and type(d) == "string" and #d > 0 then return d end
end
local f = io.open(rel, "rb")
if f then
local d = f:read("*a")
local d = CacheBlob.decode(rel, f:read("*a"))
f:close()
if type(d) == "string" and #d > 0 then return d end
end
+2 -1
View File
@@ -1,4 +1,5 @@
package.path = "./?.lua;./?/init.lua;" .. package.path
local CacheBlob = require("src.import.CacheBlob")
local T = require("tests.harness")
local check, eq = T.check, T.eq
@@ -62,7 +63,7 @@ local function readFile(path)
if not IDROOT then return nil end
local h = io.open(IDROOT .. path, "rb")
if not h then return nil end
local s = h:read("*a")
local s = CacheBlob.decode(IDROOT .. path, h:read("*a"))
h:close()
return s
end
+2 -1
View File
@@ -1,4 +1,5 @@
package.path = "./?.lua;./?/init.lua;" .. package.path
local CacheBlob = require("src.import.CacheBlob")
local T = require("tests.harness")
local check, eq = T.check, T.eq
@@ -29,7 +30,7 @@ end
local function read(rel)
local f = io.open(ROOT .. "/" .. rel, "rb")
if not f then return nil end
local s = f:read("*a")
local s = CacheBlob.decode(ROOT .. "/" .. rel, f:read("*a"))
f:close()
return s
end
+3 -3
View File
@@ -16,8 +16,8 @@ local function digest(list)
return h
end
eq(CacheContract.markerFor("emerald", SHA), "rom-cache-v4-emerald:" .. SHA, "emerald marker")
check(CacheContract.markerMatches("emerald", "rom-cache-v4-emerald:" .. SHA), "emerald marker matches")
eq(CacheContract.markerFor("emerald", SHA), "rom-cache-v5-emerald:" .. SHA, "emerald marker")
check(CacheContract.markerMatches("emerald", "rom-cache-v5-emerald:" .. SHA), "emerald marker matches")
check(not CacheContract.markerMatches("emerald", "rom-cache-v17-firered:" .. SHA), "a FireRed marker does not")
eq(#CacheContract.requiredFiles("firered"), 456, "FireRed required list size")
@@ -83,7 +83,7 @@ check(not CacheContract.cacheVersionCurrent("emerald", stale), "an emerald meta
local complete = {}
for _, p in ipairs(em) do complete["emerald/" .. p] = "x" end
complete["emerald/" .. CacheContract.MARKER_PATH] = "rom-cache-v4-emerald:" .. SHA
complete["emerald/" .. CacheContract.MARKER_PATH] = "rom-cache-v5-emerald:" .. SHA
complete["emerald/data/generated/gba/meta.json"] = emMeta
check(CacheContract.isReady("emerald", memfs(complete)), "a complete emerald cache is ready")
@@ -59,9 +59,11 @@ check(png:find("tRNS", 1, true) ~= nil, "transparent png has tRNS")
check(K.encodeIndexed(1, 1, { 0 }, { [0] = 0 }, false):find("tRNS", 1, true) == nil, "opaque png has no tRNS")
eq(select(1, K.pngSize(K.encodeGray(4, 5, K.blank(4, 5)))), 4, "gray png width")
local stored = K.zlibStored(string.rep("a", 70000))
eq(stored:byte(1), 0x78, "zlib header")
eq(#stored, 2 + 70000 + 5 * 2 + 4, "two stored blocks plus adler")
local CacheBlob = require("src.import.CacheBlob")
local deflated = CacheBlob.deflate(string.rep("a", 70000), 9)
eq(deflated:byte(1), 0x78, "zlib header")
check(#deflated < 1000, "png idat is deflated")
eq(CacheBlob.inflate(deflated), string.rep("a", 70000), "deflate round trip")
local mods = {
"extract_intro_emerald", "intro_credits_gfx_extract", "extract_title_rse",
@@ -167,7 +167,7 @@ local GameVersion = require("src.core.GameVersion")
for _, profile in ipairs(profiles) do
local version = GameVersion.forSha1(profile[2])
Versions.select(profile[2])
T.eq(Versions.CACHE_VERSION, 129, profile[1] .. " active edition retains shared129 cache stamp")
T.eq(Versions.CACHE_VERSION, 130, profile[1] .. " active edition retains shared130 cache stamp")
local files, set = {}, {}
for _, path in ipairs(Contract.requiredFiles(version)) do
files[version .. "/" .. path] = "fixture"
@@ -178,10 +178,10 @@ for _, profile in ipairs(profiles) do
local profileFs = { prefix = "" }
profileFs.exists = function(path) return files[profileFs.prefix .. path] ~= nil end
profileFs.read = function(path) return files[profileFs.prefix .. path] end
files[meta] = '{"cache_version":128}'
T.eq(Contract.isReady(version, profileFs), false, profile[1] .. " old128 stamp requires reimport")
files[meta] = '{"cache_version":129}'
T.eq(Contract.isReady(version, profileFs), true, profile[1] .. " complete129 cache is ready")
T.eq(Contract.isReady(version, profileFs), false, profile[1] .. " old129 stamp requires reimport")
files[meta] = '{"cache_version":130}'
T.eq(Contract.isReady(version, profileFs), true, profile[1] .. " complete130 cache is ready")
local count = 0
for key, info in pairs(frlgManifests[profile[1]].terrains) do
count = count + 1
@@ -202,6 +202,6 @@ for _, profile in ipairs(profiles) do
end
end
Versions.select("firered")
T.eq(V.CACHE_VERSION, 14, "Emerald cache version advanced once to14")
T.eq(require("src.import.gba.versions_frlg").CACHE_VERSION, 129, "FRLG cache version advanced once to129")
T.eq(V.CACHE_VERSION, 15, "Emerald cache version advanced once to15")
T.eq(require("src.import.gba.versions_frlg").CACHE_VERSION, 130, "FRLG cache version advanced once to130")
T.finish("game3_post_dex_background_2637")
+2 -1
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env luajit
package.path = "./?.lua;./?/init.lua;" .. package.path
local GameCache = require("tests.game3_cache")
local CacheBlob = require("src.import.CacheBlob")
local root = GameCache.mountOrSkip("game3_ball_sheets_test")
require("tests.fixture_data.game3_items").install()
@@ -17,7 +18,7 @@ end
local function slurp(path)
local f = io.open(path, "rb")
if not f then return nil end
local d = f:read("*a")
local d = CacheBlob.decode(path, f:read("*a"))
f:close()
return d
end
+3 -2
View File
@@ -1,3 +1,4 @@
local CacheBlob = require("src.import.CacheBlob")
local M = {}
local function readable(path)
@@ -40,7 +41,7 @@ end
local function metaVersions(root)
local f = io.open(root .. "/meta.json", "rb")
if not f then return nil end
local src = f:read("*a") or ""
local src = CacheBlob.decode(root .. "/meta.json", f:read("*a")) or ""
f:close()
return tonumber(src:match('"cache_version"%s*:%s*(%d+)')) or 0,
tonumber(src:match('"native_version"%s*:%s*(%d+)')) or 0
@@ -104,7 +105,7 @@ function M.cache()
read = function(_, rel)
local f = io.open(rel, "rb")
if not f then return nil end
local data = f:read("*a")
local data = CacheBlob.decode(rel, f:read("*a"))
f:close()
if type(data) == "string" and #data > 0 then return data end
return nil
+2 -1
View File
@@ -28,6 +28,7 @@ print("[info] FireRed cache at " .. cacheRoot)
local FameChecker = require("src.core.game3.fame_checker")
local Ui = require("src.ui.game3.fame_checker")
local Stack = require("src.ui.game3.stack")
local CacheBlob = require("src.import.CacheBlob")
local PERSON = FameChecker.PERSON
local PICK = FameChecker.PICKSTATE
@@ -131,7 +132,7 @@ do
local f = io.open(path, "rb")
check(f ~= nil, "the trainer pic is in the cache today")
if f then
local bytes = f:read("*a")
local bytes = CacheBlob.decode(path, f:read("*a"))
f:close()
eq(#bytes, 64 * 64 * 4, "it is a 64x64 RGBA sprite")
end
+2 -1
View File
@@ -31,6 +31,7 @@ local Versions = require("src.import.gba.versions")
local Slot = require("src.import.gba.slot_machine_extract")
local Trade = require("src.import.gba.trade_extract")
local LinkArt = require("src.import.gba.link_art_extract")
local CacheBlob = require("src.import.CacheBlob")
local SHEETS = {
{ "slot_machine/reel_icons.rgba", 32, 224 },
@@ -139,7 +140,7 @@ print("[info] FireRed cache at " .. root)
local function readFile(rel)
local f = io.open(root .. "/" .. rel, "rb")
if not f then return nil end
local d = f:read("*a")
local d = CacheBlob.decode(root .. "/" .. rel, f:read("*a"))
f:close()
return d
end
+2 -1
View File
@@ -35,6 +35,7 @@ local TrainerTowerExtract = require("src.import.gba.trainer_tower_extract")
local TrainerCardExtract = require("src.import.gba.trainer_card_extract")
local RegionMapExtract = require("src.import.gba.region_map_extract")
local EggExtract = require("src.import.gba.egg_extract")
local CacheBlob = require("src.import.CacheBlob")
print("[test] 1. the ROM offsets follow pret's declaration order")
-- src/script_menu.c:647 aerodactyl tiles, palette, then kabutops tiles, palette
@@ -188,7 +189,7 @@ print("[info] FireRed cache at " .. root)
local function readFile(rel)
local f = io.open(root .. "/" .. rel, "rb")
if not f then return nil end
local d = f:read("*a")
local d = CacheBlob.decode(root .. "/" .. rel, f:read("*a"))
f:close()
return d
end
+2 -1
View File
@@ -35,6 +35,7 @@ local MysteryGiftExtract = require("src.import.gba.mystery_gift_extract")
local TrainerTowerExtract = require("src.import.gba.trainer_tower_extract")
local TutorExtract = require("src.import.gba.tutor_extract")
local AltLayouts = require("src.import.gba.alt_layouts")
local CacheBlob = require("src.import.CacheBlob")
local SHEETS = {
{ "fame_checker/bg.rgba", 240, 160 },
@@ -160,7 +161,7 @@ print("[info] FireRed cache at " .. root)
local function readFile(rel)
local f = io.open(root .. "/" .. rel, "rb")
if not f then return nil end
local d = f:read("*a")
local d = CacheBlob.decode(root .. "/" .. rel, f:read("*a"))
f:close()
return d
end
+2 -1
View File
@@ -27,6 +27,7 @@ local Seagallop = require("src.import.gba.seagallop_extract")
local BattleChrome = require("src.import.gba.battle_chrome_extract")
local CacheContract = require("src.import.CacheContract")
local Versions = require("src.import.gba.versions")
local CacheBlob = require("src.import.CacheBlob")
local function fakeRom(str)
return {
@@ -256,7 +257,7 @@ print("[info] FireRed cache at " .. root)
local function readFile(rel)
local f = io.open(root .. "/" .. rel, "rb")
if not f then return nil end
local data = f:read("*a")
local data = CacheBlob.decode(root .. "/" .. rel, f:read("*a"))
f:close()
return data
end
+2 -1
View File
@@ -14,6 +14,7 @@ end
local BattleChromeExtract = require("src.import.gba.battle_chrome_extract")
local Versions = require("src.import.gba.versions")
local CacheBlob = require("src.import.CacheBlob")
-- include/constants/battle.h:287
local PRET_KEYS = {
@@ -108,7 +109,7 @@ print("[info] FireRed cache at " .. root)
local function readFile(rel)
local f = io.open(root .. "/pokemon/battle/" .. rel, "rb")
if not f then return nil end
local data = f:read("*a")
local data = CacheBlob.decode(root .. "/pokemon/battle/" .. rel, f:read("*a"))
f:close()
return data
end
+2 -1
View File
@@ -2,6 +2,7 @@
-- src/data/party_menu.h:111
package.path = "./?.lua;./?/init.lua;" .. package.path
local CacheBlob = require("src.import.CacheBlob")
local failed = 0
local function check(cond, msg)
@@ -25,7 +26,7 @@ end
local function slurp(path)
local f = io.open(path, "rb")
if not f then return nil end
local d = f:read("*a")
local d = CacheBlob.decode(path, f:read("*a"))
f:close()
return d
end
+2 -1
View File
@@ -24,6 +24,7 @@ end
local Extract = require("src.import.gba.pokedex_chrome_extract")
local Versions = require("src.import.gba.versions")
local CacheContract = require("src.import.CacheContract")
local CacheBlob = require("src.import.CacheBlob")
local PAPER_BYTES = 240 * 160 * 4
local FOOT_BYTES = 16 * 16 * 4
@@ -179,7 +180,7 @@ print("[info] FireRed cache at " .. root)
local function readFile(rel)
local f = io.open(root .. "/pokemon/pokedex/" .. rel, "rb")
if not f then return nil end
local data = f:read("*a")
local data = CacheBlob.decode(root .. "/pokemon/pokedex/" .. rel, f:read("*a"))
f:close()
return data
end
+3 -2
View File
@@ -33,6 +33,7 @@ print("[info] FireRed cache at " .. cacheRoot)
local ExtractScripts = require("src.import.gba.extract_scripts")
local Objects = require("src.core.game3.objects")
local Field = require("src.core.game3.field")
local CacheBlob = require("src.import.CacheBlob")
Space.bundle = ExtractScripts.loadBundle(Cache.cache(), cacheRoot, { allowIncomplete = true })
check(Space.bundle ~= nil, "script bundle loads")
@@ -163,7 +164,7 @@ if gym then
local f = io.open(cacheRoot .. "/native/" .. pairName .. "/mids.idx", "rb")
local packed = {}
if f then
local idx = NativePack.decodeIdx(f:read("*a"))
local idx = NativePack.decodeIdx(CacheBlob.decode(cacheRoot .. "/native/" .. pairName .. "/mids.idx", f:read("*a")))
f:close()
for _, mid in ipairs(idx and idx.midIds or {}) do packed[mid] = true end
end
@@ -192,7 +193,7 @@ if gym then
local f = io.open(cacheRoot .. "/native/" .. pairName .. "/mids.idx", "rb")
local packed = {}
if f then
local idx = NativePack.decodeIdx(f:read("*a"))
local idx = NativePack.decodeIdx(CacheBlob.decode(cacheRoot .. "/native/" .. pairName .. "/mids.idx", f:read("*a")))
f:close()
for _, mid in ipairs(idx and idx.midIds or {}) do packed[mid] = true end
end
+2 -1
View File
@@ -2,6 +2,7 @@
-- src/data/party_menu.h:664, src/party_menu.c:2743, :2785
package.path = "./?.lua;./?/init.lua;" .. package.path
local CacheBlob = require("src.import.CacheBlob")
local failed = 0
local function check(cond, msg)
@@ -29,7 +30,7 @@ end
local function slurp(path)
local f = io.open(path, "rb")
if not f then return nil end
local d = f:read("*a")
local d = CacheBlob.decode(path, f:read("*a"))
f:close()
return d
end
+2 -1
View File
@@ -30,6 +30,7 @@ local Versions = require("src.import.gba.versions")
local Extract = require("src.import.gba.pokedex_chrome_extract")
local PokedexChrome = require("src.ui.game3.pokedex_chrome")
local Pokedex = require("src.ui.game3.pokedex")
local CacheBlob = require("src.import.CacheBlob")
print("[test] 1. versions.lua carries the area-page / size-page ROM offsets")
check(Versions.CACHE_VERSION >= 103, "CACHE_VERSION at or past the dex chrome import ("
@@ -233,7 +234,7 @@ else
local function slurp(rel)
local f = io.open(dexRoot .. "/" .. rel, "rb")
if not f then return nil end
local d = f:read("*a")
local d = CacheBlob.decode(dexRoot .. "/" .. rel, f:read("*a"))
f:close()
return d
end
+2 -1
View File
@@ -50,6 +50,7 @@ check(MultichoiceExtract.ready({
print("[test] 2. baked assets in an imported cache")
local Cache = require("tests.game3_cache")
local CacheBlob = require("src.import.CacheBlob")
local root = Cache.root("region_map/extract_status.json")
if not root then
print("[skip] region map assets: " .. tostring(Cache.reason))
@@ -65,7 +66,7 @@ print("[info] FireRed cache at " .. root)
local function readFile(rel)
local f = io.open(root .. "/" .. rel, "rb")
if not f then return nil end
local data = f:read("*a")
local data = CacheBlob.decode(root .. "/" .. rel, f:read("*a"))
f:close()
return data
end
+2 -1
View File
@@ -11,6 +11,7 @@
-- * bag: listPocket rows are reused until the pocket changes.
package.path = package.path .. ";./?.lua"
local CacheBlob = require("src.import.CacheBlob")
local passed, failed = 0, 0
local function test(name, fn)
@@ -89,7 +90,7 @@ love = {
filesystem = {
read = function(path)
counts.fsRead = counts.fsRead + 1
if path:find("trainers/front/", 1, true) then return string.rep("\0", 64 * 64 * 4) end
if path:find("trainers/front/", 1, true) then return CacheBlob.deflate(string.rep("\0", 64 * 64 * 4)) end
return nil
end,
},
+2 -1
View File
@@ -28,6 +28,7 @@ end
local Versions = require("src.import.gba.versions")
local MapCatalog = require("src.import.gba.map_catalog")
local NativePack = require("src.import.gba.native_pack")
local CacheBlob = require("src.import.CacheBlob")
MapCatalog.rebuildIndex()
-- pokefirered/include/constants/layouts.h:253,267,268,308
@@ -169,7 +170,7 @@ else
local function readFile(rel)
local f = io.open(root .. "/" .. rel, "rb")
if not f then return nil end
local d = f:read("*a")
local d = CacheBlob.decode(root .. "/" .. rel, f:read("*a"))
f:close()
return d
end
+2 -1
View File
@@ -3,6 +3,7 @@
-- pokefirered/src/region_map.c:425
package.path = "./?.lua;./?/init.lua;" .. package.path
local CacheBlob = require("src.import.CacheBlob")
local failed = 0
local function check(cond, msg)
@@ -21,7 +22,7 @@ end
local function slurp(path)
local f = io.open(path, "rb")
if not f then return nil end
local s = f:read("*a")
local s = CacheBlob.decode(path, f:read("*a"))
f:close()
return s
end
+2 -1
View File
@@ -39,11 +39,12 @@ Pokemon.install(nil)
local DIR = root .. "/pokemon/pokedex/footprints"
local NUM_SPECIES = require("src.import.gba.versions").NUM_SPECIES or 412
local CacheBlob = require("src.import.CacheBlob")
local function file_bytes(rel)
local f = io.open(DIR .. "/" .. rel, "rb")
if not f then return nil end
local d = f:read("*a")
local d = CacheBlob.decode(DIR .. "/" .. rel, f:read("*a"))
f:close()
if type(d) == "string" and #d > 0 then return d end
return nil
+2 -1
View File
@@ -4,6 +4,7 @@
package.path = "./?.lua;./?/init.lua;" .. package.path
local T = require("tests.harness")
local CacheBlob = require("src.import.CacheBlob")
local check, eq = T.check, T.eq
local PRET = "../pokefirered"
@@ -13,7 +14,7 @@ local ROM_SHA1 = "41cb23d8dccc8ebd7c649cd8fbb58eeace6e2fdc"
local function slurp(p)
local f = io.open(p, "rb")
if not f then return nil end
local d = f:read("*a")
local d = CacheBlob.decode(p, f:read("*a"))
f:close()
return d
end
+2 -1
View File
@@ -28,6 +28,7 @@ end
local Versions = require("src.import.gba.versions")
local Trade = require("src.import.gba.trade_extract")
local CacheBlob = require("src.import.CacheBlob")
local MENU_SHEETS = {
{ "menu_bg1", 240, 160 },
@@ -136,7 +137,7 @@ print("[test] 3. the offsets hit pret's graphics/trade bins in a matching build"
local function slurp(path)
local f = io.open(path, "rb")
if not f then return nil end
local d = f:read("*a")
local d = CacheBlob.decode(path, f:read("*a"))
f:close()
return d
end
+3 -1
View File
@@ -92,7 +92,9 @@ end
local fs = { prefix = "" }
function fs.exists(rel) return isFile(saveDir .. "/" .. fs.prefix .. rel) end
function fs.read(rel) return readFile(saveDir .. "/" .. fs.prefix .. rel) end
function fs.read(rel)
return require("src.import.CacheBlob").decode(rel, readFile(saveDir .. "/" .. fs.prefix .. rel))
end
if not identityOnly and sourceTreeHasData() then
print("READY source tree")
+2 -1
View File
@@ -3,6 +3,7 @@
from pathlib import Path
import sys
import zlib
from PIL import Image, ImageOps
@@ -29,7 +30,7 @@ def invert(source: Path, destination: Path) -> None:
def invert_rgba(source: Path, destination: Path) -> None:
raw = source.read_bytes()
raw = zlib.decompress(source.read_bytes())
size = GBA_PIC * GBA_PIC * 4
if len(raw) < size:
raise SystemExit(f"{source}: expected {size} bytes of 64x64 RGBA, got {len(raw)}")