diff --git a/src/core/Game.lua b/src/core/Game.lua index 1bad3b9f..ca4811e7 100644 --- a/src/core/Game.lua +++ b/src/core/Game.lua @@ -391,9 +391,7 @@ end -- LÖVE process ensures scripts, registries, and assets are all rebuilt from -- the newly selected mod state. function Game:restartWithMods() - if love.event and love.event.quit then - love.event.quit("restart") - end + require("src.core.HostShell").restart() end function Game:keyreleased(key) diff --git a/src/core/HostShell.lua b/src/core/HostShell.lua index 2ce06b9b..587a22f4 100644 --- a/src/core/HostShell.lua +++ b/src/core/HostShell.lua @@ -20,4 +20,32 @@ function HostShell.popen(command, mode) return pipe end +-- Restart the whole app. The obvious love.event.quit("restart") re-runs LÖVE's +-- boot in-process, which calls love.filesystem.init a second time -- and inside +-- an AppImage physfs is already initialized, so that second init throws +-- ("Failed to initialize filesystem: already initialized") and the relaunch +-- crashes. So on an AppImage we relaunch the executable; the fresh process's +-- Boot step mounts any downloaded update exactly as a manual relaunch would. +-- On every other platform the in-process restart works, so keep it. +function HostShell.restart() + if not (love and love.event and love.event.quit) then return end + local appimage = os.getenv("APPIMAGE") + if not appimage then + love.event.quit("restart") + return + end + + -- We have to restart the process with this cursed execv call to prevent the + -- PID from changing, which might cause SteamOS and other Linux launchers to + -- think the app has crashed. + local ffi = require("ffi") + pcall(ffi.cdef, [[ + int execv(const char *path, char *const argv[]); + int unsetenv(const char *name); + ]]) + ffi.C.unsetenv("LD_LIBRARY_PATH") + local argv = ffi.new("const char *[2]", appimage, nil) + ffi.C.execv(appimage, ffi.cast("char *const *", argv)) +end + return HostShell diff --git a/src/import/RomImporter.lua b/src/import/RomImporter.lua index c604f1cf..99618938 100644 --- a/src/import/RomImporter.lua +++ b/src/import/RomImporter.lua @@ -1860,7 +1860,7 @@ function RomImporter:mousepressed(x, y, button) if action == "download" and self.Check then pcall(self.Check.download) elseif action == "restart" then - love.event.quit("restart") + HostShell.restart() elseif action == "openurl" and self.Check then love.system.openURL(self.Check.releaseUrl()) end