110 lines
4.5 KiB
GDScript
110 lines
4.5 KiB
GDScript
class_name TestRun
|
|
extends RefCounted
|
|
## ALT (Karte t_1cdc1a72): dieser Client-Start ist seit dem Lauf-Modus im
|
|
## Map-Builder selbst NICHT mehr der Standard-Weg — „▶ Karte testen" startet
|
|
## jetzt IN DIESER APP (core/editor/playtest/, kein Client-Ordner, kein
|
|
## zweiter Prozess, kein VR). Der Rückbau dieser Datei kommt in einer
|
|
## späteren Karte; bis dahin bleibt die Export-/Such-Logik als Fallback
|
|
## erhalten und getestet (tests/test_testrun.gd).
|
|
##
|
|
## Ursprünglicher Zweck (Karte t_b84af40f): Export der AKTUELLEN Map nach Temp
|
|
## + Start des scopedvr-client als EIGENES Fenster im Testlauf-Modus
|
|
## (--testmap <pfad>). Der Editor bleibt offen — der Client ist ein eigener
|
|
## Prozess; das Spiel beendet sich selbst sauber (ESC = „Zurück zum Editor").
|
|
##
|
|
## Client-Suche (erste Treffer-Zeile gewinnt):
|
|
## 1. Konfigurationsdatei user://scopedvr_editor.cfg, Abschnitt [test]:
|
|
## client_dir="/pfad/zu/scopedvr-client"
|
|
## 2. Klon neben dem Editor: <Editor-Projektordner>/../scopedvr-client
|
|
## (erkennbar an project.godot im Ordner).
|
|
##
|
|
## Godot-Binary für den Start: das Binary, unter dem der Editor selbst läuft
|
|
## (OS.get_executable_path — Sly startet den Editor über den Godot-Editor,
|
|
## also kann DAS auch den Client starten). Läuft der Editor irgendwann als
|
|
## exportierte App, muss [test] godot_path gesetzt werden.
|
|
##
|
|
## Alles static + testbar ohne UI (tests/test_testrun.gd).
|
|
|
|
const CFG_PATH := "user://scopedvr_editor.cfg"
|
|
const TESTRUN_DIR := "user://testrun"
|
|
|
|
|
|
static func load_cfg() -> ConfigFile:
|
|
var cfg := ConfigFile.new()
|
|
if FileAccess.file_exists(CFG_PATH):
|
|
cfg.load(CFG_PATH) # Fehler → Default-Logik greift weiter unten.
|
|
return cfg
|
|
|
|
|
|
## Liefert den Client-Projektordner (mit project.godot) oder "".
|
|
static func find_client(project_dir: String, cfg: ConfigFile = null) -> String:
|
|
var candidates: Array = []
|
|
if cfg != null:
|
|
var configured := str(cfg.get_value("test", "client_dir", ""))
|
|
# Explizit gesetzter Pfad gewinnt, sobald der ORDNER existiert
|
|
# (bewusst ohne project.godot-Check — wer ihn konfiguriert, weiß es besser).
|
|
if not configured.is_empty() and DirAccess.dir_exists_absolute(configured):
|
|
return configured
|
|
var parent := project_dir.simplify_path().get_base_dir()
|
|
candidates.append(parent.path_join("scopedvr-client"))
|
|
for candidate in candidates:
|
|
var dir := str(candidate).simplify_path()
|
|
if FileAccess.file_exists(dir.path_join("project.godot")):
|
|
return dir
|
|
return ""
|
|
|
|
|
|
## Godot-Binary zum Starten des Clients (Editor-Binary oder Konfiguration).
|
|
static func find_godot(cfg: ConfigFile = null) -> String:
|
|
var exe := OS.get_executable_path()
|
|
if exe.get_file().to_lower().contains("godot"):
|
|
return exe
|
|
if cfg != null:
|
|
return str(cfg.get_value("test", "godot_path", ""))
|
|
return ""
|
|
|
|
|
|
## Deterministischer Temp-Pfad aus dem Map-Namen (erneuter Testlauf
|
|
## überschreibt die alte Export-Datei — kein Müll-Berg).
|
|
static func temp_map_path(doc: Dictionary) -> String:
|
|
var raw := str(doc.get("info", {}).get("name", "")).strip_edges()
|
|
if raw.is_empty():
|
|
raw = "karte"
|
|
var safe := ""
|
|
for ch in raw:
|
|
var c := ch.to_lower()
|
|
if (c >= "a" and c <= "z") or (c >= "0" and c <= "9") or ch == "_" or ch == "-" or ch == " ":
|
|
safe += ch
|
|
else:
|
|
safe += "_"
|
|
safe = safe.strip_edges().replace(" ", "_").rstrip("_")
|
|
if safe.is_empty():
|
|
safe = "karte"
|
|
return TESTRUN_DIR.path_join(safe + ".svmap")
|
|
|
|
|
|
## Exportiert das AKTUELLE Dokument (auch ungespeicherte Maps!) nach Temp.
|
|
## Rückgabe: {ok, errors, path} — path ist globalisiert (für den Client-Prozess).
|
|
static func export_temp_map(doc: Dictionary) -> Dictionary:
|
|
var rel := temp_map_path(doc)
|
|
DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(TESTRUN_DIR))
|
|
var result := SvmapIO.save_to_file(rel, doc)
|
|
result["path"] = ProjectSettings.globalize_path(rel)
|
|
return result
|
|
|
|
|
|
## Hand-Haltungs-Tool: liegt im Client-Projekt, weil es dessen Rig und Waffen
|
|
## direkt benutzt (kein VR, eigenes Fenster).
|
|
static func hand_pose_args(client_dir: String) -> PackedStringArray:
|
|
return PackedStringArray(["--xr-mode", "off", "--path", client_dir,
|
|
"res://tools/hand_pose_tool/hand_pose_tool.tscn"])
|
|
|
|
|
|
## Import-Lauf für den Client, nötig nach neuem Stand (neue Modelle/Skripte).
|
|
static func import_args(client_dir: String) -> PackedStringArray:
|
|
return PackedStringArray(["--headless", "--path", client_dir, "--import"])
|
|
|
|
|
|
## Argumentliste für den Client-Start (getestet: exakt diese Form).
|
|
static func launch_args(client_dir: String, map_path: String) -> PackedStringArray:
|
|
return PackedStringArray(["--path", client_dir, "--", "--testmap", map_path, "--mock-master"])
|