Converted buildings loading to flecs

This commit is contained in:
2025-04-17 19:30:39 +03:00
parent fd23aa6287
commit dd00a41024
22 changed files with 845 additions and 812 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,20 @@
#include "building_grid_instance.h"
#include "buildings_data.h"
AABB BuildingGridInstance::get_aabb() const
{
return AABB();
}
PoolVector<Face3> BuildingGridInstance::get_faces(uint32_t p_usage_flags) const
{
return PoolVector<Face3>();
}
BuildingGridInstance::BuildingGridInstance()
{
}
BuildingGridInstance::~BuildingGridInstance()
{
}

View File

@@ -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 <flecs.h>
#include <scene/3d/visual_instance.h>
class BuildingGridInstance : public GeometryInstance {
GDCLASS(BuildingGridInstance, GeometryInstance)
flecs::entity e;
public:
virtual AABB get_aabb() const;
virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const;
BuildingGridInstance();
~BuildingGridInstance();
};
#endif // BUILDING_GRID_INSTANCE_H_

View File

@@ -0,0 +1,97 @@
#include <scene/3d/area.h>
#include <scene/3d/collision_shape.h>
#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<PropertyInfo> *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<int> 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<int> 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<Face3>
BuildingLayoutInstance::get_faces(uint32_t p_usage_flags) const
{
return PoolVector<Face3>();
}

View File

@@ -0,0 +1,21 @@
#include <scene/3d/visual_instance.h>
class BuildingLayoutInstance : public GeometryInstance {
GDCLASS(BuildingLayoutInstance, GeometryInstance)
public:
BuildingLayoutInstance();
~BuildingLayoutInstance();
protected:
void _notification(int which);
void _get_property_list(List<PropertyInfo> *p_list) const;
bool _get(const StringName &name, Variant &val) const;
bool _set(const StringName &name, const Variant &val);
Vector<int> floors;
int size;
int level;
public:
virtual AABB get_aabb() const;
virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const;
};

View File

@@ -9,13 +9,14 @@
#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 "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<PackedScene> 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<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>()
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);
// 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()
{
}
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: " +
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<CBuildingStats>());
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<CBuildingStats>());
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<const CBuildingData> qb =
ecs().query_builder<const CBuildingData>();
flecs::query<const CBuildingData> 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<CSceneData>();
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<CBuildingInstance>({ 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<CSceneData>({ sd });
pending_scene.insert(path);
assert(e.get_mut<CSceneData>());
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<CBuildingInstance>({ 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<String> BuildingsData::scene_get_items(const String &key) const
@@ -700,11 +895,14 @@ int BuildingsData::get_building_count() const
flecs::query<const CBuildingData> q =
ecs().query<const CBuildingData>();
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<CBuildingStats>());
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<CBuildingStats>());
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<CBuildingData>({ building });
assert(e.is_valid());
int tile_size = config.get_value("world", "tile_size");
assert(tile_size > 0);
e.set<CBuildingData>({ building });
int tile_x = building.xform.origin.x / tile_size;
int tile_z = building.xform.origin.z / tile_size;
std::tuple<int, int> tile = { tile_x, tile_z };
e.set<CBuildingTile>({ tile });
CBuildingTileData *td = ecs().get_mut<CBuildingTileData>();
if (td->tiles.find(tile) != td->tiles.end())
td->tiles[tile].push_back(e);
else
td->tiles[tile] = { e };
ecs().get_mut<CBuildingStats>()->created_entities++;
ecs().modified<CBuildingStats>();
if (building.id.begins_with("residental-"))
e.add<CBTypeResidental>();
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();

View File

@@ -1,7 +1,9 @@
#ifndef BUILDINGS_DATA_H
#define BUILFINGS_DATA_H
#include <unordered_map>
#include <vector>
#include <core/reference.h>
#include <flecs.h>
class PackedScene;
class ResourceInteractiveLoader;
class BuildingsData {
@@ -21,10 +23,49 @@ public:
Dictionary to_dict() const;
String line_name;
};
Set<String> pending_scene;
/* Scene objects data */
//private:
// HashMap<String, struct scene_data> scenes;
struct CBuildingData {
struct BuildingsData::building building;
};
struct CBTypeResidental {};
struct CBCustomLayout {
int size;
Vector<int> 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<int, int>;
struct tile_hash
: public std::unary_function<key_t, std::size_t> {
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<flecs::entity>, tile_hash>;
tile_map_t tiles;
tile_map_t loaded_tiles;
};
struct CBuildingTile {
std::tuple<int, int> tile;
};
struct CBuildingLoad {};
struct CBuildingUnload {};
struct CBuildingLoaded {};
struct CBuildingEdited {};
public:
void get_scene_keys_list(List<String> *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

View File

@@ -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<BuildingsData>()
->get_closest_building_entity(xform);
assert(e.is_valid());
e.add<BuildingsData::CBuildingEdited>();
const BuildingsData::CBuildingData *b =
e.get<BuildingsData::CBuildingData>();
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<Spatial>("%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);
}

View File

@@ -37,5 +37,6 @@ public:
template <class T> const T *get_as_node(const String &path) const;
Node *scene();
const Node *scene() const;
void create_layout_editor();
};
#endif

View File

@@ -1,3 +1,5 @@
#undef NDEBUG
#include <cassert>
#include <vector>
#include <algorithm>
#include <core/os/memory.h>
@@ -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<NPC>();
ecs.component<struct NPCBase>();
ecs.observer<NPCControl>()
.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<const BuildingsData::CBuildingData> query =
ecs.query_builder<const BuildingsData::CBuildingData>()
.with<BuildingsData::CBTypeResidental>()
.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<struct NPCResidence>();
ecs.component<struct NPCOccupation>();
ecs.component<struct NPCLeisure>();
ecs.observer<struct NPCSkeleton>()
.event(flecs::OnSet)
.with<struct NPCBase>()
.with<struct NPCLocation>()
.write<struct NPCNode>()
.each([](flecs::entity e, const NPCSkeleton &s) {
Ref<SkeletonData> skeleton_data;
String path = s.skeleton_path;
if (e.has<NPCNode>()) {
if (e.get<NPCNode>()->skeleton) {
e.get_mut<NPCNode>()
->skeleton
->queue_delete();
e.get_mut<NPCNode>()->skeleton =
nullptr;
e.remove<NPCNode>();
}
}
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<NPCNode>({ skeleton });
root->call_deferred("add_child",
skeleton);
} else
print_error(
"ERROR: Could not load skeleton: " +
path);
});
ecs.observer<struct NPCSkeleton>()
.event(flecs::OnRemove)
.write<struct NPCNode>()
.each([](flecs::entity e, const NPCSkeleton &s) {
if (e.has<NPCNode>()) {
if (e.get<NPCNode>()->skeleton) {
e.get_mut<NPCNode>()
->skeleton
->queue_delete();
e.get_mut<NPCNode>()->skeleton =
nullptr;
e.remove<NPCNode>();
}
}
});
/* moving NPC despawned NPC */
ecs.system<NPCBase>("Update").each(
[](flecs::entity e, NPCBase &b) {
// TODO: implement;
});
}
};
}
NPC::NPC()
void NPC::create()
{
flecs::world ecs = BaseData::get_singleton()->get();
ecs.import <NPCModule::module>();
@@ -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<NPCModule::NPCBase>())
ch.set<NPCModule::NPCBase>({ 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<flecs::entity_t> keep_components = {
ecs.component<NPCModule::NPCBase>()
};
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<int> *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<Variant> &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<Variant> &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

View File

@@ -1,23 +1,37 @@
#ifndef NPC_H_
#define NPC_H_
class ConfigFile;
class NPC {
static NPC *singleton;
NPC();
#include <flecs.h>
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<int> *character_list);
private:
void editor_event_handler(const String &event,
const Vector<Variant> &args);
void game_event_handler(const String &event,
const Vector<Variant> &args);
#endif
};
#endif

View File

@@ -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<BuildingLayoutEditor>();
ClassDB::register_class<MainTabs>();
ClassDB::register_class<SkeletonData>();
ClassDB::register_class<BuildingGridInstance>();
ClassDB::register_class<BuildingLayoutInstance>();
#ifdef TOOLS_ENABLED
ClassDB::APIType prev_api = ClassDB::get_current_api();
ClassDB::set_current_api(ClassDB::API_EDITOR);

View File

@@ -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<BuildingsData>();
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<Spatial>(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,8 +1306,7 @@ class EdgeEditorHandler {
String lot_id = side.lot_type;
if (side.buildings.size() > 1) {
const AABB &aabb_lot =
BuildingsData::get_singleton()
->building_aabbs
bd()->building_aabbs
["lot-" +
lot_id];
bool pack_result =
@@ -1372,8 +1375,7 @@ class EdgeEditorHandler {
String lot_id = side.lot_type;
if (side.buildings.size() > 1) {
const AABB &aabb_lot =
BuildingsData::get_singleton()
->building_aabbs
bd()->building_aabbs
["lot-" +
lot_id];
bool pack_result =

View File

@@ -487,6 +487,21 @@ struct LotPacker {
Vector<String> buildings;
float area;
};
inline BuildingsData *bd()
{
BuildingsData *ret = BaseData::get_singleton()
->get()
.get_mut<BuildingsData>();
assert(ret);
return ret;
}
const inline BuildingsData *bd() const
{
const BuildingsData *ret =
BaseData::get_singleton()->get().get<BuildingsData>();
assert(ret);
return ret;
}
Vector<struct config_buildings> 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<Lot>()->polygon.points.size() > 0);
List<String> buildings;
BuildingsData::get_singleton()
->get_building_keys_list(&buildings);
bd()->get_building_keys_list(&buildings);
List<String>::Element *be = buildings.front();
e.get_mut<Lot>()->polygon.update_aabb();
if (e.has<PreOccupied>())
@@ -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<String> &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<struct config_buildings> &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,

View File

@@ -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<Vector3> &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<BuildingsData>();
assert(ret);
return ret;
}
inline const BuildingsData *bd() const
{
const BuildingsData *ret =
BaseData::get_singleton()->get().get<BuildingsData>();
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<struct line_check> 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<struct wedge> &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<struct wedge> &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<String> line_keys;
List<String>::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<String> keys;
@@ -852,13 +483,13 @@ out_skip_end:;
->get()
.query_builder<Lot>()
.build()
.each([&](flecs::entity e, Lot &lot) {
.each([&](flecs::entity ev, Lot &lot) {
BaseData::get_singleton()
->get()
.query_builder<Lot>()
.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<Lot>()
.build()
.each([&](flecs::entity e, const Lot &lot) {
.each([&](flecs::entity em, const Lot &lot) {
List<Pair<AABB, String> > lot_data;
Lot::get_lot_data(e, &lot_data);
Lot::get_lot_data(em, &lot_data);
List<Pair<AABB, String> >::Element *lot_e =
lot_data.front();
int ccount = 0;
while (lot_e) {
Pair<AABB, String> 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<Lot>()
.build()
.each([&](flecs::entity e, const Lot &lot) {
.each([&](flecs::entity ev, const Lot &lot) {
List<Pair<AABB, String> > lot_data;
List<Transform> 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<Pair<AABB, String> >::Element *lot_e =
lot_data.front();
List<Transform>::Element *lotx_e =
@@ -955,7 +585,7 @@ out_skip_end:;
while (lot_e) {
Pair<AABB, String> 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>();
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<String, struct mesh_data> road_meshes;
MergeGroup *road_mgroup;
std::vector<MeshInstance *> 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<RoadLinesProcessing>();
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<RoadLinesProcessing>();
}
};
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<RoadLinesProcessing>();
BaseData::get_singleton()->get().ensure<RoadMeshProcessing>();
RoadLinesProcessing *r =
BaseData::get_singleton()->get().get_mut<RoadLinesProcessing>();
r->set_debug_flags(debug_flags);
r->road_setup();
BaseData::get_singleton()
->get()
.get_mut<RoadMeshProcessing>()
->create_road_meshes(target);
}
void RoadProcessing::remove_road_meshes(Node *target)
{
RoadMeshProcessing::get_singleton()->clear_road_meshes();
BaseData::get_singleton()
->get()
.get_mut<RoadMeshProcessing>()
->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",
BaseData::get_singleton()->get().ensure<RoadMeshProcessing>();
RoadMeshProcessing *rmp =
BaseData::get_singleton()->get().get_mut<RoadMeshProcessing>();
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"));
RoadMeshProcessing::get_singleton()->load_road_mesh(
"common", "sidewalk_start",
rmp->load_road_mesh("common", "sidewalk_start",
config.get_value("road", "sidewalk_start_mesh"));
RoadMeshProcessing::get_singleton()->load_road_mesh(
"common", "sidewalk_end",
rmp->load_road_mesh("common", "sidewalk_end",
config.get_value("road", "sidewalk_end_mesh"));
RoadMeshProcessing::get_singleton()->load_road_mesh(
"common", "sidewalk_sideroad",
rmp->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"));
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<RoadLinesProcessing>();
std::unordered_map<int, RoadLinesProcessing::edgedata>::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<RoadLinesProcessing>();
BaseData::get_singleton()->get().remove<RoadMeshProcessing>();
}

View File

@@ -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<BuildingsData>();
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);
@@ -124,7 +134,8 @@ void StreamWorld::update_view()
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<BuildingsData::CBuildingLoaded>())
eb.add<BuildingsData::CBuildingLoad>();
}
}
}
@@ -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<BuildingsData::CBuildingLoaded>())
eb.add<BuildingsData::CBuildingUnload>();
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<BuildingsData::CBuildingLoaded>())
eb.add<BuildingsData::CBuildingLoad>();
}
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<BuildingsData::CBuildingLoaded>())
eb.add<BuildingsData::CBuildingUnload>();
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<BuildingsData>();
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");
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 <NPC>();
flecs::entity npcctrl = BaseData::get_singleton()->get().entity();
npcctrl.set<NPC::NPCControl>({ NPC::NPCControl::CMD_PRESIM });
initialized = true;
}
void StreamWorld::cleanup()

View File

@@ -16,6 +16,7 @@ private:
VoxelLodTerrain *terrain;
Node *current_scene;
ConfigFile config;
#if 0
using tile_key_t = std::tuple<int, int>;
struct tile_hash : public std::unary_function<key_t, std::size_t> {
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();

View File

@@ -18,6 +18,14 @@
#include "signal_handler.h"
#include "terrain_editor.h"
static inline BuildingsData *bd()
{
BuildingsData *ret =
BaseData::get_singleton()->get().get_mut<BuildingsData>();
assert(ret);
return ret;
}
void TerrainEditor::exit()
{
if (active)
@@ -358,15 +366,13 @@ end:;
case 2001: {
List<String> building_keys;
List<String>::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:

View File

@@ -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());
}