From 310aa695e6733a072389039d5b792b5a392cb183 Mon Sep 17 00:00:00 2001 From: "Hermes (scopedvr-dev)" Date: Mon, 19 Oct 2026 18:02:12 +0000 Subject: [PATCH] A6 (t_c5a27ca7): Editor loest Kategorie-GLBs aus der Registry auf (GlbMeshStore + gen_thumbs), Thumbs fuer Beispiel-Objekte --- library/thumbs/beispiel_fass_01.png | Bin 0 -> 869 bytes library/thumbs/beispiel_fass_02.png | Bin 0 -> 869 bytes src/viewport/glb_mesh_store.gd | 45 ++++++++++++++++++++++++---- tests/probe_store_a6.gd | 9 ++++++ tools/gen_thumbs.gd | 29 ++++++++++++++++-- 5 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 library/thumbs/beispiel_fass_01.png create mode 100644 library/thumbs/beispiel_fass_02.png create mode 100644 tests/probe_store_a6.gd diff --git a/library/thumbs/beispiel_fass_01.png b/library/thumbs/beispiel_fass_01.png new file mode 100644 index 0000000000000000000000000000000000000000..21ac75123c5f1070c2899891d501dc0f1d6eb6f7 GIT binary patch literal 869 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V3zlEaSW-L z^Y+f}zFQ6wZ4d7YGz&O|#4xbB2C2jrNoEE;YYSfH>D=hz=-fKt=)s0y7X`lA4RaeC z|5wk?+RJXdy3%mX@q17H9zWme7^eG;K|q|bLz$tFMWK)3h+u;SlYl$JBMt`{stevb zDtEy4@2{WAC+h5KehH=6pV#>KWxkWM?+?>?O%*>G@@9UqIj`#*e0tLvwaJ~lY|RP% z|6dt;>|yt~eC5oUTW`xQoRsHlKln|w+lAr#hTCtG_!T*rR&+4Tb6Io!!P~Oz`2Ds0 zpKd7btzp=hv;FoBXO1QYty?)}8`}j~7(=E!uY9A(;>aMn_WEmxRFvLyh}4m4h8+$N zFNcT}1!}4>2|QP7_*n7h!|^X0L~@=zXqvFsJ(hRN_gCUgZ+2QR+02@L`9K;=K<(t0UIz5 z8o2hXVV)t_U;~O5(TYe8qhgT*%HruZcLcXQS8H(B#Shr_ zGsV4QwRon-Fy*mPL$yt?t=;dlbJ!BZ$`0-E+c$G@HS>DS>h}wtd)liBAK3X>Aw=!Z ooE(N9hu>B++-ak2Dyw6@F1R#xN4W(fFyAnEy85}Sb4q9e0M7JRuK)l5 literal 0 HcmV?d00001 diff --git a/library/thumbs/beispiel_fass_02.png b/library/thumbs/beispiel_fass_02.png new file mode 100644 index 0000000000000000000000000000000000000000..21ac75123c5f1070c2899891d501dc0f1d6eb6f7 GIT binary patch literal 869 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V3zlEaSW-L z^Y+f}zFQ6wZ4d7YGz&O|#4xbB2C2jrNoEE;YYSfH>D=hz=-fKt=)s0y7X`lA4RaeC z|5wk?+RJXdy3%mX@q17H9zWme7^eG;K|q|bLz$tFMWK)3h+u;SlYl$JBMt`{stevb zDtEy4@2{WAC+h5KehH=6pV#>KWxkWM?+?>?O%*>G@@9UqIj`#*e0tLvwaJ~lY|RP% z|6dt;>|yt~eC5oUTW`xQoRsHlKln|w+lAr#hTCtG_!T*rR&+4Tb6Io!!P~Oz`2Ds0 zpKd7btzp=hv;FoBXO1QYty?)}8`}j~7(=E!uY9A(;>aMn_WEmxRFvLyh}4m4h8+$N zFNcT}1!}4>2|QP7_*n7h!|^X0L~@=zXqvFsJ(hRN_gCUgZ+2QR+02@L`9K;=K<(t0UIz5 z8o2hXVV)t_U;~O5(TYe8qhgT*%HruZcLcXQS8H(B#Shr_ zGsV4QwRon-Fy*mPL$yt?t=;dlbJ!BZ$`0-E+c$G@HS>DS>h}wtd)liBAK3X>Aw=!Z ooE(N9hu>B++-ak2Dyw6@F1R#xN4W(fFyAnEy85}Sb4q9e0M7JRuK)l5 literal 0 HcmV?d00001 diff --git a/src/viewport/glb_mesh_store.gd b/src/viewport/glb_mesh_store.gd index 560cbc5..031e2a9 100644 --- a/src/viewport/glb_mesh_store.gd +++ b/src/viewport/glb_mesh_store.gd @@ -24,6 +24,10 @@ class_name GlbMeshStore const QUELLEN_SETTING := "scopedvr/editor/glb_quellen" ## Voreinstellung = dieselben Quellen wie tools/gen_thumbs.gd (Sibling-Repos). const DEFAULT_QUELLEN := ["../scopedvr-match-server/assets/objekte", "../scopedvr-client/assets/objekte"] +## Registry (A6): liefert das Feld "glb" für die Kategorie-verschachtelte Ablage. +const MANIFEST_PATH := "res://library/objects.json" +static var _manifest: Dictionary = {} +static var _manifest_geladen := false # Cache pro OID: Mesh (normalisiert) oder `false` = GLB gefunden, aber nicht # ladbar (Parse-Fehler — kein endloser Retry pro Rebuild). Fehlende Datei @@ -44,6 +48,36 @@ static func quellen() -> Array: return out if not out.is_empty() else DEFAULT_QUELLEN.duplicate() +## Kandidaten-Pfade (absolut) in Ladereihenfolge: Registry-`glb` (A6, Kategorie- +## Ablage assets/objekte/military_desert//.glb) VOR der flachen +## Alt-Ablage /.glb. Die Quelle ist ein Mesh-Lager (/assets/ +## objekte) — für den verschachtelten Pfad wird sie auf die Repo-Wurzel gekürzt. +static func _kandidaten(oid: String) -> Array: + var basis := ProjectSettings.globalize_path("res://") + var out: Array = [] + var rel := str(_eintrag(oid).get("glb", "")) + if rel.begins_with("res://"): + var sub := rel.substr(6) + for quelle in quellen(): + var q := str(quelle) + var marke := "/assets/objekte" + var wurzel := q.substr(0, q.length() - marke.length()) if q.ends_with(marke) else q + out.append(basis.path_join(wurzel).path_join(sub)) + for quelle in quellen(): + out.append(basis.path_join(str(quelle)).path_join(oid + ".glb")) + return out + + +## Registry-Eintrag der OID (einmal gelesen, dann gecacht). +static func _eintrag(oid: String) -> Dictionary: + if not _manifest_geladen: + _manifest_geladen = true + var parsed: Variant = JSON.parse_string(FileAccess.get_file_as_string(MANIFEST_PATH)) + if parsed is Dictionary: + _manifest = (parsed as Dictionary).get("objects", {}) + return _manifest.get(oid, {}) + + ## Echtes Mesh für eine Objekt-ID (normalisiert, Fußpunkt-Koordinaten) oder ## null = keine brauchbare GLB → Aufrufer zeigt den Platzhalter. static func mesh_fuer(oid: String) -> Mesh: @@ -51,9 +85,7 @@ static func mesh_fuer(oid: String) -> Mesh: return null if _cache.has(oid): return _cache[oid] if _cache[oid] is Mesh else null - for quelle in quellen(): - var basis := ProjectSettings.globalize_path("res://") - var pfad := basis.path_join(quelle).path_join(oid + ".glb") + for pfad in _kandidaten(oid): if FileAccess.file_exists(pfad): var m := _glb_mesh(pfad) if m != null: @@ -73,9 +105,8 @@ static func fehlt(oid: String) -> bool: return true if _cache.has(oid): return not (_cache[oid] is Mesh) - var basis := ProjectSettings.globalize_path("res://") - for quelle in quellen(): - if FileAccess.file_exists(basis.path_join(quelle).path_join(oid + ".glb")): + for pfad in _kandidaten(oid): + if FileAccess.file_exists(pfad): return false return true @@ -83,6 +114,8 @@ static func fehlt(oid: String) -> bool: ## Cache leeren (Tests / nach manuellem Eingriff ins Mesh-Lager). static func cache_leeren() -> void: _cache.clear() + _manifest.clear() + _manifest_geladen = false # ------------------------------------------------------------ Laden -------- diff --git a/tests/probe_store_a6.gd b/tests/probe_store_a6.gd new file mode 100644 index 0000000..1ce1eaf --- /dev/null +++ b/tests/probe_store_a6.gd @@ -0,0 +1,9 @@ +extends SceneTree +func _initialize() -> void: + var m := GlbMeshStore.mesh_fuer("beispiel_fass_01") + var m2 := GlbMeshStore.mesh_fuer("crate_wood") + print("GlbMeshStore beispiel_fass_01: ", "MESH " + str((m as Mesh).get_surface_count()) + " Flaechen, AABB " + str((m as Mesh).get_aabb().size) if m != null else "null") + print("GlbMeshStore crate_wood: ", "MESH" if m2 != null else "null (erwartet: kein GLB im Lager)") + print("GlbMeshStore.fehlt(fass)=", GlbMeshStore.fehlt("beispiel_fass_01"), " fehlt(crate_wood)=", GlbMeshStore.fehlt("crate_wood")) + print("STORE_PROBE_OK") + quit(0) diff --git a/tools/gen_thumbs.gd b/tools/gen_thumbs.gd index cb86b18..f59afd3 100644 --- a/tools/gen_thumbs.gd +++ b/tools/gen_thumbs.gd @@ -119,10 +119,15 @@ func _process(_delta: float) -> bool: ## Mesh für ein Thumbnail: echtes GLB aus dem Mesh-Lager (Sibling-Repos), ## sonst Kollisions-Platzhalter (alte Fallback-Regel). +## +## A6-Fundament (19.10.): Military-Objekte liegen KATEGORIE-verschachtelt +## (assets/objekte/military_desert//.glb, Pfad im Registry-Feld +## "glb"). Deshalb stehen die Kandidaten jetzt in dieser Reihenfolge: +## 1. Registry-`glb` gegen jede QUELLEN-WURZEL (deren "/assets/objekte"-Suffix +## entfernt, damit derselbe relative Pfad aufgeht), +## 2. flache Alt-Ablage /.glb. func _mesh_fuer(oid: String, col: Dictionary) -> Mesh: - var basis := ProjectSettings.globalize_path("res://") - for quelle in GLB_QUELLEN: - var pfad := basis.path_join(str(quelle)).path_join(oid + ".glb") + for pfad in _kandidaten(oid): if FileAccess.file_exists(pfad): var m := _glb_mesh(pfad) if m != null: @@ -130,6 +135,24 @@ func _mesh_fuer(oid: String, col: Dictionary) -> Mesh: return MeshShapes.make_placeholder(str(col.get("shape", "box")), col, 1.0) +## Kandidaten-Pfade (absolut) für eine OID — Registry-Pfad vor flacher Alt-Ablage. +func _kandidaten(oid: String) -> Array: + var basis := ProjectSettings.globalize_path("res://") + var out: Array = [] + var eintrag: Dictionary = (manifest.get("objects", {}) as Dictionary).get(oid, {}) + var rel := str(eintrag.get("glb", "")) + if rel.begins_with("res://"): + var sub := rel.substr(6) + for quelle in GLB_QUELLEN: + var q := str(quelle) + var marke := "/assets/objekte" + var wurzel := q.substr(0, q.length() - marke.length()) if q.ends_with(marke) else q + out.append(basis.path_join(wurzel).path_join(sub)) + for quelle in GLB_QUELLEN: + out.append(basis.path_join(str(quelle)).path_join(oid + ".glb")) + return out + + ## GLB OHNE Import-System laden (GLTFDocument) und das erste Mesh liefern. ## null = Load-Fehlschlag → Aufrufer fällt auf den Platzhalter zurück. func _glb_mesh(pfad: String) -> Mesh: