From 6e1e864197e4f0df24639cbb39aadfdfec760f56 Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Wed, 30 Oct 2024 03:04:03 +0300 Subject: [PATCH] Working on initial stages of procedural generator --- .vscode/settings.json | 3 +- godot/astream/building_layout_data.conf | 112 +-- src/modules/stream/base_data.cpp | 65 ++ src/modules/stream/base_data.h | 2 + src/modules/stream/npc/npc.cpp | 34 - src/modules/stream/register_types.cpp | 2 + .../stream/ui/building_layout_graph.cpp | 764 +++++++++++++++++- src/modules/stream/ui/building_layout_graph.h | 5 + .../stream/ui/building_layout_graph_ui.h | 158 +++- src/modules/stream/ui/ui_field_builder.cpp | 2 +- src/modules/stream/world_editor.cpp | 1 - src/modules/stream/world_editor.h | 14 + 12 files changed, 1057 insertions(+), 105 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index c5771ff..87816e5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -68,7 +68,8 @@ "typeinfo": "cpp", "variant": "cpp", "format": "cpp", - "future": "cpp" + "future": "cpp", + "cassert": "cpp" }, "cmake.ignoreCMakeListsMissing": true } \ No newline at end of file diff --git a/godot/astream/building_layout_data.conf b/godot/astream/building_layout_data.conf index 58cbebf..d6ae831 100644 --- a/godot/astream/building_layout_data.conf +++ b/godot/astream/building_layout_data.conf @@ -2,112 +2,132 @@ entries=[ { "children": [ 1, 2, 3 ], +"floor_index": 0, "index": 0, "name": "v1", "type": "layout" }, { -"children": [ 4, 5 ], +"children": [ 4, 5, 6 ], "index": 1, +"name": "zone_0", +"type": "zone", +"zone_type": 0 +}, { +"children": [ 7, 8, 9, 10 ], +"index": 2, +"name": "zone_1", +"type": "zone", +"zone_type": 1 +}, { +"children": [ 11, 12 ], +"index": 3, "name": "unit_0", "type": "unit" }, { -"children": [ 6, 7, 8 ], -"index": 2, -"name": "zone_0", -"type": "zone", -"zone_type": 0 -}, { -"children": [ 9, 10, 11 ], -"index": 3, -"name": "zone_1", -"type": "zone", -"zone_type": 1 -}, { -"children": [ 12, 13, 14 ], -"index": 4, -"name": "zone_0", -"type": "zone", -"zone_type": 0 -}, { -"children": [ 15, 16 ], -"index": 5, -"name": "zone_1", -"type": "zone", -"zone_type": 1 -}, { "children": [ ], -"index": 6, +"index": 4, "name": "wc_0", +"room_area": 4.0, "room_type": 200, "type": "room", "window": false }, { "children": [ ], -"index": 7, +"index": 5, "name": "bathroom_0", +"room_area": 16.0, "room_type": 201, "type": "room", "window": false }, { "children": [ ], -"index": 8, +"index": 6, "name": "bedroom_0", +"room_area": 36.0, "room_type": 202, "type": "room", "window": true }, { "children": [ ], +"index": 7, +"name": "living_room_0", +"room_area": 36.0, +"room_type": 300, +"type": "room", +"window": true +}, { +"children": [ ], +"index": 8, +"name": "kitchen_0", +"room_area": 16.0, +"room_type": 302, +"type": "room", +"window": true +}, { +"children": [ ], "index": 9, -"name": "living_room_0", -"room_type": 300, -"type": "room", -"window": true -}, { -"children": [ ], -"index": 10, -"name": "kitchen_0", -"room_type": 302, -"type": "room", -"window": true -}, { -"children": [ ], -"index": 11, "name": "storage_room_0", +"room_area": 16.0, "room_type": 307, "type": "room", "window": true }, { "children": [ ], +"index": 10, +"name": "enterance_0", +"room_area": 16.0, +"room_type": 304, +"type": "room", +"window": true +}, { +"children": [ 13, 14, 15 ], +"index": 11, +"name": "zone_0", +"type": "zone", +"zone_type": 0 +}, { +"children": [ 16, 17 ], "index": 12, +"name": "zone_1", +"type": "zone", +"zone_type": 1 +}, { +"children": [ ], +"index": 13, "name": "bedroom_0", +"room_area": 36.0, "room_type": 202, "type": "room", "window": true }, { "children": [ ], -"index": 13, +"index": 14, "name": "bathroom_0", +"room_area": 16.0, "room_type": 201, "type": "room", "window": false }, { "children": [ ], -"index": 14, +"index": 15, "name": "wc_0", +"room_area": 4.0, "room_type": 200, "type": "room", "window": false }, { "children": [ ], -"index": 15, +"index": 16, "name": "living_room_0", +"room_area": 36.0, "room_type": 300, "type": "room", "window": true }, { "children": [ ], -"index": 16, +"index": 17, "name": "kitchen_0", +"room_area": 16.0, "room_type": 302, "type": "room", "window": true diff --git a/src/modules/stream/base_data.cpp b/src/modules/stream/base_data.cpp index 3d7ec1b..a810c0c 100644 --- a/src/modules/stream/base_data.cpp +++ b/src/modules/stream/base_data.cpp @@ -1,12 +1,69 @@ +#undef NDEBUG +#include #include +#include +#include #include "base_data.h" static BaseData *base_data = nullptr; +class Updater : public Object { + GDCLASS(Updater, Object) + BaseData *base; + +public: + Updater(BaseData *base) + : Object() + , base(base) + { + } + virtual ~Updater() + { + } + void update() + { + float delta = + SceneTree::get_singleton()->get_physics_process_time(); + base->update(delta); + } + +protected: + static void _bind_methods() + { + ClassDB::bind_method(D_METHOD("update"), &Updater::update); + ClassDB::bind_method(D_METHOD("setup"), &Updater::setup); + } + void _notification(int what) + { + switch (what) { + case NOTIFICATION_POSTINITIALIZE: + call_deferred("setup"); + break; + case NOTIFICATION_PREDELETE: + SceneTree::get_singleton()->disconnect("physics_frame", + this, "update"); + break; + } + } + void setup() + { + assert(SceneTree::get_singleton()); + SceneTree::get_singleton()->connect("physics_frame", this, + "update"); + } +}; + +static Updater *updater = nullptr; + BaseData::BaseData() { } +void BaseData::update(float delta) +{ + BaseData::get_singleton()->get().progress(delta); +} + flecs::world &BaseData::get() { return ecs; @@ -14,6 +71,8 @@ flecs::world &BaseData::get() BaseData::~BaseData() { + if (updater) + memdelete(updater); } BaseData *BaseData::get_singleton() @@ -30,3 +89,9 @@ void BaseData::cleanup() base_data = nullptr; } } + +void BaseData::setup() +{ + if (!updater) + updater = memnew(Updater(this)); +} diff --git a/src/modules/stream/base_data.h b/src/modules/stream/base_data.h index 4910b6b..6ea49bc 100644 --- a/src/modules/stream/base_data.h +++ b/src/modules/stream/base_data.h @@ -12,5 +12,7 @@ public: virtual ~BaseData(); static BaseData *get_singleton(); void cleanup(); + void setup(); + void update(float delta); }; #endif \ No newline at end of file diff --git a/src/modules/stream/npc/npc.cpp b/src/modules/stream/npc/npc.cpp index a89d6a7..5dcf58b 100644 --- a/src/modules/stream/npc/npc.cpp +++ b/src/modules/stream/npc/npc.cpp @@ -84,45 +84,12 @@ struct module { } -class Updater : public Object { - GDCLASS(Updater, Object) - NPC *base; - -public: - Updater(NPC *base) - : Object() - , base(base) - { - SceneTree::get_singleton()->connect("physics_frame", this, - "update"); - } - virtual ~Updater() - { - } - void update() - { - float delta = - SceneTree::get_singleton()->get_physics_process_time(); - base->update(delta); - print_line("Update running"); - } - -protected: - static void _bind_methods() - { - ClassDB::bind_method(D_METHOD("update"), &Updater::update); - } -}; - -static Updater *updater = nullptr; NPC::NPC() { flecs::world ecs = BaseData::get_singleton()->get(); ecs.import (); flecs::entity npcs_e = ecs.entity("npc"); - if (!updater) - updater = memnew(Updater(this)); } NPC *NPC::get_singleton() @@ -143,5 +110,4 @@ NPC::~NPC() void NPC::update(float delta) { - BaseData::get_singleton()->get().progress(delta); } diff --git a/src/modules/stream/register_types.cpp b/src/modules/stream/register_types.cpp index dd8a798..cf37883 100644 --- a/src/modules/stream/register_types.cpp +++ b/src/modules/stream/register_types.cpp @@ -6,6 +6,7 @@ #include "line_metadata_editor.h" #include "buildings/building_layout_editor.h" #include "ui/main_tabs.h" +#include "base_data.h" void register_stream_types() { @@ -16,6 +17,7 @@ void register_stream_types() ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); + BaseData::get_singleton()->setup(); } void unregister_stream_types() diff --git a/src/modules/stream/ui/building_layout_graph.cpp b/src/modules/stream/ui/building_layout_graph.cpp index 23fa61f..d0dae9f 100644 --- a/src/modules/stream/ui/building_layout_graph.cpp +++ b/src/modules/stream/ui/building_layout_graph.cpp @@ -1,12 +1,16 @@ #include #include "base_data.h" #include "world_editor.h" +#include "editor_event.h" #include "building_layout_graph.h" BuildingLayoutGraph *BuildingLayoutGraph::singleton = nullptr; BuildingLayoutGraph::BuildingLayoutGraph() { + BaseData::get_singleton() + ->get() + .import (); Error err = config.load("res://astream/building_layout.conf"); assert(err == OK); public_rooms = config.get_value("rooms", "public", Array()); @@ -80,7 +84,7 @@ void BuildingLayoutGraph::create_unit(const String &base_path) void BuildingLayoutGraph::create_floor(const String &base_path) { - flecs::entity new_e = create_graph_entity(base_path, "unit"); + flecs::entity new_e = create_graph_entity(base_path, "floor"); new_e.set({ 0 }); } @@ -96,6 +100,7 @@ void BuildingLayoutGraph::create_room(const String &base_path, int id) flecs::entity new_e = create_graph_entity(base_path, type_name); new_e.set( { id, window }); + new_e.set({ 0.0f }); } void BuildingLayoutGraph::destroy_graph_entity(const String &path) @@ -125,6 +130,25 @@ flecs::entity BuildingLayoutGraph::get_layout_base() const } } +flecs::entity BuildingLayoutGraph::get_layout_grid_base() const +{ + const String &layout_grid_name = "buildings_layout_grid_v2"; + flecs::world ecs = BaseData::get_singleton()->get(); + flecs::entity layout_base_e = + ecs.lookup(layout_grid_name.ascii().ptr()); + if (layout_base_e.is_valid()) { + assert(layout_base_e.has< + WorldEditor::components::buildings_layout_grid_base>()); + return layout_base_e; + } else { + layout_base_e = ecs.entity(layout_grid_name.ascii().ptr()); + assert(layout_base_e.is_valid()); + layout_base_e.add< + WorldEditor::components::buildings_layout_grid_base>(); + return layout_base_e; + } +} + void BuildingLayoutGraph::get_layout_list(List *keys) const { flecs::entity base = get_layout_base(); @@ -145,6 +169,7 @@ void BuildingLayoutGraph::create_new_layout(const String &layout_name) if (e.is_valid()) { e.add(); e.set({ 0 }); + e.set({ 0 }); } } @@ -378,10 +403,23 @@ void BuildingLayoutGraph::save_layouts() if (e.has()) { entry["type"] = "layout"; /* remember it has floor component too */ + if (e.has()) { + int floor_index = + e.get() + ->index; + entry["floor_index"] = floor_index; + } } else if (e.has()) { + buildings_layout_floor_index>()) { /* non-root floor */ entry["type"] = "floor"; + int floor_index = + e.get() + ->index; + entry["floor_index"] = floor_index; } else if (e.has()) { entry["type"] = "zone"; @@ -403,6 +441,15 @@ void BuildingLayoutGraph::save_layouts() buildings_layout_room>() ->window; entry["window"] = window; + if (e.has()) { + float room_area = + e.get() + ->area; + entry["room_area"] = room_area; + } else + entry["room_area"] = 0.0f; } entries[index] = entry; } @@ -416,6 +463,7 @@ void BuildingLayoutGraph::load_layouts() List queue; flecs::world ecs = BaseData::get_singleton()->get(); flecs::entity base = get_layout_base(); + assert(base.is_valid()); ConfigFile config_layouts; config_layouts.load("res://astream/building_layout_data.conf"); Array entities = @@ -447,27 +495,61 @@ void BuildingLayoutGraph::load_layouts() flecs::entity parent_e = base; if (parent >= 0) parent_e = entity_index[parent]; + assert(parent_e.is_valid()); flecs::entity e = ecs.entity(name.ascii().ptr()).child_of(parent_e); + assert(e.is_valid()); + print_line(String(e.path())); if (type == "layout") { e.add(); - e.set( - { 0 }); + if (entry.has("floor_index")) { + int floor_index = entry["floor_index"]; + e.set({ 0 }); + e.set( + { floor_index }); + } else + e.set({ 0 }); } else if (type == "floor") { - e.set( - { 0 }); + if (entry.has("floor_index")) { + int floor_index = entry["floor_index"]; + e.set({ 0 }); + e.set( + { floor_index }); + } else { + e.set({ 0 }); + e.set( + { 0 }); + } } else if (type == "zone") { int zone_type = entry["zone_type"]; e.set( { zone_type }); + e.add(); } else if (type == "unit") { e.set( { 0 }); + e.add(); } else if (type == "room") { int room_type = entry["room_type"]; bool window = entry["window"]; e.set( { room_type, window }); + if (entry.has("room_area")) { + float room_area = entry["room_area"]; + assert(e.is_valid()); + e.set( + { room_area }); + } else + e.set({ 0.0f }); } else assert(false); entity_index[index] = e; @@ -477,10 +559,676 @@ void BuildingLayoutGraph::load_layouts() } } +void BuildingLayoutGraph::create_interior_tilemap(const String &layout_name) +{ +#if 0 + List queue; + flecs::entity base_e = get_layout_base(); + queue.push_back(base_e); + while (!queue.empty()) { + flecs::entity e = queue.front()->get(); + queue.pop_front(); + if (e.has()) { + if (e.parent() + .has()) { + if (e.parent() + .has()) { + } + } + } + e.children([&queue](flecs::entity ce) { queue.push_back(ce); }); + } +#endif +} + int BuildingLayoutGraph::get_layout_count() const { - flecs::entity e = get_layout_base(); + flecs::entity base_e = get_layout_base(); int count = 0; - e.children([&count](flecs::entity e) { count++; }); + base_e.children([&count](flecs::entity e) { count++; }); return count; } + +BuildingLayoutGraph::graph_module::graph_module(flecs::world ecs) +{ + ecs.component(); + ecs.component(); + ecs.system("FloorArea") + .kind(flecs::OnUpdate) + .without() + .write() + .each([](flecs::iter &it, size_t count, + WorldEditor::components::buildings_layout_floor &f) { + flecs::entity floor_e = it.entity(count); + floor_e.set< + WorldEditor::components::buildings_layout_area>( + { 0.0f }); + }); + ecs.system("UnitArea") + .kind(flecs::OnUpdate) + .without() + .write() + .each([](flecs::iter &it, size_t count, + WorldEditor::components::buildings_layout_unit &f) { + flecs::entity floor_e = it.entity(count); + floor_e.set< + WorldEditor::components::buildings_layout_area>( + { 0.0f }); + }); + ecs.system("ZoneArea") + .kind(flecs::OnUpdate) + .without() + .write() + .each([](flecs::iter &it, size_t count, + WorldEditor::components::buildings_layout_zone &f) { + flecs::entity floor_e = it.entity(count); + floor_e.set< + WorldEditor::components::buildings_layout_area>( + { 0.0f }); + }); + ecs.system( + "MakeZoneAreas") + .kind(flecs::OnUpdate) + .with() + .write() + .each([](flecs::iter &it, size_t count, + WorldEditor::components::buildings_layout_area &area, + const WorldEditor::components::buildings_layout_zone &f, + const WorldEditor::components:: + buildings_layout_floor_index &idx) { + flecs::entity zone_e = it.entity(count); + int index = idx.index; + float parea = 0.0f; + zone_e.children([index, &parea](flecs::entity ec) { + if (ec.has() && + ec.has() && + ec.has()) { + if (ec.get() + ->index == index) + parea += + ec.get() + ->area; + } + }); + area.area = parea; + print_line(String(zone_e.path()) + + " area: " + String::num(area.area)); + }); + ecs.system( + "MakeUnitAreas") + .kind(flecs::OnUpdate) + .with() + .write() + .each([](flecs::iter &it, size_t count, + WorldEditor::components::buildings_layout_area &area, + const WorldEditor::components::buildings_layout_unit &f, + const WorldEditor::components:: + buildings_layout_floor_index &idx) { + flecs::entity zone_e = it.entity(count); + int index = idx.index; + float parea = 0.0f; + zone_e.children([index, &parea](flecs::entity ec) { + if (ec.has() && + ec.has() && + ec.has()) { + if (ec.get() + ->index == index) + parea += + ec.get() + ->area; + } + }); + area.area = parea; + print_line(String(zone_e.path()) + + " area: " + String::num(area.area)); + }); + ecs.system( + "MakeFloorAreas") + .kind(flecs::OnUpdate) + .with() + .write() + .each([](flecs::iter &it, size_t count, + WorldEditor::components::buildings_layout_area &area, + const WorldEditor::components::buildings_layout_floor + &f, + const WorldEditor::components:: + buildings_layout_floor_index &idx) { + flecs::entity floor_e = it.entity(count); + int index = idx.index; + float parea = 0.0f; + floor_e.children([index, &parea](flecs::entity ec) { + if (ec.has() && + ec.has() && + ec.has()) { + if (ec.get() + ->index == index) + parea += + ec.get() + ->area; + } + if (ec.has() && + ec.has() && + ec.has()) { + if (ec.get() + ->index == index) + parea += + ec.get() + ->area; + } + }); + area.area = parea; + print_line(String(floor_e.path()) + + " area: " + String::num(area.area)); + }); +#if 0 + ecs.system( + "MakeAreas") + .kind(flecs::OnUpdate) + // .read() + .with() + .each([](flecs::iter &it, size_t count, + WorldEditor::components::buildings_layout_area &area, + const WorldEditor::components::buildings_layout_floor + &f, + const WorldEditor::components:: + buildings_layout_floor_index &idx) { + flecs::entity floor_e = it.entity(count); + flecs::world ecs_ = floor_e.world(); + ecs_.system(ecs_.lookup("MakeZoneAreas")).run(); + ecs_.system(ecs_.lookup("MakeUnitAreas")).run(); + ecs_.system(ecs_.lookup("MakeFloorAreas")).run(); + }); +#endif + ecs.system( + "MakeGridEntities") + .kind(flecs::OnUpdate) + // .read() + .with() + .each([](flecs::iter &it, size_t count, + WorldEditor::components::buildings_layout_area &area, + const WorldEditor::components::buildings_layout_floor + &f, + const WorldEditor::components:: + buildings_layout_floor_index &idx) { +#if 0 + flecs::entity floor_e = it.entity(count); + List queue; + assert(false); + floor_e.children([&queue](flecs::entity ec) { + if (!ec.has()) + queue.push_back(ec); + }); + while (!queue.empty()) { + flecs::entity e = queue.front()->get(); + queue.pop_front(); + } +#endif + }); +#if 0 + ecs.system( + "CreateZoneData") + .kind(flecs::OnUpdate) + .without() + .write() + .write() + .each([](flecs::iter &it, size_t count, + const WorldEditor::components::buildings_layout_zone + &p) { + flecs::entity e = it.entity(count); + e.set( + { 0.0f, false }); + e.add(); + String path(it.entity(count).path()); + print_line("Create zone data: entity: " + path); + }); + ecs.system( + "CreateUnitData") + .kind(flecs::OnUpdate) + .without() + .write() + .write() + .each([](flecs::iter &it, size_t count, + const WorldEditor::components::buildings_layout_unit + &p) { + flecs::entity e = it.entity(count); + e.set( + { 0.0f }); + e.add(); + String path(it.entity(count).path()); + print_line("Create unit data: entity: " + path); + }); +#if 0 + ecs.system("CreateFloorIndex") + .kind(flecs::OnUpdate) + .without() + .write() + .each([](flecs::iter &it, size_t count, + const WorldEditor::components::buildings_layout_floor + &p) { + flecs::entity e = it.entity(count); + e.set( + { 0.0f }); + }); +#endif + ecs.system( + "UpdateUnitData") + .kind(flecs::OnUpdate) + .with() + .with() + .write() + .write() + .each([](flecs::iter &it, size_t count, + const WorldEditor::components::buildings_layout_unit + &p) { + flecs::entity e = it.entity(count); + float area = 0.0f; + e.children([&area](flecs::entity ec) { + if (ec.has()) + area += ec.get() + ->area; + }); + WorldEditor::components::buildings_layout_unit_data + *udata = e.get_mut< + WorldEditor::components:: + buildings_layout_unit_data>(); + udata->area = area; + String path(it.entity(count).path()); + print_line("Update unit data: entity: " + path + + " area: " + String::num(area)); + e.remove(); + BuildingLayoutGraph::get_singleton() + ->get_layout_base() + .add(); + }); + ecs.system( + "UpdateZoneData") + .kind(flecs::OnUpdate) + .with() + .with() + .write() + .write() + .each([](flecs::iter &it, size_t count, + const WorldEditor::components::buildings_layout_zone + &p) { + flecs::entity e = it.entity(count); + float area = 0.0f; + bool window = false; + e.children([&area, &window](flecs::entity ec) { + if (ec.has()) + area += ec.get() + ->area; + if (ec.has()) { + bool w = + ec.get() + ->window; + if (w) + window = true; + } + }); + WorldEditor::components::buildings_layout_zone_data + *zdata = e.get_mut< + WorldEditor::components:: + buildings_layout_zone_data>(); + zdata->area = area; + zdata->align_wall = window; + String path(it.entity(count).path()); + print_line("Update zone data: entity: " + path + + " area: " + String::num(area)); + e.remove(); + flecs::entity parent_e = e.parent(); + if (parent_e.has()) + parent_e.add(); + BuildingLayoutGraph::get_singleton() + ->get_layout_base() + .add(); + }); + ecs.system( + "PropogateFloorIndex") + .kind(flecs::OnUpdate) + .with() + .write() + .write() + .write() + .immediate() + .each([](flecs::iter &it, size_t count, + const WorldEditor::components::buildings_layout_floor + &r) { + flecs::entity e = it.entity(count); + print_line("propogate: " + String(e.path()) + " " + + itos(r.index)); + List queue; + float area = 0.0f; + /* e is a floor so skip it and add children instead*/ + e.children([&area](flecs::entity ec) { + if (ec.has()) + area += ec.get() + ->area; + if (ec.has()) + area += ec.get() + ->area; + }); + float size = Math::ceil(Math::sqrt(area) * 2.0f); + int grid_size = (int)Math::ceil(size / 2.0f); + e.set( + { area, grid_size }); + e.children([&queue](flecs::entity ec) { + /* do not add children floors to the queue */ + if (!ec.has()) + queue.push_back(ec); + }); + while (!queue.empty()) { + flecs::entity qe = queue.front()->get(); + queue.pop_front(); + if (!qe.has()) { + /* do not add children under another floor either */ + qe.set( + { r.index }); + qe.children([&queue](flecs::entity ec) { + queue.push_back(ec); + }); + } + } + BuildingLayoutGraph::get_singleton() + ->get_layout_base() + .add(); + e.remove(); + }); +#if 0 + ecs.system( + "CollectFloors") + .kind(flecs::OnUpdate) + .with() + .write() + .each([](flecs::iter &it, size_t count, + const WorldEditor::components::buildings_layout_graph + &p) { + flecs::entity e = it.entity(count); + List queue; + queue.push_back(e); + while (!queue.empty()) { + flecs::entity em = queue.front()->get(); + if (em.has(); + }); + + ecs.system( + "DestroyGrid") + .kind(flecs::OnUpdate) + .with() + .write() + .immediate() + .each([](flecs::iter &it, size_t count, + const WorldEditor::components::buildings_layout_base + &p) { + flecs::entity e = it.entity(count); + flecs::entity grid_base_e = + BuildingLayoutGraph::get_singleton() + ->get_layout_grid_base(); + grid_base_e.children([](flecs::entity ce) { + print_line("delete: " + String(ce.path())); + ce.destruct(); + }); + }); + ecs.system("CreateGrid") + .kind(flecs::OnUpdate) + .with() + .write() + .immediate() + .each([](flecs::iter &it, size_t count, + const WorldEditor::components::buildings_layout_base + &p) { + flecs::entity e = it.entity(count); + flecs::entity grid_base_e = + BuildingLayoutGraph::get_singleton() + ->get_layout_grid_base(); + e.children([&grid_base_e](flecs::entity ec) { + if (ec.has()) { + print_line(String(grid_base_e.path())); + flecs::entity gc = + ec.world() + .entity(ec.name()) + .child_of(grid_base_e); + gc.add(); + gc.add(); + print_line("create: " + + String(gc.path())); + } + }); + }); +#endif +#if 0 + ecs.system( + "PopulateGrid") + .kind(flecs::OnUpdate) + .with() + .write() + .immediate() + .each([](flecs::iter &it, size_t count, + const WorldEditor::components::buildings_layout_grid + &p) { + flecs::entity e = it.entity(count); + flecs::entity grid_layout_e = + BuildingLayoutGraph::get_singleton() + ->get_layout_base(); + flecs::entity layout_e + + }); +#endif + ecs.system( + "UpdateGraph") + .kind(flecs::OnUpdate) + .with() + .write() + .each([](flecs::iter &it, size_t count, + const WorldEditor::components::buildings_layout_base + &p) { + flecs::entity e = it.entity(count); + EditorEvent::get_singleton()->event.emit( + "update_layout_view", varray()); + e.remove(); + }); +#endif +#if 0 + ecs.observer() + .event(flecs::OnSet) + .each([](flecs::entity e, + WorldEditor::components::buildings_layout_room &r) { + e.add(); + print_line("room set " + String(e.path())); + }); + ecs.observer() + .event(flecs::OnSet) + .each([](flecs::entity e, + WorldEditor::components::buildings_layout_zone &r) { + e.add(); + print_line("zone set " + String(e.path())); + }); + ecs.observer() + .event(flecs::OnSet) + .each([](flecs::entity e, + WorldEditor::components::buildings_layout_unit &r) { + e.add(); + print_line("unit set " + String(e.path())); + }); +#endif + ecs.system( + "FinishGraphUpdate") + .kind(flecs::OnUpdate) + .with() + .write() + .each([](flecs::iter &it, size_t count, + const WorldEditor::components::buildings_layout_floor + &p, + const WorldEditor::components:: + buildings_layout_floor_index &idx, + const WorldEditor::components::buildings_layout_area + &area) { + flecs::entity e = it.entity(count); + EditorEvent::get_singleton()->event.emit( + "update_layout_view", varray()); + e.remove(); + }); + + ecs.observer() + .event(flecs::OnSet) + .with() + .write() + .each([](flecs::entity e, + const WorldEditor::components::buildings_layout_area + &r) { + /* if set for room make zone dirty */ + flecs::entity parent_e = e.parent(); + while (parent_e.is_valid()) { + print_line(String(parent_e.path())); + if (parent_e.has< + WorldEditor::components:: + buildings_layout_floor>()) { + parent_e.add< + WorldEditor::components:: + buildings_layout_dirty>(); + break; + } + parent_e = parent_e.parent(); + } +#if 0 + if (parent_e.has()) + parent_e.add< + WorldEditor::components:: + buildings_layout_dirty>(); + parent_e.set( + { 0.0f }); +#endif +#if 0 + flecs::world ecs_ = e.world(); + ecs_.system(ecs_.lookup("MakeZoneAreas")).run(); + ecs_.system(ecs_.lookup("MakeUnitAreas")).run(); + ecs_.system(ecs_.lookup("MakeFloorAreas")).run(); +#endif + print_line(String(e.path()) + ": set area"); + }); + /* Propagate floor index to children which are not floor */ + ecs.observer() + .event(flecs::OnSet) + .with() + .each([](flecs::entity e, + const WorldEditor::components:: + buildings_layout_floor_index &r) { + // e.add(); + if (e.has()) { + List queue; + e.children([&queue](flecs::entity ec) { + queue.push_back(ec); + }); + while (!queue.empty()) { + flecs::entity qe = queue.front()->get(); + queue.pop_front(); + if (!qe.has()) { + qe.set( + { r.index }); + print_line(String(qe.path()) + + " index set"); + qe.children( + [&queue](flecs::entity + ec) { + queue.push_back( + ec); + }); + } + } + } + EditorEvent::get_singleton()->event.emit( + "update_layout_view", varray()); + print_line("floor set"); +#if 0 + List queue; + queue.push_back(e); + while (!queue.empty()) { + flecs::entity qe = queue.front()->get(); + queue.pop_front(); + if (!qe.has()) { + qe.set( + { r.index }); + } + } + BuildingLayoutGraph::get_singleton() + ->get_layout_base() + .add(); +#endif + }); +} diff --git a/src/modules/stream/ui/building_layout_graph.h b/src/modules/stream/ui/building_layout_graph.h index 0a2b78d..d5e9043 100644 --- a/src/modules/stream/ui/building_layout_graph.h +++ b/src/modules/stream/ui/building_layout_graph.h @@ -34,6 +34,7 @@ public: void create_room(const String &base_path, int id); void destroy_graph_entity(const String &path); flecs::entity get_layout_base() const; + flecs::entity get_layout_grid_base() const; void get_layout_list(List *keys) const; void create_new_layout(const String &layout_name); flecs::entity get_layout(const String &layout_name) const; @@ -45,5 +46,9 @@ public: List > *list) const; void save_layouts(); void load_layouts(); + void create_interior_tilemap(const String &layout_name); int get_layout_count() const; + struct graph_module { + graph_module(flecs::world ecs); + }; }; \ No newline at end of file diff --git a/src/modules/stream/ui/building_layout_graph_ui.h b/src/modules/stream/ui/building_layout_graph_ui.h index 1a0ed9b..1d7c1f4 100644 --- a/src/modules/stream/ui/building_layout_graph_ui.h +++ b/src/modules/stream/ui/building_layout_graph_ui.h @@ -138,9 +138,15 @@ public: "select_layout"); } else if (event == "button:building_layouts_save") BuildingLayoutGraph::get_singleton()->save_layouts(); + else if (event == "button:building_layouts_create_grid") + BuildingLayoutGraph::get_singleton() + ->create_interior_tilemap(current_layout); else if (event == "building_layouts_layout_selected") { update_graph(); dlg->update(); + } else if (event == "update_layout_view") { + update_graph(); + dlg->update(); } } void tree_entered() @@ -176,6 +182,27 @@ public: void room_size_entered(float value, Control *item, const String &path) { print_line(String::num(value)); + flecs::world ecs = BaseData::get_singleton()->get(); + flecs::entity e = ecs.lookup(path.ascii().ptr()); + float value_r = Math::ceil(Math::sqrt(Math::abs(value))); + float value_div = Math::ceil(value_r / 2); + float area_final = (value_div * 2) * (value_div * 2); + assert(e.is_valid()); + e.set( + { area_final }); + print_line("data set room_size"); + } + void floor_index_entered(float value, Control *item, const String &path) + { + print_line(String::num(value)); + flecs::world ecs = BaseData::get_singleton()->get(); + flecs::entity e = ecs.lookup(path.ascii().ptr()); + assert(e.is_valid()); + e.get_mut() + ->index = (int)value; + e.modified< + WorldEditor::components::buildings_layout_floor_index>(); + print_line("data set floor"); } Vector buttons; #define DEPTH_MUL 160 @@ -248,12 +275,48 @@ public: button->set_text(button->get_text() + "Floor\n" + String(e.name())); + std::vector args = { + "Floor: ", "floor_index" + }; + HashMap save_data; + int floor_index = + e.get() + ->index; + ui_field::ui_field_builder(canvas, box, + "p{h{lx#$}}", + args.data(), + args.size(), + &save_data); + assert(save_data.has("floor_index")); + Object::cast_to( + save_data["floor_index"]) + ->set_value(floor_index); + save_data["floor_index"]->connect( + "value_changed", this, + "floor_index_entered", + varray(save_data["floor_index"], + String(e.path()))); } if (e.has()) { button->set_text(button->get_text() + "Unit\n" + String(e.name())); + if (e.has()) { + float area = + e.get() + ->area; + std::vector args = { + "Area: " + itos(area) + }; + ui_field::ui_field_builder( + canvas, box, "l", + args.data(), + args.size()); + } } if (e.has()) { @@ -274,6 +337,21 @@ public: } button->set_text(button->get_text() + String(e.name())); + if (e.has()) { + float area = + e.get() + ->area; + std::vector args = { + "Area: " + + String::num(area) + }; + ui_field::ui_field_builder( + canvas, box, "l", + args.data(), + args.size()); + } } if (e.has()) { @@ -285,21 +363,67 @@ public: button->get_text() + "Room\n" + String(e.name() + " " + itos(room_type))); + if (e.has()) { + std::vector args = { + "Area: ", "area_value" + }; + HashMap + save_data; + float area = + e.get() + ->area; + ui_field::ui_field_builder( + canvas, box, + "p{h{lx#$}}", + args.data(), + args.size(), + &save_data); + assert(save_data.has( + "area_value")); + Object::cast_to( + save_data["area_value"]) + ->set_value(area); + save_data["area_value"]->connect( + "value_changed", this, + "room_size_entered", + varray(save_data["area_value"], + String(e.path()))); + } + } + if (e.has()) { + int index = + e.get() + ->index; std::vector args = { - "Area: ", "area_value" + "Floor index: " + itos(index) }; - HashMap save_data; ui_field::ui_field_builder(canvas, box, - "p{h{lx#$}}", + "l", args.data(), - args.size(), - &save_data); - assert(save_data.has("area_value")); - save_data["area_value"]->connect( - "value_changed", this, - "room_size_entered", - varray(save_data["area_value"], - String(e.path()))); + args.size()); + } + if (e.has()) { + float area = + e.get() + ->area; + int grid_size = + e.get() + ->grid_size; + std::vector args = { + "Area: " + String::num(area), + "Grid size: " + itos(grid_size) + }; + ui_field::ui_field_builder(canvas, box, + "ll", + args.data(), + args.size()); } button->get_popup()->connect( "id_pressed", this, "menu_pressed", @@ -382,8 +506,7 @@ public: Rect2(p1x - Vector2(0, r), (p2x - p1x) + Vector2(0, r * 2.0)), - Color(0.4, 0.4, 0.55, 1.0), true, 4.0f, - true); + Color(0.4, 0.4, 0.55, 1.0), true); canvas_item->draw_circle( p1x, r, Color(0.4, 0.4, 0.55, 1.0)); canvas_item->draw_circle( @@ -428,10 +551,12 @@ public: "building_layouts_create_new", varray(), "Save", "building_layouts_save_button", "building_layouts_save", varray(), + "Build", "building_layouts_create_grid", + "building_layouts_create_grid", varray(), /* clang-format on */ }; ui_field::ui_field_builder(gui, tab, - "l_p{v{li.#!lh{e#+!b#!Q}b#!Q}}", + "l_p{v{li.#!lh{e#+!b#!Q}b#!Qb#!Q}}", args_data.data(), args_data.size()); } static void _bind_methods() @@ -449,6 +574,11 @@ public: "item" "path"), &BuildingLayoutGraphUI::room_size_entered); + ClassDB::bind_method( + D_METHOD("floor_index_entered", "value", + "item" + "path"), + &BuildingLayoutGraphUI::floor_index_entered); } }; diff --git a/src/modules/stream/ui/ui_field_builder.cpp b/src/modules/stream/ui/ui_field_builder.cpp index 77be8bc..f0abc7e 100644 --- a/src/modules/stream/ui/ui_field_builder.cpp +++ b/src/modules/stream/ui/ui_field_builder.cpp @@ -121,7 +121,7 @@ void ui_field::ui_field_builder(Node *owner, Node *parent, const String format, } break; case 'l': case 'L': - assert(i < fmt_size - 1); + assert(i < fmt_size); assert(argp < args_size); { Label *l = memnew(Label); diff --git a/src/modules/stream/world_editor.cpp b/src/modules/stream/world_editor.cpp index df844a2..458a298 100644 --- a/src/modules/stream/world_editor.cpp +++ b/src/modules/stream/world_editor.cpp @@ -83,7 +83,6 @@ WorldEditor::WorldEditor() ecs.component(); ecs.component(); ecs.component(); - ecs.component(); e = ecs.lookup("world_editor"); assert(!e.is_valid()); if (!InputMap::get_singleton()->has_action("left")) diff --git a/src/modules/stream/world_editor.h b/src/modules/stream/world_editor.h index b00e409..8f3cc3b 100644 --- a/src/modules/stream/world_editor.h +++ b/src/modules/stream/world_editor.h @@ -68,6 +68,8 @@ public: String current_type; }; struct buildings_layout_base {}; + struct buildings_layout_grid_base {}; + struct buildings_layout_grid {}; struct buildings_layout_graph {}; struct buildings_layout_graph_node { int depth; @@ -79,14 +81,26 @@ public: }; struct buildings_layout_zone { int type; + bool align_wall; }; struct buildings_layout_floor { int flags; }; + struct buildings_layout_floor_data { + int grid_size; + }; struct buildings_layout_room { int room_type; bool window; }; + struct buildings_layout_area { + float area; + }; + struct buildings_layout_dirty {}; + /* for all things except floor */ + struct buildings_layout_floor_index { + int index; + }; }; };