feat(editor): add bundled 3D prop models and sample picker in Creator Studio
checkpoint / checkpoint (push) Failing after 3h14m9s

This commit is contained in:
2026-09-17 23:35:33 +00:00
parent 48aefe95ed
commit 2b355d0ed8
18 changed files with 444 additions and 3 deletions
+30 -1
View File
@@ -92,11 +92,40 @@ func _setup_import_ui() -> void:
path_row.add_child(_model_path_edit)
_btn_browse = Button.new()
_btn_browse.text = "..."
_btn_browse.text = "Browse..."
_btn_browse.pressed.connect(_on_browse_pressed)
path_row.add_child(_btn_browse)
_import_panel.add_child(path_row)
var sample_row := HBoxContainer.new()
var sample_lbl := Label.new()
sample_lbl.text = "Sample:"
sample_lbl.custom_minimum_size = Vector2(50, 0)
sample_row.add_child(sample_lbl)
var sample_option := OptionButton.new()
sample_option.add_item("— Pick a sample model —", 0)
sample_option.add_item("Treasure Chest", 1)
sample_option.set_item_metadata(1, {"path": "res://assets/props/chest.glb", "name": "Treasure Chest"})
sample_option.add_item("Pine Tree", 2)
sample_option.set_item_metadata(2, {"path": "res://assets/props/tree_pine_01.glb", "name": "Pine Tree"})
sample_option.add_item("Lamp Post", 3)
sample_option.set_item_metadata(3, {"path": "res://assets/props/lamp_post_01.glb", "name": "Lamp Post"})
sample_option.add_item("Buffalo Chip Coin", 4)
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.size_flags_horizontal = Control.SIZE_EXPAND_FILL
sample_option.item_selected.connect(func(idx: int):
if idx > 0:
var meta: Dictionary = sample_option.get_item_metadata(idx)
_model_path_edit.text = meta.get("path", "")
if _model_name_edit.text.strip_edges().is_empty():
_model_name_edit.text = meta.get("name", "")
)
sample_row.add_child(sample_option)
_import_panel.add_child(sample_row)
_import_status_label = Label.new()
_import_status_label.text = ""
_import_status_label.add_theme_font_size_override("font_size", 10)
+152
View File
@@ -0,0 +1,152 @@
extends SceneTree
func _initialize() -> void:
_generate()
func _save_model(root_node: Node3D, out_path: String) -> void:
var gltf := GLTFDocument.new()
var state := GLTFState.new()
var err := gltf.append_from_scene(root_node, state)
if err == OK:
var dir := out_path.get_base_dir()
DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(dir))
var w_err := gltf.write_to_filesystem(state, out_path)
print("Saved %s: error=%d" % [out_path, w_err])
else:
printerr("Failed append_from_scene for %s: %d" % [out_path, err])
func _generate() -> void:
print("Generating prop models...")
# 1. Crate Small
var crate_root := Node3D.new()
var crate_mesh := MeshInstance3D.new()
var box := BoxMesh.new()
box.size = Vector3(1.0, 1.0, 1.0)
var mat_wood := StandardMaterial3D.new()
mat_wood.albedo_color = Color(0.6, 0.4, 0.2)
mat_wood.roughness = 0.8
box.material = mat_wood
crate_mesh.mesh = box
crate_mesh.position.y = 0.5
crate_root.add_child(crate_mesh)
_save_model(crate_root, "res://assets/props/crate_small.glb")
# 2. Rock
var rock_root := Node3D.new()
var rock_mesh := MeshInstance3D.new()
var sphere := SphereMesh.new()
sphere.radius = 0.6
sphere.height = 0.9
sphere.radial_segments = 8
sphere.rings = 6
var mat_rock := StandardMaterial3D.new()
mat_rock.albedo_color = Color(0.45, 0.45, 0.48)
mat_rock.roughness = 0.9
sphere.material = mat_rock
rock_mesh.mesh = sphere
rock_mesh.position.y = 0.45
rock_root.add_child(rock_mesh)
_save_model(rock_root, "res://assets/props/rock_01.glb")
# 3. Pine Tree
var tree_root := Node3D.new()
var trunk := MeshInstance3D.new()
var trunk_mesh := CylinderMesh.new()
trunk_mesh.top_radius = 0.15
trunk_mesh.bottom_radius = 0.2
trunk_mesh.height = 1.0
var mat_trunk := StandardMaterial3D.new()
mat_trunk.albedo_color = Color(0.38, 0.25, 0.12)
mat_trunk.roughness = 0.9
trunk_mesh.material = mat_trunk
trunk.mesh = trunk_mesh
trunk.position.y = 0.5
tree_root.add_child(trunk)
var foliage := MeshInstance3D.new()
var cone_mesh := CylinderMesh.new()
cone_mesh.top_radius = 0.0
cone_mesh.bottom_radius = 0.9
cone_mesh.height = 1.8
var mat_leaf := StandardMaterial3D.new()
mat_leaf.albedo_color = Color(0.15, 0.45, 0.2)
mat_leaf.roughness = 0.7
cone_mesh.material = mat_leaf
foliage.mesh = cone_mesh
foliage.position.y = 1.8
tree_root.add_child(foliage)
_save_model(tree_root, "res://assets/props/tree_pine_01.glb")
# 4. Lamp Post
var lamp_root := Node3D.new()
var pole := MeshInstance3D.new()
var pole_mesh := CylinderMesh.new()
pole_mesh.top_radius = 0.05
pole_mesh.bottom_radius = 0.08
pole_mesh.height = 2.4
var mat_metal := StandardMaterial3D.new()
mat_metal.albedo_color = Color(0.2, 0.22, 0.25)
mat_metal.metallic = 0.8
mat_metal.roughness = 0.3
pole_mesh.material = mat_metal
pole.mesh = pole_mesh
pole.position.y = 1.2
lamp_root.add_child(pole)
var light_mesh := MeshInstance3D.new()
var light_box := BoxMesh.new()
light_box.size = Vector3(0.3, 0.35, 0.3)
var mat_glow := StandardMaterial3D.new()
mat_glow.albedo_color = Color(1.0, 0.9, 0.4)
mat_glow.emission_enabled = true
mat_glow.emission = Color(1.0, 0.85, 0.3)
mat_glow.emission_energy_multiplier = 2.0
light_box.material = mat_glow
light_mesh.mesh = light_box
light_mesh.position.y = 2.4
lamp_root.add_child(light_mesh)
_save_model(lamp_root, "res://assets/props/lamp_post_01.glb")
# 5. Treasure Chest
var chest_root := Node3D.new()
var chest_body := MeshInstance3D.new()
var cbox := BoxMesh.new()
cbox.size = Vector3(0.9, 0.6, 0.6)
var mat_chest := StandardMaterial3D.new()
mat_chest.albedo_color = Color(0.45, 0.26, 0.12)
mat_chest.roughness = 0.6
cbox.material = mat_chest
chest_body.mesh = cbox
chest_body.position.y = 0.3
chest_root.add_child(chest_body)
var latch := MeshInstance3D.new()
var latch_box := BoxMesh.new()
latch_box.size = Vector3(0.12, 0.15, 0.06)
var mat_gold := StandardMaterial3D.new()
mat_gold.albedo_color = Color(0.95, 0.8, 0.2)
mat_gold.metallic = 0.9
mat_gold.roughness = 0.2
latch_box.material = mat_gold
latch.mesh = latch_box
latch.position = Vector3(0, 0.35, 0.31)
chest_root.add_child(latch)
_save_model(chest_root, "res://assets/props/chest.glb")
# 6. Buffalo Chip Coin
var coin_root := Node3D.new()
var coin_mesh := MeshInstance3D.new()
var cyl := CylinderMesh.new()
cyl.top_radius = 0.35
cyl.bottom_radius = 0.35
cyl.height = 0.08
cyl.material = mat_gold
coin_mesh.mesh = cyl
coin_mesh.rotation_degrees = Vector3(90, 0, 0)
coin_mesh.position.y = 0.4
coin_root.add_child(coin_mesh)
_save_model(coin_root, "res://assets/props/buffalo_chip_coin.glb")
print("All prop models generated!")
quit(0)
+1
View File
@@ -95,6 +95,7 @@ func _try_load_asset(asset_id: String) -> Node:
# 2. Try direct path or custom asset path
var candidate_paths: Array[String] = [
asset_id,
"res://assets/%s" % asset_id,
"user://custom_assets/%s" % asset_id,
"user://custom_assets/%s" % asset_id.get_file()
]
+1
View File
@@ -16,6 +16,7 @@ const PACK_PATH := "res://.export_check.pck"
## resources (so they only get packed via export_presets include_filter).
const REQUIRED := [
"res://assets/avatars/catalog.json",
"res://assets/editor/object_catalog.json",
]
## A resource we know should be there, as a sanity check that the pack loaded.