From f62dbbf5056d34c1fd51cdd4cb4c31da7ea1f537 Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Mon, 7 Oct 2024 18:38:46 +0300 Subject: [PATCH] ECS redesign for buildings layout editor --- godot/astream/blayout.conf | 105 +++- .../buildings/building_layout_editor.cpp | 571 +++++++++++++++--- 2 files changed, 581 insertions(+), 95 deletions(-) diff --git a/godot/astream/blayout.conf b/godot/astream/blayout.conf index 7620781..bde5d2c 100644 --- a/godot/astream/blayout.conf +++ b/godot/astream/blayout.conf @@ -64,249 +64,336 @@ elements={ "type": "e1" } } -exterior_grid={ -"default": [ { +grid_layouts={ +"default": { +"exterior": { +"floor_0": [ { "element": "empty", +"index": 0, "rotation": 0 }, { "element": "empty", +"index": 1, "rotation": 0 }, { "element": "empty", +"index": 2, "rotation": 0 }, { "element": "empty", +"index": 3, "rotation": 0 }, { "element": "empty", +"index": 4, "rotation": 0 }, { "element": "empty", +"index": 5, "rotation": 0 }, { "element": "empty", +"index": 6, "rotation": 0 }, { "element": "empty", +"index": 7, "rotation": 0 }, { "element": "empty", +"index": 8, "rotation": 0 }, { "element": "empty", +"index": 9, "rotation": 0 }, { "element": "empty", +"index": 10, "rotation": 0 }, { "element": "empty", +"index": 11, "rotation": 0 }, { "element": "empty", +"index": 12, "rotation": 0 }, { "element": "empty", +"index": 13, "rotation": 0 }, { "element": "empty", +"index": 14, "rotation": 0 }, { "element": "empty", +"index": 15, "rotation": 0 }, { "element": "empty", +"index": 16, "rotation": 0 }, { "element": "empty", +"index": 17, "rotation": 0 }, { "element": "empty", +"index": 18, "rotation": 0 }, { "element": "empty", +"index": 19, "rotation": 0 }, { "element": "empty", +"index": 20, "rotation": 0 }, { "element": "empty", +"index": 21, "rotation": 0 }, { "element": "empty", +"index": 22, "rotation": 0 }, { "element": "empty", +"index": 23, "rotation": 0 }, { "element": "empty", +"index": 24, "rotation": 0 }, { "element": "empty", +"index": 25, "rotation": 0 }, { "element": "empty", +"index": 26, "rotation": 0 }, { "element": "empty", +"index": 27, "rotation": 0 }, { "element": "empty", +"index": 28, "rotation": 0 }, { "element": "empty", +"index": 29, "rotation": 0 }, { "element": "empty", +"index": 30, "rotation": 0 }, { "element": "empty", +"index": 31, "rotation": 0 }, { "element": "empty", +"index": 32, "rotation": 0 }, { "element": "empty", +"index": 33, "rotation": 0 }, { "element": "empty", +"index": 34, "rotation": 0 }, { "element": "empty", +"index": 35, "rotation": 0 }, { "element": "empty", +"index": 36, "rotation": 0 }, { "element": "empty", +"index": 37, "rotation": 0 }, { "element": "empty", +"index": 38, "rotation": 0 }, { "element": "empty", +"index": 39, "rotation": 0 }, { "element": "empty", +"index": 40, "rotation": 0 }, { "element": "empty", +"index": 41, "rotation": 0 }, { "element": "empty", +"index": 42, "rotation": 0 }, { "element": "empty", +"index": 43, "rotation": 0 }, { "element": "empty", +"index": 44, "rotation": 0 }, { "element": "empty", +"index": 45, "rotation": 0 }, { "element": "empty", +"index": 46, "rotation": 0 }, { "element": "empty", +"index": 47, "rotation": 0 }, { "element": "empty", +"index": 48, "rotation": 0 }, { "element": "empty", +"index": 49, "rotation": 0 }, { "element": "empty", +"index": 50, "rotation": 0 }, { "element": "empty", +"index": 51, "rotation": 0 }, { "element": "empty", +"index": 52, "rotation": 0 }, { "element": "empty", +"index": 53, "rotation": 0 }, { "element": "empty", +"index": 54, "rotation": 0 }, { "element": "empty", +"index": 55, "rotation": 0 }, { "element": "empty", +"index": 56, "rotation": 0 }, { "element": "empty", +"index": 57, "rotation": 0 }, { "element": "empty", +"index": 58, "rotation": 0 }, { "element": "empty", +"index": 59, "rotation": 0 }, { "element": "empty", +"index": 60, "rotation": 0 }, { "element": "empty", +"index": 61, "rotation": 0 }, { "element": "empty", +"index": 62, "rotation": 0 }, { "element": "empty", +"index": 63, "rotation": 0 }, { "element": "empty", +"index": 64, "rotation": 0 }, { "element": "empty", +"index": 65, "rotation": 0 }, { "element": "empty", +"index": 66, "rotation": 0 }, { "element": "empty", +"index": 67, "rotation": 0 }, { "element": "empty", +"index": 68, "rotation": 0 }, { "element": "empty", +"index": 69, "rotation": 0 }, { "element": "empty", +"index": 70, "rotation": 0 }, { "element": "empty", +"index": 71, "rotation": 0 }, { -"element": "empty", +"element": "corner", +"index": 72, "rotation": 0 }, { -"element": "empty", +"element": "side_window", +"index": 73, "rotation": 0 }, { -"element": "empty", +"element": "side_window", +"index": 74, "rotation": 0 }, { -"element": "empty", +"element": "side_door", +"index": 75, "rotation": 0 }, { -"element": "empty", +"element": "side_window", +"index": 76, "rotation": 0 }, { -"element": "empty", +"element": "side_window", +"index": 77, "rotation": 0 }, { -"element": "empty", +"element": "side_wall", +"index": 78, "rotation": 0 }, { "element": "empty", +"index": 79, "rotation": 0 }, { "element": "empty", +"index": 80, "rotation": 0 } ] +}, +"interior": { +} +} } diff --git a/src/modules/stream/buildings/building_layout_editor.cpp b/src/modules/stream/buildings/building_layout_editor.cpp index 1fc006c..0607f91 100644 --- a/src/modules/stream/buildings/building_layout_editor.cpp +++ b/src/modules/stream/buildings/building_layout_editor.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "editor_event.h" #include "building_layout_editor.h" @@ -36,10 +37,43 @@ template T *get_as_node(const String &path) return ret; } +template +void select_control_item(const String &path, const String &item) +{ + int i; + T *ctl = get_as_node(path); + int selected = -1; + for (i = 0; i < ctl->get_item_count(); i++) + if (ctl->get_item_text(i) == item) { + selected = i; + break; + } + if (selected >= 0) { + ctl->select(selected); + print_line("selected: " + item); + } +} +template void select_control_item(T *ctl, const String &item) +{ + int i; + int selected = -1; + for (i = 0; i < ctl->get_item_count(); i++) + if (ctl->get_item_text(i) == item) { + selected = i; + break; + } + if (selected >= 0) { + ctl->select(selected); + print_line("selected: " + item); + } +} + #define ELEMENT_SOCKETS 16 class ElementData { -public: + flecs::world ecs; static ElementData *singleton; + +public: static ElementData *get_singleton() { if (!singleton) @@ -66,13 +100,37 @@ public: String element; int rotation; }; - Vector grid; + struct grid_layouts {}; + struct grid_layout { + int floor_count; + }; + struct grid_layout_exterior {}; + struct grid_layout_interior {}; + struct grid_floor {}; + struct grid_floor_item { + int index; + String element; + int rotation; + }; + struct grid_floor_item_node { + Spatial *node; + }; protected: ElementData() { - grid.resize(grid_size * grid_size); - grid.fill({ "empty", 0 }); + ecs.component(); + ecs.component(); + ecs.component(); + ecs.component(); + ecs.component(); + ecs.component(); + ecs.component(); + flecs::entity e = ecs.entity("grid_layouts"); + e.add(); + create_new_layout("default"); + create_new_exterior_floor("default"); + create_new_interior_floor("default"); load_data(); struct grid_element_type t_empty; struct grid_element e_empty; @@ -81,34 +139,370 @@ protected: e_empty.type = "empty"; element_type["empty"] = t_empty; elements["empty"] = e_empty; + ecs.observer() + .event(flecs::OnRemove) + .each([](flecs::entity em, + struct grid_floor_item_node &s) { + if (s.node) + s.node->queue_delete(); + s.node = nullptr; + }); } HashMap element_type; HashMap elements; public: + void create_new_layout(const String &key) + { + flecs::entity top = ecs.lookup("grid_layouts"); + assert(top.is_valid()); + flecs::entity layout = + ecs.entity(key.ascii().ptr()).child_of(top); + // one floor by default + layout.set({ 0 }); + flecs::entity extr = ecs.entity("exterior").child_of(layout); + extr.add(); + flecs::entity intr = ecs.entity("interior").child_of(layout); + intr.add(); + } + void create_new_exterior_floor(const String &key) + { + int i; + flecs::entity top = ecs.lookup("grid_layouts"); + assert(top.is_valid()); + flecs::entity layout = top.lookup(key.ascii().ptr()); + assert(layout.is_valid()); + struct grid_layout *l = layout.get_mut(); + int floor = l->floor_count; + flecs::entity ext = layout.lookup("exterior"); + assert(ext.is_valid()); + flecs::entity fl = + ecs.entity(("floor_" + itos(floor)).ascii().ptr()) + .child_of(ext); + assert(fl.is_valid()); + + for (i = 0; i < grid_size * grid_size; i++) { + flecs::entity item = + ecs.entity(("item_" + itos(i)).ascii().ptr()) + .child_of(fl); + item.set({ i, "empty", 0 }); + } + l->floor_count++; + } + void create_new_interior_floor(const String &key) + { + int i; + flecs::entity top = ecs.lookup("grid_layouts"); + assert(top.is_valid()); + flecs::entity layout = top.lookup(key.ascii().ptr()); + assert(layout.is_valid()); + struct grid_layout *l = layout.get_mut(); + int floor = l->floor_count; + flecs::entity intr = layout.lookup("interior"); + assert(intr.is_valid()); + flecs::entity fl = + ecs.entity(("floor_" + itos(floor)).ascii().ptr()) + .child_of(intr); + assert(fl.is_valid()); + + for (i = 0; i < grid_size * grid_size; i++) { + flecs::entity item = + ecs.entity(("item_" + itos(i)).ascii().ptr()) + .child_of(fl); + item.set({ i, "empty", 0 }); + } + l->floor_count++; + } inline int constexpr get_grid_size() { return grid_size; } - inline const String &get_grid_element(int i) const + inline flecs::entity get_grid_entity(const String &key, bool exterior, + int fl, int i) const { - assert(i >= 0 && i < grid_size * grid_size); - return grid[i].element; + flecs::entity top = ecs.lookup("grid_layouts"); + assert(top.is_valid()); + flecs::entity layout = top.lookup(key.ascii().ptr()); + assert(layout.is_valid()); + struct grid_layout *l = layout.get_mut(); + int floor_count = l->floor_count; + assert(fl >= 0 && fl < floor_count); + flecs::entity base; + if (exterior) + base = layout.lookup("exterior"); + else + base = layout.lookup("interior"); + assert(base.is_valid()); + String floor_key = "floor_" + itos(fl); + String item_key = "item_" + itos(i); + flecs::entity item_data = base.lookup( + (floor_key + "::" + item_key).ascii().ptr()); + if (!item_data.is_valid()) + print_error("lookup failed: " + floor_key + + "::" + item_key); + assert(item_data.is_valid()); + return item_data; } - inline int get_grid_rotation(int i) const + inline const String &get_grid_element(const String &key, bool exterior, + int fl, int i) const { - assert(i >= 0 && i < grid_size * grid_size); - return grid[i].rotation; + flecs::entity item_data = get_grid_entity(key, exterior, fl, i); + const String &element = + item_data.get()->element; + return element; } - void set_grid_element(int i, const String &element) + inline int get_grid_rotation(const String &key, bool exterior, int fl, + int i) const { - assert(i >= 0 && i < grid_size * grid_size); - grid.write[i].element = element; + flecs::entity item_data = get_grid_entity(key, exterior, fl, i); + int rotation = item_data.get()->rotation; + return rotation; } - void set_grid_rotation(int i, int rotation) + void set_grid_element(const String &key, bool exterior, int fl, int i, + const String &element) { - assert(i >= 0 && i < grid_size * grid_size); - grid.write[i].rotation = rotation; + flecs::entity item_data = get_grid_entity(key, exterior, fl, i); + item_data.get_mut()->element = element; + } + void set_grid_rotation(const String &key, bool exterior, int fl, int i, + int rotation) + { + flecs::entity item_data = get_grid_entity(key, exterior, fl, i); + item_data.get_mut()->rotation = rotation; + } + Spatial *get_grid_node(const String &key, bool exterior, int fl, int i) + { + flecs::entity item_data = get_grid_entity(key, exterior, fl, i); + if (!item_data.has()) { + Spatial *sp = memnew(Spatial); + get_as_node("%bg_floor") + ->call_deferred("add_child", sp); + item_data.set({ sp }); + int x = i % grid_size; + int z = i / grid_size; + int rotation = get_grid_rotation(key, exterior, fl, i); + sp->set_transform(Transform( + Basis().rotated(Vector3(0, 1, 0), + Math_PI * rotation / 2.0f), + Vector3((x - 4) * 4, 0, (z - 4) * 4) - + get_as_node("%bg_floor") + ->get_transform() + .origin)); + } + return item_data.get()->node; + } + int get_closest_node_on_floor(const String &key, bool exterior, int fl, + const Vector3 &position) + { + int i; + String full_key = "grid_layouts::" + key; + if (exterior) + full_key += "::exterior"; + else + full_key += "::interior"; + String floor_key = "floor_" + itos(fl); + full_key += "::" + floor_key; + flecs::entity floor_e = ecs.lookup(full_key.ascii().ptr()); + assert(floor_e.is_valid()); + int selected = -1; + float dst = Math_INF; + for (i = 0; i < grid_size * grid_size; i++) { + Spatial *node = get_grid_node(key, exterior, fl, i); + Vector3 pos = node->get_transform().origin; + float mdst = position.distance_squared_to(pos); + if (dst > mdst) { + dst = mdst; + selected = i; + } + } + return selected; + } + void get_grid_layouts_key_list(List *keys) + { + flecs::entity top = ecs.lookup("grid_layouts"); + assert(top.is_valid()); + flecs::query_builder qb = + ecs.query_builder().with( + flecs::ChildOf, top); + flecs::query q = qb.build(); + q.each([keys](flecs::entity e, const struct grid_layout &data) { + keys->push_back(String(e.name())); + }); + } + void serialize_layouts(Dictionary &store) + { + flecs::entity top = ecs.lookup("grid_layouts"); + assert(top.is_valid()); + top.children([this, &store](flecs::entity l) { + Dictionary layout, exterior_layout, interior_layout; + if (l.has()) { + flecs::entity intr = l.lookup("interior"); + assert(intr.is_valid()); + flecs::entity extr = l.lookup("exterior"); + assert(extr.is_valid()); + intr.children([this, &interior_layout]( + flecs::entity intr_fl) { + if (intr_fl.has()) { + Array items; + intr_fl.children([&items]( + flecs::entity + floor_item) { + if (floor_item.has< + struct grid_floor_item>()) { + const struct grid_floor_item *item = + floor_item + .get(); + Dictionary sitem; + sitem["index"] = + item->index; + sitem["element"] = + item->element; + sitem["rotation"] = + item->rotation; + items.push_back( + sitem); + } + }); + String floor_key( + intr_fl.name()); + interior_layout[floor_key] = + items; + } + }); + extr.children([this, &exterior_layout]( + flecs::entity extr_fl) { + Array items; + extr_fl.children([&items]( + flecs::entity + floor_item) { + if (floor_item.has< + struct grid_floor_item>()) { + const struct grid_floor_item *item = + floor_item.get< + struct grid_floor_item>(); + Dictionary sitem; + sitem["index"] = + item->index; + sitem["element"] = + item->element; + sitem["rotation"] = + item->rotation; + items.push_back(sitem); + } + }); + String floor_key(extr_fl.name()); + exterior_layout[floor_key] = items; + }); + layout["interior"] = interior_layout; + layout["exterior"] = exterior_layout; + } + String layout_name(l.name()); + store[layout_name] = layout; + }); + } + void unserialize_layouts(const Dictionary &store) + { + int i; + flecs::entity top = ecs.lookup("grid_layouts"); + assert(top.is_valid()); + // delete all layouts + top.children([this](flecs::entity l) { l.destruct(); }); + List layout_keys; + store.get_key_list(&layout_keys); + List::Element *e; + e = layout_keys.front(); + while (e) { + String layout_name = e->get(); + flecs::entity layout = + ecs.entity(layout_name.ascii().ptr()) + .child_of(top); + layout.set({ 0 }); + flecs::entity extr = + ecs.entity("exterior").child_of(layout); + extr.add(); + flecs::entity intr = + ecs.entity("interior").child_of(layout); + intr.add(); + Dictionary store_layout = store[e->get()]; + Dictionary store_interior = store_layout["interior"]; + Dictionary store_exterior = store_layout["exterior"]; + List::Element *ve; + List interior_keys; + List exterior_keys; + store_interior.get_key_list(&interior_keys); + store_exterior.get_key_list(&exterior_keys); + for (ve = interior_keys.front(); ve; ve = ve->next()) { + String floor_key = ve->get(); + if (floor_key.begins_with("floor_")) { + flecs::entity floor_e = + ecs.entity(floor_key.ascii() + .ptr()) + .child_of(intr); + assert(floor_e.is_valid()); + floor_e.add(); + const Array &floor_interior = + store_interior[floor_key]; + for (i = 0; i < floor_interior.size(); + i++) { + const Dictionary &item = + floor_interior[i]; + int index = item["index"]; + String element = + item["element"]; + int rotation = item["rotation"]; + String item_key = + "item_" + itos(index); + flecs::entity item_e = + ecs.entity(item_key.ascii() + .ptr()) + .child_of( + floor_e); + item_e.set( + { index, element, + rotation }); + } + struct grid_layout *l = layout.get_mut< + struct grid_layout>(); + l->floor_count++; + } + } + for (ve = exterior_keys.front(); ve; ve = ve->next()) { + String floor_key = ve->get(); + if (floor_key.begins_with("floor_")) { + flecs::entity floor_e = + ecs.entity(floor_key.ascii() + .ptr()) + .child_of(extr); + assert(floor_e.is_valid()); + floor_e.add(); + const Array &floor_exterior = + store_exterior[floor_key]; + for (i = 0; i < floor_exterior.size(); + i++) { + const Dictionary &item = + floor_exterior[i]; + int index = item["index"]; + String element = + item["element"]; + int rotation = item["rotation"]; + String item_key = + "item_" + itos(index); + flecs::entity item_e = + ecs.entity(item_key.ascii() + .ptr()) + .child_of( + floor_e); + item_e.set( + { index, element, + rotation }); + } + struct grid_layout *l = layout.get_mut< + struct grid_layout>(); + l->floor_count++; + } + } + e = e->next(); + } } void get_element_type_key_list(List *keys) { @@ -243,20 +637,12 @@ public: 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; + serialize_layouts(conf_exterior_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", + config.set_value("buildings_layout", "grid_layouts", conf_exterior_grid); config.save("res://astream/blayout.conf"); } @@ -266,7 +652,7 @@ public: ConfigFile config; Dictionary conf_element_types; Dictionary conf_elements; - Dictionary conf_exterior_grid; + Dictionary conf_grid_layouts; List keys; List::Element *e; elements.clear(); @@ -276,8 +662,8 @@ public: "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_grid_layouts = config.get_value( + "buildings_layout", "grid_layouts", Dictionary()); conf_element_types.get_key_list(&keys); e = keys.front(); while (e) { @@ -311,6 +697,8 @@ public: set_element_mesh_name(key, i, mesh_names[i]); e = e->next(); } + unserialize_layouts(conf_grid_layouts); +#if 0 if (conf_exterior_grid.has("default")) { Array default_grid = conf_exterior_grid["default"]; if (default_grid.size() == grid_size * grid_size) { @@ -323,6 +711,7 @@ public: } } } +#endif } }; ElementData *ElementData::singleton = nullptr; @@ -331,7 +720,6 @@ class LayoutEditor : public Object { GDCLASS(LayoutEditor, Object) BuildingLayoutEditor *editor; String grid_elements; - Vector grid_nodes; int current_cell; public: @@ -364,37 +752,30 @@ public: int grid_size = ElementData::get_singleton()->get_grid_size(); assert(grid_size > 0); - grid_nodes.resize(grid_size * grid_size); + const String layout_key = "default"; + bool exterior = true; + int floor = 0; for (i = 0; i < grid_size * grid_size; i++) { - int x = i % grid_size; - int z = i / grid_size; - Spatial *node = memnew(Spatial); - int rotation = ElementData::get_singleton() - ->get_grid_rotation(i); - get_as_node("%bg_floor") - ->call_deferred("add_child", node); - node->set_transform(Transform( - Basis().rotated(Vector3(0, 1, 0), - Math_PI * rotation / - 2.0f), - Vector3((x - 4) * 4, 0, (z - 4) * 4) - - get_as_node("%bg_floor") - ->get_transform() - .origin)); - String element = ElementData::get_singleton() - ->get_grid_element(i); + Spatial *node = + ElementData::get_singleton() + ->get_grid_node(layout_key, + exterior, floor, + i); + String element = + ElementData::get_singleton() + ->get_grid_element(layout_key, + exterior, + floor, i); editor->visualize_element_at(element, node); - grid_nodes.write[i] = node; print_line("element: " + element); } - assert(grid_nodes.size() > 0); } editor->get_viewport()->get_camera()->set_global_translation( Vector3(-14, 23, 32)); List element_keys; List::Element *e; - ElementData::get_singleton()->get_element_type_key_list( + ElementData::get_singleton()->get_element_key_list( &element_keys); e = element_keys.front(); get_as_node(grid_elements)->clear(); @@ -415,7 +796,6 @@ public: } void event_signal_handler(const String &event, const Array &args) { - int i; print_line("event: " + event); if (event == "mouse_press") { Vector2 position = args[0]; @@ -441,40 +821,71 @@ public: Math::stepify(proj.z, 4.0f))); get_as_node("%refcube") ->set_global_transform(xf); - float dst = Math_INF; - int selected = -1; - for (i = 0; i < grid_nodes.size(); i++) { - assert(grid_nodes[i]->is_inside_tree()); - Vector3 o = - grid_nodes[i] - ->get_global_transform() - .origin; - float mdst = o.distance_squared_to( - xf.origin); - if (dst > mdst) { - selected = i; - dst = mdst; - } - } + String layout_key = "default"; + bool exterior = true; + int floor = 0; + int selected = + ElementData::get_singleton() + ->get_closest_node_on_floor( + layout_key, exterior, + floor, xf.origin); if (selected >= 0) { current_cell = selected; get_as_node("%refcube") ->set_global_transform( - grid_nodes[current_cell] + ElementData::get_singleton() + ->get_grid_node( + layout_key, + exterior, + floor, + current_cell) ->get_global_transform()); print_line( "cell: " + itos(current_cell) + "pos: " + - (grid_nodes[current_cell] + (ElementData::get_singleton() + ->get_grid_node( + layout_key, + exterior, + floor, + current_cell) ->get_global_transform() .origin .operator String())); + String element = + ElementData::get_singleton() + ->get_grid_element( + layout_key, + exterior, floor, + current_cell); + select_control_item( + "%grid_elements", element); } } } } + void select_grid_element(int index) + { + String layout_key = "default"; + bool exterior = true; + int floor = 0; + + print_line("selected: " + itos(current_cell) + " " + + itos(index)); + const String &element = + get_as_node("%grid_elements") + ->get_item_text(index); + ElementData::get_singleton()->set_grid_element( + layout_key, exterior, floor, current_cell, element); + editor->visualize_element_at( + element, + ElementData::get_singleton()->get_grid_node( + layout_key, exterior, floor, current_cell)); + } static void _bind_methods() { + ClassDB::bind_method(D_METHOD("select_grid_element", "index"), + &LayoutEditor::select_grid_element); } }; @@ -588,7 +999,7 @@ public: } void select_element(int element) { - int i, j; + int i; print_line("selected element: " + itos(element)); String item = get_as_node("%element_list") ->get_item_text(element); @@ -614,27 +1025,13 @@ public: ElementData::get_singleton()->set_element_type( current_element, b->get_item_text(0)); } - int selected = 0; for (i = 0; i < used_socket_count; i++) { String selected_mesh = ElementData::get_singleton() ->get_element_mesh_name(current_element, i); - selected = 0; - for (j = 0; - j < mesh_select_buttons[i]->get_item_count(); - j++) { - String mesh_item = - mesh_select_buttons[i]->get_item_text( - j); - if (mesh_item == selected_mesh) { - selected = j; - break; - } - } - print_line(itos(i) + - ": selecting mesh: " + itos(selected)); - mesh_select_buttons[i]->select(selected); + select_control_item( + mesh_select_buttons[i], selected_mesh); } editor->visualize_element_type(type, current_element); } @@ -1186,6 +1583,8 @@ void BuildingLayoutEditor::visualize_element_at(const String &element, return; const String &element_type = ElementData::get_singleton()->get_element_type(element); + for (i = 0; i < node->get_child_count(); i++) + node->get_child(i)->queue_delete(); for (i = 0; i < ELEMENT_SOCKETS; i++) { Transform xform = ElementData::get_singleton()->get_element_type_socket(