Page 1 of 1

Use love error handler back to back

Posted: Sun Mar 27, 2022 6:41 pm
by Syrius_Märx
Hello everyone !
I have question about error handling.

With the function love.errorhandler(msg) we can do stuff and go back to the game if an unexpected error occurs. It’s really nice.
BUT, it works once. The second time an error occurs, love.errorhandler(msg) seems to be void and the game just end.
Here is a very simplified version of my code :

Code: Select all

BOOT = 0

function love.errorhandler(msg)
  CRASH = true
  love.window.setMode(640,360)
  while CRASH do
    love.event.pump()
    for e, a, b, c in love.event.poll() do
      if e == "keypressed" and a == "escape" then
        CRASH = false
        return love.run() -- restart mainloop beginning with love.load
      end
    end
    love.graphics.printf("Game crashed "..tostring(BOOT).." time(s)\n\n\nPress ESC to restart", 0, 160, 640, 'center')
    love.graphics.present()
    love.timer.sleep(0.1)
  end
end

function love.load()
  BOOT = BOOT + 1
  CLOCK = 0
  love.window.setMode(640,360)
  love.graphics.printf("Game is loading\n#"..tostring(BOOT), 0, 160, 640, 'center')
  love.graphics.present()
  love.timer.sleep(2)
end

function love.update(dt)
  CLOCK = CLOCK + dt
  if love.keyboard.isDown('space') then fakefunction() end 
end

function love.draw()
  love.graphics.printf("Game is running for:\n"..tostring(math.floor(CLOCK)).." sec\n\nPress SPACE to crash", 0, 160, 640,'center')
end

function love.quit()
  love.graphics.printf("THE END !", 0, 160, 640, 'center')
  love.timer.sleep(2)
end
  • Boot #1 is launch
  • Boot #2 is reboot after crash
  • Boot #3 never exists
How to go to boot #3 and further ?

I think I misanderstood something about the way it should work and I would appreciate some help.
It may be around the return love.run() but without this line, game stops at the end of love.errorhandler . . .
I already develop the parts about save log, restart a match, live hot fix with console but i'm stuck with the possibility to use error handlder back to back.

Hope I'm clear enough and you could help me !

Syrius

Re: Use love error handler back to back

Posted: Mon Mar 28, 2022 7:44 am
by ReFreezed
love.errorhandler is just supposed to be used for error reporting right before the game quits - not to restore or restart the state of the game. If you return a function (which the `return love.run()` line does) that function is supposed to just display the error. LÖVE doesn't expect the game to continue at that point.

If you have a function call somewhere that you want to catch errors from you should wrap the call with pcall or xpcall and handle the error manually (instead of letting LÖVE know about the error and do things you don't want). If you want to restart the whole game after an error you can call love.event.quit("restart"). (Note that it doesn't work if we've reached the point when LÖVE calls love.errorhandler.)

Re: Use love error handler back to back

Posted: Mon Mar 28, 2022 8:33 pm
by Syrius_Märx
Even if it's not supposed to be used like that, the fact is : it works fine . . . at least once.
It could be a powerfull tool for smoothly passing over critical errors (or for debugging).
What I understand is that return love.run() is not a root reboot, but a reboot whithin love.errorhandler which is not recursive itself. So the end of program happens.

I know pcall. I already use it, especially for system input/ouput. I also add conditionnals to secure against void variables.
But it never will catch all errors. That's the core of the problem, an 'unexpected error'.

Anyway thanks for the anwser, it was clear !

If anyone find a workaround in future, i'm still open to hear it.

Re: Use love error handler back to back

Posted: Tue Mar 29, 2022 12:20 pm
by ReFreezed
Syrius_Märx wrote: Mon Mar 28, 2022 8:33 pm it works fine . . . at least once.
(...)
What I understand is that return love.run() is not a root reboot, but a reboot whithin love.errorhandler which is not recursive itself. So the end of program happens.
The call to love.run() does not restart anything as far as LÖVE is concerned, and is not important. It's that LÖVE expects love.errorhandler to return a function that handles one frame during the time the error should be reported, before LÖVE quits. That's all. love.run() just happens to return such a function.

It's important to know why something works. You can continue doing things with graphics, sound, controller input etc. in the error handler because the program hasn't started shutting itself off yet when it's called. LÖVE could have simply printed out the error message to the console and shut down immediately when an uncaught error happened, but that's not very good user experience. Showing that an error happened graphically is less confusing than suddenly getting kicked out to the desktop, so LÖVE delays shutting things down until the user knows an error happened and is ready to close the window. Still, LÖVE's error handling only happens as a last line of defense against "getting kicked out to the desktop with no information" - if you want to handle an error yourself (in a non-hacky way) you have to catch it before LÖVE catches it.

Anyway, here's a way to catch errors and even using LÖVE's error handler to report the error, but without letting LÖVE itself catch and know about the error.

Code: Select all

local function reportErrorAndRestart(err)
	local errHandler  = love.errorhandler or love.errhand
	local errMainLoop = errHandler(err)

	repeat until errMainLoop() -- Repeat until the callback returns an exit code.

	-- We can restart the game now.
	love.load() -- Or call love.event.quit("restart").
end

local function onKeypressed(key)
	if key == "space" then  doesNotExist()  end -- Triggers an error.
end
local function onUpdate(dt)
	-- ...
end
local function onDraw()
	love.graphics.print("Running game!", 10, 10)
end

-- Wrap all your code in protected calls.
function love.keypressed(...)  xpcall(onKeypressed, reportErrorAndRestart, ...)  end
function love.update    (...)  xpcall(onUpdate    , reportErrorAndRestart, ...)  end
function love.draw      (...)  xpcall(onDraw      , reportErrorAndRestart, ...)  end

Re: Use love error handler back to back

Posted: Tue Mar 29, 2022 9:23 pm
by Syrius_Märx
Ok, thanks for precisions.

I know the way i used it was a bit tricky
In a second hand, I was wondering about protect main functions. And you confirm it could be a solution.

I dont have time to test tonight but i'll post feedback in next days.

Re: Use love error handler back to back

Posted: Sat Apr 02, 2022 9:39 pm
by pgimeno
Syrius_Märx wrote: Mon Mar 28, 2022 8:33 pm I know pcall. I already use it, especially for system input/ouput. I also add conditionnals to secure against void variables.
But it never will catch all errors. That's the core of the problem, an 'unexpected error'.
Can you name an example of an error that pcall won't catch but love.errorhandler will?