diff --git a/library/thumbs/beispiel_fass_01.png b/library/thumbs/beispiel_fass_01.png new file mode 100644 index 0000000..21ac751 Binary files /dev/null and b/library/thumbs/beispiel_fass_01.png differ diff --git a/library/thumbs/beispiel_fass_02.png b/library/thumbs/beispiel_fass_02.png new file mode 100644 index 0000000..21ac751 Binary files /dev/null and b/library/thumbs/beispiel_fass_02.png differ 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: