Prevent Guide detail render crashes

This commit is contained in:
AverageConsumer
2026-08-24 18:42:13 +02:00
parent d175451d75
commit f748c340b7
2 changed files with 79 additions and 11 deletions
+20 -11
View File
@@ -3419,11 +3419,11 @@ return function(mod)
end
end
if not row then displayRuntime.guideDetail = nil; drawGuide(); return end
displayRuntime.guideDetail.page = math.max(1,
math.min(displayRuntime.guideDetail.page, row.detailPages))
local pages = math.max(1, tonumber(row.detailPages) or 1)
local current = tonumber(displayRuntime.guideDetail.page) or 1
displayRuntime.guideDetail.page = math.max(1, math.min(current, pages))
header(THEME:format("WHERE %d/%d", displayRuntime.guideDetail.page,
row.detailPages),
true, row.detailPages > 1)
pages), true, pages > 1)
text(fit(row.name, 17), 5, 24, INK)
text(row.availability == "now" and THEME:translate("NOW")
or row.availability == "time" and guide.time
@@ -4551,8 +4551,7 @@ return function(mod)
end
end
local function draw()
G.push("all")
displayRuntime.drawContents = function()
G.setCanvas(canvas)
G.origin()
G.setScissor()
@@ -4632,7 +4631,13 @@ return function(mod)
outline(1, 1, WIDTH - 2, HEIGHT - 2, INK)
end
G.setCanvas()
end
local function draw()
G.push("all")
local ok, err = pcall(displayRuntime.drawContents)
G.pop()
if not ok then error(err, 0) end
end
local function pumpDisplay()
@@ -5198,9 +5203,11 @@ return function(mod)
end
end
if row and row.detailPages > 1 then
displayRuntime.guideDetail.page = carouselSubpage(
displayRuntime.guideDetail.page, row.detailPages, direction)
dirty = true
local nextPage = carouselSubpage(displayRuntime.guideDetail.page,
row.detailPages, direction)
if nextPage then
displayRuntime.guideDetail.page, dirty = nextPage, true
end
end
return
end
@@ -5465,13 +5472,15 @@ return function(mod)
end
end
if row and row.detailPages > 1 then
local nextPage
if x >= 22 and x < 48 then
displayRuntime.guideDetail.page = carouselSubpage(
nextPage = carouselSubpage(
displayRuntime.guideDetail.page, row.detailPages, -1)
elseif x >= 80 and x < 106 then
displayRuntime.guideDetail.page = carouselSubpage(
nextPage = carouselSubpage(
displayRuntime.guideDetail.page, row.detailPages, 1)
end
if nextPage then displayRuntime.guideDetail.page = nextPage end
end
end
dirty = true
+59
View File
@@ -318,12 +318,71 @@ do
if name == target then return value end
end
end
local function setUpvalue(fn, target, value)
for index = 1, debug.getinfo(fn, "u").nups do
if debug.getupvalue(fn, index) == target then
debug.setupvalue(fn, index, value)
return true
end
end
end
local inputHook
for _, entry in ipairs(run.loader.hooks.chains["input.step"] or {}) do
if entry.owner == "kanto_gear" then inputHook = entry.callback end
end
local changePage = upvalue(upvalue(inputHook, "pollTriggerTabs"),
"changePage")
local composeHook
for _, entry in ipairs(run.loader.hooks.chains["render.compose"] or {}) do
if entry.owner == "kanto_gear" then composeHook = entry.callback end
end
local touchEvent = upvalue(composeHook, "touchEvent")
local tap = upvalue(touchEvent, "tap")
local displayRuntime = upvalue(changePage, "displayRuntime")
local guideData = upvalue(changePage, "guideData")
T.check(setUpvalue(changePage, "page", "GUIDE"),
"Guide regression can select the GUIDE tab")
T.check(guideData().rows[1].detailPages > 1,
"Guide regression fixture has multiple detail pages")
tap(10, 50)
T.eq(displayRuntime.guideDetail.page, 1,
"tapping a Guide row opens its first detail page")
changePage(-1)
T.eq(displayRuntime.guideDetail.page, 1,
"swiping back at the first detail boundary keeps a valid page")
tap(30, 10)
T.eq(displayRuntime.guideDetail.page, 1,
"tapping back at the first detail boundary keeps a valid page")
local lastDetailPage = guideData().rows[1].detailPages
displayRuntime.guideDetail.page = lastDetailPage
tap(90, 10)
T.eq(displayRuntime.guideDetail.page, lastDetailPage,
"tapping forward at the last detail boundary keeps a valid page")
displayRuntime.guideDetail = nil
setUpvalue(changePage, "page", "MAP")
local pumpDisplay = upvalue(composeHook, "pumpDisplay")
local draw = upvalue(pumpDisplay, "draw")
local drawContents = displayRuntime.drawContents
local push, pop = T.love.graphics.push, T.love.graphics.pop
local graphicsDepth = 0
T.love.graphics.push = function(...)
graphicsDepth = graphicsDepth + 1
return push(...)
end
T.love.graphics.pop = function(...)
graphicsDepth = graphicsDepth - 1
return pop(...)
end
displayRuntime.drawContents = function() error("expected draw failure") end
local ok = pcall(draw)
displayRuntime.drawContents = drawContents
T.love.graphics.push, T.love.graphics.pop = push, pop
T.check(not ok, "companion draw failures remain observable")
T.eq(graphicsDepth, 0,
"companion draw failures restore the graphics stack")
for _ = 1, 6 do changePage(1) end
local previousParty, previousIcons = game.save.party, run.data.gen2Icons