diff --git a/assets/editor/object_catalog.json b/assets/editor/object_catalog.json index e27dd11..1b11de4 100644 --- a/assets/editor/object_catalog.json +++ b/assets/editor/object_catalog.json @@ -30,6 +30,12 @@ "display_name": "Treasure Chest", "category": "interactables" }, + "buffalo_chip_coin": { + "asset_id": "props/buffalo_chip_coin.glb", + "type": "prop", + "display_name": "Buffalo Chip Coin", + "category": "props" + }, "spawn_point": { "asset_id": "", "type": "spawn_point", diff --git a/assets/props/buffalo_chip_coin.glb b/assets/props/buffalo_chip_coin.glb new file mode 100644 index 0000000..cc048a8 Binary files /dev/null and b/assets/props/buffalo_chip_coin.glb differ diff --git a/assets/props/buffalo_chip_coin.glb.import b/assets/props/buffalo_chip_coin.glb.import new file mode 100644 index 0000000..6103989 --- /dev/null +++ b/assets/props/buffalo_chip_coin.glb.import @@ -0,0 +1,42 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://dxjew7eex2jh4" +path="res://.godot/imported/buffalo_chip_coin.glb-ccee212ee6fb7ddcc2555bc23ea60f4b.scn" + +[deps] + +source_file="res://assets/props/buffalo_chip_coin.glb" +dest_files=["res://.godot/imported/buffalo_chip_coin.glb-ccee212ee6fb7ddcc2555bc23ea60f4b.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 diff --git a/assets/props/chest.glb b/assets/props/chest.glb new file mode 100644 index 0000000..bb25d6c Binary files /dev/null and b/assets/props/chest.glb differ diff --git a/assets/props/chest.glb.import b/assets/props/chest.glb.import new file mode 100644 index 0000000..fd9989d --- /dev/null +++ b/assets/props/chest.glb.import @@ -0,0 +1,42 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://kik8lcd3jp7x" +path="res://.godot/imported/chest.glb-22b4964b33afcd001921fbaa02f82b8a.scn" + +[deps] + +source_file="res://assets/props/chest.glb" +dest_files=["res://.godot/imported/chest.glb-22b4964b33afcd001921fbaa02f82b8a.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 diff --git a/assets/props/crate_small.glb b/assets/props/crate_small.glb new file mode 100644 index 0000000..2bf3e4a Binary files /dev/null and b/assets/props/crate_small.glb differ diff --git a/assets/props/crate_small.glb.import b/assets/props/crate_small.glb.import new file mode 100644 index 0000000..5f71557 --- /dev/null +++ b/assets/props/crate_small.glb.import @@ -0,0 +1,42 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://n18xbm0q3jai" +path="res://.godot/imported/crate_small.glb-e6fdaf315193cd20d4514609adaa68f2.scn" + +[deps] + +source_file="res://assets/props/crate_small.glb" +dest_files=["res://.godot/imported/crate_small.glb-e6fdaf315193cd20d4514609adaa68f2.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 diff --git a/assets/props/lamp_post_01.glb b/assets/props/lamp_post_01.glb new file mode 100644 index 0000000..3f4c199 Binary files /dev/null and b/assets/props/lamp_post_01.glb differ diff --git a/assets/props/lamp_post_01.glb.import b/assets/props/lamp_post_01.glb.import new file mode 100644 index 0000000..5e75658 --- /dev/null +++ b/assets/props/lamp_post_01.glb.import @@ -0,0 +1,42 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://b3nfmxbm87pl3" +path="res://.godot/imported/lamp_post_01.glb-eea7873c5c7bafcb4d19a09b9d97e53c.scn" + +[deps] + +source_file="res://assets/props/lamp_post_01.glb" +dest_files=["res://.godot/imported/lamp_post_01.glb-eea7873c5c7bafcb4d19a09b9d97e53c.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 diff --git a/assets/props/rock_01.glb b/assets/props/rock_01.glb new file mode 100644 index 0000000..215f2b8 Binary files /dev/null and b/assets/props/rock_01.glb differ diff --git a/assets/props/rock_01.glb.import b/assets/props/rock_01.glb.import new file mode 100644 index 0000000..2e5b2fc --- /dev/null +++ b/assets/props/rock_01.glb.import @@ -0,0 +1,42 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://boi3fsj4ehqvb" +path="res://.godot/imported/rock_01.glb-b0b73bccccfa933f3863bdc2afcb3246.scn" + +[deps] + +source_file="res://assets/props/rock_01.glb" +dest_files=["res://.godot/imported/rock_01.glb-b0b73bccccfa933f3863bdc2afcb3246.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 diff --git a/assets/props/tree_pine_01.glb b/assets/props/tree_pine_01.glb new file mode 100644 index 0000000..e963305 Binary files /dev/null and b/assets/props/tree_pine_01.glb differ diff --git a/assets/props/tree_pine_01.glb.import b/assets/props/tree_pine_01.glb.import new file mode 100644 index 0000000..23015af --- /dev/null +++ b/assets/props/tree_pine_01.glb.import @@ -0,0 +1,42 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://b84vjc1c3d650" +path="res://.godot/imported/tree_pine_01.glb-519f726dc86fdb9eefd0928153fa0181.scn" + +[deps] + +source_file="res://assets/props/tree_pine_01.glb" +dest_files=["res://.godot/imported/tree_pine_01.glb-519f726dc86fdb9eefd0928153fa0181.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 diff --git a/export_presets.cfg b/export_presets.cfg index 571e2ae..38ea719 100644 --- a/export_presets.cfg +++ b/export_presets.cfg @@ -7,7 +7,7 @@ advanced_options=false dedicated_server=false custom_features="" export_filter="all_resources" -include_filter="*.json" +include_filter="*.json, *.glb" exclude_filter="" export_path="export/linux/modbison.x86_64" encryption_include_filters="" @@ -38,7 +38,7 @@ advanced_options=false dedicated_server=false custom_features="" export_filter="all_resources" -include_filter="*.json" +include_filter="*.json, *.glb" exclude_filter="" export_path="export/windows/modbison.exe" encryption_include_filters="" diff --git a/scripts/editor/ui/palette_panel.gd b/scripts/editor/ui/palette_panel.gd index bd628d1..842d146 100644 --- a/scripts/editor/ui/palette_panel.gd +++ b/scripts/editor/ui/palette_panel.gd @@ -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) diff --git a/scripts/generate_props.gd b/scripts/generate_props.gd new file mode 100644 index 0000000..6faead5 --- /dev/null +++ b/scripts/generate_props.gd @@ -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) diff --git a/scripts/static_object_node.gd b/scripts/static_object_node.gd index 7be9f5a..70dfefb 100644 --- a/scripts/static_object_node.gd +++ b/scripts/static_object_node.gd @@ -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() ] diff --git a/scripts/verify_export_contents.gd b/scripts/verify_export_contents.gd index 0c9411d..9ac909d 100644 --- a/scripts/verify_export_contents.gd +++ b/scripts/verify_export_contents.gd @@ -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.