extends SceneTree
## Gate: [MountainStats] worst= reports the REAL worst frame (hyper-games #93 §2).
##
## It took max(delta), and the engine CLAMPS delta: when a frame needs more than
## max_physics_steps_per_frame physics steps (default 8), main.cpp cuts
## process_step to 8 × the physics step (~133 ms at 60 Hz). So a 4117 ms stall
## printed worst=135ms. The hitch logger already times frames by the wall clock;
## MountainStats now does too.
##
## Part 1 shows the cause on this engine; part 2 checks map_mountain's timing.
##
## Run: "$HYPER_TPS_GODOT" --headless --path . --script res://scenes/test/gate_mountain_stats_worst.gd
const STALL_MS := 600
var ok := true
var _frame := 0
var _stall_delta := -1.0
func _p(c: bool, m: String) -> void:
print(("ok " if c else "FAIL: ") + m)
if not c:
ok = false
func _process(delta: float) -> bool:
_frame += 1
if _frame == 10:
OS.delay_msec(STALL_MS) # this frame takes > 600 ms of wall time
elif _frame == 11:
_stall_delta = delta # what the next _process is told it took
elif _frame == 12:
_run()
print("GATE mountain_stats_worst: %s" % ("PASS" if ok else "FAIL"))
quit(0 if ok else 1)
return true
return false
func _run() -> void:
print("-- the cause: delta is clamped")
_p(_stall_delta > 0.0 and _stall_delta < 0.2,
"a %d ms stall is reported to _process as %.0f ms (clamped by max_physics_steps_per_frame)" % [STALL_MS, _stall_delta * 1000.0])
print("-- MountainStats times frames by the wall clock")
var m: Node = load("res://scenes/maps/map_mountain.gd").new()
_p(m.has_method("_stat_note_frame"), "map_mountain has _stat_note_frame()")
if not m.has_method("_stat_note_frame"):
m.free()
return
m._stat_note_frame()
OS.delay_msec(STALL_MS)
m._stat_note_frame()
var worst_ms: float = float(m.get("_stat_worst")) * 1000.0
_p(worst_ms >= STALL_MS - 20, "a %d ms gap is recorded as worst=%.0f ms" % [STALL_MS, worst_ms])
m.free()