Add bison model to default editor palette and object catalog
checkpoint / checkpoint (push) Successful in 6m10s

This commit is contained in:
2026-09-21 18:11:06 +00:00
parent ddcc0866b8
commit 509e85b53e
10 changed files with 251 additions and 2 deletions
+12 -2
View File
@@ -48,11 +48,21 @@ func is_loaded() -> bool:
func resolve(id: String) -> Dictionary:
if not _loaded:
return {}
return _catalog.get(id, {})
if _catalog.has(id):
return _catalog[id]
if (id.contains("bizon") or id.contains("bison")) and _catalog.has("bison"):
return _catalog["bison"]
return {}
func has_object(id: String) -> bool:
return _loaded and _catalog.has(id)
if not _loaded:
return false
if _catalog.has(id):
return true
if (id.contains("bizon") or id.contains("bison")) and _catalog.has("bison"):
return true
return false
func get_all_ids() -> Array[String]:
+2
View File
@@ -115,6 +115,8 @@ func _setup_import_ui() -> void:
sample_option.set_item_metadata(4, {"path": "res://assets/props/buffalo_chip_coin.glb", "name": "Buffalo Chip Coin"})
sample_option.add_item("Small Crate", 5)
sample_option.set_item_metadata(5, {"path": "res://assets/props/crate_small.glb", "name": "Small Crate"})
sample_option.add_item("Bison", 6)
sample_option.set_item_metadata(6, {"path": "res://assets/props/bison.glb", "name": "Bison"})
sample_option.size_flags_horizontal = Control.SIZE_EXPAND_FILL
sample_option.item_selected.connect(func(idx: int):
if idx > 0:
+37
View File
@@ -0,0 +1,37 @@
extends SceneTree
## Test loading and instantiating bison.glb prop
func _init() -> void:
print("=== Smoke Test: Bison Model ===")
var path := "res://assets/props/bison.glb"
if not FileAccess.file_exists(path):
printerr("FAIL: bison.glb does not exist on disk at ", path)
quit(1)
return
var res := load(path)
if res == null:
printerr("FAIL: Could not load ", path)
quit(1)
return
print("PASS: Loaded PackedScene: ", res)
if res is PackedScene:
var inst = (res as PackedScene).instantiate()
if inst == null:
printerr("FAIL: Could not instantiate bison scene")
quit(1)
return
print("PASS: Instantiated bison: ", inst.name, " (", inst.get_class(), ")")
_print_node(inst, 0)
inst.queue_free()
print("=== Bison Model Smoke Test Passed ===")
quit(0)
func _print_node(n: Node, depth: int) -> void:
print(" ".repeat(depth), "- ", n.name, " [", n.get_class(), "]")
for c in n.get_children():
_print_node(c, depth + 1)
+103
View File
@@ -0,0 +1,103 @@
extends SceneTree
## Headless smoke test verifying Bison model is present in the editor palette
## and loads properly via StaticObjectNode and EditorCore.
const ChunkEditorModelClass := preload("res://scripts/editor/chunk_editor_model.gd")
const EditorObjectCatalogClass := preload("res://scripts/editor/object_catalog.gd")
const EditorCoreClass := preload("res://scripts/editor/editor_core.gd")
const PalettePanelClass := preload("res://scripts/editor/ui/palette_panel.gd")
const StaticObjectNodeClass := preload("res://scripts/static_object_node.gd")
const WorldObjectClass := preload("res://scripts/world_object.gd")
var passed := 0
var failed := 0
func _check(label: String, cond: bool) -> void:
if cond:
passed += 1
print(" PASS: ", label)
else:
failed += 1
printerr(" FAIL: ", label)
func _initialize() -> void:
await _run()
func _run() -> void:
print("=== Running Bison Model in Editor Palette Smoke Test ===")
var root := Node.new()
root.name = "TestRoot"
get_root().add_child(root)
# 1. Check catalog loading
var catalog := EditorObjectCatalogClass.new()
var err := catalog.load_catalog()
_check("Loaded EditorObjectCatalog from JSON", err == OK)
# 2. Check bison in default ids
var all_ids := catalog.get_all_ids()
_check("Catalog contains 'bison'", all_ids.has("bison"))
var bison_entry := catalog.resolve("bison")
_check("Bison entry has asset_id props/bison.glb", bison_entry.get("asset_id") == "props/bison.glb")
_check("Bison entry display_name is Bison", bison_entry.get("display_name") == "Bison")
_check("Bison asset file exists in project", FileAccess.file_exists("res://assets/props/bison.glb"))
# 3. Check alias resolution for legacy custom import id
var alias_entry := catalog.resolve("custom_bizon_by_madtrollstudio_rqk_lny_pnfx")
_check("Legacy custom id resolves to bison", alias_entry.get("asset_id") == "props/bison.glb")
# 4. Check PalettePanel populates bison in list
var palette := PalettePanelClass.new()
root.add_child(palette)
await process_frame
palette.set_catalog(catalog)
var found_in_palette := false
for i in range(palette._list.item_count):
var item_text := palette._list.get_item_text(i)
if item_text == "Bison":
found_in_palette = true
break
_check("PalettePanel list contains 'Bison'", found_in_palette)
# 5. Place bison in a chunk model
var model := ChunkEditorModelClass.new()
var core := EditorCoreClass.new(model, catalog)
var obj_id := core.place_object("bison", Vector3(10.0, 0.0, 15.0))
_check("Placed bison via EditorCore", not obj_id.is_empty())
var placed_obj := model.find_object(obj_id)
_check("Placed object has props/bison.glb", placed_obj != null and placed_obj.asset_id == "props/bison.glb")
# 6. StaticObjectNode with default props/bison.glb
var wo1 := WorldObjectClass.new()
wo1.id = "test_bison_1"
wo1.type = "prop"
wo1.asset_id = "props/bison.glb"
wo1.position = Vector3(10.0, 0.0, 15.0)
var node1 := StaticObjectNodeClass.new()
node1.world_object = wo1
root.add_child(node1)
await process_frame
_check("StaticObjectNode loaded visuals for props/bison.glb", node1.get_child_count() > 0)
# 7. StaticObjectNode with legacy user:// path as saved in World 6
var wo2 := WorldObjectClass.new()
wo2.id = "test_bison_legacy"
wo2.type = "prop"
wo2.asset_id = "user://custom_assets/Bizon by madtrollstudio - RqkLNYPnfx.glb"
wo2.properties = {"catalog_id": "custom_bizon_by_madtrollstudio_rqk_lny_pnfx"}
var node2 := StaticObjectNodeClass.new()
node2.world_object = wo2
root.add_child(node2)
await process_frame
_check("StaticObjectNode loaded visuals for legacy world chunk bison", node2.get_child_count() > 0)
print("Bison Palette Smoke Test complete. Passed: %d, Failed: %d" % [passed, failed])
if failed > 0:
quit(1)
else:
quit(0)
+6
View File
@@ -61,6 +61,8 @@ func _load_mesh() -> void:
add_child(asset_node)
if asset_node is MeshInstance3D:
_mesh_instance = asset_node as MeshInstance3D
else:
_mesh_instance = asset_node.find_child("*", true, false) as MeshInstance3D
return
# 2. Build a stylized, recognizable 3D representation based on catalog ID / asset ID
@@ -96,9 +98,13 @@ func _try_load_asset(asset_id: String) -> Node:
var candidate_paths: Array[String] = [
asset_id,
"res://assets/%s" % asset_id,
"res://assets/props/%s" % asset_id.get_file(),
"user://custom_assets/%s" % asset_id,
"user://custom_assets/%s" % asset_id.get_file()
]
var lower_id := asset_id.to_lower()
if lower_id.contains("bizon") or lower_id.contains("bison") or lower_id.contains("madtrollstudio"):
candidate_paths.append("res://assets/props/bison.glb")
for cpath in candidate_paths:
if FileAccess.file_exists(cpath):