mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-18 19:54:21 +02:00
Merge pull request #1446 from 1Jamie/feat/launcher-fixes-and-patch-notes
This commit is contained in:
@@ -979,7 +979,7 @@ function LauncherView._updateControl(imp)
|
|||||||
end
|
end
|
||||||
-- idle / uptodate / error: offer a manual check, with no glow.
|
-- idle / uptodate / error: offer a manual check, with no glow.
|
||||||
return status, Strings("Check for updates"),
|
return status, Strings("Check for updates"),
|
||||||
function() pcall(imp.Check.start) end, false
|
function() pcall(imp.Check.start, true) end, false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- ------------------------------------------------------------ game panel
|
-- ------------------------------------------------------------ game panel
|
||||||
|
|||||||
@@ -155,11 +155,12 @@ local function drain()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Begin (or, on a prior error, retry) an async check. Safe to call every frame:
|
-- Begin (or, on a prior error, retry) an async check. Safe to call every frame:
|
||||||
-- once a check is in flight or has reached a terminal state it is a no-op.
|
-- once a check is in flight or has reached a terminal state it is a no-op unless
|
||||||
function Check.start()
|
-- force=true is passed (e.g. from an explicit button press).
|
||||||
|
function Check.start(force)
|
||||||
drain()
|
drain()
|
||||||
if cache.status == "checking" or cache.status == "downloading" then return end
|
if cache.status == "checking" or cache.status == "downloading" then return end
|
||||||
if requested and cache.status ~= "error" and cache.status ~= "idle" then return end
|
if not force and requested and cache.status ~= "error" and cache.status ~= "idle" then return end
|
||||||
if not ensureWorker() then
|
if not ensureWorker() then
|
||||||
cache = { status = "error", error = "background threads unavailable" }
|
cache = { status = "error", error = "background threads unavailable" }
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ PatchNotes.FILES = {
|
|||||||
"assets/PATCH_NOTES.md",
|
"assets/PATCH_NOTES.md",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PatchNotes.CACHE_FILES = {
|
||||||
|
"updates/notes_cache.json",
|
||||||
|
}
|
||||||
|
|
||||||
PatchNotes.REPO_FILES = {
|
PatchNotes.REPO_FILES = {
|
||||||
"mobile/ios/app-repo.json",
|
"mobile/ios/app-repo.json",
|
||||||
}
|
}
|
||||||
@@ -48,6 +52,29 @@ local function readPath(path)
|
|||||||
return nonempty(text) and text or nil
|
return nonempty(text) and text or nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function PatchNotes.fromCache(engine)
|
||||||
|
for _, path in ipairs(PatchNotes.CACHE_FILES) do
|
||||||
|
local text = readPath(path)
|
||||||
|
if text then
|
||||||
|
local ok, doc = pcall(Json.decode, text)
|
||||||
|
if ok and type(doc) == "table" then
|
||||||
|
if engine and engine ~= "0.0.0-dev" then
|
||||||
|
if doc[engine] and nonempty(doc[engine]) then
|
||||||
|
return doc[engine], engine
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for ver, notes in pairs(doc) do
|
||||||
|
if nonempty(notes) then
|
||||||
|
return notes, ver
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil, nil
|
||||||
|
end
|
||||||
|
|
||||||
function PatchNotes.fromFile()
|
function PatchNotes.fromFile()
|
||||||
for _, path in ipairs(PatchNotes.FILES) do
|
for _, path in ipairs(PatchNotes.FILES) do
|
||||||
local text = readPath(path)
|
local text = readPath(path)
|
||||||
@@ -88,6 +115,7 @@ function PatchNotes.fromRepo(engine)
|
|||||||
return row.notes, row.version
|
return row.notes, row.version
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
return nil, nil
|
||||||
end
|
end
|
||||||
return list[1].notes, list[1].version
|
return list[1].notes, list[1].version
|
||||||
end
|
end
|
||||||
@@ -96,17 +124,24 @@ function PatchNotes.fromRepo(engine)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function PatchNotes.body(Check)
|
function PatchNotes.body(Check)
|
||||||
local notes, ver = PatchNotes.fromCheck(Check)
|
|
||||||
if notes then return notes, ver end
|
|
||||||
notes = PatchNotes.fromFile()
|
|
||||||
if notes then return notes, ver end
|
|
||||||
local Version = require("src.core.Version")
|
local Version = require("src.core.Version")
|
||||||
local engine = (Version and Version.engine) or "?"
|
local engine = (Version and Version.engine) or "?"
|
||||||
|
|
||||||
|
local notes, ver = PatchNotes.fromCheck(Check)
|
||||||
|
if notes and (engine == "0.0.0-dev" or ver == engine or ver == nil) then
|
||||||
|
return notes, ver or engine
|
||||||
|
end
|
||||||
|
|
||||||
|
notes, ver = PatchNotes.fromCache(engine)
|
||||||
|
if notes then return notes, ver end
|
||||||
|
|
||||||
|
notes = PatchNotes.fromFile()
|
||||||
|
if notes then return notes, engine end
|
||||||
|
|
||||||
notes, ver = PatchNotes.fromRepo(engine)
|
notes, ver = PatchNotes.fromRepo(engine)
|
||||||
if notes then return notes, ver end
|
if notes then return notes, ver end
|
||||||
return "No patch notes loaded yet for gen1recomp v" .. engine .. ".\n\n"
|
|
||||||
.. "They appear here after the launcher checks GitHub for the latest "
|
return "Unable to fetch patch notes.", engine
|
||||||
.. "release.", engine
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return PatchNotes
|
return PatchNotes
|
||||||
|
|||||||
@@ -151,6 +151,28 @@ local function gatePasses(rel)
|
|||||||
return not (info.minShell and info.minShell > shell)
|
return not (info.minShell and info.minShell > shell)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function cacheNotes(ver, notes)
|
||||||
|
if not (ver and type(notes) == "string" and notes ~= "" and Json) then return end
|
||||||
|
if not (love and love.filesystem) then return end
|
||||||
|
pcall(function()
|
||||||
|
love.filesystem.createDirectory("updates")
|
||||||
|
local cachePath = "updates/notes_cache.json"
|
||||||
|
local existing = {}
|
||||||
|
if love.filesystem.getInfo and love.filesystem.getInfo(cachePath) then
|
||||||
|
local text = love.filesystem.read(cachePath)
|
||||||
|
if text then
|
||||||
|
local ok, doc = pcall(Json.decode, text)
|
||||||
|
if ok and type(doc) == "table" then existing = doc end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
existing[ver] = notes
|
||||||
|
local ok, encoded = pcall(Json.encode, existing)
|
||||||
|
if ok and encoded then
|
||||||
|
love.filesystem.write(cachePath, encoded)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
-- check
|
-- check
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
@@ -177,6 +199,9 @@ local function doCheck()
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
pending = rel
|
pending = rel
|
||||||
|
if rel.version and type(rel.notes) == "string" and rel.notes ~= "" then
|
||||||
|
cacheNotes(rel.version, rel.notes)
|
||||||
|
end
|
||||||
|
|
||||||
-- Unstamped dev build: the working tree always looks "newer", so never
|
-- Unstamped dev build: the working tree always looks "newer", so never
|
||||||
-- pester the developer with an update (contract item, Check design).
|
-- pester the developer with an update (contract item, Check design).
|
||||||
|
|||||||
+203
-279
File diff suppressed because it is too large
Load Diff
@@ -68,6 +68,12 @@ do
|
|||||||
"stashed notes name a release version")
|
"stashed notes name a release version")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local notes, ver = PatchNotes.fromRepo("999.999.999")
|
||||||
|
eq(notes, nil, "fromRepo returns nil when a specific engine version is missing")
|
||||||
|
eq(ver, nil, "fromRepo version is nil when missing")
|
||||||
|
end
|
||||||
|
|
||||||
do
|
do
|
||||||
local f = assert(io.open("mobile/ios/app-repo.json", "rb"))
|
local f = assert(io.open("mobile/ios/app-repo.json", "rb"))
|
||||||
local list = PatchNotes.parseRepo(f:read("*a"))
|
local list = PatchNotes.parseRepo(f:read("*a"))
|
||||||
@@ -78,6 +84,15 @@ do
|
|||||||
eq(notes, list[2].notes, "fromRepo returns that version's notes")
|
eq(notes, list[2].notes, "fromRepo returns that version's notes")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local oldVersion = package.loaded["src.core.Version"]
|
||||||
|
package.loaded["src.core.Version"] = { engine = "999.999.999" }
|
||||||
|
local body, ver = PatchNotes.body(nil)
|
||||||
|
eq(body, "Unable to fetch patch notes.", "returns Unable to fetch patch notes when version is uncached and unlisted")
|
||||||
|
eq(ver, "999.999.999", "returns the requested engine version")
|
||||||
|
package.loaded["src.core.Version"] = oldVersion
|
||||||
|
end
|
||||||
|
|
||||||
imp._appPatchNotes = true
|
imp._appPatchNotes = true
|
||||||
local modal = drawAndCapture(imp)
|
local modal = drawAndCapture(imp)
|
||||||
check(modal:find("Patch notes", 1, true) ~= nil, "the modal titles itself")
|
check(modal:find("Patch notes", 1, true) ~= nil, "the modal titles itself")
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
-- Source file LuaJIT limits gate.
|
||||||
|
-- Verifies that every game engine source file compiles cleanly under
|
||||||
|
-- LuaJIT without exceeding LuaJIT's strict 200 local variables per-scope limit,
|
||||||
|
-- 60 upvalue limit, or bytecode compiler limits.
|
||||||
|
-- luajit tests/engine/luajit_source_limits_test.lua
|
||||||
|
|
||||||
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
||||||
|
|
||||||
|
local T = require("tests.harness")
|
||||||
|
local check, eq = T.check, T.eq
|
||||||
|
|
||||||
|
-- Find all .lua files in a directory recursively.
|
||||||
|
local function findLuaFiles(dir, out)
|
||||||
|
out = out or {}
|
||||||
|
local p = io.popen("find " .. dir .. " -type f -name '*.lua'")
|
||||||
|
if p then
|
||||||
|
for line in p:lines() do
|
||||||
|
out[#out + 1] = line
|
||||||
|
end
|
||||||
|
p:close()
|
||||||
|
end
|
||||||
|
table.sort(out)
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
|
local files = findLuaFiles("src")
|
||||||
|
findLuaFiles("tools/save-editor", files)
|
||||||
|
files[#files + 1] = "main.lua"
|
||||||
|
files[#files + 1] = "conf.lua"
|
||||||
|
|
||||||
|
check(#files > 50, "discovered project source files (found " .. tostring(#files) .. ")")
|
||||||
|
|
||||||
|
for _, path in ipairs(files) do
|
||||||
|
local f = assert(io.open(path, "rb"), "could not open " .. path)
|
||||||
|
local source = f:read("*a")
|
||||||
|
f:close()
|
||||||
|
|
||||||
|
-- Compile through LuaJIT loadstring: detects 'main function has more than 200 local variables'
|
||||||
|
-- or 'function has more than 200 local variables' across any function scope in the file.
|
||||||
|
local chunk, err = loadstring(source, "@" .. path)
|
||||||
|
check(chunk ~= nil, path .. " compiles under LuaJIT: " .. tostring(err))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Meta-test: prove that exceeding 200 locals fails the gate
|
||||||
|
do
|
||||||
|
local overflowLocals = {}
|
||||||
|
for i = 1, 201 do overflowLocals[i] = "v" .. i end
|
||||||
|
local badCode = "local " .. table.concat(overflowLocals, ", ")
|
||||||
|
local chunk, err = loadstring(badCode, "@overflow_test.lua")
|
||||||
|
check(chunk == nil, "LuaJIT strictly rejects chunks exceeding 200 locals")
|
||||||
|
check(tostring(err):find("200 local variables", 1, true) ~= nil, "error message specifies 200 local variable limit")
|
||||||
|
end
|
||||||
|
|
||||||
|
T.finish("luajit_source_limits")
|
||||||
Reference in New Issue
Block a user