diff --git a/assets/blender/buildings/building-elements.blend b/assets/blender/buildings/building-elements.blend index 4cc25b8..ab0a978 100644 Binary files a/assets/blender/buildings/building-elements.blend and b/assets/blender/buildings/building-elements.blend differ diff --git a/godot/astream/blayout.conf b/godot/astream/blayout.conf new file mode 100644 index 0000000..7620781 --- /dev/null +++ b/godot/astream/blayout.conf @@ -0,0 +1,312 @@ +[buildings_layout] + +element_types={ +"corner1": { +"name": "corner1", +"sockets": [ Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 0, -2 ), Transform( 7.54979e-08, 0, -1, 0, 1, 0, 1, 0, 7.54979e-08, 2, 0, -4 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 0, -2 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 0, -2 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ) ] +}, +"e1": { +"name": "e1", +"sockets": [ Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ) ] +}, +"e2": { +"name": "e2", +"sockets": [ Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ) ] +}, +"just_floor": { +"name": "just_floor", +"sockets": [ Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ) ] +}, +"side_wall": { +"name": "side_wall", +"sockets": [ Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -2 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -2 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ), Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ) ] +} +} +elements={ +"corner": { +"mesh_names": [ "exterior_floor3", "exterior_wall2", "", "", "exterior_wall2", "exterior_corner2", "", "", "", "", "", "", "", "", "", "" ], +"name": "corner", +"type": "corner1" +}, +"f1": { +"mesh_names": [ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" ], +"name": "f1", +"type": "e1" +}, +"f2": { +"mesh_names": [ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" ], +"name": "f2", +"type": "e1" +}, +"normal_floor": { +"mesh_names": [ "exterior_floor", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" ], +"name": "normal_floor", +"type": "just_floor" +}, +"side_door": { +"mesh_names": [ "exterior_floor2", "", "", "", "exterior_door1", "", "", "", "", "", "", "", "", "", "", "" ], +"name": "side_door", +"type": "side_wall" +}, +"side_wall": { +"mesh_names": [ "exterior_floor2", "", "", "", "exterior_wall1", "", "", "", "", "", "", "", "", "", "", "" ], +"name": "side_wall", +"type": "side_wall" +}, +"side_window": { +"mesh_names": [ "exterior_floor2", "", "", "", "exterior_window1", "", "", "", "", "", "", "", "", "", "", "" ], +"name": "side_window", +"type": "side_wall" +}, +"test_element": { +"mesh_names": [ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" ], +"name": "test_element", +"type": "e1" +} +} +exterior_grid={ +"default": [ { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +}, { +"element": "empty", +"rotation": 0 +} ] +} diff --git a/godot/astream/building-layouts/building-elements.glb b/godot/astream/building-layouts/building-elements.glb index 62869ca..c1b847c 100644 Binary files a/godot/astream/building-layouts/building-elements.glb and b/godot/astream/building-layouts/building-elements.glb differ diff --git a/godot/astream/building-layouts/material_atlas_73934_1.material b/godot/astream/building-layouts/material_atlas_73934_1.material new file mode 100644 index 0000000..6c7d163 Binary files /dev/null and b/godot/astream/building-layouts/material_atlas_73934_1.material differ diff --git a/godot/main/building_layout_editor.tscn b/godot/main/building_layout_editor.tscn index 917e7de..12705fa 100644 --- a/godot/main/building_layout_editor.tscn +++ b/godot/main/building_layout_editor.tscn @@ -1,11 +1,25 @@ -[gd_scene load_steps=4 format=2] +[gd_scene load_steps=7 format=2] [ext_resource path="res://main/building_layout_editor.gd" type="Script" id=1] [ext_resource path="res://astream/building-layouts/building-elements.glb" type="PackedScene" id=2] +[sub_resource type="SpatialMaterial" id=4] +flags_transparent = true +albedo_color = Color( 1, 1, 1, 0.654902 ) + [sub_resource type="CubeMesh" id=1] +material = SubResource( 4 ) size = Vector3( 40, 1, 40 ) +[sub_resource type="SpatialMaterial" id=2] +flags_transparent = true +flags_unshaded = true +albedo_color = Color( 0.745098, 0.105882, 0.105882, 0.192157 ) + +[sub_resource type="CubeMesh" id=3] +material = SubResource( 2 ) +size = Vector3( 4, 8, 4 ) + [node name="building_layout_editor" type="Spatial"] script = ExtResource( 1 ) @@ -46,7 +60,8 @@ focus_mode = 2 text = "Interior" switch_on_hover = true -[node name="MeshInstance" type="MeshInstance" parent="."] +[node name="bg_floor" type="MeshInstance" parent="."] +unique_name_in_owner = true transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.5, 0 ) mesh = SubResource( 1 ) @@ -97,13 +112,13 @@ size_flags_vertical = 3 unique_name_in_owner = true margin_top = 138.0 margin_right = 314.0 -margin_bottom = 420.0 +margin_bottom = 444.0 [node name="v" type="VBoxContainer" parent="VBoxContainer/socket_editor"] margin_left = 7.0 margin_top = 7.0 margin_right = 307.0 -margin_bottom = 275.0 +margin_bottom = 299.0 [node name="socket_new_element" type="Button" parent="VBoxContainer/socket_editor/v"] unique_name_in_owner = true @@ -250,11 +265,17 @@ margin_right = 299.0 margin_bottom = 24.0 text = "Set" +[node name="test_element" type="OptionButton" parent="VBoxContainer/socket_editor/v"] +unique_name_in_owner = true +margin_top = 272.0 +margin_right = 300.0 +margin_bottom = 292.0 + [node name="element_editor" type="PanelContainer" parent="VBoxContainer"] unique_name_in_owner = true -margin_top = 424.0 +margin_top = 448.0 margin_right = 314.0 -margin_bottom = 691.0 +margin_bottom = 715.0 [node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/element_editor"] margin_left = 7.0 @@ -304,3 +325,11 @@ columns = 2 [node name="BuildingLayoutEditor" type="BuildingLayoutEditor" parent="."] source = ExtResource( 2 ) + +[node name="refcube" type="Spatial" parent="."] +unique_name_in_owner = true + +[node name="refcube" type="MeshInstance" parent="refcube"] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 4, -2 ) +mesh = SubResource( 3 ) +skeleton = NodePath("../..") diff --git a/src/modules/stream/buildings/building_layout_editor.cpp b/src/modules/stream/buildings/building_layout_editor.cpp index 9379e03..373a33a 100644 --- a/src/modules/stream/buildings/building_layout_editor.cpp +++ b/src/modules/stream/buildings/building_layout_editor.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include #include @@ -33,6 +35,7 @@ template T *get_as_node(const String &path) return ret; } +#define ELEMENT_SOCKETS 16 class ElementData { public: static ElementData *singleton; @@ -51,12 +54,38 @@ public: String name; Transform sockets[ELEMENT_SOCKETS]; }; + struct grid_element { + String name; + String type; + String mesh_names[ELEMENT_SOCKETS]; + }; + int grid_step{ 4 }; + int grid_size{ 9 }; + struct grid_cell { + String element; + int rotation; + }; + Vector grid; protected: + ElementData() + { + grid.resize(grid_size * grid_size); + grid.fill({ "empty", 0 }); + load_data(); + struct grid_element_type t_empty; + struct grid_element e_empty; + t_empty.name = "empty"; + e_empty.name = "empty"; + e_empty.type = "empty"; + element_type["empty"] = t_empty; + elements["empty"] = e_empty; + } HashMap element_type; + HashMap elements; public: - void get_key_list(List *keys) + void get_element_type_key_list(List *keys) { element_type.get_key_list(keys); } @@ -79,7 +108,7 @@ public: assert(element_type.has(key)); element_type[key].name = name; } - bool has(const String &key) + bool has_element_type(const String &key) { return element_type.has(key); } @@ -93,14 +122,434 @@ public: { return element_type.size(); } + void create_element(const String &key, const String &type) + { + struct grid_element g; + assert(!elements.has(key)); + assert(element_type.has(type)); + g.name = key; + g.type = type; + elements[key] = g; + } + void set_element_type(const String &key, const String &type) + { + assert(elements.has(key)); + assert(element_type.has(type)); + elements[key].type = type; + } + const String &get_element_type(const String &key) const + { + assert(elements.has(key)); + return elements[key].type; + } + void set_element_mesh_name(const String &key, int socket, + const String &mesh_name) + { + assert(elements.has(key)); + assert(socket >= 0 && socket < ELEMENT_SOCKETS); + elements[key].mesh_names[socket] = mesh_name; + } + const String &get_element_mesh_name(const String &key, int socket) + { + assert(elements.has(key)); + assert(socket >= 0 && socket < ELEMENT_SOCKETS); + return elements[key].mesh_names[socket]; + } + int get_element_size() + { + return elements.size(); + } + void get_element_key_list(List *keys) + { + elements.get_key_list(keys); + } + bool has_element(const String &key) + { + return elements.has(key); + } + void save_data() + { + int i; + ConfigFile config; + Dictionary conf_element_types; + Dictionary conf_elements; + Dictionary conf_exterior_grid; + List keys; + List::Element *e; + element_type.get_key_list(&keys); + e = keys.front(); + while (e) { + Dictionary item; + const struct grid_element_type &g = + element_type[e->get()]; + if (e->get() == "empty") { + e = e->next(); + continue; + } + item["name"] = e->get(); + Array sockets; + sockets.resize(ELEMENT_SOCKETS); + for (i = 0; i < ELEMENT_SOCKETS; i++) + sockets[i] = g.sockets[i]; + item["sockets"] = sockets; + + conf_element_types[e->get()] = item; + e = e->next(); + } + keys.clear(); + elements.get_key_list(&keys); + e = keys.front(); + while (e) { + Dictionary item; + const struct grid_element &g = elements[e->get()]; + if (e->get() == "empty") { + e = e->next(); + continue; + } + item["name"] = e->get(); + item["type"] = g.type; + Array mesh_names; + mesh_names.resize(ELEMENT_SOCKETS); + for (i = 0; i < ELEMENT_SOCKETS; i++) + mesh_names[i] = g.mesh_names[i]; + item["mesh_names"] = mesh_names; + + conf_elements[e->get()] = item; + e = e->next(); + } + // TODO: support multiple layouts; + Array default_grid; + default_grid.resize(grid_size * grid_size); + for (i = 0; i < grid_size * grid_size; i++) { + Dictionary item; + item["element"] = grid[i].element; + item["rotation"] = grid[i].rotation; + default_grid[i] = item; + } + conf_exterior_grid["default"] = default_grid; + + config.set_value("buildings_layout", "element_types", + conf_element_types); + config.set_value("buildings_layout", "elements", conf_elements); + config.set_value("buildings_layout", "exterior_grid", + conf_exterior_grid); + config.save("res://astream/blayout.conf"); + } + void load_data() + { + int i; + ConfigFile config; + Dictionary conf_element_types; + Dictionary conf_elements; + Dictionary conf_exterior_grid; + List keys; + List::Element *e; + elements.clear(); + element_type.clear(); + config.load("res://astream/blayout.conf"); + conf_element_types = config.get_value( + "buildings_layout", "element_types", Dictionary()); + conf_elements = config.get_value("buildings_layout", "elements", + Dictionary()); + conf_exterior_grid = config.get_value( + "buildings_layout", "exterior_grid", Dictionary()); + conf_element_types.get_key_list(&keys); + e = keys.front(); + while (e) { + String key = e->get(); + Dictionary item = conf_element_types[key]; + assert(item.has("sockets")); + create_element_type(key); + Array sockets = item["sockets"]; + for (i = 0; i < sockets.size(); i++) + set_element_type_socket(key, i, sockets[i]); + e = e->next(); + } + keys.clear(); + conf_elements.get_key_list(&keys); + e = keys.front(); + while (e) { + String key = e->get(); + Dictionary item = conf_elements[key]; + assert(item.has("type")); + assert(item.has("mesh_names")); + String type = item["type"]; + print_line("loading element: " + key + + " type: " + type); + if (key == "empty") { + e = e->next(); + continue; + } + create_element(key, type); + Array mesh_names = item["mesh_names"]; + for (i = 0; i < mesh_names.size(); i++) + set_element_mesh_name(key, i, mesh_names[i]); + e = e->next(); + } + if (conf_exterior_grid.has("default")) { + Array default_grid = conf_exterior_grid["default"]; + if (default_grid.size() == grid_size * grid_size) { + grid.fill({ "empty, 0" }); + for (i = 0; i < grid_size * grid_size; i++) { + Dictionary item = default_grid[i]; + grid.write[i].element = item["element"]; + grid.write[i].rotation = + item["rotation"]; + } + } + } + } }; ElementData *ElementData::singleton = nullptr; +class ElementEditor : public Object { + GDCLASS(ElementEditor, Object) + BuildingLayoutEditor *editor; + String current_element; + int used_socket_count; + HashMap mesh_select_buttons; + +public: + ElementEditor(BuildingLayoutEditor *editor) + : Object() + , editor(editor) + , current_element("") + , used_socket_count(-1) + { + get_as_node("%element_list") + ->connect("item_selected", this, "select_element"); + get_as_node