scopedvr-map-editor/tests/probe_playtest_fps.gd

105 lines
4.1 KiB
GDScript

extends SceneTree
## FPS-Probe (Karte t_1da96275, Punkt 5 der Spec): Playtest mit ECHTER Physik
## (SubViewport + World3D + CharacterBody3D + Trimesh-Kollider: Terrain +
## several Gebäude/Bauteile) darf die Editor-Sicht NICHT unter ~60 fps drücken.
##
## Ausführen (braucht einen Bildschirm — virtueller Screen):
## xvfb-run -a godot4 --path . --rendering-driver opengl3 -s res://tests/probe_playtest_fps.gd
## Messung RELATIV (der Container rendert Software-OpenGL/llvmpipe — die
## absolute FPS-Zahl ist dort ein Render-Artefakt): Editor-Sicht OHNE Playtest
## vs. MIT Playtest-Physik (SubViewport + World3D + CharacterBody3D +
## Trimesh-Kollider). Exit 0, wenn der Physik-Zusatz ≤ 20 % Kosten bringt und
## die Editor-Basis unverändert flüssig bleibt (echte 60-fps-Abnahme: Sly-Test).
var main: Control
func _initialize() -> void:
_run.call_deferred()
func _run() -> void:
var scene: PackedScene = load("res://scenes/main.tscn")
main = scene.instantiate()
root.add_child(main)
await process_frame
await process_frame
# Probe-Map: Terrain + mehrere Objekte (Trimeshe) + Bauteile — echte Last.
var doc: Dictionary = SvmapDocument.create_new("FPS-Probe", 200.0, "mittag")
doc["objects"] = [
{"id": "building_001", "pos": [0.0, 0.0, -30.0], "rot_y_deg": 0.0, "scale": 1.0},
{"id": "barracks_001", "pos": [20.0, 0.0, 30.0], "rot_y_deg": 90.0, "scale": 1.0},
{"id": "hangar_001", "pos": [-40.0, 0.0, 20.0], "rot_y_deg": 45.0, "scale": 1.0},
{"id": "container_001", "pos": [10.0, 0.0, 10.0], "rot_y_deg": 0.0, "scale": 1.0},
{"id": "tent_001", "pos": [-20.0, 0.0, -10.0], "rot_y_deg": 0.0, "scale": 1.0},
{"id": "box_006", "pos": [6.0, 0.0, 4.0], "rot_y_deg": 0.0, "scale": 1.0},
]
var build_ops := load("res://src/editor/build_ops.gd")
var teile: Array = []
for i in 24:
var kind: String = ["wand", "boden", "tuer", "treppe"][i % 4]
var px := -16.0 + float(i % 6) * 2.0
var pz := 40.0 + float(i / 6) * 2.0
teile.append(build_ops.call("make_piece", kind, Vector3(px, 0.0, pz), 0.0))
doc["gebaeude"] = teile
doc["spawn_zones"] = {"0": {"points": [{"id": "A1", "pos": [0.0, 0.0, 20.0]},
{"id": "A2", "pos": [5.0, 0.0, 20.0]}, {"id": "A3", "pos": [-5.0, 0.0, 20.0]},
{"id": "A4", "pos": [10.0, 0.0, 20.0]}]}}
main.set("doc", doc)
main.set("current_path", "")
main.set("dirty", false)
main.get("history").begin(doc)
main.call("_clear_edit_state")
main.call("_refresh_all")
await process_frame
await process_frame
# --- Basis: Editor-Sicht OHNE Playtest (240 Frames) ----------------------
await process_frame
var basis: Dictionary = await _messfenster(240)
print("FPS_PROBE ZAHLEN Basis (ohne Playtest): avg=%.1f min=%.0f max=%.0f" %
[basis.avg, basis.min, basis.max])
main.call("_on_test_run")
await process_frame
var pt: Node = main.get("playtest")
if pt == null:
print("FPS_PROBE FAIL: Playtest läuft nicht")
quit(1)
return
var body: Node = pt.get("body")
# Auto-Lauf durch die Szene (Bewegung + Physik + Render gleichzeitig).
body.set("auto_move_dir", Vector3(0, 0, -1))
var kollider: Node3D = pt.get("_kollider_root")
print("FPS_PROBE: Kollider-Kinder=%d (Terrain + Objekte + Bauteile)" % kollider.get_child_count())
# --- Playtest: Physik + Render (240 Frames) ------------------------------
await process_frame
var mit: Dictionary = await _messfenster(240)
body.set("auto_move_dir", Vector3.ZERO)
print("FPS_PROBE ZAHLEN Playtest (mit Physik): avg=%.1f min=%.0f max=%.0f" %
[mit.avg, mit.min, mit.max])
var overhead := 0.0
if basis.avg > 0.0:
overhead = (basis.avg - mit.avg) / basis.avg * 100.0
print("FPS_PROBE ZAHLEN Overhead: %.1f %%" % overhead)
if overhead <= 20.0:
print("FPS_PROBE OK: Physik-Zusatz %.1f %% ≤ 20 %% — keine Editor-Regression" % overhead)
quit(0)
else:
print("FPS_PROBE FAIL: Physik-Zusatz %.1f %% > 20 %%" % overhead)
quit(1)
func _messfenster(frames: int) -> Dictionary:
var n_min := 9999.0
var n_max := 0.0
var sum := 0.0
for i in frames:
await process_frame
var fps := float(Engine.get_frames_per_second())
n_min = minf(n_min, fps)
n_max = maxf(n_max, fps)
sum += fps
return {"avg": sum / float(frames), "min": n_min, "max": n_max}