Completed conversion of buildings handling to ECS systems

This commit is contained in:
2025-04-29 16:15:37 +03:00
parent dd00a41024
commit bc0dcfaead
20 changed files with 974 additions and 638 deletions

View File

@@ -5,12 +5,14 @@ EDITOR_PLATFORM=x11es
EDITOR2_PLATFORM=x11
DEMO_PLATFORMS=x11 x11es
EDITOR = src/godot/bin/godot.$(EDITOR_PLATFORM).opt.tools.$(ARCH)
EDITOR_DBG = src/godot/bin/godot.$(EDITOR_PLATFORM).tools.$(ARCH)
EDITOR2 = src/godot/bin/godot.$(EDITOR2_PLATFORM).opt.tools.$(ARCH)
EDITOR2_DBG = src/godot/bin/godot.$(EDITOR2_PLATFORM).tools.$(ARCH)
.PHONY: all godot-editor-main export export-models export-clothes \
.PHONY: all godot-editor-main godot-editor-debug export export-models export-clothes \
export-clean export-linux-demo export-windows-demo \
export-binaries patch tests import-vrm export-buildings
all: godot-editor-main godot-main
all: godot-editor-main godot-editor-debug godot-main
SCONS_EXTRA=-j16
define build_godot
$(4): $(5)
@@ -31,12 +33,15 @@ $(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) $(EDITOR2)
godot-editor-debug: $(EDITOR_DBG) $(EDITOR2_DBG)
#$(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,x11es,debug,yes,$(EDITOR_DBG),patch))
$(eval $(call build_godot,x11,release_debug,yes,$(EDITOR2),patch))
$(eval $(call build_godot,x11,debug,yes,$(EDITOR2_DBG),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

View File

@@ -15,13 +15,7 @@
#include "base_data.h"
#include "buildings_data.h"
static ConfigFile config;
static ConfigFile custom_layouts;
struct scene_data {
Ref<PackedScene> packed_scene;
String path;
Ref<ResourceInteractiveLoader> loader;
};
ConfigFile BuildingsData::config;
static flecs::world &ecs()
{
@@ -37,250 +31,12 @@ static flecs::entity lookup(const char *key)
{
return ecs().lookup(key);
}
struct CBuildingInstance {
String key;
Node *node;
};
struct CSceneData {
struct scene_data sd;
};
#if 0
void BuildingsData::load_tile(std::tuple<int, int> key)
{
int i;
const std::vector<String> &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<BuildingsData::CBuildingLoaded>())
eb.add<BuildingsData::CBuildingLoad>();
}
}
}
#endif
BuildingsData::BuildingsData()
: undo_log_size(64)
{
flecs::world ecs_ = ecs();
ecs_.component<CBuildingStats>();
ecs_.component<CBuildingData>();
ecs_.component<CBTypeResidental>();
ecs_.component<CBCustomLayout>();
ecs_.component<CBuildingEdited>();
ecs_.component<CBuildingTileData>();
ecs_.component<CBuildingsEye>();
bool deferred = ecs_.is_deferred();
if (deferred)
ecs_.defer_suspend();
ecs_.set<CBuildingStats>({ 0 });
ecs_.set<CBuildingTileData>({});
assert(ecs_.has<CBuildingStats>());
load_data();
ecs_.query_builder<const CBuildingData>().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<CBuildingStats>()->created_entities));
assert(ecs().get<CBuildingStats>()->created_entities > 0);
fill_door_locations();
build_building_aabbs();
ecs_.observer<CBuildingInstance>()
.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);
}
});
ecs_.observer<CBuildingEdited>()
.event(flecs::OnAdd)
.with<CBuildingData>()
.run([&](flecs::iter &it) {
flecs::query<const CBuildingData> q =
it.world()
.query_builder<const CBuildingData>()
.with<CBuildingEdited>()
.build();
if (it.next()) {
flecs::entity qe = it.entity(0);
q.each([qe](flecs::entity e,
const CBuildingData &d) {
if (e != qe)
e.remove<CBuildingEdited>();
});
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<CBuildingsEye>()) {
int old_x = it.world().get<CBuildingsEye>()->tile_x;
int old_z = it.world().get<CBuildingsEye>()->tile_z;
if (old_x == tile_x && old_z == tile_z)
need_update = false;
}
it.world().set<CBuildingsEye>({ xform, tile_x, tile_z });
if (need_update)
return;
if (!it.world().has<CBuildingTileData>())
return;
CBuildingTileData *td = it.world().get_mut<CBuildingTileData>();
it.world()
.query_builder<CBuildingData>()
.without<CBuildingLoaded>()
.without<CBuildingLoad>()
.with<CBuildingTile>()
.build()
.each([&](flecs::entity e, const CBuildingData &bd) {
const CBuildingTile *bt =
e.get<CBuildingTile>();
std::tuple<int, int> 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<BuildingsData::
CBuildingLoad>();
}
}
});
it.world()
.query_builder<CBuildingData>()
.with<CBuildingLoaded>()
.with<CBuildingTile>()
.without<CBuildingUnload>()
.build()
.each([&](flecs::entity e, const CBuildingData &bd) {
const CBuildingTile *bt =
e.get<CBuildingTile>();
std::tuple<int, int> 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<BuildingsData::
CBuildingUnload>();
}
});
});
ecs_.system<const CBuildingData>("LoadData")
.kind(flecs::OnUpdate)
.without<CBuildingLoaded>()
.with<CBuildingLoad>()
.write<CBuildingLoaded>()
.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<CBuildingLoaded>();
e.remove<CBuildingLoad>();
e.world().defer_resume();
});
ecs_.system<const CBuildingData>("UnloadData")
.kind(flecs::OnUpdate)
.with<CBuildingUnload>()
.with<CBuildingLoaded>()
.write<CBuildingLoaded>()
.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<CBuildingLoaded>();
e.remove<CBuildingUnload>();
});
}
BuildingsData::~BuildingsData()
{
}
void BuildingsData::build_building_aabbs()
{
building_aabbs.clear();
List<String> keys;
building_data.get_key_list(&keys);
List<String>::Element *e = keys.front();
while (e) {
Error err;
const String &path = building_data[e->get()];
Ref<PackedScene> ps =
ResourceLoader::load(path, "PackedScene", true, &err);
if (err == OK && ps.is_valid()) {
AABB aabb;
Node *scene = ps->instance();
List<Node *> queue;
queue.push_back(scene);
while (!queue.empty()) {
int i;
Node *item = queue.front()->get();
queue.pop_front();
MeshInstance *mi =
Object::cast_to<MeshInstance>(item);
if (mi) {
if (aabb.size.length_squared() < 0.1f)
aabb = mi->get_aabb();
else
aabb.merge_with(mi->get_aabb());
}
for (i = 0; i < item->get_child_count(); i++)
queue.push_back(item->get_child(i));
}
building_aabbs[e->get()] = aabb;
scene->queue_delete();
ps.unref();
} else
print_error("Could not load: " + path);
e = e->next();
}
// building_aabbs.clear();
// List<String> keys;
// building_data.get_key_list(&keys);
// List<String>::Element *e = keys.front();
}
void BuildingsData::update_building_transform(const String &key,
@@ -301,7 +57,7 @@ bool BuildingsData::has_building(const String &key)
return e.is_valid();
}
String BuildingsData::get_closest_building(const Transform &xform) const
String BuildingsData::get_closest_building(const Transform &xform)
{
float dst = Math_INF;
String rkey;
@@ -318,8 +74,7 @@ String BuildingsData::get_closest_building(const Transform &xform) const
});
return rkey;
}
flecs::entity
BuildingsData::get_closest_building_entity(const Transform &xform) const
flecs::entity BuildingsData::get_closest_building_entity(const Transform &xform)
{
float dst = Math_INF;
String rkey;
@@ -500,6 +255,7 @@ void BuildingsData::load_data()
assert(ecs().has<CBuildingStats>());
Error result = config.load("res://config/stream.conf");
ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
#if 0
Dictionary buildings_data =
config.get_value("buildings", "building_data");
List<Variant> keys;
@@ -507,7 +263,23 @@ void BuildingsData::load_data()
List<Variant>::Element *e = keys.front();
while (e) {
String key = e->get();
building_data[key] = buildings_data[key];
// building_data[key] = buildings_data[key];
flecs::entity se = ecs().entity(key.ascii().ptr());
// print_line("scene key: " + key);
assert(buildings_data.has(key));
String path = buildings_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());
se.set<CSceneData>({ sd });
pending_scene.insert(path);
assert(se.get_mut<CSceneData>());
e = e->next();
}
e = keys.front();
@@ -516,12 +288,14 @@ void BuildingsData::load_data()
// print_line(key + ": " + buildings_data[key]);
e = e->next();
}
#endif
String buildings_path = config.get_value("buildings", "buildings_path");
read_buildings_json(buildings_path);
}
void BuildingsData::checkpoint()
{
#if 0
struct checkpoint_data cp;
cp.building_data = building_data;
cp.buildings.clear();
@@ -531,9 +305,11 @@ void BuildingsData::checkpoint()
undo_log.push_back(cp);
while ((int)undo_log.size() > undo_log_size)
undo_log.erase(undo_log.begin());
#endif
}
void BuildingsData::undo()
{
#if 0
int i;
struct checkpoint_data cp = *undo_log.end();
building_data = cp.building_data;
@@ -545,98 +321,44 @@ void BuildingsData::undo()
flecs::entity e = ecs().entity(ename.ascii().ptr());
e.set<CBuildingData>({ cp.buildings[i] });
}
#endif
}
void BuildingsData::fill_door_locations()
{
/*
func fill_door_locations():
for k in building_data.keys():
var bdoors = []
var l = building_data[k].instance()
var queue = [l]
while queue.size() > 0:
var item = queue.pop_front()
if item.name.find("-portal") >= 0:
var xform = item.transform
var tmp = item.get_parent()
while tmp != null:
var parent_xform = tmp.transform
xform = parent_xform * xform
tmp = tmp.get_parent()
bdoors.push_back(var2str(xform))
for c in item.get_children():
queue.push_back(c)
door_locations[k] = bdoors
l.queue_free()
*/
List<String> keys;
building_data.get_key_list(&keys);
List<String>::Element *e = keys.front();
while (e) {
Error err;
const String &path = building_data[e->get()];
Ref<PackedScene> ps =
ResourceLoader::load(path, "PackedScene", true, &err);
if (err == OK && ps.is_valid()) {
Vector<Transform> doors;
Node *scene = ps->instance();
List<Node *> queue;
queue.push_back(scene);
while (!queue.empty()) {
int i;
Node *item = queue.front()->get();
queue.pop_front();
String name = item->get_name();
if (name.find("-portal") >= 0) {
Spatial *sp =
Object::cast_to<Spatial>(item);
if (sp) {
Transform xform =
sp->get_transform();
Node *tmp = item->get_parent();
while (tmp) {
Transform parent_xform;
Spatial *parent_sp =
Object::cast_to<
Spatial>(
tmp);
if (parent_sp)
parent_xform =
parent_sp
->get_transform();
xform = parent_xform *
xform;
tmp = tmp->get_parent();
}
doors.push_back(xform);
}
}
for (i = 0; i < item->get_child_count(); i++)
queue.push_back(item->get_child(i));
}
building_doors[e->get()] = doors;
scene->queue_delete();
ps.unref();
}
e = e->next();
}
}
void BuildingsData::get_scene_keys_list(List<String> *keys) const
void BuildingsData::get_scene_keys_list(List<String> *keys)
{
ecs().each([keys](flecs::entity e, const CSceneData &d) {
keys->push_back(String(e.name()));
});
}
bool BuildingsData::has_scene(const String &key) const
bool BuildingsData::has_scene(const String &key)
{
flecs::entity e = ecs().lookup(key.ascii().ptr());
return e.is_valid();
return e.is_valid() && e.has<CSceneData>();
}
flecs::entity BuildingsData::get_building_entity(const String &key) const
AABB BuildingsData::get_scene_aabb(const String &key)
{
flecs::entity e = ecs().lookup(key.ascii().ptr());
if (!e.is_valid()) {
uint64_t key_hash = key.hash64();
e = ecs().query_builder<const CSceneData>().build().find(
[key_hash](const CSceneData &sd) {
print_line("scene: " + sd.sd.key);
return sd.sd.key.hash64() == key_hash;
});
if (!e.is_valid())
print_line("scene not found: " + key);
}
assert(e.is_valid());
if (!e.has<CSceneData>() || !e.has<CSceneAABB>())
print_error("not found: " + key);
assert(e.has<CSceneData>());
return e.get<CSceneAABB>()->aabb;
}
flecs::entity BuildingsData::get_building_entity(const String &key)
{
flecs::query_builder<const CBuildingData> qb =
ecs().query_builder<const CBuildingData>();
@@ -689,6 +411,11 @@ void BuildingsData::add_scene_item(const String &key, const String &bkey)
{
flecs::entity e = ecs().lookup(key.ascii().ptr());
assert(e.is_valid());
assert(e.has<CSceneData>());
flecs::entity be = get_building_entity(bkey);
assert(be.is_valid());
assert(be.has<CBuildingData>());
const CBuildingData *b = be.get<CBuildingData>();
CSceneData *d = e.get_mut<CSceneData>();
assert(d);
String ename = "bi:" + bkey;
@@ -697,54 +424,46 @@ void BuildingsData::add_scene_item(const String &key, const String &bkey)
if (ce.is_valid())
ce.destruct();
ce = ecs().entity(ename.ascii().ptr()).child_of(e);
Ref<PackedScene> ps = scene_get_packed_scene(key);
if (!ps.is_valid())
return;
Node *where = SceneTree::get_singleton()->get_current_scene();
assert(where);
if (ps.is_valid()) {
Spatial *scene = Object::cast_to<Spatial>(ps->instance());
assert(scene);
where->call_deferred("add_child", scene);
scene->set_transform(b->building.xform);
ce.set<CBuildingInstance>({ bkey, scene });
} else
ce.set<CBuildingInstance>({ bkey, nullptr });
// 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<CSceneData>({ sd });
pending_scene.insert(path);
assert(e.get_mut<CSceneData>());
String ename = "bi:" + bkey;
flecs::entity ce = e.lookup(ename.ascii().ptr());
if (ce.is_valid())
ce.destruct();
ce = ecs().entity(ename.ascii().ptr());
ce.child_of(e);
ce.set<CBuildingInstance>({ bkey, nullptr });
// print_line("child name: " + String(ce.name()));
}
}
Ref<PackedScene> BuildingsData::scene_get_packed_scene(const String &key) const
Ref<PackedScene> BuildingsData::scene_get_packed_scene(const String &key)
{
flecs::entity e = ecs().lookup(key.ascii().ptr());
if (!e.has<CScenePackLoaded>())
return Ref<PackedScene>();
assert(e.is_valid());
assert(e.has<CSceneData>());
assert(e.has<CScenePack>());
assert(e.get<CScenePack>());
assert(e.get<CScenePack>()->sp.packed_scene.is_valid());
if (!e.is_valid())
return Ref<PackedScene>();
if (!e.get<CSceneData>())
return Ref<PackedScene>();
if (!e.get<CScenePack>())
return Ref<PackedScene>();
assert(e.is_valid());
const CSceneData *d = e.get<CSceneData>();
const CScenePack *d = e.get<CScenePack>();
assert(d);
return d->sd.packed_scene;
return d->sp.packed_scene;
}
int BuildingsData::scene_get_item_count(const String &key) const
int BuildingsData::scene_get_item_count(const String &key)
{
flecs::entity e = ecs().lookup(key.ascii().ptr());
if (!e.is_valid())
@@ -769,7 +488,7 @@ int BuildingsData::scene_get_item_count(const String &key) const
// print_line("scene_get_item_count: " + itos(result));
return result;
}
List<String> BuildingsData::scene_get_items(const String &key) const
List<String> BuildingsData::scene_get_items(const String &key)
{
List<String> ret;
flecs::entity e = ecs().lookup(key.ascii().ptr());
@@ -803,8 +522,9 @@ void BuildingsData::set_scene_item_node(const String &key, const String &bkey,
assert(bi);
assert(bi->key == bkey);
bi->node = node;
ce.modified<CBuildingInstance>();
}
bool BuildingsData::has_scene_item(const String &key, const String &bkey) const
bool BuildingsData::has_scene_item(const String &key, const String &bkey)
{
flecs::entity e = ecs().lookup(key.ascii().ptr());
assert(e.is_valid());
@@ -814,8 +534,7 @@ bool BuildingsData::has_scene_item(const String &key, const String &bkey) const
flecs::entity ce = e.lookup(ename.ascii().ptr());
return ce.is_valid();
}
Node *BuildingsData::get_scene_item_node(const String &key,
const String &bkey) const
Node *BuildingsData::get_scene_item_node(const String &key, const String &bkey)
{
flecs::entity e = ecs().lookup(key.ascii().ptr());
assert(e.is_valid());
@@ -823,6 +542,8 @@ Node *BuildingsData::get_scene_item_node(const String &key,
assert(d);
String ename = "bi:" + bkey;
flecs::entity ce = e.lookup(ename.ascii().ptr());
if (!ce.is_valid()) /* no instance */
return nullptr;
assert(ce.is_valid());
CBuildingInstance *bi = ce.get_mut<CBuildingInstance>();
assert(bi);
@@ -836,7 +557,7 @@ void BuildingsData::save_buildings()
save_buildings_json(buildings_path);
}
Node *BuildingsData::item_nodes_get_node(const String &key) const
Node *BuildingsData::item_nodes_get_node(const String &key)
{
flecs::query_builder<const CBuildingInstance> qb =
ecs().query_builder<const CBuildingInstance>();
@@ -851,29 +572,6 @@ Node *BuildingsData::item_nodes_get_node(const String &key) const
return nullptr;
}
Error BuildingsData::scene_loader_poll(const String &key)
{
if (has_scene(key)) {
flecs::entity e = ecs().lookup(key.ascii().ptr());
assert(e.is_valid());
CSceneData *d = e.get_mut<CSceneData>();
assert(d);
assert(d->sd.loader.is_valid());
Error err = d->sd.loader->poll();
if (err == ERR_FILE_EOF || err == OK) {
Ref<PackedScene> sc = d->sd.loader->get_resource();
d->sd.packed_scene = sc;
print_line("Loaded scene: " + d->sd.path + " OK");
return OK;
} else {
print_error("Could not load the resource :( " +
d->sd.path + " " + itos(err));
return err;
}
}
return FAILED;
}
void BuildingsData::scene_update()
{
List<String> keys;
@@ -885,12 +583,11 @@ void BuildingsData::scene_update()
e = e->next();
continue;
}
scene_loader_poll(key);
e = e->next();
}
}
int BuildingsData::get_building_count() const
int BuildingsData::get_building_count()
{
flecs::query<const CBuildingData> q =
ecs().query<const CBuildingData>();
@@ -906,20 +603,24 @@ int BuildingsData::get_building_count() const
return result;
}
const struct BuildingsData::building &
BuildingsData::get_building(const String &building_key) const
{
String ename = "base:" + building_key;
flecs::entity e = lookup(ename);
assert(e.is_valid());
return e.get<CBuildingData>()->building;
}
struct BuildingsData::building &
BuildingsData::get_building(const String &building_key)
{
String ename = "base:" + building_key;
flecs::entity e = lookup(ename);
if (!e.is_valid()) {
// print_error("bad building: " + ename);
e = ecs().query_builder<const CBuildingData>().build().find(
[&](flecs::entity se, const CBuildingData &bd) {
// print_line(String(se.name() + "#" +
// bd.building.key));
if (bd.building.key == building_key)
return true;
if (String(se.name()) == ename)
return true;
return false;
});
}
assert(e.is_valid());
return e.get_mut<CBuildingData>()->building;
}

View File

@@ -3,10 +3,14 @@
#include <unordered_map>
#include <vector>
#include <core/reference.h>
#include <scene/resources/packed_scene.h>
#include <core/io/config_file.h>
#include <flecs.h>
class PackedScene;
class ResourceInteractiveLoader;
class BuildingsData {
static ConfigFile config;
public:
/* Per-building information */
struct building {
@@ -23,6 +27,15 @@ public:
Dictionary to_dict() const;
String line_name;
};
struct scene_data {
String key;
String path;
};
struct scene_pack {
Ref<PackedScene> packed_scene;
Ref<ResourceInteractiveLoader> loader;
};
Set<String> pending_scene;
/* Scene objects data */
//private:
@@ -31,6 +44,9 @@ public:
struct CBuildingData {
struct BuildingsData::building building;
};
struct CBuildingSceneLoaded {};
struct CBuildingSceneLoad {};
struct CBuildingSceneUnload {};
struct CBTypeResidental {};
struct CBCustomLayout {
int size;
@@ -65,39 +81,54 @@ public:
struct CBuildingUnload {};
struct CBuildingLoaded {};
struct CBuildingEdited {};
struct CSceneData {
struct scene_data sd;
};
struct CScenePack {
struct scene_pack sp;
};
struct CScenePackLoaded {};
struct CSceneDoors {
Vector<Transform> doors;
};
struct CSceneAABB {
AABB aabb;
};
struct CScenesLoaded {}; /* all scenes loaded */
struct CBuildingInstance {
String key;
Node *node;
};
struct CBuildingInstanced {};
public:
void get_scene_keys_list(List<String> *keys) const;
bool has_scene(const String &key) const;
void remove_scene_item(const String &key, const String &bkey);
void add_scene_item(const String &key, const String &bkey);
void create_scene_data(const String &key, const String &bkey);
Ref<PackedScene> scene_get_packed_scene(const String &key) const;
int scene_get_item_count(const String &key) const;
static void get_scene_keys_list(List<String> *keys);
static bool has_scene(const String &key);
static AABB get_scene_aabb(const String &key);
static void remove_scene_item(const String &key, const String &bkey);
static void add_scene_item(const String &key, const String &bkey);
static Ref<PackedScene> scene_get_packed_scene(const String &key);
static int scene_get_item_count(const String &key);
// String scene_get_item(const String &key, int index) const;
List<String> scene_get_items(const String &key) const;
void set_scene_item_node(const String &key, const String &bkey,
static List<String> scene_get_items(const String &key);
static void set_scene_item_node(const String &key, const String &bkey,
Node *node);
bool has_scene_item(const String &key, const String &bkey) const;
Node *get_scene_item_node(const String &key, const String &bkey) const;
void save_buildings();
static bool has_scene_item(const String &key, const String &bkey);
static Node *get_scene_item_node(const String &key, const String &bkey);
static void save_buildings();
public:
Node *item_nodes_get_node(const String &key) const;
private:
Error scene_loader_poll(const String &key);
static Node *item_nodes_get_node(const String &key);
public:
void scene_update();
static void scene_update();
/* Path for each building type */
HashMap<String, String> building_data;
HashMap<String, Vector<Transform> > building_doors;
HashMap<String, AABB> building_aabbs;
// HashMap<String, String> building_data;
// HashMap<String, Vector<Transform> > building_doors;
// HashMap<String, AABB> building_aabbs;
public:
struct building &get_building(const String &building_key);
const struct building &get_building(const String &building_key) const;
static struct building &get_building(const String &building_key);
struct callme {
class H {};
H *obj;
@@ -126,8 +157,9 @@ public:
void *)>(obj);
}
void for_each_building(struct callme &c);
template <typename Func> void for_each_building(Func &&func, void *data)
static void for_each_building(struct callme &c);
template <typename Func>
static void for_each_building(Func &&func, void *data)
{
List<String> keys;
get_building_keys_list(&keys);
@@ -137,40 +169,41 @@ public:
e = e->next();
}
}
void for_each_building(void (*func)(const String &key, void *data),
static void for_each_building(void (*func)(const String &key,
void *data),
void *data);
void get_building_keys_list(List<String> *keys);
static void get_building_keys_list(List<String> *keys);
int get_building_count() const;
String create_building(const Dictionary &dict);
String create_building(const struct building &building);
String create_building(const struct building *building);
bool destroy_building(const String &key);
static int get_building_count();
static String create_building(const Dictionary &dict);
static String create_building(const struct building &building);
static String create_building(const struct building *building);
static bool destroy_building(const String &key);
struct checkpoint_data {
HashMap<String, String> building_data;
std::vector<struct building> buildings;
};
std::vector<struct checkpoint_data> undo_log;
int undo_log_size;
BuildingsData();
BuildingsData(flecs::world &e);
virtual ~BuildingsData();
public:
void read_buildings_json(const String &buildings_path);
void save_buildings_json(const String &buildings_path);
void filter_generated_stuff();
void remove_generated_stuff();
static void read_buildings_json(const String &buildings_path);
static void save_buildings_json(const String &buildings_path);
static void filter_generated_stuff();
static void remove_generated_stuff();
void load_data();
void checkpoint();
void undo();
void fill_door_locations();
void build_building_aabbs();
void update_building_transform(const String &key,
static void build_building_aabbs();
static void update_building_transform(const String &key,
const Transform &xform);
bool has_building(const String &key);
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;
static bool has_building(const String &key);
static String get_closest_building(const Transform &xform);
static flecs::entity
get_closest_building_entity(const Transform &xform);
static flecs::entity get_building_entity(const String &key);
void load_tile(int x, int z);
};
#endif

View File

@@ -0,0 +1,400 @@
#include <scene/resources/packed_scene.h>
#include <scene/3d/spatial.h>
#include <scene/3d/mesh_instance.h>
#include <scene/3d/camera.h>
#include <scene/main/viewport.h>
#include "base_data.h"
#include "buildings_data.h"
static flecs::world &ecs()
{
return BaseData::get_singleton()->get();
}
BuildingsData::BuildingsData(flecs::world &ecs_)
: undo_log_size(64)
{
ecs_.module<BuildingsData>();
// print_line("e0");
// flecs::world ecs_ = ecs();
ecs_.component<CBuildingStats>();
ecs_.component<CBuildingData>();
ecs_.component<CBTypeResidental>();
ecs_.component<CBCustomLayout>();
ecs_.component<CBuildingEdited>();
ecs_.component<CBuildingTileData>();
ecs_.component<CBuildingLoaded>();
ecs_.component<CBuildingsEye>();
ecs_.component<CSceneData>();
ecs_.component<CScenePack>();
ecs_.component<CScenesLoaded>();
ecs_.component<CSceneAABB>();
// print_line("e1");
// bool deferred = ecs_.is_deferred();
// if (deferred)
// ecs_.defer_suspend();
ecs_.set<CBuildingStats>({ 0 });
ecs_.set<CBuildingTileData>({});
assert(ecs_.has<CBuildingStats>());
load_data();
print_line("=== buildings");
ecs_.query_builder<const CBuildingData>().build().each(
[](flecs::entity e, const CBuildingData &bd) {
print_line("created: building: " + bd.building.key +
" / " + String(e.name()));
});
/* no scene data loaded yet */
print_line("=== scenes");
ecs_.query_builder<const CSceneData>().build().each(
[](flecs::entity e, const CSceneData &sd) {
print_line("created: scene: " + sd.sd.path + " / " +
String(e.name()));
});
print_line("loaded buildings: " +
itos(ecs().get<CBuildingStats>()->created_entities));
assert(ecs().get<CBuildingStats>()->created_entities > 0);
/* Fill door locations */
ecs().query_builder<CSceneData>().build().each([&](flecs::entity e,
CSceneData &sd) {
Error err;
const String &path = sd.sd.path;
Ref<PackedScene> ps =
ResourceLoader::load(path, "PackedScene", true, &err);
if (err == OK && ps.is_valid()) {
Vector<Transform> doors;
Node *scene = ps->instance();
List<Node *> queue;
queue.push_back(scene);
while (!queue.empty()) {
int i;
Node *item = queue.front()->get();
queue.pop_front();
String name = item->get_name();
if (name.find("-portal") >= 0) {
Spatial *sp =
Object::cast_to<Spatial>(item);
if (sp) {
Transform xform =
sp->get_transform();
Node *tmp = item->get_parent();
while (tmp) {
Transform parent_xform;
Spatial *parent_sp =
Object::cast_to<
Spatial>(
tmp);
if (parent_sp)
parent_xform =
parent_sp
->get_transform();
xform = parent_xform *
xform;
tmp = tmp->get_parent();
}
doors.push_back(xform);
}
}
for (i = 0; i < item->get_child_count(); i++)
queue.push_back(item->get_child(i));
}
e.set<CSceneDoors>({ doors });
scene->queue_delete();
ps.unref();
}
});
// if (deferred)
// ecs_.defer_resume();
ecs_.system("CreateSceneData")
.kind(flecs::OnUpdate)
.write<CSceneData>()
.run([&](flecs::iter &it) {
Dictionary buildings_data =
config.get_value("buildings", "building_data");
List<Variant> keys;
buildings_data.get_key_list(&keys);
List<Variant>::Element *e = keys.front();
while (e) {
String key = e->get();
if (!has_scene(key)) {
// building_data[key] = buildings_data[key];
String path = buildings_data[key];
flecs::entity se =
ecs().entity(key.ascii().ptr());
se.set<CSceneData>({ key, path });
}
e = e->next();
}
});
ecs_.system<const CSceneData>("LoadPackedScene")
.kind(flecs::OnUpdate)
.without<CScenePack>()
.write<CScenePack>()
.each([&](flecs::entity e, const CSceneData &sd) {
struct scene_pack sp;
sp.loader = ResourceLoader::load_interactive(
sd.sd.path, "PackedScene", true);
assert(sp.loader.is_valid());
e.set<CScenePack>({ sp });
});
ecs_.system<CScenePack>("LoadPackedScenePoll")
.kind(flecs::OnUpdate)
.without<CScenePackLoaded>()
.each([&](flecs::entity e, CScenePack &sp) {
const CSceneData *sd = e.get<CSceneData>();
assert(sd);
assert(sp.sp.loader.is_valid());
Error err = sp.sp.loader->poll();
if (err == OK) {
return;
} else if (err == ERR_FILE_EOF) {
Ref<PackedScene> sc =
sp.sp.loader->get_resource();
sp.sp.packed_scene = sc;
uint64_t m_id = (uint64_t)&sp.sp.loader;
print_line("Loaded scene: " + sd->sd.path +
" OK " +
String::num_int64(m_id, 16));
e.add<CScenePackLoaded>();
assert(sp.sp.packed_scene.is_valid());
} else {
print_error("Could not load the resource :( " +
sd->sd.path + " " + itos(err));
}
});
ecs_.system<CSceneData>("CalculateAABBs")
.without<CSceneAABB>()
.each([&](flecs::entity e, CSceneData &sd) {
Error err;
const String &path = sd.sd.path;
Ref<PackedScene> ps = ResourceLoader::load(
path, "PackedScene", true, &err);
if (err == OK && ps.is_valid()) {
AABB aabb;
Node *scene = ps->instance();
List<Node *> queue;
queue.push_back(scene);
while (!queue.empty()) {
int i;
Node *item = queue.front()->get();
queue.pop_front();
MeshInstance *mi =
Object::cast_to<MeshInstance>(
item);
if (mi) {
if (aabb.size.length_squared() <
0.1f)
aabb = mi->get_aabb();
else
aabb.merge_with(
mi->get_aabb());
}
for (i = 0; i < item->get_child_count();
i++)
queue.push_back(
item->get_child(i));
}
scene->queue_delete();
ps.unref();
e.set<CSceneAABB>({ aabb });
} else
print_error("Could not load: " + path);
});
ecs_.system("CheckScenesLoaded")
.kind(flecs::OnUpdate)
.run([&](flecs::iter &it) {
int count_csdata = (int)it.world()
.query_builder<CSceneData>()
.build()
.count();
int count_pack =
(int)it.world()
.query_builder<CScenePackLoaded>()
.build()
.count();
int count_aabb = (int)it.world()
.query_builder<CSceneAABB>()
.build()
.count();
if (count_csdata > 0 && count_csdata == count_pack &&
count_csdata == count_aabb)
it.world().add<CScenesLoaded>();
else
it.world().remove<CScenesLoaded>();
});
ecs_.observer<CBuildingInstance>()
.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);
}
});
ecs_.observer<CBuildingEdited>()
.event(flecs::OnAdd)
.with<CBuildingData>()
.run([&](flecs::iter &it) {
flecs::query<const CBuildingData> q =
it.world()
.query_builder<const CBuildingData>()
.with<CBuildingEdited>()
.build();
if (it.next()) {
flecs::entity qe = it.entity(0);
q.each([qe](flecs::entity e,
const CBuildingData &d) {
if (e != qe)
e.remove<CBuildingEdited>();
});
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<CBuildingsEye>()) {
int old_x = it.world().get<CBuildingsEye>()->tile_x;
int old_z = it.world().get<CBuildingsEye>()->tile_z;
if (old_x == tile_x && old_z == tile_z)
need_update = false;
else
print_line("UpdateEye need update");
}
it.world().set<CBuildingsEye>({ xform, tile_x, tile_z });
if (!need_update)
return;
if (!it.world().has<CBuildingTileData>())
return;
CBuildingTileData *td = it.world().get_mut<CBuildingTileData>();
it.world()
.query_builder<CBuildingData>()
.without<CBuildingLoaded>()
.without<CBuildingLoad>()
.with<CBuildingTile>()
.build()
.each([&](flecs::entity e, const CBuildingData &bd) {
const CBuildingTile *bt =
e.get<CBuildingTile>();
std::tuple<int, int> 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()) {
print_line("CBuildingLoad");
e.add<BuildingsData::
CBuildingLoad>();
}
}
});
it.world()
.query_builder<CBuildingData>()
.with<CBuildingLoaded>()
.with<CBuildingTile>()
.without<CBuildingUnload>()
.build()
.each([&](flecs::entity e, const CBuildingData &bd) {
const CBuildingTile *bt =
e.get<CBuildingTile>();
std::tuple<int, int> 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()) {
print_line("CBuildingUnload");
e.add<BuildingsData::
CBuildingUnload>();
}
});
});
ecs_.system<const CBuildingData>("LoadData")
.kind(flecs::OnUpdate)
.without<CBuildingLoaded>()
.without<CBuildingUnload>()
.with<CBuildingLoad>()
.write<CBuildingLoaded>()
.write<CBuildingLoad>()
.write<CBuildingInstanced>()
.each([&](flecs::entity e, const CBuildingData &bd) {
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 (!SceneTree::get_singleton()->get_current_scene())
return;
if (!scene_get_packed_scene(id).is_valid())
return;
if (!has_scene(id))
return;
else {
if (!e.has<CBuildingInstanced>()) {
add_scene_item(id, bd.building.key);
e.add<CBuildingInstanced>();
}
}
if (debug)
print_verbose("added to scene id: " + id);
assert(e.is_valid());
// e.world().defer_suspend();
e.add<CBuildingLoaded>();
e.remove<CBuildingLoad>();
print_line("CBuildingLoaded");
// e.world().defer_resume();
print_line("LoadData");
});
ecs_.system<const CBuildingData>("UnloadData")
.kind(flecs::OnUpdate)
.read<CBuildingInstanced>()
.with<CBuildingUnload>()
.with<CBuildingLoaded>()
.write<CBuildingLoaded>()
.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<CBuildingLoaded>();
e.remove<CBuildingUnload>();
e.remove<CBuildingInstanced>();
print_line("UnloadData");
});
ecs_.system<const CBuildingData>("SpawnNode")
.kind(flecs::OnUpdate)
.without<CBuildingUnload>()
.with<CBuildingLoaded>()
.write<CBuildingLoaded>()
.each([&](flecs::entity e, const CBuildingData &bd) {});
print_line("SpawnNode initialized");
}
BuildingsData::~BuildingsData()
{
}

View File

@@ -4,28 +4,28 @@
#include <scene/3d/immediate_geometry.h>
#include "wedge.h"
#include "base_data.h"
#include "buildings_data.h"
#include "contours.h"
Contours *Contours::singleton = nullptr;
Contours *Contours::get_singleton()
{
if (!singleton)
singleton = memnew(Contours);
return singleton;
}
Contours::Contours()
Contours::Contours(flecs::world &ecs)
: dbg(nullptr)
{
BaseData::get_singleton()->get().component<Lot>();
ecs.module<Contours>();
ecs.import <BuildingsData>();
Lot::import_packer(ecs);
ecs.component<Lot>();
base_e = BaseData::get_singleton()->get().lookup("lots");
if (base_e.is_valid())
base_e.destruct();
base_e = BaseData::get_singleton()->get().entity("lots");
assert(base_e.is_valid());
}
Contours::~Contours()
{
}
bool Contours::is_in_closed_contour(const struct wedge *w)
bool Contours::is_in_closed_contour(const struct wedge *w) const
{
int i, j;
bool found = false;
@@ -51,6 +51,7 @@ static Vector3 normal(const Vector3 &v)
void Contours::build()
{
int i, j;
print_line("Contours::build()");
contours.clear();
for (i = 0; i < (int)wedge_contours.size(); i++) {
struct main_contour mc;
@@ -86,10 +87,6 @@ void Contours::build()
}
contours.push_back(mc);
}
flecs::entity base_e = BaseData::get_singleton()->get().lookup("lots");
if (base_e.is_valid())
base_e.destruct();
base_e = BaseData::get_singleton()->get().entity("lots");
List<struct Lot::polygon> polygon_queue;
List<struct Lot::polygon> polygon_output;
Vector<struct Lot::polygon> check;
@@ -141,7 +138,7 @@ void Contours::build()
List<struct Lot::polygon>::Element *e = polygon_queue.front();
while (e) {
struct Lot::polygon item = e->get();
print_line("queue: " + itos(polygon_queue.size()));
// print_line("queue: " + itos(polygon_queue.size()));
polygon_queue.pop_front();
float area = item.area();
if (area > 120.0f * 120.0f &&
@@ -162,12 +159,15 @@ void Contours::build()
e = polygon_queue.front();
}
e = polygon_output.front();
assert(base_e.is_valid());
while (e) {
print_line("creating entity");
flecs::entity lot_e = BaseData::get_singleton()
->get()
.entity()
.child_of(base_e);
lot_e.set<Lot>({ e->get() });
print_line("created entity: " + String(lot_e.name()));
e = e->next();
}
}
@@ -186,7 +186,6 @@ void Contours::build()
}
});
});
Lot::pack();
}
void Contours::debug()

View File

@@ -2,6 +2,7 @@
#ifndef CONTOURS_H_
#define CONTOURS_H_
#include <vector>
#include <flecs.h>
#include "road_lot.h"
class ImmediateGeometry;
@@ -20,12 +21,11 @@ struct Contours {
Ref<SpatialMaterial> imm_mat;
std::vector<std::vector<struct wedge *> > wedge_contours;
std::vector<struct main_contour> contours;
static Contours *singleton;
static Contours *get_singleton();
Contours();
Contours(flecs::world &ecs);
virtual ~Contours();
bool is_in_closed_contour(const struct wedge *w);
bool is_in_closed_contour(const struct wedge *w) const;
void debug();
flecs::entity base_e;
};
#endif // CONTOURS_H_

View File

@@ -26,6 +26,7 @@ LineMetadataEditor::~LineMetadataEditor()
void LineMetadataEditor::_notification(int which)
{
#if 0
switch (which) {
case NOTIFICATION_ENTER_TREE: {
VBoxContainer *box = memnew(VBoxContainer);
@@ -64,6 +65,7 @@ void LineMetadataEditor::_notification(int which)
}
} break;
}
#endif
}
void LineMetadataEditor::_bind_methods()

View File

@@ -1125,7 +1125,7 @@ class EdgeEditorHandler {
continue;
}
const AABB &aabb_building =
bd()->building_aabbs[buildings[i].id];
bd()->get_scene_aabb(buildings[i].id);
Transform building_rot(
Basis().rotated(
Vector3(0, 1, 0),
@@ -1306,9 +1306,9 @@ class EdgeEditorHandler {
String lot_id = side.lot_type;
if (side.buildings.size() > 1) {
const AABB &aabb_lot =
bd()->building_aabbs
["lot-" +
lot_id];
bd()->get_scene_aabb(
"lot-" +
lot_id);
bool pack_result =
pack_buildings(
aabb_lot,
@@ -1375,9 +1375,9 @@ class EdgeEditorHandler {
String lot_id = side.lot_type;
if (side.buildings.size() > 1) {
const AABB &aabb_lot =
bd()->building_aabbs
["lot-" +
lot_id];
bd()->get_scene_aabb(
"lot-" +
lot_id);
bool pack_result =
pack_buildings(
aabb_lot,

View File

@@ -121,9 +121,9 @@ template <typename T> static Vector<Vector2> get_polygon2(const T &polygon)
bool Lot::polygon::intersects(const polygon *other) const
{
print_line("intersection_test");
dump();
other->dump();
// print_line("intersection_test");
// dump();
// other->dump();
Vector<Vector2> p1 = get_polygon2(points);
Vector<Vector2> p2 = get_polygon2(other->points);
Vector<Vector<Vector2> > intersection =
@@ -510,14 +510,16 @@ struct LotPacker {
lbs.clear();
Array lb = config.get_value("road", varname, Array());
int i, j;
print_line("start building list");
for (i = 0; i < (int)lb.size(); i++) {
struct config_buildings cb;
cb.area = 0.0f;
Array entries = lb[i];
for (j = 0; j < entries.size(); j++) {
String bname = entries[j];
print_line("building: " + bname);
cb.buildings.push_back(bname);
AABB aabb = get_building_type_aabb(bname);
AABB aabb = bd()->get_scene_aabb(bname);
cb.area += aabb.size.x * aabb.size.z;
print_line("config building: " + bname);
}
@@ -525,6 +527,7 @@ struct LotPacker {
String::num(cb.area));
lbs.push_back(cb);
}
print_line("end building list");
struct lbsort {
_FORCE_INLINE_ bool
operator()(const struct config_buildings &b1,
@@ -536,29 +539,45 @@ struct LotPacker {
lbs.sort_custom<struct lbsort>();
lbs.invert();
}
LotPacker(Vector2 cell_size)
: cell_size(cell_size)
LotPacker(flecs::world &ecs)
: cell_size(Vector2(16, 16))
{
BaseData::get_singleton()->get().component<LotGrid>();
BaseData::get_singleton()->get().component<LotBuildings>();
BaseData::get_singleton()->get().component<PreOccupied>();
BaseData::get_singleton()->get().component<Industrial>();
BaseData::get_singleton()->get().component<Commercial>();
BaseData::get_singleton()->get().component<Residental>();
ecs.module<LotPacker>();
ecs.import <BuildingsData>();
ecs.component<LotGrid>();
ecs.component<PreOccupied>();
ecs.component<Industrial>();
ecs.component<Commercial>();
ecs.component<Residental>();
struct PackerState {
int state;
};
ecs.component<PackerState>();
Error err = config.load("res://config/stream.conf");
assert(err == OK);
get_building_list("lot_buildings_residental",
ecs.system("MakeStuff")
.kind(flecs::OnUpdate)
.run([&](flecs::iter &it) {
if (!it.world().has<PackerState>())
it.world().set<PackerState>({ 0 });
if (it.world().has<PackerState>() &&
it.world().get<PackerState>()->state == 1) {
get_building_list(
"lot_buildings_residental",
lot_buildings_residental);
get_building_list("lot_buildings_commercial",
get_building_list(
"lot_buildings_commercial",
lot_buildings_commercial);
get_building_list("lot_buildings_industrial",
get_building_list(
"lot_buildings_industrial",
lot_buildings_industrial);
}
static LotPacker *get_singleton()
{
if (!singleton)
singleton = memnew(LotPacker(Vector2(16, 16)));
return singleton;
if (it.world().has<PackerState>())
it.world()
.get_mut<PackerState>()
->state++;
});
}
static inline Rect2 aabb2rect(const AABB &aabb)
@@ -840,17 +859,17 @@ out_bad:
}
bool tmp_found = false;
int office_count = 0;
// FIXME use components and find instead of direct lookup
AABB get_building_aabb(const String &key) const
{
const struct BuildingsData::building &b =
bd()->get_building(key);
const AABB &building_aabb = bd()->building_aabbs[b.id];
return building_aabb;
return bd()->get_scene_aabb(b.id);
}
// FIXME use components and find instead of direct lookup
AABB get_building_type_aabb(const String &building) const
{
const AABB &building_aabb = bd()->building_aabbs[building];
return building_aabb;
return bd()->get_scene_aabb(building);
}
Transform get_building_transform(const String &key)
{
@@ -872,20 +891,34 @@ out_bad:
void create()
{
int lot_count = 0;
int i, j;
Vector<flecs::entity> entities;
Vector<flecs::entity> entities_all;
Vector<Rect2> vrects;
Vector<Transform> xforms;
List<String> buildings;
Vector<BuildingsData::building> vbuildings;
bd()->get_building_keys_list(&buildings);
BaseData::get_singleton()
->get()
.query_builder<Lot>()
.write<LotBuildings>()
.write<PreOccupied>()
.read<PreOccupied>()
.build()
.each([&](flecs::entity e, Lot &lot_) {
assert(e.get<Lot>()->polygon.points.size() > 0);
List<String> buildings;
bd()->get_building_keys_list(&buildings);
List<String>::Element *be = buildings.front();
e.get_mut<Lot>()->polygon.update_aabb();
if (e.has<PreOccupied>())
return;
if (!e.has<PreOccupied>())
entities.push_back(e);
});
BaseData::get_singleton()
->get()
.query_builder<Lot>()
.build()
.each([&](flecs::entity e, Lot &lot_) {
entities_all.push_back(e);
});
print_line("entities: " + itos(entities.size()));
List<String>::Element *be = buildings.front();
while (be) {
const String &key = be->get();
const struct BuildingsData::building &b =
@@ -898,54 +931,59 @@ out_bad:
be = be->next();
continue;
}
AABB lot_aabb =
e.get<Lot>()->polygon.aabb;
Rect2 lot_rect = aabb2rect(
e.get<Lot>()->polygon.aabb);
Rect2 building_rect =
get_rect_transformed(key);
Transform xform =
get_building_transform(key);
Vector2 building_pos = Vector2(
xform.origin.x, xform.origin.z);
vbuildings.push_back(b);
Rect2 building_rect = get_rect_transformed(b.key);
vrects.push_back(building_rect);
Transform xform = get_building_transform(b.key);
xforms.push_back(xform);
be = be->next();
}
print_line("buildings: " + itos(vbuildings.size()));
for (i = 0; i < entities.size(); i++) {
flecs::entity e = entities[i];
print_line("Lot: " + itos(i) + " " + String(e.name()));
assert(e.is_valid());
assert(e.get<Lot>()->polygon.points.size() > 0);
}
// assert(false);
for (i = 0; i < entities.size(); i++) {
flecs::entity e = entities[i];
print_line("Lot: " + itos(i) + " " + String(e.name()));
Lot *lot_ = e.get_mut<Lot>();
be = buildings.front();
AABB lot_aabb = e.get<Lot>()->polygon.aabb;
Rect2 lot_rect = aabb2rect(e.get<Lot>()->polygon.aabb);
for (j = 0; j < vbuildings.size(); j++) {
const struct BuildingsData::building &b =
vbuildings[j];
Rect2 building_rect = vrects[j];
Transform xform = xforms[j];
Vector2 building_pos =
Vector2(xform.origin.x, xform.origin.z);
bool intersects = false;
if (e.get<Lot>()->polygon.is_inside(
building_rect))
intersects = true;
assert(e.get<Lot>()
->polygon.points.size() >
0);
if (intersects) {
assert(e.get<Lot>()
->polygon.points
.size() > 0);
e.add<PreOccupied>();
assert(e.get<Lot>()
->polygon.points
.size() > 0);
LotBuildings &lb =
e.ensure<LotBuildings>();
lb.buildings.push_back(
{ building_rect, key });
Vector<Vector2> pt =
get_polygon2(
e.get<Lot>()
->polygon
.points);
{ building_rect, b.key });
Vector<Vector2> pt = get_polygon2(
e.get<Lot>()->polygon.points);
assert(pt.size() > 0);
lb.polygons.push_back(pt);
e.modified<LotBuildings>();
}
be = be->next();
}
});
}
BaseData::get_singleton()
->get()
.query_builder<Lot, LotBuildings>()
.with<PreOccupied>()
.build()
.each([&](flecs::entity e, Lot &lot, LotBuildings &lb) {
int i;
for (i = 0; i < lb.buildings.size(); i++) {
const Pair<Rect2, String> &mp =
lb.buildings[i];
@@ -956,6 +994,9 @@ out_bad:
get_rect_transformed(key);
Rect2 lot_rect =
aabb2rect(lot.polygon.aabb);
assert(bd()->has_scene(
"office-exterior"));
print_line("building type: " + b.id);
if (b.id == "office-exterior") {
print_line("id: " + b.id);
print_line("xform: " +
@@ -972,6 +1013,19 @@ out_bad:
}
}
});
for (i = 0; i < entities.size(); i++) {
flecs::entity e = entities[i];
if (e.has<PreOccupied>())
continue;
if ((lot_count % 5) == 0)
e.add<Industrial>();
else if (lot_count % 3 == 0)
e.add<Commercial>();
else
e.add<Residental>();
lot_count++;
}
#if 0
BaseData::get_singleton()
->get()
.query_builder<Lot>()
@@ -1080,14 +1134,12 @@ out_bad:
e.add<Residental>();
lot_count++;
});
#endif
assert(tmp_found);
print_line("office_count: " + itos(office_count));
// assert(office_count > 1);
BaseData::get_singleton()
->get()
.query_builder<Lot>()
.build()
.each([&](flecs::entity e, Lot &lot) { add_lot(e); });
for (i = 0; i < entities_all.size(); i++)
add_lot(entities_all[i]);
BaseData::get_singleton()
->get()
.query_builder<Lot>()
@@ -1292,31 +1344,42 @@ out_bad:
return lb->polygons;
}
};
LotPacker *LotPacker::singleton = nullptr;
void Lot::pack()
{
LotPacker::get_singleton()->create();
LotPacker::get_singleton()->pack_lots();
BaseData::get_singleton()->get().get_mut<LotPacker>()->create();
BaseData::get_singleton()->get().get_mut<LotPacker>()->pack_lots();
BaseData::get_singleton()->get().modified<LotPacker>();
}
void Lot::get_lot_data(flecs::entity e, List<Pair<AABB, String> > *lot_data)
{
LotPacker::get_singleton()->get_lot_data(e, lot_data);
BaseData::get_singleton()->get().get_mut<LotPacker>()->get_lot_data(
e, lot_data);
}
void Lot::get_lot_rotations(flecs::entity e, List<Transform> *lot_xform)
{
LotPacker::get_singleton()->get_lot_rotations(e, lot_xform);
BaseData::get_singleton()->get().get_mut<LotPacker>()->get_lot_rotations(
e, lot_xform);
}
void Lot::get_lot_buildings(flecs::entity e,
Vector<Pair<Rect2, String> > *lot_buildings)
{
LotPacker::get_singleton()->get_lot_buildings(e, lot_buildings);
BaseData::get_singleton()->get().get_mut<LotPacker>()->get_lot_buildings(
e, lot_buildings);
}
Vector<Vector<Vector2> > Lot::get_lot_polygons(flecs::entity e)
{
return LotPacker::get_singleton()->get_lot_polygons(e);
return BaseData::get_singleton()
->get()
.get_mut<LotPacker>()
->get_lot_polygons(e);
}
void Lot::import_packer(flecs::world &ecs)
{
ecs.import <LotPacker>();
}

View File

@@ -33,6 +33,7 @@ struct Lot {
get_lot_buildings(flecs::entity e,
Vector<Pair<Rect2, String> > *lot_buildings);
static Vector<Vector<Vector2> > get_lot_polygons(flecs::entity e);
static void import_packer(flecs::world &ecs);
};
#endif // ROAD_LOT_H_

View File

@@ -88,9 +88,10 @@ struct RoadLinesProcessing {
int debug_flags;
DebugGeo *dbg;
static ConfigFile config;
RoadLinesProcessing()
RoadLinesProcessing(flecs::world &ecs)
: dbg(nullptr)
{
ecs.module<RoadLinesProcessing>();
Error err = config.load("res://config/stream.conf");
assert(err == OK);
}
@@ -158,7 +159,7 @@ struct RoadLinesProcessing {
}
bd()->create_building(b);
if (!bd()->has_scene(b.id))
bd()->create_scene_data(b.id, b.key);
return;
else
bd()->add_scene_item(b.id, b.key);
print_line("created building: " + b.key + " " + b.id);
@@ -919,7 +920,10 @@ out2:;
void find_closed_contours()
{
int i, j;
Contours *contours = Contours::get_singleton();
print_line("find_closed_contours");
assert(this);
Contours *contours =
BaseData::get_singleton()->get().get_mut<Contours>();
// RoadLinesProcessing *r = BaseData::get_singleton() ->get() .get_mut<RoadLinesProcessing>();
RoadLinesProcessing *r = this;
if (r->nodes.size() == 0)
@@ -985,7 +989,7 @@ out2:;
}
if (finished) {
int k;
print_line("complete contour");
// print_line("complete contour");
std::vector<struct wedge *> wedge_contour;
Vector<Vector2> polygon;
for (k = 0; k < (int)contour.size(); k++) {
@@ -993,8 +997,8 @@ out2:;
wedges_ref[contour[k]];
wedge_contour.push_back(
&wedges[wr.first][wr.second]);
print_line(itos(k) + ": " +
itos(contour[k]));
// print_line(itos(k) + ": " +
// itos(contour[k]));
Vector3 p1 =
wedges[wr.first][wr.second].p[0];
Vector3 p2 =
@@ -1007,8 +1011,7 @@ out2:;
used.push_back(contour[k]);
}
if (Geometry::is_polygon_clockwise(polygon))
contours->get_singleton()
->wedge_contours.push_back(
contours->wedge_contours.push_back(
wedge_contour);
contour.clear();
contour_count++;
@@ -1018,8 +1021,6 @@ out2:;
if (base >= (int)wedges_ref.size())
break;
}
contours->build();
contours->debug();
}
~RoadLinesProcessing()
{
@@ -1032,27 +1033,10 @@ out2:;
{
return debug_flags;
}
void road_setup()
void road_setup2()
{
int i, j;
RoadLinesData *rld = RoadLinesData::get_singleton();
std::vector<Vector3> road_lines_nodes;
std::unordered_map<uint32_t, std::vector<Vector3> >
road_lines_nodes_hash;
road_lines_nodes.clear();
road_lines_nodes_hash.clear();
rld->update_line_edges();
test_lines();
calculate_lot_depths();
rld->set_debug_flags(debug_flags);
rld->process_lines(road_lines_nodes_hash, road_lines_nodes);
create_nodes(road_lines_nodes);
create_edges();
optimize_nodes(16.0f);
sort_neighbors();
wedges.clear();
build_wedges(wedges);
find_closed_contours();
// update_lot_depths();
ImmediateGeometry *d = rld->get_debug_node();
d->clear();
@@ -1114,7 +1098,6 @@ out2:;
}
d->end();
}
create_structures();
print_line("ROAD SETUP DONE");
}
};
@@ -1703,7 +1686,9 @@ public:
out_surfaces[h], 0.0f);
} else if (k == params.nlanes + 1 &&
mside1.lot > 0) { /* lot */
if (!Contours::get_singleton()
if (!BaseData::get_singleton()
->get()
.get<Contours>()
->is_in_closed_contour(
&wedge))
build_split_segment(
@@ -1779,7 +1764,9 @@ public:
"m2: " +
String::num(
mside2.lot_depth_eff));
if (!Contours::get_singleton()
if (!BaseData::get_singleton()
->get()
.get<Contours>()
->is_in_closed_contour(
&wedge))
build_split_segment(
@@ -1864,25 +1851,51 @@ public:
nodes_mi.push_back(mi);
}
}
RoadMeshProcessing()
RoadMeshProcessing(flecs::world &ecs)
: road_mgroup(nullptr)
{
BaseData::get_singleton()->get().ensure<RoadLinesProcessing>();
ecs.module<RoadMeshProcessing>();
ecs.import <RoadLinesProcessing>();
}
};
void RoadProcessing::road_setup(Node *target, int debug_flags)
{
BaseData::get_singleton()->get().ensure<RoadLinesProcessing>();
BaseData::get_singleton()->get().ensure<RoadMeshProcessing>();
RoadLinesData *rld = RoadLinesData::get_singleton();
int i, j;
RoadLinesProcessing *r =
BaseData::get_singleton()->get().get_mut<RoadLinesProcessing>();
r->set_debug_flags(debug_flags);
r->road_setup();
std::vector<Vector3> road_lines_nodes;
std::unordered_map<uint32_t, std::vector<Vector3> >
road_lines_nodes_hash;
road_lines_nodes.clear();
road_lines_nodes_hash.clear();
rld->update_line_edges();
r->test_lines();
r->calculate_lot_depths();
rld->set_debug_flags(debug_flags);
rld->process_lines(road_lines_nodes_hash, road_lines_nodes);
r->create_nodes(road_lines_nodes);
r->create_edges();
r->optimize_nodes(16.0f);
r->sort_neighbors();
r->wedges.clear();
r->build_wedges(r->wedges);
print_line("find_closed_contours");
r->find_closed_contours();
Contours *contours =
BaseData::get_singleton()->get().get_mut<Contours>();
contours->build();
Lot::pack();
contours->debug();
BaseData::get_singleton()->get().modified<Contours>();
r->create_structures();
BaseData::get_singleton()
->get()
.get_mut<RoadMeshProcessing>()
->create_road_meshes(target);
r->road_setup2();
}
void RoadProcessing::remove_road_meshes(Node *target)
@@ -1900,7 +1913,6 @@ void RoadProcessing::load_data()
ConfigFile config;
Error result = config.load("res://config/stream.conf");
ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
BaseData::get_singleton()->get().ensure<RoadMeshProcessing>();
RoadMeshProcessing *rmp =
BaseData::get_singleton()->get().get_mut<RoadMeshProcessing>();
assert(rmp);
@@ -2025,3 +2037,15 @@ void RoadProcessing::cleanup()
BaseData::get_singleton()->get().remove<RoadLinesProcessing>();
BaseData::get_singleton()->get().remove<RoadMeshProcessing>();
}
RoadProcessing::RoadProcessing(flecs::world &ecs)
{
ecs.module<RoadProcessing>();
ecs.import <Contours>();
ecs.import <RoadLinesProcessing>();
ecs.import <RoadMeshProcessing>();
}
RoadProcessing::~RoadProcessing()
{
}

View File

@@ -1,5 +1,6 @@
#ifndef ROAD_LINES_PROCESSING_H_
#define ROAD_LINES_PROCESSSING_H_
#include <flecs.h>
class Node;
class ImmediateGeometry;
class RoadProcessing {
@@ -8,5 +9,7 @@ public:
static void remove_road_meshes(Node *target);
static void load_data();
static void cleanup();
RoadProcessing(flecs::world &ecs);
virtual ~RoadProcessing();
};
#endif

View File

@@ -53,7 +53,7 @@ void StreamWorld::create_tilemap()
void StreamWorld::update_view()
{
int i, j;
int i;
ERR_FAIL_COND_MSG(!initialized,
"The Stream object is incorrectly initialized");
if (!viewer || !terrain) {
@@ -84,6 +84,12 @@ void StreamWorld::update_view()
ERR_FAIL_COND_MSG(!t, "VoxelLodTerrain was not found");
viewer = v;
terrain = t;
assert(terrain);
assert(viewer);
BaseData::get_singleton()
->get()
.set<StreamWorld::components::WorldData>(
{ viewer, terrain });
viewer->connect("tree_exiting", this, "viewer_dead");
terrain->connect("tree_exiting", this, "terrain_dead");
current_x = world_extent + 1;
@@ -218,7 +224,7 @@ void StreamWorld::unload_building(const String &key)
void StreamWorld::update_items()
{
List<String> keys;
data()->get_scene_keys_list(&keys);
BuildingsData::get_scene_keys_list(&keys);
List<String>::Element *e = keys.front();
while (e) {
const String &key = e->get();
@@ -260,6 +266,7 @@ void StreamWorld::remove_building(const String &key)
VoxelLodTerrain *StreamWorld::get_terrain()
{
assert(terrain);
return terrain;
}
@@ -316,7 +323,7 @@ void StreamWorld::run_command(const String &command,
String new_type = args[1];
Dictionary buildings_data =
config.get_value("buildings", "building_data");
if (!data()->building_data.has(new_type)) {
if (!data()->has_scene(new_type)) {
print_error("unknown building type: " + new_type);
return;
}
@@ -403,7 +410,7 @@ void StreamWorld::run_command(const String &command,
create_tilemap();
#endif
update_view();
data()->scene_update();
BuildingsData::scene_update();
update_items();
#if 0
data()->for_each_building(
@@ -453,7 +460,17 @@ void StreamWorld::_notification(int which)
if (current_scene)
current_scene = get_tree()->get_root();
}
#if 0
BaseData::get_singleton()
->get()
.add<StreamWorld::components::Initialized>();
#endif
ERR_FAIL_COND_MSG(!current_scene, "No current scene");
if (Engine::get_singleton()->is_editor_hint())
break;
set_process(true);
#if 0
BaseData::get_singleton()->get().defer_suspend();
RoadProcessing::road_setup(this, 0);
#if 0
data()->for_each_building(
@@ -471,6 +488,7 @@ void StreamWorld::_notification(int which)
#if 0
create_tilemap();
#endif
BaseData::get_singleton()->get().defer_resume();
set_process(true);
if (Engine::get_singleton()->is_editor_hint())
break;
@@ -480,12 +498,14 @@ void StreamWorld::_notification(int which)
update_view();
assert(terrain);
assert(viewer);
#endif
}
break;
case NOTIFICATION_EXIT_TREE:
frame_count = 0;
break;
case NOTIFICATION_PROCESS: {
#if 0
if (frame_count % 60 == 0) {
float fmon = Performance::get_singleton()->get_monitor(
Performance::RENDER_DRAW_CALLS_IN_FRAME);
@@ -497,6 +517,12 @@ void StreamWorld::_notification(int which)
update_view();
data()->scene_update();
update_items();
#endif
if (road_setup_needed && !road_setup_complete) {
road_setup();
road_setup_needed = false;
road_setup_complete = true;
}
} break;
}
@@ -525,14 +551,30 @@ StreamWorld::StreamWorld()
, view_distance(0)
, initialized(false)
, frame_count(0)
, road_setup_needed(false)
, road_setup_complete(false)
, count_shit(0)
{
BaseData::get_singleton()->get().component<BuildingsData>();
BaseData::get_singleton()->get().import <BuildingsData>();
BaseData::get_singleton()->get().import <RoadProcessing>();
BaseData::get_singleton()
->get()
.component<StreamWorld::components::RoadSetupDone>();
BaseData::get_singleton()
->get()
.component<StreamWorld::components::RoadSetupNeeded>();
BaseData::get_singleton()
->get()
.component<StreamWorld::components::Initialized>();
BaseData::get_singleton()
->get()
.component<StreamWorld::components::WorldData>();
Error result = config.load("res://config/stream.conf");
ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
BaseData::get_singleton()->get().ensure<BuildingsData>();
RoadProcessing::load_data();
world_extent = config.get_value("world", "world_extent");
tile_size = config.get_value("world", "tile_size");
view_distance = config.get_value("world", "view_distance");
ERR_FAIL_COND_MSG(tile_size <= 0 || world_extent <= 0 ||
world_extent <= tile_size,
"Failed to configure world");
@@ -548,11 +590,40 @@ StreamWorld::StreamWorld()
map_it++;
}
#endif
view_distance = config.get_value("world", "view_distance");
BaseData::get_singleton()->get().import <NPC>();
flecs::entity npcctrl = BaseData::get_singleton()->get().entity();
npcctrl.set<NPC::NPCControl>({ NPC::NPCControl::CMD_PRESIM });
initialized = true;
flecs::log::set_level(-3);
BaseData::get_singleton()
->get()
.system("WaitForUpdate")
.kind(flecs::OnUpdate)
.run([&](flecs::iter &it) {
if (road_setup_complete)
return;
if (!road_setup_needed && !road_setup_complete)
road_setup_needed = true;
#if 0
if (it.world()
.has<StreamWorld::components::RoadSetupDone>())
return;
if (it.world()
.has<StreamWorld::components::Initialized>() &&
!it.world()
.has<StreamWorld::components::
RoadSetupNeeded>()) {
road_setup_needed = true;
it.world()
.add<StreamWorld::components::
RoadSetupNeeded>();
} else if (it.world()
.has<BuildingsData::CScenesLoaded>())
it.world()
.add<StreamWorld::components::
Initialized>();
#endif
});
}
void StreamWorld::cleanup()
{
@@ -592,3 +663,16 @@ void StreamWorld::undo()
update_view();
update_items();
}
void StreamWorld::road_setup()
{
assert(count_shit == 0);
RoadProcessing::road_setup(this, 0);
update_view();
data()->scene_update();
update_items();
update_view();
count_shit++;
assert(terrain);
assert(viewer);
}

View File

@@ -37,6 +37,9 @@ private:
bool initialized;
int current_x, current_z;
int frame_count;
bool road_setup_needed;
bool road_setup_complete;
int count_shit;
void _notification(int which);
// void create_tilemap();
void update_view();
@@ -51,10 +54,20 @@ private:
void remove_generated_stuff();
void place_zebras();
void undo();
void road_setup();
static void _bind_methods();
public:
struct components {
struct Initialized {};
struct WorldData {
VoxelViewer *viewer;
VoxelLodTerrain *terrain;
};
struct RoadSetupNeeded {};
struct RoadSetupDone {};
};
VoxelLodTerrain *get_terrain();
void run_command(const String &command, const Vector<Variant> &args);
StreamWorld();

View File

@@ -34,8 +34,14 @@ void TerrainEditor::exit()
void TerrainEditor::update(float delta)
{
if (!active)
if (!active) {
if (BaseData::get_singleton()
->get()
.has<StreamWorld::components::WorldData>())
activate();
else
return;
}
if (!cursor_enabled && get_camera_mode() == 3) {
cursor_enabled = true;
get_as_node<Spatial>(cursor_name)->show();
@@ -382,7 +388,7 @@ end:;
"building elevation: " +
String::num(imgmapper->get_height_full(
b.xform.origin)));
AABB aabb = bd()->building_aabbs[b.id];
AABB aabb = bd()->get_scene_aabb(b.id);
print_line("building AABB: " +
(aabb.operator String()));
float max_elevation_c = -Math_INF,

View File

@@ -614,6 +614,7 @@ void MainTabs::_notification(int which)
std::vector<Variant> args_data = {
items[i].header
};
assert(items[i].header.length() > 0);
ui_field::ui_field_builder(this, tab,
"l_p{v{}}",
args_data.data(),

View File

@@ -40,9 +40,10 @@ void ui_field::ui_field_builder(Node *owner, Node *parent, const String format,
.get<WorldEditor::components::buildings_editor_node>()
->node;
assert(owner->is_inside_tree());
for (i = 0; i < format.length(); i++) {
const char *fmt = format.ascii().ptr();
int c = fmt[i];
CharString cformat = format.ascii();
for (i = 0; i < format.ascii().length(); i++) {
assert(i < cformat.length());
int c = (int)cformat.ptr()[i];
// printf("character: %c : argp: %d\n", (char)c, argp);
switch (c) {
case '{':