hajimehoshi / ebiten

Ebitengine - A dead simple 2D game engine for Go
https://ebitengine.org
Apache License 2.0
11.01k stars 659 forks source link

Recovery from panic in game loop #2262

Closed erexo closed 2 years ago

erexo commented 2 years ago

Currently I'm facing a strange bug in production that occurs very randomly and to random people. My strategy was to recover from panic and to log given message, but the problem is that the ebiten.Run() function is staging an internal goroutine for the loop, so I cant really catch given panic outside of that goroutine. It would be really helpful to recover a panic of that goroutine and throw it back in the actual method, or return that panic as an error.

package main

import (
    "log"

    "github.com/hajimehoshi/ebiten/v2"
)

func main() {
    defer func() {
        if r := recover(); r != nil {
            // r will always be nil here
            log.Println(r)
        }
    }()
    if err := ebiten.RunGame(&game{}); err != nil {
        // err will be nil as well
        log.Println(err)
    }
}

type game struct{}

func (g *game) Update() error { return nil }

func (g *game) Draw(screen *ebiten.Image) {
    _ = []int{}[0]
}

func (g *game) Layout(outsideWidth, outsideHeight int) (int, int) {
    return outsideWidth, outsideHeight
}
hajimehoshi commented 2 years ago

What panic is happening? Is this in Ebitengine or in your game?

erexo commented 2 years ago

What panic is happening?

This is the case, I have no idea and I would like to know, hence this Issue was created 😄

The panic is probably somewhere in the code, something like given example. The main problem is that, as I mentioned, it happens randomly and to random people so I cant really debug it to find out, I want to have it logged to a file so I could ask those people to send me their log files, but I can't log it because I can't recover from an internal goroutine

hajimehoshi commented 2 years ago

I think you should catch the log in all of your game's goroutines first.

hajimehoshi commented 2 years ago

Unfortunately there is no way to recover a panic in a different goroutine. This is Go's restriction, and there is nothing we can do in Ebitengine.

erexo commented 2 years ago

You can catch it in the actual loop goroutine...

erexo commented 2 years ago

did you read the example I wrote? Ebitengine offers me no tool to actually know that the Draw method panicked...

hajimehoshi commented 2 years ago

did you read the example I wrote? Ebitengine offers me no tool to actually know that the Draw method panicked...

What about recovering the panic in Draw?

erexo commented 2 years ago

and that might be the solution, thanks