Merge pull request #1808 from 1Jamie/fix/mobile-lc

fix(mobile): in-process launcher return for Android and iOS
This commit is contained in:
bryanthaboi
2026-08-25 15:14:05 -04:00
committed by GitHub
8 changed files with 115 additions and 25 deletions
+17 -1
View File
@@ -158,7 +158,15 @@ end
-- and the app dies. There we relaunch through the GameActivity.restartApp
-- JNI bridge (love.system.restartApp), which schedules our launch intent
-- and kills the process so no native state can leak into the fresh run.
-- On every other platform the in-process restart works, so keep it.
-- iOS is the same class of problem with a sharper edge: love.cpp under
-- LOVE_IOS forces DONE_RESTART for *every* quit (Apple forbids programmatic
-- exit) and comments that leftover threads make that restart unreliable --
-- which our ChipAudio / Fetch / Check workers are. There is no
-- restartApp bridge on iOS, so callers that want "back to launcher" must
-- use main.lua's in-process returnToLauncher (love.quit aborts the quit);
-- HostShell.restart itself refuses quit("restart") and falls back to a
-- bare quit() so a mod that still calls restart does not pick the worst
-- path on purpose.
function HostShell.restart()
if not (love and love.event and love.event.quit) then return end
@@ -174,6 +182,14 @@ function HostShell.restart()
love.event.quit()
return
end
if osName == "iOS" then
-- No process-kill bridge. A bare quit still becomes DONE_RESTART in
-- love.cpp, but quit("restart") is the path that also runs our
-- endProcess worker joins first and then re-enters runlove -- the
-- combination that crashes EXIT GAME. Prefer the softer quit.
love.event.quit()
return
end
local appimage = os.getenv("APPIMAGE")
if not appimage then
+13 -6
View File
@@ -64,11 +64,18 @@ end
-- EXIT GAME / intent_game before dropping Game. Stops audio and resets the
-- live game instance so map/GPU holders are gone before endMountedSession.
--
-- ChipAudio's worker stays alive across game sessions (see tier comment
-- above). shutdown() joins the thread and is process-exit only -- calling
-- it here on every Android EXIT GAME has been observed to leave the Gen1
-- Game singleton unbootable (Game.load nil) on the next Play of a version
-- already opened this process, while a debug APK with a different liblove
-- did not reproduce.
function SessionLifecycle.endGameSession(game)
pcall(function() require("src.core.Music").stop() end)
pcall(function() require("src.core.Sound").stop() end)
if package.loaded["src.core.ChipAudio"] then
pcall(package.loaded["src.core.ChipAudio"].shutdown)
pcall(package.loaded["src.core.ChipAudio"].stopMusic)
end
if package.loaded["src.core.DiscordPresence"] then
pcall(package.loaded["src.core.DiscordPresence"].shutdown)
@@ -87,11 +94,11 @@ function SessionLifecycle.endGameSession(game)
if game and game.reset then
pcall(function() game:reset() end)
end
-- Gen1 Game is the module singleton. If teardown left it without load,
-- drop the cached module so the next require rebuilds a clean table
-- (bootGame also guards this; doing it here keeps Play-again reliable).
if game and type(game.load) ~= "function"
and package.loaded["src.core.Game"] == game then
-- Gen1 Game is the module singleton. Always drop the cached module after
-- a session that owned it so the next bootGame require rebuilds a clean
-- table. A type(game.load) check is not enough: a wrong table parked in
-- package.loaded (e.g. with __index) can still look like it has load.
if game and package.loaded["src.core.Game"] == game then
package.loaded["src.core.Game"] = nil
end