diff --git a/Makefile b/Makefile index 867fbc3..6972a4c 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,10 @@ ARCH=$(patsubst aarch64,arm64,$(shell uname -m)) BLENDER = ../../blender-3.6.20-linux-x64/blender SERVER = src/godot/bin/godot_server.x11.opt.tools.$(ARCH) EDITOR_PLATFORM=x11es +EDITOR2_PLATFORM=x11 DEMO_PLATFORMS=x11 x11es EDITOR = src/godot/bin/godot.$(EDITOR_PLATFORM).opt.tools.$(ARCH) +EDITOR2 = src/godot/bin/godot.$(EDITOR2_PLATFORM).opt.tools.$(ARCH) .PHONY: all godot-editor-main export export-models export-clothes \ export-clean export-linux-demo export-windows-demo \ @@ -28,12 +30,13 @@ $(foreach pt,$(DEMO_PLATFORMS),$(eval $(call build_godot_platform,$(pt)))) godot-main: $(GODOT_MAIN_TARGETS) godot-editor-main godot-server-main godot-server-main: $(SERVER) -godot-editor-main: $(EDITOR) -$(SERVER): patch - cd src/godot; \ - scons platform=server arch=$(ARCH) target=release_debug tools=yes custom_modules=../modules -j16 +godot-editor-main: $(EDITOR) $(EDITOR2) +#$(SERVER): patch +# cd src/godot; \ +# scons platform=server arch=$(ARCH) target=release_debug tools=yes custom_modules=../modules -j16 $(eval $(call build_godot,server,release_debug,yes,$(SERVER),patch)) $(eval $(call build_godot,x11es,release_debug,yes,$(EDITOR),patch)) +$(eval $(call build_godot,x11,release_debug,yes,$(EDITOR2),patch)) patch: ./src/godot/scene/animation/skeleton_ik.cpp cd ./src/godot && git reset --hard HEAD && rm -Rf platform/x11es && for p in ../patches/*.patch; do git apply $$p; done sed -e 's/ERR_FAIL_COND_V(-1 == p_task->root_bone, false);//g' -i ./src/godot/scene/animation/skeleton_ik.cpp diff --git a/godot/astream/terrain/details/Atlas_73934.png.import b/godot/astream/terrain/details/Atlas_73934.png.import index 1317dd1..84e8ca5 100644 --- a/godot/astream/terrain/details/Atlas_73934.png.import +++ b/godot/astream/terrain/details/Atlas_73934.png.import @@ -27,7 +27,7 @@ flags/repeat=true flags/filter=true flags/mipmaps=true flags/anisotropic=false -flags/srgb=2 +flags/srgb=1 process/fix_alpha_border=true process/premult_alpha=false process/HDR_as_SRGB=false diff --git a/godot/astream/terrain/details/residental-house1.tscn b/godot/astream/terrain/details/residental-house1.tscn index 11627d1..5bbf29e 100644 --- a/godot/astream/terrain/details/residental-house1.tscn +++ b/godot/astream/terrain/details/residental-house1.tscn @@ -54,3 +54,6 @@ transform = Transform( 1.7, 0, 0, 0, 1, 0, 0, 0, 1.2, 0, 0, 2.03699 ) [node name="2" type="Spatial" parent="LOD"] visible = false + +[node name="BuildingLayoutInstance" type="BuildingLayoutInstance" parent="."] +size = 8 diff --git a/godot/project.godot b/godot/project.godot index b7da0bb..f2764ee 100644 --- a/godot/project.godot +++ b/godot/project.godot @@ -17,6 +17,10 @@ boot_splash/minimum_display_time=4 settings/fps/force_fps=60 +[display] + +window/vsync/use_vsync=false + [input] forward={ @@ -87,5 +91,5 @@ portals/optimize/remove_danglers=false gles3/shaders/shader_compilation_mode=2 gles3/shaders/shader_compilation_mode.mobile=2 gles3/shaders/max_simultaneous_compiles=4 -limits/buffers/immediate_buffer_size_kb=4096 limits/buffers/blend_shape_max_buffer_size_kb=8192 +limits/buffers/immediate_buffer_size_kb=4096 diff --git a/src/modules/stream/building_grid_instance.cpp b/src/modules/stream/building_grid_instance.cpp new file mode 100644 index 0000000..8187ca4 --- /dev/null +++ b/src/modules/stream/building_grid_instance.cpp @@ -0,0 +1,20 @@ +#include "building_grid_instance.h" +#include "buildings_data.h" + +AABB BuildingGridInstance::get_aabb() const +{ + return AABB(); +} + +PoolVector BuildingGridInstance::get_faces(uint32_t p_usage_flags) const +{ + return PoolVector(); +} + +BuildingGridInstance::BuildingGridInstance() +{ +} + +BuildingGridInstance::~BuildingGridInstance() +{ +} diff --git a/src/modules/stream/building_grid_instance.h b/src/modules/stream/building_grid_instance.h new file mode 100644 index 0000000..a249852 --- /dev/null +++ b/src/modules/stream/building_grid_instance.h @@ -0,0 +1,17 @@ +/* ~/godot-projects/streaming_world/src/modules/stream/building_grid_instance.h */ +#ifndef BUILDING_GRID_INSTANCE_H_ +#define BUILDING_GRID_INSTANCE_H_ +#include +#include +class BuildingGridInstance : public GeometryInstance { + GDCLASS(BuildingGridInstance, GeometryInstance) + flecs::entity e; + +public: + virtual AABB get_aabb() const; + virtual PoolVector get_faces(uint32_t p_usage_flags) const; + BuildingGridInstance(); + ~BuildingGridInstance(); +}; + +#endif // BUILDING_GRID_INSTANCE_H_ \ No newline at end of file diff --git a/src/modules/stream/buildings/building_layout_instance.cpp b/src/modules/stream/buildings/building_layout_instance.cpp new file mode 100644 index 0000000..a0220c4 --- /dev/null +++ b/src/modules/stream/buildings/building_layout_instance.cpp @@ -0,0 +1,97 @@ +#include +#include +#include "building_layout_instance.h" + +BuildingLayoutInstance::BuildingLayoutInstance() + : GeometryInstance() + , size(0) + , level(0) +{ +} + +BuildingLayoutInstance::~BuildingLayoutInstance() +{ +} + +void BuildingLayoutInstance::_notification(int which) +{ + switch (which) { + case NOTIFICATION_ENTER_TREE: + break; + case NOTIFICATION_EXIT_TREE: + break; + } +} + +void BuildingLayoutInstance::_get_property_list(List *p_list) const +{ + int i, j; + p_list->push_back(PropertyInfo(Variant::INT, "size", PROPERTY_HINT_NONE, + "", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::POOL_INT_ARRAY, "walls", + PROPERTY_HINT_NONE, "", + PROPERTY_USAGE_DEFAULT)); +} + +bool BuildingLayoutInstance::_get(const StringName &name, Variant &val) const +{ + int i; + if (name == "size") { + val = size; + return true; + } else if (name == "walls") { + PoolVector mfloors; + mfloors.resize(size); + mfloors.fill(0); + if (floors.size() < 2) { + val = mfloors; + return true; + } + for (i = 0; i < floors.size(); i += 2) { + int cell_index = floors[i]; + int cell_data = floors[i + 1]; + if (cell_index >= 0 && cell_index < mfloors.size()) + continue; + if (cell_data & (1 << 0)) + mfloors.write()[cell_index] = 1; + else + mfloors.write()[cell_index] = 0; + } + return true; + } + return false; +} + +bool BuildingLayoutInstance::_set(const StringName &name, const Variant &val) +{ + int i; + if (name == "size") { + size = val; + property_list_changed_notify(); + return true; +#if 0 + } else if (name == "walls") { + PoolVector mfloors = val; + floors.resize(mfloors.size()); + for (i = 0; i < mfloors.size(); i++) { + if (mfloors[i] > 0) + floors.ptrw()[i] |= (1 << 0); + else + floors.ptrw()[i] &= ~(1 << 0); + } + return true; +#endif + } + return false; +} + +AABB BuildingLayoutInstance::get_aabb() const +{ + return AABB(); +} + +PoolVector +BuildingLayoutInstance::get_faces(uint32_t p_usage_flags) const +{ + return PoolVector(); +} diff --git a/src/modules/stream/buildings/building_layout_instance.h b/src/modules/stream/buildings/building_layout_instance.h new file mode 100644 index 0000000..1e1fa0d --- /dev/null +++ b/src/modules/stream/buildings/building_layout_instance.h @@ -0,0 +1,21 @@ +#include + +class BuildingLayoutInstance : public GeometryInstance { + GDCLASS(BuildingLayoutInstance, GeometryInstance) +public: + BuildingLayoutInstance(); + ~BuildingLayoutInstance(); + +protected: + void _notification(int which); + void _get_property_list(List *p_list) const; + bool _get(const StringName &name, Variant &val) const; + bool _set(const StringName &name, const Variant &val); + Vector floors; + int size; + int level; + +public: + virtual AABB get_aabb() const; + virtual PoolVector get_faces(uint32_t p_usage_flags) const; +}; diff --git a/src/modules/stream/buildings_data.cpp b/src/modules/stream/buildings_data.cpp index e0a6826..583be85 100644 --- a/src/modules/stream/buildings_data.cpp +++ b/src/modules/stream/buildings_data.cpp @@ -9,13 +9,14 @@ #include #include #include +#include +#include #include "from_string.h" #include "base_data.h" #include "buildings_data.h" -BuildingsData *BuildingsData::singleton; - static ConfigFile config; +static ConfigFile custom_layouts; struct scene_data { Ref packed_scene; String path; @@ -42,43 +43,206 @@ struct CBuildingInstance { Node *node; }; -struct CBuildingData { - struct BuildingsData::building building; -}; - struct CSceneData { struct scene_data sd; }; +#if 0 +void BuildingsData::load_tile(std::tuple key) +{ + int i; + const std::vector &items = tiles[key]; + for (i = 0; i < (int)items.size(); i++) { + print_verbose("load item: " + itos(i) + ": key: " + (items[i]) + + ": " /* + data()->get_building(items[i]).id */); + const String &bkey = items[i]; + flecs::entity eb = get_building_entity(bkey); + if (eb.is_valid()) { + if (!eb.has()) + eb.add(); + } + } +} +#endif + BuildingsData::BuildingsData() : undo_log_size(64) { + flecs::world ecs_ = ecs(); + ecs_.component(); + ecs_.component(); + ecs_.component(); + ecs_.component(); + ecs_.component(); + ecs_.component(); + ecs_.component(); + bool deferred = ecs_.is_deferred(); + if (deferred) + ecs_.defer_suspend(); + ecs_.set({ 0 }); + ecs_.set({}); + assert(ecs_.has()); load_data(); + ecs_.query_builder().build().each( + [](flecs::entity e, const CBuildingData &bd) { + print_line("created: " + bd.building.key + " / " + + String(e.name())); + }); + if (deferred) + ecs_.defer_resume(); + print_line("loaded buildings: " + + itos(ecs().get()->created_entities)); + assert(ecs().get()->created_entities > 0); fill_door_locations(); build_building_aabbs(); - ecs().observer() + ecs_.observer() .event(flecs::OnRemove) .each([](flecs::entity e, CBuildingInstance &bi) { if (bi.node) { bi.node->queue_delete(); bi.node = nullptr; - print_line("instance destroyed for " + bi.key); + // print_line("instance destroyed for " + bi.key); } }); + ecs_.observer() + .event(flecs::OnAdd) + .with() + .run([&](flecs::iter &it) { + flecs::query q = + it.world() + .query_builder() + .with() + .build(); + if (it.next()) { + flecs::entity qe = it.entity(0); + q.each([qe](flecs::entity e, + const CBuildingData &d) { + if (e != qe) + e.remove(); + }); + print_line("Selected building " + + String(qe.name())); + // it.fini(); + } + }); + ecs_.system("UpdateEye").kind(flecs::OnUpdate).run([&](flecs::iter &it) { + Viewport *viewport = SceneTree::get_singleton() + ->get_current_scene() + ->get_viewport(); + int i, j, l; + int tile_size = config.get_value("world", "tile_size"); + int view_distance = config.get_value("world", "view_distance"); + assert(tile_size > 0); + Transform xform = + viewport->get_camera()->get_global_transform(); + Vector3 eye = xform.origin; + int tile_x = int(eye.x / tile_size); + int tile_z = int(eye.z / tile_size); + bool need_update = true; + if (it.world().has()) { + int old_x = it.world().get()->tile_x; + int old_z = it.world().get()->tile_z; + if (old_x == tile_x && old_z == tile_z) + need_update = false; + } + it.world().set({ xform, tile_x, tile_z }); + if (need_update) + return; + if (!it.world().has()) + return; + CBuildingTileData *td = it.world().get_mut(); + it.world() + .query_builder() + .without() + .without() + .with() + .build() + .each([&](flecs::entity e, const CBuildingData &bd) { + const CBuildingTile *bt = + e.get(); + std::tuple tile = bt->tile; + int t_x = std::get<0>(tile); + int t_z = std::get<1>(tile); + if (t_x > tile_x - view_distance && + t_x < tile_x + view_distance && + t_z > tile_z - view_distance && + t_z < tile_z + view_distance) { + if (e.is_valid()) { + e.add(); + } + } + }); + it.world() + .query_builder() + .with() + .with() + .without() + .build() + .each([&](flecs::entity e, const CBuildingData &bd) { + const CBuildingTile *bt = + e.get(); + std::tuple tile = bt->tile; + int erase_distance = view_distance + 1; + int ed2 = erase_distance * erase_distance; + + int t_x = std::get<0>(tile); + int t_z = std::get<1>(tile); + int d1 = t_x - tile_x; + int d2 = t_z - tile_z; + if (d1 * d1 > ed2 || d2 * d2 > ed2) + if (e.is_valid()) { + e.add(); + } + }); + }); + ecs_.system("LoadData") + .kind(flecs::OnUpdate) + .without() + .with() + .write() + .each([&](flecs::entity e, const CBuildingData &bd) { + e.world().defer_suspend(); + bool debug = false; + // if (bd.building.key.begins_with("road__")) + // debug = true; + String id = bd.building.id; + if (debug) + print_verbose("add to scene id: " + id); + if (!has_scene(id)) + create_scene_data(id, bd.building.key); + else + add_scene_item(id, bd.building.key); + if (debug) + print_verbose("added to scene id: " + id); + e.add(); + e.remove(); + e.world().defer_resume(); + }); + ecs_.system("UnloadData") + .kind(flecs::OnUpdate) + .with() + .with() + .write() + .each([&](flecs::entity e, const CBuildingData &bd) { + bool debug = false; + // if (bd.building.key.begins_with("road__")) + // debug = true; + String id = bd.building.key; + if (debug) + print_verbose("removed from scene id: " + id); + if (has_scene(id)) + remove_scene_item(id, bd.building.key); + e.remove(); + e.remove(); + }); } BuildingsData::~BuildingsData() { } -BuildingsData *BuildingsData::get_singleton() -{ - if (!singleton) - singleton = memnew(BuildingsData); - - return singleton; -} - void BuildingsData::build_building_aabbs() { building_aabbs.clear(); @@ -130,14 +294,14 @@ bool BuildingsData::has_building(const String &key) String ename = "base:" + key; flecs::entity e = lookup(ename.ascii().ptr()); if (!e.is_valid()) - print_line("no key: " + key); + print_verbose("no key: " + key); else - print_line("has building with parent: " + - String(e.parent().name())); + print_verbose("has building with parent: " + + String(e.parent().name())); return e.is_valid(); } -String BuildingsData::get_closest_building(const Transform &xform) +String BuildingsData::get_closest_building(const Transform &xform) const { float dst = Math_INF; String rkey; @@ -154,18 +318,30 @@ String BuildingsData::get_closest_building(const Transform &xform) }); return rkey; } - -void BuildingsData::cleanup() +flecs::entity +BuildingsData::get_closest_building_entity(const Transform &xform) const { - if (singleton) { - singleton->~BuildingsData(); - Memory::free_static(singleton, false); - singleton = nullptr; - } + float dst = Math_INF; + String rkey; + flecs::entity qe; + // int id = -1; + ecs().each([xform, &rkey, &dst, &qe](flecs::entity e, + const CBuildingData &d) { + Vector3 o = xform.origin; + Vector3 m = d.building.xform.origin; + float mdst = o.distance_squared_to(m); + if (dst > mdst && !d.building.key.begins_with("road__")) { + dst = mdst; + rkey = d.building.key; + qe = e; + } + }); + return qe; } void BuildingsData::read_buildings_json(const String &buildings_path) { + assert(ecs().has()); String buildings_json = FileAccess::get_file_as_string(buildings_path); Variant json_v; String es; @@ -213,7 +389,7 @@ void BuildingsData::save_buildings_json(const String &buildings_path) fa->close(); Dictionary json; int index = 0; - ecs().each([&index, &json](const CBuildingData &b) { + ecs().each([&index, &json](flecs::entity e, const CBuildingData &b) { String key = b.building.key; /* do not save roadside generated stuff */ if (!key.begins_with("road::") && !key.begins_with("road__")) { @@ -321,6 +497,7 @@ void BuildingsData::filter_generated_stuff() void BuildingsData::load_data() { + assert(ecs().has()); Error result = config.load("res://config/stream.conf"); ERR_FAIL_COND_MSG(result != OK, "Failed to load config"); Dictionary buildings_data = @@ -336,7 +513,7 @@ void BuildingsData::load_data() e = keys.front(); while (e) { String key = e->get(); - print_line(key + ": " + buildings_data[key]); + // print_line(key + ": " + buildings_data[key]); e = e->next(); } String buildings_path = config.get_value("buildings", "buildings_path"); @@ -459,6 +636,19 @@ bool BuildingsData::has_scene(const String &key) const return e.is_valid(); } +flecs::entity BuildingsData::get_building_entity(const String &key) const +{ + flecs::query_builder qb = + ecs().query_builder(); + flecs::query q = qb.build(); + uint64_t key_hash = key.hash64(); + flecs::entity em = q.find([key_hash](const CBuildingData &bd) { + // print_line("search: " + bd.building.key); + return bd.building.key.hash64() == key_hash; + }); + return em; +} + void BuildingsData::remove_scene_item(const String &key, const String &bkey) { flecs::entity e = ecs().lookup(key.ascii().ptr()); @@ -502,28 +692,33 @@ void BuildingsData::add_scene_item(const String &key, const String &bkey) CSceneData *d = e.get_mut(); assert(d); String ename = "bi:" + bkey; - print_line("creating entity: " + ename + " on top of: " + key); + // print_line("creating entity: " + ename + " on top of: " + key); flecs::entity ce = e.lookup(ename.ascii().ptr()); if (ce.is_valid()) ce.destruct(); ce = ecs().entity(ename.ascii().ptr()).child_of(e); ce.set({ bkey, nullptr }); - print_line("child name: " + String(ce.name())); + // print_line("child name: " + String(ce.name())); } void BuildingsData::create_scene_data(const String &key, const String &bkey) { if (!has_scene(key)) { flecs::entity e = ecs().entity(key.ascii().ptr()); + // print_line("scene key: " + key); + assert(building_data.has(key)); String path = building_data[key]; + // print_line("path: " + path); assert(path.length() > 5); print_line("Requesting " + (bkey) + " " + path); + assert(!pending_scene.has(path)); struct scene_data sd; sd.path = path; sd.loader = ResourceLoader::load_interactive( path, "PackedScene", true); assert(sd.loader.is_valid()); e.set({ sd }); + pending_scene.insert(path); assert(e.get_mut()); String ename = "bi:" + bkey; flecs::entity ce = e.lookup(ename.ascii().ptr()); @@ -532,7 +727,7 @@ void BuildingsData::create_scene_data(const String &key, const String &bkey) ce = ecs().entity(ename.ascii().ptr()); ce.child_of(e); ce.set({ bkey, nullptr }); - print_line("child name: " + String(ce.name())); + // print_line("child name: " + String(ce.name())); } } @@ -571,7 +766,7 @@ int BuildingsData::scene_get_item_count(const String &key) const it.fini(); }); // assert(result == d->sd.buildings.size()); - print_line("scene_get_item_count: " + itos(result)); + // print_line("scene_get_item_count: " + itos(result)); return result; } List BuildingsData::scene_get_items(const String &key) const @@ -700,11 +895,14 @@ int BuildingsData::get_building_count() const flecs::query q = ecs().query(); int result; + result = q.count(); +#if 0 q.run([&result](flecs::iter &it) { it.next(); result = it.count(); it.fini(); }); +#endif return result; } @@ -728,6 +926,7 @@ BuildingsData::get_building(const String &building_key) String BuildingsData::create_building(const Dictionary &dict) { + assert(ecs().has()); struct building b; building::from_dict(&b, dict); return create_building(b); @@ -736,13 +935,29 @@ String BuildingsData::create_building(const Dictionary &dict) String BuildingsData::create_building(const struct building &building) { assert(building.key.length() > 0); + assert(ecs().has()); String ename = "base:" + building.key; - print_line("create_building: " + ename); + // print_line("create_building: " + ename); flecs::entity e = ecs().lookup(ename.ascii().ptr()); assert(!e.is_valid()); e = ecs().entity(ename.ascii().ptr()); - e.set({ building }); assert(e.is_valid()); + int tile_size = config.get_value("world", "tile_size"); + assert(tile_size > 0); + e.set({ building }); + int tile_x = building.xform.origin.x / tile_size; + int tile_z = building.xform.origin.z / tile_size; + std::tuple tile = { tile_x, tile_z }; + e.set({ tile }); + CBuildingTileData *td = ecs().get_mut(); + if (td->tiles.find(tile) != td->tiles.end()) + td->tiles[tile].push_back(e); + else + td->tiles[tile] = { e }; + ecs().get_mut()->created_entities++; + ecs().modified(); + if (building.id.begins_with("residental-")) + e.add(); print_line("create_building: " + ename + " created"); return building.key; @@ -779,7 +994,7 @@ bool BuildingsData::destroy_building(const String &key) { assert(key.length() > 0); String ename = "base:" + key; - print_line("destroy_building: " + ename); + // print_line("destroy_building: " + ename); flecs::entity e = ecs().lookup(ename.ascii().ptr()); assert(e.is_valid()); e.destruct(); diff --git a/src/modules/stream/buildings_data.h b/src/modules/stream/buildings_data.h index ad57a9b..41433c1 100644 --- a/src/modules/stream/buildings_data.h +++ b/src/modules/stream/buildings_data.h @@ -1,7 +1,9 @@ #ifndef BUILDINGS_DATA_H #define BUILFINGS_DATA_H +#include #include #include +#include class PackedScene; class ResourceInteractiveLoader; class BuildingsData { @@ -21,10 +23,49 @@ public: Dictionary to_dict() const; String line_name; }; + Set pending_scene; /* Scene objects data */ //private: // HashMap scenes; + struct CBuildingData { + struct BuildingsData::building building; + }; + struct CBTypeResidental {}; + struct CBCustomLayout { + int size; + Vector floors; + }; + struct CBuildingStats { + int created_entities; + }; + struct CBuildingsEye { + Transform cam_xform; + int tile_x; + int tile_z; + }; + struct CBuildingTileData { + using tile_key_t = std::tuple; + struct tile_hash + : public std::unary_function { + std::size_t operator()(const tile_key_t &k) const + { + return std::get<0>(k) ^ std::get<1>(k); + } + }; + using tile_map_t = std::unordered_map< + const tile_key_t, std::vector, tile_hash>; + tile_map_t tiles; + tile_map_t loaded_tiles; + }; + struct CBuildingTile { + std::tuple tile; + }; + struct CBuildingLoad {}; + struct CBuildingUnload {}; + struct CBuildingLoaded {}; + struct CBuildingEdited {}; + public: void get_scene_keys_list(List *keys) const; bool has_scene(const String &key) const; @@ -113,7 +154,6 @@ public: int undo_log_size; BuildingsData(); virtual ~BuildingsData(); - static BuildingsData *singleton; public: void read_buildings_json(const String &buildings_path); @@ -128,8 +168,9 @@ public: void update_building_transform(const String &key, const Transform &xform); bool has_building(const String &key); - String get_closest_building(const Transform &xform); - static BuildingsData *get_singleton(); - static void cleanup(); + String get_closest_building(const Transform &xform) const; + flecs::entity get_closest_building_entity(const Transform &xform) const; + flecs::entity get_building_entity(const String &key) const; + void load_tile(int x, int z); }; #endif \ No newline at end of file diff --git a/src/modules/stream/buildings_editor.cpp b/src/modules/stream/buildings_editor.cpp index 99377e4..d28e846 100644 --- a/src/modules/stream/buildings_editor.cpp +++ b/src/modules/stream/buildings_editor.cpp @@ -67,6 +67,8 @@ void BuildingsEditor::event_handler(const String &event, handle_create_building(); else if (event == "button:delete_building") delete_building_handler(); + else if (event == "button:edit_layout") + create_layout_editor(); else if (event == "result:get_closest_building") { select_building(args[0], args[3], args[4]); if (get_buildings_editor_mode() == 2 /* rotate */) { @@ -249,8 +251,26 @@ void BuildingsEditor::mouse_press(const Vector2 &position) case 0: { /* select */ Transform xform(Basis(), proj); - editor->editor_command("get_closest_building", - varray(xform)); + flecs::entity e = + BaseData::get_singleton() + ->get() + .get_mut() + ->get_closest_building_entity(xform); + assert(e.is_valid()); + e.add(); + const BuildingsData::CBuildingData *b = + e.get(); + print_line("selected: " + b->building.id); + select_building(b->building.xform, b->building.key, + b->building.id); + if (get_buildings_editor_mode() == 2 /* rotate */) { + /* move rot cursor too */ + get_as_node("%building_rot_cursor") + ->set_global_transform( + selected_building_xform); + } + // editor->editor_command("get_closest_building", + // varray(xform)); } break; case 1: { /* move */ @@ -417,3 +437,8 @@ const Node *BuildingsEditor::scene() const const Node *ret = editor->get_tree()->get_current_scene(); return ret; } + +void BuildingsEditor::create_layout_editor() +{ + assert(false); +} diff --git a/src/modules/stream/buildings_editor.h b/src/modules/stream/buildings_editor.h index f6b6be9..ab4c718 100644 --- a/src/modules/stream/buildings_editor.h +++ b/src/modules/stream/buildings_editor.h @@ -37,5 +37,6 @@ public: template const T *get_as_node(const String &path) const; Node *scene(); const Node *scene() const; + void create_layout_editor(); }; #endif diff --git a/src/modules/stream/npc/npc.cpp b/src/modules/stream/npc/npc.cpp index 470a237..307a5e5 100644 --- a/src/modules/stream/npc/npc.cpp +++ b/src/modules/stream/npc/npc.cpp @@ -1,3 +1,5 @@ +#undef NDEBUG +#include #include #include #include @@ -14,8 +16,61 @@ #include "editor_event.h" #include "game_event.h" #include "persistent_data.h" +#include "buildings_data.h" #include "npc.h" +static ConfigFile npcconf; +NPC::NPC(flecs::world &ecs) +{ + ecs.module(); + ecs.component(); + ecs.observer() + .event(flecs::OnSet) + .each([&](flecs::iter &it, size_t i, + struct NPCControl &control) { + if (control.command_id == NPCControl::CMD_PRESIM) { + generate_random_npcs(it.world()); + simulate_past(it.world()); + } + it.entity(i).destruct(); + }); +} +/* should be run on new game */ +void NPC::simulate_past(flecs::world ecs) +{ + int i; + Error err = npcconf.load("res://config/npc.conf"); + assert(err == OK); +#if 0 + for (i = 0; i < 100000; i++) { + if (npcconf.has_section("npc/" + itos(i))) { + String name = npcconf.get_value("npc/" + itos(i), + "name", "Nobody"); + int age = + npcconf.get_value("npc/" + itos(i), "age", 18); + String sex = npcconf.get_value("npc/" + itos(i), "name", + "male"); + flecs::entity e = + } + } +#endif + // assert(false); +} + +void NPC::generate_random_npcs(flecs::world ecs) +{ + flecs::query query = + ecs.query_builder() + .with() + .build(); + query.each([](flecs::entity e, const BuildingsData::CBuildingData &bd) { + print_line(String(e.name())); + print_line("id: " + bd.building.id); + }); +} + +#if 0 + class NPCSaveData : public PersistentData::SaveHandler { public: NPC *npc; @@ -39,58 +94,6 @@ struct NPCBase { int id; }; -struct NPCSkeleton { - String skeleton_path; -}; - -struct NPCNode { - Skeleton *skeleton; -}; - -struct NPCLocation { - Transform global_location, local_position; -}; -struct NPCTarget { - Transform target; -}; -struct NPCTargetKey { - String location_key; -}; -struct NPCBackgroundMotion { - float speed; -}; - -struct NPCBody { - /* TODO: implement */ - void *nothing; -}; - -struct NPCAnimation { - /* TODO: implement */ - void *nothing; -}; - -struct NPCResidence { - String residence_key; -}; - -struct NPCOccupation { - /* building key */ - String occupation_key; - // index in building's job list - int job_type; - int start_hour; - int end_hour; - // bit field from mon to sun - int week_days; -}; - -/* Assign leisure on the go depending on -character mood and stats */ -struct NPCLeisure { - String leisure_key; -}; - struct module { module(flecs::world &ecs) { @@ -105,70 +108,12 @@ struct module { ecs.component(); ecs.component(); ecs.component(); - ecs.observer() - .event(flecs::OnSet) - .with() - .with() - .write() - .each([](flecs::entity e, const NPCSkeleton &s) { - Ref skeleton_data; - String path = s.skeleton_path; - if (e.has()) { - if (e.get()->skeleton) { - e.get_mut() - ->skeleton - ->queue_delete(); - e.get_mut()->skeleton = - nullptr; - e.remove(); - } - } - Node *root = SceneTree::get_singleton() - ->get_current_scene(); - if (!root) { - print_error("No scene"); - return; - } - skeleton_data = ResourceLoader::load( - path, "SkeletonData"); - if (skeleton_data.is_valid()) { - Skeleton *skeleton = memnew(Skeleton); - - skeleton_data->load_skeleton(skeleton); - e.set({ skeleton }); - root->call_deferred("add_child", - skeleton); - } else - print_error( - "ERROR: Could not load skeleton: " + - path); - }); - ecs.observer() - .event(flecs::OnRemove) - .write() - .each([](flecs::entity e, const NPCSkeleton &s) { - if (e.has()) { - if (e.get()->skeleton) { - e.get_mut() - ->skeleton - ->queue_delete(); - e.get_mut()->skeleton = - nullptr; - e.remove(); - } - } - }); - /* moving NPC despawned NPC */ - ecs.system("Update").each( - [](flecs::entity e, NPCBase &b) { - // TODO: implement; - }); } }; } -NPC::NPC() +void NPC::create() { flecs::world ecs = BaseData::get_singleton()->get(); ecs.import (); @@ -176,10 +121,12 @@ NPC::NPC() if (base.is_valid()) { /* create components for top level */ } +#if 0 EditorEvent::get_singleton()->event.add_listener( this, &NPC::editor_event_handler); GameEvent::get_singleton()->event.add_listener( this, &NPC::game_event_handler); +#endif } NPC *NPC::get_singleton() @@ -202,70 +149,13 @@ void NPC::update(float delta) { } -flecs::entity NPC::foreground_character(int id) -{ - String ch_name = "ch_" + itos(id); - flecs::world ecs = BaseData::get_singleton()->get(); - flecs::entity base = ecs.lookup("characters"); - flecs::entity ch = base.lookup(ch_name.ascii().ptr()); - if (!ch.is_valid()) - ch = ecs.entity(ch_name.ascii().ptr()).child_of(base); - assert(ch.is_valid()); - if (!ch.has()) - ch.set({ id }); - return ch; -} - -void NPC::background_character(int id) -{ - String ch_name = "ch_" + itos(id); - flecs::world ecs = BaseData::get_singleton()->get(); - flecs::entity base = ecs.lookup("characters"); - flecs::entity ch = base.lookup(ch_name.ascii().ptr()); - assert(ch.is_valid()); - /* remove all components */ - std::vector keep_components = { - ecs.component() - }; - ch.each([&ch, keep_components](flecs::entity_t c) { - if (std::find(keep_components.begin(), keep_components.end(), - c) == keep_components.end()) - ch.remove(c); - }); -} - -void NPC::get_character_list(List *character_list) -{ - Error err; - DirAccess *d = DirAccess::open("res://character/config", &err); - d->list_dir_begin(); - String conf_path; - while ((conf_path = d->get_next()) != "") { - ConfigFile config; - config.load(conf_path); - int id = config.get_value("base", "id"); - } - d->list_dir_end(); -} - void NPC::editor_event_handler(const String &event, const Vector &args) { - if (event == "npc_foreground") { - int npc_id = args[0]; - foreground_character(npc_id); - } else if (event == "npc_background") { - int npc_id = args[0]; - background_character(npc_id); - } + /* not implemented */ } void NPC::game_event_handler(const String &event, const Vector &args) { - if (event == "npc_foreground") { - int npc_id = args[0]; - foreground_character(npc_id); - } else if (event == "npc_background") { - int npc_id = args[0]; - background_character(npc_id); - } + /* not implemented */ } +#endif \ No newline at end of file diff --git a/src/modules/stream/npc/npc.h b/src/modules/stream/npc/npc.h index 6bcca92..dde079f 100644 --- a/src/modules/stream/npc/npc.h +++ b/src/modules/stream/npc/npc.h @@ -1,23 +1,37 @@ #ifndef NPC_H_ #define NPC_H_ -class ConfigFile; -class NPC { - static NPC *singleton; - NPC(); - +#include +struct NPC { + NPC(flecs::world &ecs); + struct NPCBase { + int id; + int age; // days + }; + struct NPCSexMale {}; + struct NPCSexFemale {}; + struct NPCControl { + enum { + CMD_IDLE = 0, + CMD_PRESIM = 1, + CMD_LOAD = 2, + CMD_SAVE = 3, + CMD_SIM = 4, + }; + int command_id; + }; + void simulate_past(flecs::world ecs); + void generate_random_npcs(flecs::world ecs); +#if 0 public: - static NPC *get_singleton(); + static void create(); static void cleanup(); virtual ~NPC(); - void update(float delta); - flecs::entity foreground_character(int id); - void background_character(int id); - static void get_character_list(List *character_list); private: void editor_event_handler(const String &event, const Vector &args); void game_event_handler(const String &event, const Vector &args); +#endif }; #endif \ No newline at end of file diff --git a/src/modules/stream/register_types.cpp b/src/modules/stream/register_types.cpp index bae5532..d5b8352 100644 --- a/src/modules/stream/register_types.cpp +++ b/src/modules/stream/register_types.cpp @@ -10,6 +10,8 @@ #include "npc/importer.h" #include "npc/skeleton_data.h" #include "base_data.h" +#include "building_grid_instance.h" +#include "buildings/building_layout_instance.h" #ifdef TOOLS_ENABLED static void _editor_init() @@ -30,6 +32,8 @@ void register_stream_types() ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); #ifdef TOOLS_ENABLED ClassDB::APIType prev_api = ClassDB::get_current_api(); ClassDB::set_current_api(ClassDB::API_EDITOR); diff --git a/src/modules/stream/road_lines_editor.cpp b/src/modules/stream/road_lines_editor.cpp index 1ca6d42..2f44f9e 100644 --- a/src/modules/stream/road_lines_editor.cpp +++ b/src/modules/stream/road_lines_editor.cpp @@ -431,15 +431,20 @@ void RoadLinesEditor::move_cursor_to_point() set_ui_cursor_position(xform.origin); } +static inline BuildingsData *bd() +{ + BuildingsData *ret = + BaseData::get_singleton()->get().get_mut(); + assert(ret); + return ret; +} + void RoadLinesEditor::move_cursor_to_closest_building() { print_line("move_cursor_to_closest_building"); Vector3 pt = get_cursor_position(); - const String &key = - BuildingsData::get_singleton()->get_closest_building( - Transform(Basis(), pt)); - const Transform &xform = - BuildingsData::get_singleton()->get_building(key).xform; + const String &key = bd()->get_closest_building(Transform(Basis(), pt)); + const Transform &xform = bd()->get_building(key).xform; set_cursor_position(xform.origin); Spatial *cursor = get_as_node(cursor_name); if (!cursor->is_visible()) @@ -1120,8 +1125,7 @@ class EdgeEditorHandler { continue; } const AABB &aabb_building = - BuildingsData::get_singleton() - ->building_aabbs[buildings[i].id]; + bd()->building_aabbs[buildings[i].id]; Transform building_rot( Basis().rotated( Vector3(0, 1, 0), @@ -1302,10 +1306,9 @@ class EdgeEditorHandler { String lot_id = side.lot_type; if (side.buildings.size() > 1) { const AABB &aabb_lot = - BuildingsData::get_singleton() - ->building_aabbs - ["lot-" + - lot_id]; + bd()->building_aabbs + ["lot-" + + lot_id]; bool pack_result = pack_buildings( aabb_lot, @@ -1372,10 +1375,9 @@ class EdgeEditorHandler { String lot_id = side.lot_type; if (side.buildings.size() > 1) { const AABB &aabb_lot = - BuildingsData::get_singleton() - ->building_aabbs - ["lot-" + - lot_id]; + bd()->building_aabbs + ["lot-" + + lot_id]; bool pack_result = pack_buildings( aabb_lot, diff --git a/src/modules/stream/road_lot.cpp b/src/modules/stream/road_lot.cpp index 2dd3496..90a0af8 100644 --- a/src/modules/stream/road_lot.cpp +++ b/src/modules/stream/road_lot.cpp @@ -487,6 +487,21 @@ struct LotPacker { Vector buildings; float area; }; + inline BuildingsData *bd() + { + BuildingsData *ret = BaseData::get_singleton() + ->get() + .get_mut(); + assert(ret); + return ret; + } + const inline BuildingsData *bd() const + { + const BuildingsData *ret = + BaseData::get_singleton()->get().get(); + assert(ret); + return ret; + } Vector lot_buildings_residental, lot_buildings_commercial, lot_buildings_industrial; void get_building_list(const String &varname, @@ -502,8 +517,7 @@ struct LotPacker { for (j = 0; j < entries.size(); j++) { String bname = entries[j]; cb.buildings.push_back(bname); - AABB aabb = BuildingsData::get_singleton() - ->building_aabbs[bname]; + AABB aabb = get_building_type_aabb(bname); cb.area += aabb.size.x * aabb.size.z; print_line("config building: " + bname); } @@ -826,18 +840,22 @@ out_bad: } bool tmp_found = false; int office_count = 0; - AABB get_building_aabb(const String &key) + AABB get_building_aabb(const String &key) const { const struct BuildingsData::building &b = - BuildingsData::get_singleton()->get_building(key); - const AABB &building_aabb = - BuildingsData::get_singleton()->building_aabbs[b.id]; + bd()->get_building(key); + const AABB &building_aabb = bd()->building_aabbs[b.id]; + return building_aabb; + } + AABB get_building_type_aabb(const String &building) const + { + const AABB &building_aabb = bd()->building_aabbs[building]; return building_aabb; } Transform get_building_transform(const String &key) { const struct BuildingsData::building &b = - BuildingsData::get_singleton()->get_building(key); + bd()->get_building(key); return b.xform; } AABB get_aabb_transformed(const String &key) @@ -863,8 +881,7 @@ out_bad: .each([&](flecs::entity e, Lot &lot_) { assert(e.get()->polygon.points.size() > 0); List buildings; - BuildingsData::get_singleton() - ->get_building_keys_list(&buildings); + bd()->get_building_keys_list(&buildings); List::Element *be = buildings.front(); e.get_mut()->polygon.update_aabb(); if (e.has()) @@ -872,8 +889,7 @@ out_bad: while (be) { const String &key = be->get(); const struct BuildingsData::building &b = - BuildingsData::get_singleton() - ->get_building(key); + bd()->get_building(key); if (key.begins_with("road__")) { be = be->next(); continue; @@ -935,8 +951,7 @@ out_bad: lb.buildings[i]; const String &key = mp.second; const struct BuildingsData::building &b = - BuildingsData::get_singleton() - ->get_building(key); + bd()->get_building(key); Rect2 building_rect = get_rect_transformed(key); Rect2 lot_rect = @@ -1096,19 +1111,19 @@ out_bad: lot.polygon.update_aabb(); }); } +#if 0 float get_required_area(const Vector &buildings) const { float ret = 0.0f; int i; for (i = 0; i < (int)buildings.size(); i++) { const String &building = buildings[i]; - const AABB &building_aabb = - BuildingsData::get_singleton() - ->building_aabbs[building]; + const AABB &building_aabb = get_building_aabb(building); ret += building_aabb.size.x * building_aabb.size.z; } return ret; } +#endif int get_selected_building(const Lot &lot, Vector &lbs) { @@ -1200,9 +1215,8 @@ out_bad: const String &building = buildings[i]; const AABB &building_aabb = - BuildingsData::get_singleton() - ->building_aabbs - [building]; + get_building_type_aabb( + building); AABB result = pack_item( e, building_aabb, diff --git a/src/modules/stream/road_processing.cpp b/src/modules/stream/road_processing.cpp index 7b8eb55..cd0edee 100644 --- a/src/modules/stream/road_processing.cpp +++ b/src/modules/stream/road_processing.cpp @@ -86,22 +86,27 @@ struct RoadLinesProcessing { String road_center_mesh_path, road_mid_mesh_path, road_sidewalk_mesh_path; int debug_flags; - static struct RoadLinesProcessing *singleton; - static RoadLinesProcessing *get_singleton() - { - if (!singleton) - singleton = memnew(RoadLinesProcessing); - return singleton; - } DebugGeo *dbg; - ConfigFile config; + static ConfigFile config; RoadLinesProcessing() : dbg(nullptr) { - singleton = this; Error err = config.load("res://config/stream.conf"); assert(err == OK); } + RoadLinesProcessing &operator=(const RoadLinesProcessing &other) + { + dbg = other.dbg; + debug_flags = other.debug_flags; + edges = other.edges; + nodes = other.nodes; + road_center_mesh_path = other.road_center_mesh_path; + road_mid_mesh_path = other.road_mid_mesh_path; + road_sidewalk_mesh_path = other.road_sidewalk_mesh_path; + side_refs = other.side_refs; + wedges = other.wedges; + return *this; + } void create_nodes(const std::vector &road_lines_nodes) { @@ -125,23 +130,37 @@ struct RoadLinesProcessing { xform = xform * rot; return xform; } + inline BuildingsData *bd() + { + BuildingsData *ret = BaseData::get_singleton() + ->get() + .get_mut(); + assert(ret); + return ret; + } + + inline const BuildingsData *bd() const + { + const BuildingsData *ret = + BaseData::get_singleton()->get().get(); + assert(ret); + return ret; + } + void create_building_structure(const BuildingsData::building &b) { assert(b.key.begins_with("road__")); assert(b.id.length() > 0); assert(b.key.length() > 0); - if (BuildingsData::get_singleton()->has_building(b.key)) { - BuildingsData::get_singleton()->remove_scene_item( - b.id, b.key); - BuildingsData::get_singleton()->destroy_building(b.key); + if (bd()->has_building(b.key)) { + bd()->remove_scene_item(b.id, b.key); + bd()->destroy_building(b.key); } - BuildingsData::get_singleton()->create_building(b); - if (!BuildingsData::get_singleton()->has_scene(b.id)) - BuildingsData::get_singleton()->create_scene_data( - b.id, b.key); + bd()->create_building(b); + if (!bd()->has_scene(b.id)) + bd()->create_scene_data(b.id, b.key); else - BuildingsData::get_singleton()->add_scene_item(b.id, - b.key); + bd()->add_scene_item(b.id, b.key); print_line("created building: " + b.key + " " + b.id); print_line("at: " + (b.xform.origin.operator String())); print_line("created ok"); @@ -414,394 +433,6 @@ out2:; /* FIXME: need to generate lots from wedges, not lines (because intersections) and join lots on the same line segment if they are adjacent and of similar depth and not too narrow */ - void update_lot_depths() - { -#if 0 - int i, j, k; - struct line_check { - struct side_ref side; - Vector3 normal; - float depth; - Vector3 startp; - AABB rect; - }; - - LocalVector check_lines; - RoadLinesProcessing *r = RoadLinesProcessing::get_singleton(); - if (r->nodes.size() == 0) - return; - if (r->nodes.empty()) - goto out_skip_end; - // dbg->set_material_override(dbg_mat); - if (!dbg && - VisualServer::get_singleton()->is_render_loop_enabled()) { - dbg = memnew(DebugGeo); - SceneTree::get_singleton() - ->get_current_scene() - ->call_deferred("add_child", dbg); - } - print_line("wedges size:" + itos(r->nodes.size())); - dbg->clear(); - dbg->begin(Mesh::PRIMITIVE_LINES); - dbg->set_color(Color(1, 0, 0, 1)); - dbg->set_color(Color(1, 0, 0, 1)); - for (i = 0; i < (int)r->nodes.size(); i++) { - const std::vector &ws = wedges[i]; - int wsize = ws.size(); - for (j = 0; j < wsize; j++) { - const struct wedge &w = wedges[i][j]; - struct RoadLinesData::road_edge_side mside1 = - RoadLinesData::get_singleton() - ->get_line_edge_side( - w.side1_ref.line_key, - w.side1_ref.edge, - w.side1_ref.side); - struct RoadLinesData::road_edge_side mside2 = - RoadLinesData::get_singleton() - ->get_line_edge_side( - w.side2_ref.line_key, - w.side2_ref.edge, - w.side2_ref.side); - Vector3 d1 = (w.p[1] - w.p[0]).normalized(); - Vector3 d2 = (w.p[2] - w.p[1]).normalized(); - Vector3 n1 = (w.p[0] - w.y[0]).normalized(); - Vector3 n2 = (w.p[1] - w.y[1]).normalized(); - Vector3 n3 = (w.p[2] - w.y[2]).normalized(); - mside1.lot_depth_eff = - MAX(mside1.lot_depth_eff, 200.0f); - mside2.lot_depth_eff = - MAX(mside2.lot_depth_eff, 200.0f); - assert(mside1.lot_depth_eff > 0.001); - assert(mside2.lot_depth_eff > 0.001); - struct line_check lc1, lc2; - int nlanes1 = w.width1 / 5.0f; - int nlanes2 = w.width2 / 5.0f; - float m = (w.p[1] - w.y[1]).length() / - (w.p[0] - w.y[0]).length(); - lc1.side = w.side1_ref; - lc1.depth = mside1.lot_depth_eff; - lc1.normal = n1; - lc1.startp = w.p[0] + (w.width1 - 4.0f) * n1; - lc1.rect.position = lc1.startp; - lc1.rect.size = Vector3(); - lc1.rect.expand_to(lc1.startp + n1 * lc1.depth); - lc2.side = w.side2_ref; - lc2.depth = MIN(mside1.lot_depth_eff, - mside2.lot_depth_eff); - lc2.normal = n2; - Vector3 x = n2 * (w.width2 - 4.0f) * m; - - lc2.startp = w.p[1] + x; - lc2.rect.position = lc2.startp; - lc2.rect.size = Vector3(); - lc2.rect.expand_to(lc2.startp + n2 * lc2.depth); - check_lines.push_back(lc1); - check_lines.push_back(lc2); - } - } - assert(check_lines.size() > 0); - for (i = 0; i < (int)check_lines.size(); i++) { - for (j = 0; j < (int)r->nodes.size(); j++) { - const std::vector &ws = wedges[j]; - int wsize = ws.size(); - for (k = 0; k < wsize; k++) { - const struct wedge &w = ws[k]; - Vector3 p0 = check_lines[i].startp; - Vector3 p1 = - p0 + - check_lines[i].normal * - check_lines[i].depth; - Vector3 p2 = w.p[0]; - Vector3 p3 = w.p[1]; - Vector3 s, t; - /* samey segments do not intersect */ - if (p0.is_equal_approx(p2) && - p1.is_equal_approx(p3)) - continue; - if (p0.is_equal_approx(p3) && - p1.is_equal_approx(p2)) - continue; - /* segments which share a point do not intersect */ - if (p0.is_equal_approx(p2)) - continue; - if (p0.is_equal_approx(p3)) - continue; - if (p1.is_equal_approx(p3)) - continue; - if (p1.is_equal_approx(p2)) - continue; - assert(!p0.is_equal_approx(p1) && - !p2.is_equal_approx(p3)); - Geometry::get_closest_points_between_segments( - p0, p1, p2, p3, s, t); - if (s.is_equal_approx(p0)) - continue; - if (s.is_equal_approx(p1)) - continue; - if (t.is_equal_approx(p2)) - continue; - if (t.is_equal_approx(p3)) - continue; - assert(!s.is_equal_approx(p0)); - assert(!s.is_equal_approx(p1)); - assert(!t.is_equal_approx(p2)); - assert(!t.is_equal_approx(p3)); - Vector3 mx(t.x, s.y, t.z); - if (!s.is_equal_approx(mx)) - continue; - if (Math::abs(s.y - t.y) < 5.0f) { - if (s.is_equal_approx(mx)) { - float l1 = - p0.distance_to( - s); - check_lines[i] - .depth = MIN( - check_lines[i] - .depth, - l1); - } - } - } - } - } - for (i = 0; i < (int)check_lines.size(); i++) { - Vector3 p0 = check_lines[i].startp; - Vector3 p1 = p0 + check_lines[i].normal * - check_lines[i].depth; - assert(p0.distance_squared_to(p1) > 0.001f); - dbg->set_color(Color(1, 0, 0, 1)); - dbg->add_vertex(p0); - dbg->add_vertex(p0 + Vector3(0, 100, 0)); - dbg->add_vertex(p1); - dbg->add_vertex(p1 + Vector3(0, 100, 0)); - dbg->set_color(Color(0, 0, 1, 1)); - dbg->add_vertex(p0); - dbg->add_vertex(p1); - for (j = 0; j < (int)check_lines.size(); j++) { - if (i == j) - continue; - Vector3 p2 = check_lines[j].startp; - Vector3 p3 = p2 + check_lines[j].normal * - check_lines[j].depth; - Vector3 s, t; - /* samey segments do not intersect */ - if (p0.is_equal_approx(p2) && - p1.is_equal_approx(p3)) - continue; - if (p0.is_equal_approx(p3) && - p1.is_equal_approx(p2)) - continue; - /* segments which share a point do not intersect */ - if (p0.is_equal_approx(p2)) - continue; - if (p0.is_equal_approx(p3)) - continue; - if (p1.is_equal_approx(p3)) - continue; - if (p1.is_equal_approx(p2)) - continue; - assert(!p0.is_equal_approx(p1) && - !p2.is_equal_approx(p3)); - Geometry::get_closest_points_between_segments( - p0, p1, p2, p3, s, t); - if (s.is_equal_approx(p0)) - continue; - if (s.is_equal_approx(p1)) - continue; - if (t.is_equal_approx(p2)) - continue; - if (t.is_equal_approx(p3)) - continue; - assert(!s.is_equal_approx(p0)); - assert(!s.is_equal_approx(p1)); - assert(!t.is_equal_approx(p2)); - assert(!t.is_equal_approx(p3)); - Vector3 mx(t.x, s.y, t.z); - if (!s.is_equal_approx(mx)) - continue; - if (Math::abs(s.y - t.y) < 5.0f) { - if (s.is_equal_approx(mx)) { - dbg->set_color( - Color(0, 1, 0, 1)); - dbg->add_vertex( - s + - Vector3(-0.5, 15, 0)); - dbg->add_vertex(s + Vector3(0.5, - 100, - 0)); - float l1 = p0.distance_to(s); - float l2 = p2.distance_to(t); - check_lines[i].depth = MIN( - check_lines[i].depth, - l1); - check_lines[j].depth = MIN( - check_lines[j].depth, - l2); - } - } - } - } - dbg->end(); - dbg->clear(); - dbg->begin(Mesh::PRIMITIVE_LINES); - dbg->set_color(Color(1, 0, 0, 1)); - for (i = 0; i < (int)check_lines.size(); i++) { - Vector3 p0 = check_lines[i].startp; - Vector3 p1 = p0 + check_lines[i].normal * - check_lines[i].depth; - assert(p0.distance_squared_to(p1) > 0.001f); - dbg->set_color(Color(1, 0, 0, 1)); - dbg->add_vertex(p0); - dbg->add_vertex(p0 + Vector3(0, 100, 0)); - dbg->add_vertex(p1); - dbg->add_vertex(p1 + Vector3(0, 100, 0)); - dbg->set_color(Color(0, 0, 1, 1)); - dbg->add_vertex(p0); - dbg->add_vertex(p1); - struct side_ref &side1 = check_lines[i].side; - struct RoadLinesData::road_edge_side mside1 = - RoadLinesData::get_singleton() - ->get_line_edge_side(side1.line_key, - side1.edge, - side1.side); - mside1.lot_depth_eff = check_lines[i].depth; - mside1.lot_depth = mside1.lot_depth_eff; - int bad_count = 0; - int lot_points = mside1.lot_points.size(); - assert(lot_points == 0 || lot_points == 2); - for (j = 0; j < mside1.lot_points.size(); j++) { - if (!mside1.lot_points[j].is_equal_approx(p0)) - bad_count++; - if (!mside1.lot_points[j].is_equal_approx(p1)) - bad_count++; - } - if (bad_count < 2) { - mside1.lot_points.push_back(p0); - mside1.lot_points.push_back(p1); - } - if (side1.side == 0) - RoadLinesData::get_singleton() - ->set_line_edge_left(side1.line_key, - side1.edge, - mside1); - else - RoadLinesData::get_singleton() - ->set_line_edge_right(side1.line_key, - side1.edge, - mside1); - } - dbg->end(); - dbg->begin(Mesh::PRIMITIVE_LINES); - dbg->set_color(Color(0, 1, 1, 1)); - { - List line_keys; - List::Element *line_e; - RoadLinesData *rld = RoadLinesData::get_singleton(); - rld->get_road_lines_key_list(&line_keys); - line_e = line_keys.front(); - while (line_e) { - const String &key = line_e->get(); - print_line("line: " + key); - int edges = rld->get_line_edge_count(key); - for (i = 0; i < edges; i++) { - RoadLinesData::road_edge_side left = - rld->get_line_edge_left(key, i); - RoadLinesData::road_edge_side right = - rld->get_line_edge_right(key, - i); - print_line("edge: " + itos(i) + - " left: lot: " + - itos(left.lot)); - print_line("edge: " + itos(i) + - " right: lot: " + - itos(right.lot)); - print_line( - "lot_points: left: " + - itos(left.lot_points.size())); - print_line( - "lot_points: right: " + - itos(right.lot_points.size())); - for (j = 0; - j < (int)left.lot_points.size(); - j++) { - dbg->add_vertex( - left.lot_points[j] + - Vector3(0, 20, 0)); - dbg->add_vertex( - left.lot_points[j] + - Vector3(0, 200, 0)); - } - if (left.lot_points.size() == 6) { - int index[] = { 0, 1, 1, 3, - 3, 5, 5, 4 }; - for (j = 0; j < 8; j++) { - dbg->add_vertex( - left.lot_points - [index[j]] + - Vector3(0, 25, - 0)); - print_line( - itos(j) + ": " + - left.lot_points[index[j]] - . - operator String()); - } - assert(false); - } else if (left.lot_points.size() == - 4) { - int index[] = { 0, 1, 1, 3, - 3, 2, 2, 0 }; - for (j = 0; j < 8; j++) - dbg->add_vertex( - left.lot_points - [index[j]] + - Vector3(0, 25, - 0)); - } - for (j = 0; - j < (int)right.lot_points.size(); - j++) { - dbg->add_vertex( - right.lot_points[j] + - Vector3(0, 20, 0)); - dbg->add_vertex( - right.lot_points[j] + - Vector3(0, 200, 0)); - } - if (right.lot_points.size() == 6) { - dbg->add_vertex( - right.lot_points[0] + - Vector3(0, 25, 0)); - dbg->add_vertex( - right.lot_points[1] + - Vector3(0, 25, 0)); - dbg->add_vertex( - right.lot_points[1] + - Vector3(0, 25, 0)); - dbg->add_vertex( - right.lot_points[3] + - Vector3(0, 25, 0)); - dbg->add_vertex( - right.lot_points[3] + - Vector3(0, 25, 0)); - dbg->add_vertex( - right.lot_points[2] + - Vector3(0, 25, 0)); - dbg->add_vertex( - right.lot_points[2] + - Vector3(0, 25, 0)); - dbg->add_vertex( - right.lot_points[0] + - Vector3(0, 25, 0)); - } - } - line_e = line_e->next(); - } - } - dbg->end(); -out_skip_end:; -#endif - } void create_structures() { List keys; @@ -852,13 +483,13 @@ out_skip_end:; ->get() .query_builder() .build() - .each([&](flecs::entity e, Lot &lot) { + .each([&](flecs::entity ev, Lot &lot) { BaseData::get_singleton() ->get() .query_builder() .build() .each([&](flecs::entity we, Lot &wlot) { - if (e != we) { + if (ev != we) { lot.polygon .update_aabb(); wlot.polygon @@ -868,7 +499,7 @@ out_skip_end:; .length() > 100000.0f * 1000000.0f) - e.destruct(); + ev.destruct(); else if (wlot.polygon .aabb .size @@ -890,7 +521,7 @@ out_skip_end:; .area()) we.destruct(); else - e.destruct(); + ev.destruct(); } } }); @@ -899,12 +530,11 @@ out_skip_end:; ->get() .query_builder() .build() - .each([&](flecs::entity e, const Lot &lot) { + .each([&](flecs::entity em, const Lot &lot) { List > lot_data; - Lot::get_lot_data(e, &lot_data); + Lot::get_lot_data(em, &lot_data); List >::Element *lot_e = lot_data.front(); - int ccount = 0; while (lot_e) { Pair data = lot_e->get(); Vector3 center = data.first.position; @@ -924,8 +554,8 @@ out_skip_end:; data.first. operator String()); for (j = 0; - j < - lot.polygon.points.size(); + j < (int)lot.polygon.points + .size(); j++) print_line( "polygon: " + @@ -942,11 +572,11 @@ out_skip_end:; ->get() .query_builder() .build() - .each([&](flecs::entity e, const Lot &lot) { + .each([&](flecs::entity ev, const Lot &lot) { List > lot_data; List lot_xform; - Lot::get_lot_data(e, &lot_data); - Lot::get_lot_rotations(e, &lot_xform); + Lot::get_lot_data(ev, &lot_data); + Lot::get_lot_rotations(ev, &lot_xform); List >::Element *lot_e = lot_data.front(); List::Element *lotx_e = @@ -955,7 +585,7 @@ out_skip_end:; while (lot_e) { Pair data = lot_e->get(); String key = "road__lot__" + - String(e.path()) + "_" + + String(ev.path()) + "_" + itos(ccount); key = key.replace("#", "_"); BuildingsData::building b; @@ -1290,7 +920,8 @@ out_skip_end:; { int i, j; Contours *contours = Contours::get_singleton(); - RoadLinesProcessing *r = RoadLinesProcessing::get_singleton(); + // RoadLinesProcessing *r = BaseData::get_singleton() ->get() .get_mut(); + RoadLinesProcessing *r = this; if (r->nodes.size() == 0) return; struct wedge_data { @@ -1393,13 +1024,6 @@ out_skip_end:; ~RoadLinesProcessing() { } - static void cleanup() - { - if (singleton) { - memfree(singleton); - singleton = nullptr; - } - } void set_debug_flags(int debug_flags) { this->debug_flags = debug_flags; @@ -1490,11 +1114,11 @@ out_skip_end:; } d->end(); } - RoadLinesProcessing::get_singleton()->create_structures(); + create_structures(); print_line("ROAD SETUP DONE"); } }; -RoadLinesProcessing *RoadLinesProcessing::singleton; +ConfigFile RoadLinesProcessing::config; class RoadMeshProcessing { struct mesh_data { @@ -1513,11 +1137,41 @@ class RoadMeshProcessing { } } }; + struct wedge_paths { + Vector3 path1[3]; + Vector3 path2[3]; + }; + struct lane { + Vector3 p[3]; + String use_mesh; /** use mesh namefor this lane */ + Transform xform1, xform2; /** rotations for ends + of this wedge start and end */ + Transform xform_m1, xform_m2; /** rotations for middle point of + wedge for end and start of segment */ + float l_seg1[3]; /** start segment scale */ + float l_seg2[3]; /** end segment scale */ + }; HashMap road_meshes; MergeGroup *road_mgroup; std::vector nodes_mi; public: + RoadMeshProcessing &operator=(const RoadMeshProcessing &other) + { + road_meshes = other.road_meshes; + road_mgroup = other.road_mgroup; + nodes_mi = other.nodes_mi; + return *this; + } +#if 0 + RoadMeshProcessing &operator=(const RoadMeshProcessing &&other) + { + road_meshes = std::move(other.road_meshes); + road_mgroup = std::move(other.road_mgroup); + nodes_mi = std::move(other.nodes_mi); + return *this; + } +#endif void load_road_mesh(const String &category, const String &name, const String &path) { @@ -1542,10 +1196,6 @@ public: } road_meshes[category + "/" + name] = md; } - struct wedge_paths { - Vector3 path1[3]; - Vector3 path2[3]; - }; void get_paths(struct wedge_paths &paths, const struct wedge &w) { Vector3 p1 = w.y[0] - w.y[1]; @@ -1561,16 +1211,6 @@ public: paths.path2[1] = p2a; paths.path2[2] = p3a; } - struct lane { - Vector3 p[3]; - String use_mesh; /** use mesh namefor this lane */ - Transform xform1, xform2; /** rotations for ends - of this wedge start and end */ - Transform xform_m1, xform_m2; /** rotations for middle point of - wedge for end and start of segment */ - float l_seg1[3]; /** start segment scale */ - float l_seg2[3]; /** end segment scale */ - }; /** * @brief transform mesh segment using start rotation @xform1 * ane end rotation @xform2 @@ -1599,9 +1239,11 @@ public: assert(vertices.size() > 0); assert(indices.size() > 0); float dlen = xform1.origin.distance_to(xform2.origin); +#if 0 float offt = 0.0f; if (dlen > start_offset) offt = start_offset; +#endif int id; Vector3 dir = xform2.origin - xform1.origin; dir = dir.normalized(); @@ -2004,7 +1646,9 @@ public: assert(out_surfaces[h].size() >= ArrayMesh::ARRAY_MAX); float sideroad_l = 3.0f; +#if 0 float lot_depth1 = mside1.lot_depth; +#endif if (k == params.nlanes && mside1.lot > 0) { /* sidewalk */ Vector3 dir = lanes[k].xform_m1.origin - @@ -2197,7 +1841,10 @@ public: void create_road_meshes(Node *base) { int i; - RoadLinesProcessing *r = RoadLinesProcessing::get_singleton(); + RoadLinesProcessing *r = + BaseData::get_singleton() + ->get() + .get_mut(); clear_road_meshes(); road_mgroup = memnew(MergeGroup); road_mgroup->set_param(MergeGroup::PARAM_GROUP_SIZE, 16); @@ -2217,38 +1864,33 @@ public: nodes_mi.push_back(mi); } } - static RoadMeshProcessing *singleton; - static RoadMeshProcessing *get_singleton() - { - if (!singleton) - singleton = memnew(RoadMeshProcessing); - return singleton; - } RoadMeshProcessing() : road_mgroup(nullptr) { - singleton = this; - } - static void cleanup() - { - if (singleton) { - memdelete(singleton); - singleton = nullptr; - } + BaseData::get_singleton()->get().ensure(); } }; -RoadMeshProcessing *RoadMeshProcessing::singleton; void RoadProcessing::road_setup(Node *target, int debug_flags) { - RoadLinesProcessing::get_singleton()->set_debug_flags(debug_flags); - RoadLinesProcessing::get_singleton()->road_setup(); - RoadMeshProcessing::get_singleton()->create_road_meshes(target); + BaseData::get_singleton()->get().ensure(); + BaseData::get_singleton()->get().ensure(); + RoadLinesProcessing *r = + BaseData::get_singleton()->get().get_mut(); + r->set_debug_flags(debug_flags); + r->road_setup(); + BaseData::get_singleton() + ->get() + .get_mut() + ->create_road_meshes(target); } void RoadProcessing::remove_road_meshes(Node *target) { - RoadMeshProcessing::get_singleton()->clear_road_meshes(); + BaseData::get_singleton() + ->get() + .get_mut() + ->clear_road_meshes(); } void RoadProcessing::load_data() @@ -2258,30 +1900,31 @@ void RoadProcessing::load_data() ConfigFile config; Error result = config.load("res://config/stream.conf"); ERR_FAIL_COND_MSG(result != OK, "Failed to load config"); - RoadMeshProcessing::get_singleton()->load_road_mesh( - "common", "center", config.get_value("road", "center_mesh")); - RoadMeshProcessing::get_singleton()->load_road_mesh( - "common", "mid", config.get_value("road", "mid_mesh")); - RoadMeshProcessing::get_singleton()->load_road_mesh( - "common", "sidewalk", - config.get_value("road", "sidewalk_mesh")); - RoadMeshProcessing::get_singleton()->load_road_mesh( - "common", "sidewalk_start", - config.get_value("road", "sidewalk_start_mesh")); - RoadMeshProcessing::get_singleton()->load_road_mesh( - "common", "sidewalk_end", - config.get_value("road", "sidewalk_end_mesh")); - RoadMeshProcessing::get_singleton()->load_road_mesh( - "common", "sidewalk_sideroad", - config.get_value("road", "sidewalk_sideroad_mesh")); - RoadMeshProcessing::get_singleton()->load_road_mesh( - "common", "lot", config.get_value("road", "lot_mesh")); + BaseData::get_singleton()->get().ensure(); + RoadMeshProcessing *rmp = + BaseData::get_singleton()->get().get_mut(); + assert(rmp); + rmp->load_road_mesh("common", "center", + config.get_value("road", "center_mesh")); + rmp->load_road_mesh("common", "mid", + config.get_value("road", "mid_mesh")); + rmp->load_road_mesh("common", "sidewalk", + config.get_value("road", "sidewalk_mesh")); + rmp->load_road_mesh("common", "sidewalk_start", + config.get_value("road", "sidewalk_start_mesh")); + rmp->load_road_mesh("common", "sidewalk_end", + config.get_value("road", "sidewalk_end_mesh")); + rmp->load_road_mesh("common", "sidewalk_sideroad", + config.get_value("road", "sidewalk_sideroad_mesh")); + rmp->load_road_mesh("common", "lot", + config.get_value("road", "lot_mesh")); } void RoadDebug::_notification(int which) { int i, j; - RoadLinesProcessing *r = RoadLinesProcessing::get_singleton(); + RoadLinesProcessing *r = + BaseData::get_singleton()->get().get_mut(); std::unordered_map::iterator it; switch (which) { case NOTIFICATION_ENTER_TREE: @@ -2379,6 +2022,6 @@ void RoadDebug::_notification(int which) } void RoadProcessing::cleanup() { - RoadLinesProcessing::cleanup(); - RoadMeshProcessing::cleanup(); + BaseData::get_singleton()->get().remove(); + BaseData::get_singleton()->get().remove(); } diff --git a/src/modules/stream/stream.cpp b/src/modules/stream/stream.cpp index 5cf01af..984726a 100644 --- a/src/modules/stream/stream.cpp +++ b/src/modules/stream/stream.cpp @@ -17,9 +17,17 @@ #include "base_data.h" #include "npc/npc.h" #include "stream.h" +static inline BuildingsData *bd() +{ + BuildingsData *ret = + BaseData::get_singleton()->get().get_mut(); + assert(ret); + return ret; +} -#define data() (BuildingsData::get_singleton()) +#define data() (bd()) +#if 0 void StreamWorld::create_tilemap() { tiles.clear(); @@ -41,6 +49,7 @@ void StreamWorld::create_tilemap() nullptr); print_verbose("Tile count: " + itos(tiles.size())); } +#endif void StreamWorld::update_view() { @@ -80,6 +89,7 @@ void StreamWorld::update_view() current_x = world_extent + 1; current_z = world_extent + 1; } +#if 0 eye = viewer->get_global_transform().origin; int tile_x = int(eye.x / tile_size); int tile_z = int(eye.z / tile_size); @@ -122,9 +132,10 @@ void StreamWorld::update_view() it++; } - current_x = tile_x; - current_z = tile_z; - } + current_x = tile_x; + current_z = tile_z; +} +#endif } void StreamWorld::viewer_dead() @@ -141,6 +152,7 @@ void StreamWorld::terrain_dead() set_process(false); } +#if 0 void StreamWorld::load_tile(int tx, int ty) { int i; @@ -151,6 +163,11 @@ void StreamWorld::load_tile(int tx, int ty) ": " /* + data()->get_building(items[i]).id */); const String &bkey = items[i]; load_building(bkey); + flecs::entity eb = data()->get_building_entity(bkey); + if (eb.is_valid()) { + if (!eb.has()) + eb.add(); + } } } @@ -163,52 +180,39 @@ void StreamWorld::erase_tile(int tx, int ty) print_verbose("unload item: " + itos(i) + ": key: " + items[i] + ": " /* + data()->get_building(items[i]).id */); const String &bkey = items[i]; - unload_building(bkey); + flecs::entity eb = data()->get_building_entity(bkey); + if (eb.is_valid()) { + if (eb.has()) + eb.add(); + print_verbose("Removing key:" + bkey); + } } } +#endif void StreamWorld::load_building(const String &key) { - request_item(0, key); + flecs::entity eb = data()->get_building_entity(key); + // print_line("key: " + bkey); + if (!eb.is_valid()) { + print_error("ERROR: Entity does not exist: " + key); + return; + } + if (!eb.has()) + eb.add(); } void StreamWorld::unload_building(const String &key) { - request_item(1, key); -} - -void StreamWorld::request_item(int type, const String &bkey) -{ - bool debug = false; - /* bkey can contain "::"'s so need to replae them with underscores */ - String ekey = bkey; - if (bkey.begins_with("road__")) { - print_verbose("loading building: " + ekey); - debug = true; - } - String id = data()->get_building(ekey).id; - if (debug) - print_verbose("building id: " + id); - if (id == "empty") + flecs::entity eb = data()->get_building_entity(key); + // print_line("key: " + bkey); + if (!eb.is_valid()) { + print_error("ERROR: Entity does not exist: " + key); return; - switch (type) { - case 0: - if (debug) - print_verbose("add to scene id: " + id); - if (!data()->has_scene(id)) - data()->create_scene_data(id, ekey); - else - data()->add_scene_item(id, ekey); - if (debug) - print_verbose("added to scene id: " + id); - break; - case 1: { - print_verbose("Removing key:" + ekey); - if (data()->has_scene(id)) { - data()->remove_scene_item(id, ekey); - } - } break; } + if (eb.has()) + eb.add(); + print_verbose("Removing key:" + key); } void StreamWorld::update_items() @@ -395,7 +399,9 @@ void StreamWorld::run_command(const String &command, RoadProcessing::road_setup(this, args[0]); else RoadProcessing::road_setup(this, 0); +#if 0 create_tilemap(); +#endif update_view(); data()->scene_update(); update_items(); @@ -419,7 +425,9 @@ void StreamWorld::run_command(const String &command, terrain->set_generator(gen); update_items(); RoadProcessing::road_setup(this, 0); +#if 0 create_tilemap(); +#endif update_view(); update_items(); assert(false); @@ -460,7 +468,9 @@ void StreamWorld::_notification(int which) nullptr); assert(false); #endif +#if 0 create_tilemap(); +#endif set_process(true); if (Engine::get_singleton()->is_editor_hint()) break; @@ -516,14 +526,17 @@ StreamWorld::StreamWorld() , initialized(false) , frame_count(0) { + BaseData::get_singleton()->get().component(); Error result = config.load("res://config/stream.conf"); ERR_FAIL_COND_MSG(result != OK, "Failed to load config"); + BaseData::get_singleton()->get().ensure(); RoadProcessing::load_data(); world_extent = config.get_value("world", "world_extent"); tile_size = config.get_value("world", "tile_size"); ERR_FAIL_COND_MSG(tile_size <= 0 || world_extent <= 0 || world_extent <= tile_size, "Failed to configure world"); +#if 0 create_tilemap(); tile_map_t::iterator map_it = tiles.begin(); while (map_it != tiles.end()) { @@ -534,11 +547,11 @@ StreamWorld::StreamWorld() itos(tile_buildings.size())); map_it++; } +#endif view_distance = config.get_value("world", "view_distance"); - NPC *npc = NPC::get_singleton(); - if (!npc) { - assert(false); - } + BaseData::get_singleton()->get().import (); + flecs::entity npcctrl = BaseData::get_singleton()->get().entity(); + npcctrl.set({ NPC::NPCControl::CMD_PRESIM }); initialized = true; } void StreamWorld::cleanup() diff --git a/src/modules/stream/stream.h b/src/modules/stream/stream.h index 0729674..c670f49 100644 --- a/src/modules/stream/stream.h +++ b/src/modules/stream/stream.h @@ -16,6 +16,7 @@ private: VoxelLodTerrain *terrain; Node *current_scene; ConfigFile config; +#if 0 using tile_key_t = std::tuple; struct tile_hash : public std::unary_function { std::size_t operator()(const tile_key_t &k) const @@ -28,6 +29,7 @@ private: Vector3 eye; tile_map_t tiles; tile_map_t loaded_tiles; +#endif int world_extent; int tile_size; @@ -36,15 +38,14 @@ private: int current_x, current_z; int frame_count; void _notification(int which); - void create_tilemap(); + // void create_tilemap(); void update_view(); void viewer_dead(); void terrain_dead(); - void load_tile(int tx, int ty); - void erase_tile(int tx, int ty); + // void load_tile(int tx, int ty); + // void erase_tile(int tx, int ty); void load_building(const String &key); void unload_building(const String &key); - void request_item(int type, const String &key); void update_items(); void remove_building(const String &key); void remove_generated_stuff(); diff --git a/src/modules/stream/terrain_editor.cpp b/src/modules/stream/terrain_editor.cpp index 32de1e0..29e941d 100644 --- a/src/modules/stream/terrain_editor.cpp +++ b/src/modules/stream/terrain_editor.cpp @@ -18,6 +18,14 @@ #include "signal_handler.h" #include "terrain_editor.h" +static inline BuildingsData *bd() +{ + BuildingsData *ret = + BaseData::get_singleton()->get().get_mut(); + assert(ret); + return ret; +} + void TerrainEditor::exit() { if (active) @@ -358,15 +366,13 @@ end:; case 2001: { List building_keys; List::Element *e; - BuildingsData::get_singleton()->get_building_keys_list( - &building_keys); - BuildingsData::get_singleton()->build_building_aabbs(); + bd()->get_building_keys_list(&building_keys); + bd()->build_building_aabbs(); e = building_keys.front(); while (e) { const String &key = e->get(); const BuildingsData::building &b = - BuildingsData::get_singleton() - ->get_building(key); + bd()->get_building(key); float i, j; print_line("building type: " + b.id); print_line("building key: " + b.key); @@ -376,8 +382,7 @@ end:; "building elevation: " + String::num(imgmapper->get_height_full( b.xform.origin))); - AABB aabb = BuildingsData::get_singleton() - ->building_aabbs[b.id]; + AABB aabb = bd()->building_aabbs[b.id]; print_line("building AABB: " + (aabb.operator String())); float max_elevation_c = -Math_INF, @@ -458,9 +463,7 @@ end:; // assert(Math::abs(max_elevation2 - // max_elevation) < 1.0f); #endif - Transform xform = BuildingsData::get_singleton() - ->get_building(key) - .xform; + Transform xform = bd()->get_building(key).xform; xform.origin.y = max_elevation * 1.4998f - 0.5f; editor->editor_command( "update_building_transform", @@ -474,7 +477,7 @@ end:; e = e->next(); } imgmapper->save_dirty_tiles(); - BuildingsData::get_singleton()->save_buildings(); + bd()->save_buildings(); editor->editor_command("nudge_generator", varray()); } break; default: diff --git a/src/modules/stream/ui/main_tabs.cpp b/src/modules/stream/ui/main_tabs.cpp index 88337a2..549fb21 100644 --- a/src/modules/stream/ui/main_tabs.cpp +++ b/src/modules/stream/ui/main_tabs.cpp @@ -426,19 +426,21 @@ void MainTabs::_notification(int which) /* 43 */ "Delete Building", "buildings_delete_building", "delete_building", varray(), /* 47 */ - "Create Building", "buildings_create_building", "create_building", varray(), + "Layout", "buildings_edit_layout", "edit_layout", varray(), /* 51 */ - "Save Buildings", "buildings_save", "buildings_save", varray(), + "Create Building", "buildings_create_building", "create_building", varray(), /* 55 */ + "Save Buildings", "buildings_save", "buildings_save", varray(), + /* 59 */ 0, Vector2(0, 80), "lines_list_building", - /* 58 */ + /* 62 */ "Assign To Line", "buildings_assign_to_line" - /* 60 */ + /* 64 */ }; /* clang-format on */ ui_field::ui_field_builder( this, tab, - "l_p{v{lh{e#!+e#!+e#!+b#!}lh{e#!+e#!+e#!+}h{le#!b#!}_lo#!Mlo#!T_b#!Qb#!QB#!qi.#!b#!}}", + "l_p{v{lh{e#!+e#!+e#!+b#!}lh{e#!+e#!+e#!+}h{le#!b#!}_lo#!Mlo#!T_b#!Qb#!Qb#!QB#!qi.#!b#!}}", args_data.data(), args_data.size()); }