t_1e82f747: Test-Umgebung aufgeraeumt — test_updater Setup robust, test_glb_view auf Pack-Palette (beide Suiten statt immer rot jetzt gruen/SKIP). test_updater: Verzeichnisname war Time.get_ticks_msec (kleine Zahl, kollidierte mit nicht loeschbaren Alt-Laeufen aus read-only git-Packs) → jetzt Unix-Zeit+ticks_usec; Cleanup chmod -R u+w (blocking via OS.execute mit output-Array, 2-Arg-Variante ist async) + include_hidden (.git ist versteckt) + rm -rf-Fallback; git-Fehler geben echten Fehlertext statt roter Zahl. Echte Updater-Pruefungen laufen wieder (75/75, vorher 15/75 FAIL an Setup). test_glb_view: Nachbar-Repos suchen wie tools/sync_objects.sh (Env SCOPEDVR_CLIENT_DIR/SCOPEDVR_MATCH_SERVER_DIR, dann ../+../../-Siblings), Quellen zur Laufzeit in ProjectSettings gesetzt (basis-relativ gerechnet, path_join ketten Absolutpfade); ohne Nachbar klare SKIP-Zeilen+Exit 0 statt 15 FAILs. Camo-Erwartungen entfernt (ueberholt seit d0d4fbd): jetzt Pack-Palette — alle Flaehen albedo_texture != null, Kante 1024², pack_datei_fuer-Zuordnung (military_base→Demonstration_Textures1.png, picture_1/2→Demonstration_picture_N.png 2048²) + Pack-Dateien im Nachbar-Repo (48/48, vorher 4/38 FAIL). Notiz tools/TEST_UMGEBUNG.md (Abhaengigkeiten + test_gui_smoke-F5 vorbestehend rot am 0adb161 via git-stash verifiziert, nicht Teil dieser Karte).
This commit is contained in:
parent
2c10863759
commit
dca0947a71
3 changed files with 267 additions and 52 deletions
|
|
@ -12,12 +12,49 @@ extends SceneTree
|
||||||
## über den Texturen.
|
## über den Texturen.
|
||||||
## 4. Fehlende GLB → Platzhalter + Eintrag in fehlende_glbs (Statuszeile).
|
## 4. Fehlende GLB → Platzhalter + Eintrag in fehlende_glbs (Statuszeile).
|
||||||
## 5. Cache pro OID: zweiter Abruf liefert DIESELBE Mesh-Instanz.
|
## 5. Cache pro OID: zweiter Abruf liefert DIESELBE Mesh-Instanz.
|
||||||
|
## 6. Pack-Texturen (Karte t_1e82f747, Stand d0d4fbd): die GLB-Flächen
|
||||||
|
## tragen ihre ORIGINAL-Texturen (GLTF löst die URIs selbst auf),
|
||||||
|
## Kante = Pack-Palette 1024²; Zuordnung pack_datei_fuer wie
|
||||||
|
## tools/PACK_TEXTURE_MAPPING.md (Client-Repo, verbindlich):
|
||||||
|
## military_base(+_00x) → Demonstration_Textures1.png (1024²),
|
||||||
|
## picture_1/2/3 → Demonstration_picture_N.png (2048² Multicam).
|
||||||
|
## Die alten Camo-Erwartungen (desert_multicam_1/2.png + geteilte
|
||||||
|
## Cache-Instanz) sind ENTFERNT — die Welt hat sich gedreht.
|
||||||
|
##
|
||||||
|
## Quelle-Fund (Karte t_1e82f747): die GLBs liegen in den NACHBAR-Repos.
|
||||||
|
## Gesucht wird wie in tools/sync_objects.sh: Env SCOPEDVR_MATCH_SERVER_DIR /
|
||||||
|
## SCOPEDVR_CLIENT_DIR zuerst, dann ../ und ../../ Siblings. Ohne Fund endet
|
||||||
|
## die Suite mit klaren SKIP-Zeilen (Exit 0) statt einer roten Zahl — die
|
||||||
|
## GLB-Prüfungen laufen, sobald ein Nachbar-Repo klonbar/abgelegt ist.
|
||||||
|
|
||||||
var failures := 0
|
var failures := 0
|
||||||
var checks := 0
|
var checks := 0
|
||||||
|
## Absolute Repo-Wurzel der gefundenen Nachbar-Repos (Ladereihenfolge).
|
||||||
|
var repos: Array = []
|
||||||
|
|
||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
|
repos = _finde_repos()
|
||||||
|
if repos.is_empty():
|
||||||
|
# Karte t_1e82f747: ohne Nachbar-Repo sind die GLB-Prüfungen hier
|
||||||
|
# nicht ausführbar — klare SKIP-Zeilen statt irreführender roter
|
||||||
|
# Zahlen. Die echten Checks laufen, sobald ein Nachbar da ist.
|
||||||
|
print("SKIP: test_glb_view — kein Nachbar-Repo mit assets/objekte gefunden.")
|
||||||
|
print("SKIP GRUND: gesucht: ../scopedvr-match-server, ../scopedvr-client, ../../… (relativ zum Editor-Repo)")
|
||||||
|
print("SKIP GRUND: sowie Env SCOPEDVR_MATCH_SERVER_DIR / SCOPEDVR_CLIENT_DIR (wie tools/sync_objects.sh).")
|
||||||
|
print("SKIP GRUND: die GLBs + Pack-Texturen liegen in den Sibling-Repos — erst klonen, dann Suite fahren.")
|
||||||
|
quit(0)
|
||||||
|
return
|
||||||
|
# Quellen konfigurierbar machen: die gefundenen Repos landen in
|
||||||
|
# ProjectSettings (GlbMeshStore.QUELLEN_SETTING) — glb_quellen sind
|
||||||
|
# Basis-relativ, deshalb ../-Pfade statt Absolutpfade.
|
||||||
|
var quellen: Array = []
|
||||||
|
for root: String in repos:
|
||||||
|
quellen.append(_relativ_zu(ProjectSettings.globalize_path("res://"),
|
||||||
|
root.path_join("assets/objekte")))
|
||||||
|
print("GLB-Quellen: %s" % ", ".join(PackedStringArray(quellen)))
|
||||||
|
ProjectSettings.set_setting(GlbMeshStore.QUELLEN_SETTING, quellen)
|
||||||
|
GlbMeshStore.cache_leeren()
|
||||||
_run_tests()
|
_run_tests()
|
||||||
if failures == 0:
|
if failures == 0:
|
||||||
print("ALL OK: %d checks" % checks)
|
print("ALL OK: %d checks" % checks)
|
||||||
|
|
@ -27,6 +64,51 @@ func _init() -> void:
|
||||||
quit(1)
|
quit(1)
|
||||||
|
|
||||||
|
|
||||||
|
## Nachbar-Repos finden wie tools/sync_objects.sh: Env-Variablen gewinnen,
|
||||||
|
## dann ../- und ../../-Siblings relativ zum Editor-Projekt. Ein Repo zählt
|
||||||
|
## nur, wenn assets/objekte existiert (Mesh-Lager).
|
||||||
|
## (Achtung, Probe 20.10.: der Repo-Name beginnt schon mit "scopedvr-" —
|
||||||
|
## die Env-Keys sind deshalb als feste Map notiert, nicht abgeleitet.)
|
||||||
|
func _finde_repos() -> Array:
|
||||||
|
var basis := ProjectSettings.globalize_path("res://")
|
||||||
|
var env_keys := {
|
||||||
|
"scopedvr-match-server": "SCOPEDVR_MATCH_SERVER_DIR",
|
||||||
|
"scopedvr-client": "SCOPEDVR_CLIENT_DIR",
|
||||||
|
}
|
||||||
|
var out: Array = []
|
||||||
|
for name: String in env_keys:
|
||||||
|
var env_pfad := OS.get_environment(env_keys[name]).simplify_path()
|
||||||
|
if not env_pfad.is_empty() and DirAccess.dir_exists_absolute(
|
||||||
|
env_pfad.path_join("assets/objekte")):
|
||||||
|
out.append(env_pfad)
|
||||||
|
for rel: String in ["../", "../../"]:
|
||||||
|
var kandidat := basis.path_join(rel + name).simplify_path()
|
||||||
|
if DirAccess.dir_exists_absolute(kandidat.path_join("assets/objekte")) \
|
||||||
|
and not out.has(kandidat):
|
||||||
|
out.append(kandidat)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
## glb_quellen sind Basis-RELATIVE Pfade (GlbMeshStore._kandidaten joinkt sie
|
||||||
|
## auf res:// — String.path_join KETTET auch bei absoluten Argumenten, ein
|
||||||
|
## Absolutpfad würde also kaputt gehen). Aus einem absoluten Env-Pfad wird
|
||||||
|
## deshalb ein ../-Pfad gerechnet.
|
||||||
|
func _relativ_zu(von: String, nach: String) -> String:
|
||||||
|
var v: PackedStringArray = von.simplify_path().split("/", false)
|
||||||
|
var n: PackedStringArray = nach.simplify_path().split("/", false)
|
||||||
|
var i := 0
|
||||||
|
while i < v.size() and i < n.size() and v[i] == n[i]:
|
||||||
|
i += 1
|
||||||
|
var teile := PackedStringArray()
|
||||||
|
for _j: int in range(i, v.size()):
|
||||||
|
teile.append("..")
|
||||||
|
for k: int in range(i, n.size()):
|
||||||
|
teile.append(n[k])
|
||||||
|
if teile.is_empty():
|
||||||
|
return "."
|
||||||
|
return "/".join(teile)
|
||||||
|
|
||||||
|
|
||||||
func _check(cond: bool, label: String) -> void:
|
func _check(cond: bool, label: String) -> void:
|
||||||
checks += 1
|
checks += 1
|
||||||
if cond:
|
if cond:
|
||||||
|
|
@ -41,7 +123,7 @@ func _run_tests() -> void:
|
||||||
_test_store_ladet_moosfelsen()
|
_test_store_ladet_moosfelsen()
|
||||||
_test_store_normalisierung()
|
_test_store_normalisierung()
|
||||||
_test_store_cache()
|
_test_store_cache()
|
||||||
_test_camo_tex()
|
_test_pack_tex()
|
||||||
_test_viewport_rebuild_echt()
|
_test_viewport_rebuild_echt()
|
||||||
_test_viewport_rebuild_fehlend()
|
_test_viewport_rebuild_fehlend()
|
||||||
|
|
||||||
|
|
@ -115,74 +197,95 @@ func _test_store_cache() -> void:
|
||||||
_check(GlbMeshStore.mesh_fuer(PROBE_OID) != null, "cache_leeren → wird neu geladen")
|
_check(GlbMeshStore.mesh_fuer(PROBE_OID) != null, "cache_leeren → wird neu geladen")
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------ Camo-Textur ----
|
# --------------------------------------------------------- Pack-Texturen ----
|
||||||
|
|
||||||
## Beweis (t_50a07d4b): das Live-GLB-Mesh trägt ECHTE Multicam-Texturen
|
## Karte t_1e82f747 (Stand d0d4fbd): die Camo-Erwartungen sind überholt —
|
||||||
## (albedo_texture != null je Fläche), Zuordnung je Kategorie wie
|
## die Pack-GLBs tragen ihre ORIGINAL-Texturen (GLTFDocument löst die externen
|
||||||
## tools/CAMO_TEXTURE_MAPPING.md (Client-Repo, verbindlich).
|
## URIs inzwischen selbst auf, je Parse eine eigene ImageTexture-Instanz;
|
||||||
## Die ImageTexture wird zur Laufzeit von der Platte geladen → resource_path
|
## der _camo_tex_cache bleibt deshalb leer). Diese Gruppe beschreibt, was IST:
|
||||||
## ist leer; der Pfad steht im Store-Cache (_camo_tex_cache) und wird hier
|
## Flächen getextured, Textur-Kante = Pack-Palette 1024², Zuordnung
|
||||||
## ausgegeben (Zahlen/Pfade ins Handoff).
|
## pack_datei_fuer wie tools/PACK_TEXTURE_MAPPING.md (Client-Repo).
|
||||||
func _test_camo_tex() -> void:
|
func _test_pack_tex() -> void:
|
||||||
print("Testgruppe: Camo-Textur im Live-Pfad — WYSIWYG Editor = Spiel (t_50a07d4b)")
|
print("Testgruppe: Pack-Texturen im Live-Pfad — WYSIWYG Editor = Spiel (d0d4fbd)")
|
||||||
var mesh_w := GlbMeshStore.mesh_fuer("wall_001")
|
var mesh_w := GlbMeshStore.mesh_fuer("wall_001")
|
||||||
_check(mesh_w != null, "wall_001 (walls → _1) geladen")
|
_check(mesh_w != null, "wall_001 (walls, military_base) geladen")
|
||||||
if mesh_w != null:
|
if mesh_w != null:
|
||||||
_camo_flachen_pruefen(mesh_w, "wall_001", "desert_multicam_1.png")
|
_pack_flachen_pruefen(mesh_w, "wall_001", 1024)
|
||||||
var mesh_g := GlbMeshStore.mesh_fuer("ground_001")
|
var mesh_g := GlbMeshStore.mesh_fuer("ground_001")
|
||||||
_check(mesh_g != null, "ground_001 (nature/ground → _2) geladen")
|
_check(mesh_g != null, "ground_001 (nature/ground, military_base) geladen")
|
||||||
if mesh_g != null:
|
if mesh_g != null:
|
||||||
_camo_flachen_pruefen(mesh_g, "ground_001", "desert_multicam_2.png")
|
_pack_flachen_pruefen(mesh_g, "ground_001", 1024)
|
||||||
# Eine-Quelle-Cache: wall_002 teilt DIESELBE ImageTexture-Instanz wie
|
# Pack-Zuordnung (pure Funktion — Quelle: tools/PACK_TEXTURE_MAPPING.md):
|
||||||
# wall_001 (291 GLBs teilen sich 2 Texturen statt je eine Kopie).
|
_check(GlbMeshStore.pack_datei_fuer("military_base") == GlbMeshStore.PACK_TEX_PALETTE,
|
||||||
var mesh_w2 := GlbMeshStore.mesh_fuer("wall_002")
|
"military_base → 1024er Palette (Demonstration_Textures1.png)")
|
||||||
if mesh_w2 != null and mesh_w != null:
|
_check(GlbMeshStore.pack_datei_fuer("military_base_003") == GlbMeshStore.PACK_TEX_PALETTE,
|
||||||
var t1 := _camo_mat_tex(mesh_w, 0)
|
"military_base_NNN → Palette (Präfix-Fallback)")
|
||||||
var t2 := _camo_mat_tex(mesh_w2, 0)
|
_check(GlbMeshStore.pack_datei_fuer("picture_1") == GlbMeshStore.PACK_TEX_PICTURE_1,
|
||||||
_check(t1 != null and t1 == t2,
|
"picture_1 → 2048er Multicam (Demonstration_picture_1.png)")
|
||||||
"wall_001 und wall_002 teilen DIESELBE Textur-Instanz (VRAM-Cache)")
|
_check(GlbMeshStore.pack_datei_fuer("picture_2") == GlbMeshStore.PACK_TEX_PICTURE_2,
|
||||||
_check(GlbMeshStore._camo_tex_cache.size() == 2,
|
"picture_2 → 2048er Multicam (Demonstration_picture_2.png)")
|
||||||
"Camo-Textur-Cache: genau 2 Texturen (Objekt _1 + Boden _2), ist %d" % GlbMeshStore._camo_tex_cache.size())
|
_check(GlbMeshStore.pack_datei_fuer("gibts_nicht_material") == GlbMeshStore.PACK_TEX_PALETTE,
|
||||||
|
"unbekanntes Material → Palette (Default-Fallback)")
|
||||||
|
_pack_dateien_pruefen()
|
||||||
|
|
||||||
|
|
||||||
func _camo_flachen_pruefen(mesh: Mesh, oid: String, erwartet_name: String) -> void:
|
## Jede Fläche trägt eine Textur und die Kante entspricht der Pack-Palette
|
||||||
|
## (1024² für military_base-Objekte) — bewiesener Live-Stand (Probe 20.10.).
|
||||||
|
func _pack_flachen_pruefen(mesh: Mesh, oid: String, erwartete_kante: int) -> void:
|
||||||
var count := mesh.get_surface_count()
|
var count := mesh.get_surface_count()
|
||||||
_check(count > 0, "%s hat Flächen (%d)" % [oid, count])
|
_check(count > 0, "%s hat Flächen (%d)" % [oid, count])
|
||||||
var textured := 0
|
var textured := 0
|
||||||
|
var kante_ok := true
|
||||||
for s in count:
|
for s in count:
|
||||||
if _camo_mat_tex(mesh, s) != null:
|
var tex := _mat_tex(mesh, s)
|
||||||
textured += 1
|
if tex == null:
|
||||||
|
continue
|
||||||
|
textured += 1
|
||||||
|
var img := tex.get_image()
|
||||||
|
if img != null and (img.get_width() != erwartete_kante
|
||||||
|
or img.get_height() != erwartete_kante):
|
||||||
|
kante_ok = false
|
||||||
_check(textured == count,
|
_check(textured == count,
|
||||||
"%s: ALLE %d Flächen haben albedo_texture != null (getextured: %d)" % [oid, count, textured])
|
"%s: ALLE %d Flächen haben albedo_texture != null (getextured: %d)" % [oid, count, textured])
|
||||||
# Pfad + Zuordnung: die Textur am Mesh ist DIESELBE Instanz wie der
|
_check(kante_ok, "%s: Textur-Kante %d² (Pack-Palette)" % [oid, erwartete_kante])
|
||||||
# Cache-Eintrag mit dem erwarteten Multicam-Pfad.
|
|
||||||
var erwartet: ImageTexture = null
|
|
||||||
var pfad_text := ""
|
|
||||||
for pfad in GlbMeshStore._camo_tex_cache.keys():
|
|
||||||
var p := str(pfad)
|
|
||||||
if p.ends_with(erwartet_name):
|
|
||||||
var v: Variant = GlbMeshStore._camo_tex_cache[pfad]
|
|
||||||
if v is ImageTexture:
|
|
||||||
erwartet = v
|
|
||||||
pfad_text = p
|
|
||||||
_check(erwartet != null, "%s: Multicam-Textur %s im Cache geladen" % [oid, erwartet_name])
|
|
||||||
if erwartet != null:
|
|
||||||
print(" info: %s → Textur-Pfad: %s" % [oid, pfad_text])
|
|
||||||
var instanz_ok := false
|
|
||||||
for s in count:
|
|
||||||
if _camo_mat_tex(mesh, s) == erwartet:
|
|
||||||
instanz_ok = true
|
|
||||||
_check(instanz_ok,
|
|
||||||
"%s: Flächen tragen DIESELBE Textur-Instanz wie der Cache (%s)" % [oid, erwartet_name])
|
|
||||||
|
|
||||||
|
|
||||||
func _camo_mat_tex(mesh: Mesh, s: int) -> Texture2D:
|
func _mat_tex(mesh: Mesh, s: int) -> Texture2D:
|
||||||
var mat := mesh.surface_get_material(s)
|
var mat := mesh.surface_get_material(s)
|
||||||
if mat is BaseMaterial3D:
|
if mat is BaseMaterial3D:
|
||||||
return (mat as BaseMaterial3D).albedo_texture
|
return (mat as BaseMaterial3D).albedo_texture
|
||||||
return null
|
return null
|
||||||
|
|
||||||
|
|
||||||
|
## Die Pack-Dateien liegen im gefundenen Nachbar-Repo: Palette 1024²,
|
||||||
|
## Multicam 2048². Fehlen sie dort, ist das ein echter Bruch (die GLBs
|
||||||
|
## kommen ja aus ebendiesem Repo) und wird laut gemeldet — kein SKIP-Fall.
|
||||||
|
func _pack_dateien_pruefen() -> void:
|
||||||
|
print("Testgruppe: Pack-Dateien im Nachbar-Repo (Palette 1024² / Multicam 2048²)")
|
||||||
|
var treffer := ""
|
||||||
|
for root: String in repos:
|
||||||
|
var dir := root.path_join("assets/textures/military_desert")
|
||||||
|
if FileAccess.file_exists(dir.path_join(GlbMeshStore.PACK_TEX_PALETTE)):
|
||||||
|
treffer = dir
|
||||||
|
break
|
||||||
|
_check(not treffer.is_empty(),
|
||||||
|
"textures/military_desert im Nachbar-Repo gefunden (%s)" % treffer)
|
||||||
|
if treffer.is_empty():
|
||||||
|
return
|
||||||
|
_kante_pruefen(treffer.path_join(GlbMeshStore.PACK_TEX_PALETTE), 1024, "Palette")
|
||||||
|
_kante_pruefen(treffer.path_join(GlbMeshStore.PACK_TEX_PICTURE_1), 2048, "picture_1")
|
||||||
|
_kante_pruefen(treffer.path_join(GlbMeshStore.PACK_TEX_PICTURE_2), 2048, "picture_2")
|
||||||
|
|
||||||
|
|
||||||
|
func _kante_pruefen(pfad: String, kante: int, label: String) -> void:
|
||||||
|
var img := Image.load_from_file(pfad)
|
||||||
|
_check(img != null, "%s ladbar (%s)" % [label, pfad.get_file()])
|
||||||
|
if img == null:
|
||||||
|
return
|
||||||
|
_check(img.get_width() == kante and img.get_height() == kante,
|
||||||
|
"%s ist %d² (ist %d×%d)" % [label, kante, img.get_width(), img.get_height()])
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------- Viewport-Rebuild --
|
# --------------------------------------------------------- Viewport-Rebuild --
|
||||||
|
|
||||||
func _proben_doc(oid: String, scale: float) -> Dictionary:
|
func _proben_doc(oid: String, scale: float) -> Dictionary:
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,18 @@ var work := ""
|
||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
_cleanup_old()
|
_cleanup_old()
|
||||||
base = ProjectSettings.globalize_path(
|
# Karte t_1e82f747: Time.get_ticks_msec() ist nur die Zeit seit Godot-Start
|
||||||
TEST_DIR_PREFIX + "_" + str(Time.get_ticks_msec()))
|
# (kleine Zahl, z.B. 115) — bei jedem CLI-Run derselbe Wert! Kollidierte
|
||||||
|
# Namen mit nicht löschbaren Alt-Läufen → git init lief in einer ALTEN
|
||||||
|
# Sitzung (remote existiert schon, alte Dateien im Baum → rote Setup-Zeilen).
|
||||||
|
# Deswegen: Unix-Zeit + ticks_usec = garantiert einzigartig pro Prozess/Run.
|
||||||
|
base = ProjectSettings.globalize_path(TEST_DIR_PREFIX + "_" +
|
||||||
|
str(int(Time.get_unix_time_from_system())) + "_" +
|
||||||
|
str(Time.get_ticks_usec()))
|
||||||
DirAccess.make_dir_recursive_absolute(base)
|
DirAccess.make_dir_recursive_absolute(base)
|
||||||
_run_tests()
|
_run_tests()
|
||||||
_test_ls_remote_warnzeile()
|
_test_ls_remote_warnzeile()
|
||||||
|
_force_writable(base)
|
||||||
_cleanup_dir(base) # best effort — git-Pack-Dateien können read-only sein
|
_cleanup_dir(base) # best effort — git-Pack-Dateien können read-only sein
|
||||||
if failures == 0:
|
if failures == 0:
|
||||||
print("ALL OK: %d checks" % checks)
|
print("ALL OK: %d checks" % checks)
|
||||||
|
|
@ -54,7 +61,27 @@ func _cleanup_old() -> void:
|
||||||
return
|
return
|
||||||
for name in root.get_directories():
|
for name in root.get_directories():
|
||||||
if name.begins_with("test_updater"):
|
if name.begins_with("test_updater"):
|
||||||
_cleanup_dir(ProjectSettings.globalize_path("user://").path_join(name))
|
var alt := ProjectSettings.globalize_path("user://").path_join(name)
|
||||||
|
_force_writable(alt)
|
||||||
|
_cleanup_dir(alt)
|
||||||
|
|
||||||
|
|
||||||
|
## Karte t_1e82f747: git macht .git-Packs read-only, dann schlägt
|
||||||
|
## DirAccess.remove_absolute fehlt → der Ordner bleibt liegen und KOLLIDIERT
|
||||||
|
## mit künftigen Läufen (derselbe ticks_msec-Name!). chmod -R u+w macht die
|
||||||
|
## Bäume löschbar. Linux/OSX-Fallback per /usr/bin/chmod (Tests sind CLI,
|
||||||
|
## Windows-spezifische ACLs sind hier nicht der Fall).
|
||||||
|
func _force_writable(path: String) -> void:
|
||||||
|
if not DirAccess.dir_exists_absolute(path):
|
||||||
|
return
|
||||||
|
var chmod := "/usr/bin/chmod"
|
||||||
|
if not FileAccess.file_exists(chmod):
|
||||||
|
chmod = "chmod"
|
||||||
|
# WICHTIG: das 2-Argument-OS.execute ist in Godot 4 ASYNCHRON (gibt nur
|
||||||
|
# eine PID zurück) — ohne output-Array wartet der Lauf nicht, und die
|
||||||
|
# Löschung passiert vor dem chmod. Mit output-Array blockiert er.
|
||||||
|
var out: PackedStringArray = []
|
||||||
|
OS.execute(chmod, PackedStringArray(["-R", "u+w", path]), out)
|
||||||
|
|
||||||
|
|
||||||
func _cleanup_dir(base_dir: String) -> void:
|
func _cleanup_dir(base_dir: String) -> void:
|
||||||
|
|
@ -63,18 +90,33 @@ func _cleanup_dir(base_dir: String) -> void:
|
||||||
var d := DirAccess.open(base_dir)
|
var d := DirAccess.open(base_dir)
|
||||||
if d == null:
|
if d == null:
|
||||||
return
|
return
|
||||||
|
# Karte t_1e82f747: get_files()/get_directories() überspringen defaultmäßig
|
||||||
|
# VERSTECKTE Ordner — und .git ist versteckt. Ohne dieses Flag blieb der
|
||||||
|
# Repo-Kern liegen, der Basisordner war nie leer und löschbar.
|
||||||
|
d.include_hidden = true
|
||||||
for file in d.get_files():
|
for file in d.get_files():
|
||||||
DirAccess.remove_absolute(base_dir.path_join(file))
|
DirAccess.remove_absolute(base_dir.path_join(file))
|
||||||
for sub in d.get_directories():
|
for sub in d.get_directories():
|
||||||
_cleanup_dir(base_dir.path_join(sub))
|
_cleanup_dir(base_dir.path_join(sub))
|
||||||
DirAccess.remove_absolute(base_dir)
|
DirAccess.remove_absolute(base_dir)
|
||||||
|
# Rückfallebene: git-Pack-Bäume haben teils noch andere Sonderfälle — wenn
|
||||||
|
# der Ordner trotzdem liegt, räumt rm -rf (CLI-Umgebung) garantiert ab.
|
||||||
|
if DirAccess.dir_exists_absolute(base_dir):
|
||||||
|
var out: PackedStringArray = []
|
||||||
|
OS.execute("/bin/rm", PackedStringArray(["-rf", base_dir]), out)
|
||||||
|
|
||||||
|
|
||||||
func _git(dir: String, args: Array) -> Dictionary:
|
func _git(dir: String, args: Array) -> Dictionary:
|
||||||
var packed := PackedStringArray()
|
var packed := PackedStringArray()
|
||||||
for a in args:
|
for a in args:
|
||||||
packed.append(str(a))
|
packed.append(str(a))
|
||||||
return EditorUpdater.git_run("git", dir, packed)
|
var r := EditorUpdater.git_run("git", dir, packed)
|
||||||
|
if not bool(r["ok"]):
|
||||||
|
# Karte t_1e82f747: rote Setup-Nummern ohne Grund sind wertlos —
|
||||||
|
# der echte git-Fehlertext gehört in die Ausgabe.
|
||||||
|
print(" git [%s] %s → code=%s: %s" % [dir, " ".join(args),
|
||||||
|
r["code"], str(r["output"]).strip_edges()])
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
func _write_file(path: String, text: String) -> void:
|
func _write_file(path: String, text: String) -> void:
|
||||||
|
|
|
||||||
70
tools/TEST_UMGEBUNG.md
Normal file
70
tools/TEST_UMGEBUNG.md
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
# Test-Umgebung: woran die Editor-Suiten hängen (Karte t_1e82f747, 20.10.2026)
|
||||||
|
|
||||||
|
Kurzreferenz für die nächste Person: was die zwei zuvor „immer rot"-Suiten
|
||||||
|
brauchen, warum sie in einem nackten Klon rot/skip waren, und wie man sie
|
||||||
|
grün fährt. Für die Pack-Textur-Zuordnung selbst siehe
|
||||||
|
`PACK_TEXTURE_MAPPING.md` im **Client-Repo** (verbindlich).
|
||||||
|
|
||||||
|
## tests/test_updater.gd (75 Checks)
|
||||||
|
|
||||||
|
Braucht: nur das `git`-Binary (keine Identität — die Suite setzt
|
||||||
|
`user.name`/`user.email` lokal in ihren Temp-Repos; kein Netz, alles läuft
|
||||||
|
gegen ein Bare-Repo unter `user://test_updater_…`).
|
||||||
|
|
||||||
|
**Früherer Dauer-Fehler (behoben):** der Lauf nutzte
|
||||||
|
`user://test_updater_<Time.get_ticks_msec()>` als Verzeichnis —
|
||||||
|
`ticks_msec` zählt nur seit Godot-Start und ist bei CLI-Läufen immer eine
|
||||||
|
kleine Zahl (z. B. 115). Die Namen kollidierten mit Alt-Läufen, die sich
|
||||||
|
nicht löschen ließen (git macht `.git`-Pack-Dateien read-only), und
|
||||||
|
`git init` lief dann in einer ALTEN Sitzung: remote „already exists",
|
||||||
|
alter Arbeitsbaum, rote Setup-Zeilen ohne echten Bug.
|
||||||
|
|
||||||
|
Jetzt:
|
||||||
|
- Verzeichnisname = Unix-Zeit + `ticks_usec` (pro Run einzigartig).
|
||||||
|
- Aufräumen erzwingt Schreibrechte (`chmod -R u+w`, **blocking** via
|
||||||
|
`OS.execute` mit output-Array — die 2-Argument-Variante ist in Godot 4
|
||||||
|
asynchron!) und löscht inkl. versteckter Ordner
|
||||||
|
(`DirAccess.include_hidden = true`, `.git` ist versteckt) mit
|
||||||
|
`rm -rf`-Rückfallebene.
|
||||||
|
- Fehlerhafte git-Aufrufe geben den echten git-Fehlertext aus
|
||||||
|
(`git [dir] args → code=…`), nicht nur eine rote Zahl.
|
||||||
|
|
||||||
|
## tests/test_glb_view.gd (48 Checks)
|
||||||
|
|
||||||
|
Braucht: ein **Nachbar-Repo** mit `assets/objekte` (Mesh-Lager) —
|
||||||
|
`scopedvr-client` oder `scopedvr-match-server`. Gesucht wird wie in
|
||||||
|
`tools/sync_objects.sh`:
|
||||||
|
|
||||||
|
1. Env `SCOPEDVR_CLIENT_DIR` / `SCOPEDVR_MATCH_SERVER_DIR` (absolute Pfade
|
||||||
|
werden testseitig in `../`-Pfade umgerechnet — `glb_quellen` müssen
|
||||||
|
basis-relativ sein, `String.path_join` ketten Absolutpfade nur an),
|
||||||
|
2. dann `../`- und `../../`-Siblings relativ zum Editor-Repo.
|
||||||
|
|
||||||
|
Ohne Fund: **klare SKIP-Zeilen + Exit 0** (kein rotes Krachen). Die
|
||||||
|
GLB-Quellen werden zur Laufzeit in `ProjectSettings` gesetzt
|
||||||
|
(`scopedvr/editor/glb_quellen`) — kein Eingriff in `src/`.
|
||||||
|
|
||||||
|
Textur-Erwartungen (Stand `d0d4fbd`): die Pack-GLBs tragen ihre
|
||||||
|
ORIGINAL-Texturen (GLTFDocument löst die externen URIs selbst auf, je Parse
|
||||||
|
eine eigene ImageTexture-Instanz — der `_camo_tex_cache` bleibt leer). Die
|
||||||
|
alten Camo-Erwartungen (`desert_multicam_1/2.png`, geteilte Cache-Instanz)
|
||||||
|
sind entfernt. Geprüft wird jetzt: alle Flächen `albedo_texture != null`,
|
||||||
|
Kante = Palette-Größe (1024²), reine Zuordnung `pack_datei_fuer`
|
||||||
|
(military_base(+_00x) → `Demonstration_Textures1.png`, picture_1/2 →
|
||||||
|
`Demonstration_picture_N.png` 2048²) und die Pack-Dateien im gefundenen
|
||||||
|
Nachbar-Repo.
|
||||||
|
|
||||||
|
Schnelltest in diesem Container:
|
||||||
|
|
||||||
|
cd <klon>/scopedvr-map-editor
|
||||||
|
/opt/data/home/bin/godot4 --headless --path . --import # Pflicht vor jeder -s-Suite
|
||||||
|
/opt/data/home/bin/godot4 --headless --path . --script res://tests/test_glb_view.gd
|
||||||
|
# ohne Nachbar-Repo: SKIP-Zeilen; mit: ALL OK: 48 checks
|
||||||
|
|
||||||
|
## test_gui_smoke (F5) — vorbestehend rot, NICHT Teil von t_1e82f747
|
||||||
|
|
||||||
|
`F5: Karte-testen-Flow angesprungen` + `F5: Fehler-Dialog im
|
||||||
|
nicht-gefunden-Zweig geöffnet` (2/89) schlagen auch am jungfräulichen
|
||||||
|
`0adb161` fehl (per `git stash`-Verfahren verifiziert, 20.10.). Ursache ist
|
||||||
|
nicht die Test-Pflege dieser Karte; Grenze der Karte war ausdrücklich nur
|
||||||
|
`test_updater.gd` + `test_glb_view.gd` + Notizen.
|
||||||
Loading…
Reference in a new issue