87 lines
2.2 KiB
Go
87 lines
2.2 KiB
Go
package player
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
|
|
"aego/app/crash"
|
|
"aego/core/ids"
|
|
"aego/core/log"
|
|
"aego/scene"
|
|
"aego/scene/sceneio"
|
|
scriptruntime "aego/script/runtime"
|
|
"aego/script/vm"
|
|
)
|
|
|
|
func scriptStack(f *vm.Fault) string {
|
|
var b strings.Builder
|
|
for _, fr := range f.Stack {
|
|
b.WriteString(fr.File + ":" + strconv.Itoa(fr.Line) + " " + fr.Function + "\n")
|
|
}
|
|
return b.String()
|
|
}
|
|
|
|
func names(s *scene.Scene) func(ids.NodeID) string {
|
|
return func(id ids.NodeID) string {
|
|
if h := s.Handle(id); !h.IsZero() && s.IsAlive(h) {
|
|
return s.Path(h)
|
|
}
|
|
return id.String()[:8]
|
|
}
|
|
}
|
|
|
|
func (p *Player) info() [][2]string {
|
|
out := [][2]string{}
|
|
if p.Data != nil {
|
|
g := p.Data.Game
|
|
out = append(out, [2]string{"game", g.Name}, [2]string{"gameVersion", g.Version}, [2]string{"profile", p.Data.Profile}, [2]string{"target", p.Data.Target})
|
|
}
|
|
if p.Engine != nil {
|
|
out = append(out, [2]string{"gpu", p.Engine.Caps().Renderer})
|
|
}
|
|
if p.Modules != nil {
|
|
ids := make([]string, len(p.Modules.Modules))
|
|
for i, m := range p.Modules.Modules {
|
|
ids[i] = m.ID
|
|
}
|
|
out = append(out, [2]string{"modules", strings.Join(ids, ",")})
|
|
}
|
|
return out
|
|
}
|
|
|
|
func (p *Player) crash(kind, where string, rec any, stack []byte, script string) {
|
|
defer func() { recover() }()
|
|
if p.crashDir == "" {
|
|
return
|
|
}
|
|
b := crash.Bundle{Dir: p.crashDir, Kind: kind, Where: where, Panic: rec, Stack: stack, Script: script, Log: p.ring, Info: p.info()}
|
|
if p.Engine != nil {
|
|
b.Trace = p.Engine.Trace()
|
|
if w := p.Engine.MainWorld(); w != nil {
|
|
b.Events = w.Recorder
|
|
}
|
|
}
|
|
if p.Scene != nil {
|
|
b.Names = names(p.Scene)
|
|
if p.crashScene {
|
|
b.Scene = sceneio.Save(p.Scene)
|
|
}
|
|
}
|
|
dir, err := crash.Write(b)
|
|
if err != nil {
|
|
p.log.Error("cannot write the crash bundle", log.F("err", err.Error()))
|
|
return
|
|
}
|
|
p.log.Error("crash bundle written", log.F("dir", dir), log.F("where", where))
|
|
}
|
|
|
|
func (p *Player) scriptPanic(boundary string, v any, stack []byte) {
|
|
p.crash("panic", boundary, v, stack, "")
|
|
}
|
|
|
|
func (p *Player) fault(rep scriptruntime.FaultReport) {
|
|
if rep.Fault != nil && rep.Fault.Code == vm.CodeNativePanic {
|
|
p.crash("fault", rep.Type, rep.Fault.Message, []byte(rep.Fault.Detail), scriptStack(rep.Fault))
|
|
}
|
|
}
|