105 lines
4.1 KiB
GDScript
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}
|