Converted buildings loading to flecs
This commit is contained in:
11
Makefile
11
Makefile
@@ -2,8 +2,10 @@ ARCH=$(patsubst aarch64,arm64,$(shell uname -m))
|
|||||||
BLENDER = ../../blender-3.6.20-linux-x64/blender
|
BLENDER = ../../blender-3.6.20-linux-x64/blender
|
||||||
SERVER = src/godot/bin/godot_server.x11.opt.tools.$(ARCH)
|
SERVER = src/godot/bin/godot_server.x11.opt.tools.$(ARCH)
|
||||||
EDITOR_PLATFORM=x11es
|
EDITOR_PLATFORM=x11es
|
||||||
|
EDITOR2_PLATFORM=x11
|
||||||
DEMO_PLATFORMS=x11 x11es
|
DEMO_PLATFORMS=x11 x11es
|
||||||
EDITOR = src/godot/bin/godot.$(EDITOR_PLATFORM).opt.tools.$(ARCH)
|
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 \
|
.PHONY: all godot-editor-main export export-models export-clothes \
|
||||||
export-clean export-linux-demo export-windows-demo \
|
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-main: $(GODOT_MAIN_TARGETS) godot-editor-main godot-server-main
|
||||||
godot-server-main: $(SERVER)
|
godot-server-main: $(SERVER)
|
||||||
godot-editor-main: $(EDITOR)
|
godot-editor-main: $(EDITOR) $(EDITOR2)
|
||||||
$(SERVER): patch
|
#$(SERVER): patch
|
||||||
cd src/godot; \
|
# cd src/godot; \
|
||||||
scons platform=server arch=$(ARCH) target=release_debug tools=yes custom_modules=../modules -j16
|
# 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,server,release_debug,yes,$(SERVER),patch))
|
||||||
$(eval $(call build_godot,x11es,release_debug,yes,$(EDITOR),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
|
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
|
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
|
sed -e 's/ERR_FAIL_COND_V(-1 == p_task->root_bone, false);//g' -i ./src/godot/scene/animation/skeleton_ik.cpp
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ flags/repeat=true
|
|||||||
flags/filter=true
|
flags/filter=true
|
||||||
flags/mipmaps=true
|
flags/mipmaps=true
|
||||||
flags/anisotropic=false
|
flags/anisotropic=false
|
||||||
flags/srgb=2
|
flags/srgb=1
|
||||||
process/fix_alpha_border=true
|
process/fix_alpha_border=true
|
||||||
process/premult_alpha=false
|
process/premult_alpha=false
|
||||||
process/HDR_as_SRGB=false
|
process/HDR_as_SRGB=false
|
||||||
|
|||||||
@@ -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"]
|
[node name="2" type="Spatial" parent="LOD"]
|
||||||
visible = false
|
visible = false
|
||||||
|
|
||||||
|
[node name="BuildingLayoutInstance" type="BuildingLayoutInstance" parent="."]
|
||||||
|
size = 8
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ boot_splash/minimum_display_time=4
|
|||||||
|
|
||||||
settings/fps/force_fps=60
|
settings/fps/force_fps=60
|
||||||
|
|
||||||
|
[display]
|
||||||
|
|
||||||
|
window/vsync/use_vsync=false
|
||||||
|
|
||||||
[input]
|
[input]
|
||||||
|
|
||||||
forward={
|
forward={
|
||||||
@@ -87,5 +91,5 @@ portals/optimize/remove_danglers=false
|
|||||||
gles3/shaders/shader_compilation_mode=2
|
gles3/shaders/shader_compilation_mode=2
|
||||||
gles3/shaders/shader_compilation_mode.mobile=2
|
gles3/shaders/shader_compilation_mode.mobile=2
|
||||||
gles3/shaders/max_simultaneous_compiles=4
|
gles3/shaders/max_simultaneous_compiles=4
|
||||||
limits/buffers/immediate_buffer_size_kb=4096
|
|
||||||
limits/buffers/blend_shape_max_buffer_size_kb=8192
|
limits/buffers/blend_shape_max_buffer_size_kb=8192
|
||||||
|
limits/buffers/immediate_buffer_size_kb=4096
|
||||||
|
|||||||
20
src/modules/stream/building_grid_instance.cpp
Normal file
20
src/modules/stream/building_grid_instance.cpp
Normal 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()
|
||||||
|
{
|
||||||
|
}
|
||||||
17
src/modules/stream/building_grid_instance.h
Normal file
17
src/modules/stream/building_grid_instance.h
Normal 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_
|
||||||
97
src/modules/stream/buildings/building_layout_instance.cpp
Normal file
97
src/modules/stream/buildings/building_layout_instance.cpp
Normal 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>();
|
||||||
|
}
|
||||||
21
src/modules/stream/buildings/building_layout_instance.h
Normal file
21
src/modules/stream/buildings/building_layout_instance.h
Normal 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;
|
||||||
|
};
|
||||||
@@ -9,13 +9,14 @@
|
|||||||
#include <scene/resources/packed_scene.h>
|
#include <scene/resources/packed_scene.h>
|
||||||
#include <scene/3d/spatial.h>
|
#include <scene/3d/spatial.h>
|
||||||
#include <scene/3d/mesh_instance.h>
|
#include <scene/3d/mesh_instance.h>
|
||||||
|
#include <scene/3d/camera.h>
|
||||||
|
#include <scene/main/viewport.h>
|
||||||
#include "from_string.h"
|
#include "from_string.h"
|
||||||
#include "base_data.h"
|
#include "base_data.h"
|
||||||
#include "buildings_data.h"
|
#include "buildings_data.h"
|
||||||
|
|
||||||
BuildingsData *BuildingsData::singleton;
|
|
||||||
|
|
||||||
static ConfigFile config;
|
static ConfigFile config;
|
||||||
|
static ConfigFile custom_layouts;
|
||||||
struct scene_data {
|
struct scene_data {
|
||||||
Ref<PackedScene> packed_scene;
|
Ref<PackedScene> packed_scene;
|
||||||
String path;
|
String path;
|
||||||
@@ -42,43 +43,206 @@ struct CBuildingInstance {
|
|||||||
Node *node;
|
Node *node;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CBuildingData {
|
|
||||||
struct BuildingsData::building building;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CSceneData {
|
struct CSceneData {
|
||||||
struct scene_data sd;
|
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()
|
BuildingsData::BuildingsData()
|
||||||
: undo_log_size(64)
|
: 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();
|
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();
|
fill_door_locations();
|
||||||
build_building_aabbs();
|
build_building_aabbs();
|
||||||
ecs().observer<CBuildingInstance>()
|
ecs_.observer<CBuildingInstance>()
|
||||||
.event(flecs::OnRemove)
|
.event(flecs::OnRemove)
|
||||||
.each([](flecs::entity e, CBuildingInstance &bi) {
|
.each([](flecs::entity e, CBuildingInstance &bi) {
|
||||||
if (bi.node) {
|
if (bi.node) {
|
||||||
bi.node->queue_delete();
|
bi.node->queue_delete();
|
||||||
bi.node = nullptr;
|
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()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildingsData *BuildingsData::get_singleton()
|
|
||||||
{
|
|
||||||
if (!singleton)
|
|
||||||
singleton = memnew(BuildingsData);
|
|
||||||
|
|
||||||
return singleton;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuildingsData::build_building_aabbs()
|
void BuildingsData::build_building_aabbs()
|
||||||
{
|
{
|
||||||
building_aabbs.clear();
|
building_aabbs.clear();
|
||||||
@@ -130,14 +294,14 @@ bool BuildingsData::has_building(const String &key)
|
|||||||
String ename = "base:" + key;
|
String ename = "base:" + key;
|
||||||
flecs::entity e = lookup(ename.ascii().ptr());
|
flecs::entity e = lookup(ename.ascii().ptr());
|
||||||
if (!e.is_valid())
|
if (!e.is_valid())
|
||||||
print_line("no key: " + key);
|
print_verbose("no key: " + key);
|
||||||
else
|
else
|
||||||
print_line("has building with parent: " +
|
print_verbose("has building with parent: " +
|
||||||
String(e.parent().name()));
|
String(e.parent().name()));
|
||||||
return e.is_valid();
|
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;
|
float dst = Math_INF;
|
||||||
String rkey;
|
String rkey;
|
||||||
@@ -154,18 +318,30 @@ String BuildingsData::get_closest_building(const Transform &xform)
|
|||||||
});
|
});
|
||||||
return rkey;
|
return rkey;
|
||||||
}
|
}
|
||||||
|
flecs::entity
|
||||||
void BuildingsData::cleanup()
|
BuildingsData::get_closest_building_entity(const Transform &xform) const
|
||||||
{
|
{
|
||||||
if (singleton) {
|
float dst = Math_INF;
|
||||||
singleton->~BuildingsData();
|
String rkey;
|
||||||
Memory::free_static(singleton, false);
|
flecs::entity qe;
|
||||||
singleton = nullptr;
|
// 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)
|
void BuildingsData::read_buildings_json(const String &buildings_path)
|
||||||
{
|
{
|
||||||
|
assert(ecs().has<CBuildingStats>());
|
||||||
String buildings_json = FileAccess::get_file_as_string(buildings_path);
|
String buildings_json = FileAccess::get_file_as_string(buildings_path);
|
||||||
Variant json_v;
|
Variant json_v;
|
||||||
String es;
|
String es;
|
||||||
@@ -213,7 +389,7 @@ void BuildingsData::save_buildings_json(const String &buildings_path)
|
|||||||
fa->close();
|
fa->close();
|
||||||
Dictionary json;
|
Dictionary json;
|
||||||
int index = 0;
|
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;
|
String key = b.building.key;
|
||||||
/* do not save roadside generated stuff */
|
/* do not save roadside generated stuff */
|
||||||
if (!key.begins_with("road::") && !key.begins_with("road__")) {
|
if (!key.begins_with("road::") && !key.begins_with("road__")) {
|
||||||
@@ -321,6 +497,7 @@ void BuildingsData::filter_generated_stuff()
|
|||||||
|
|
||||||
void BuildingsData::load_data()
|
void BuildingsData::load_data()
|
||||||
{
|
{
|
||||||
|
assert(ecs().has<CBuildingStats>());
|
||||||
Error result = config.load("res://config/stream.conf");
|
Error result = config.load("res://config/stream.conf");
|
||||||
ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
|
ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
|
||||||
Dictionary buildings_data =
|
Dictionary buildings_data =
|
||||||
@@ -336,7 +513,7 @@ void BuildingsData::load_data()
|
|||||||
e = keys.front();
|
e = keys.front();
|
||||||
while (e) {
|
while (e) {
|
||||||
String key = e->get();
|
String key = e->get();
|
||||||
print_line(key + ": " + buildings_data[key]);
|
// print_line(key + ": " + buildings_data[key]);
|
||||||
e = e->next();
|
e = e->next();
|
||||||
}
|
}
|
||||||
String buildings_path = config.get_value("buildings", "buildings_path");
|
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();
|
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)
|
void BuildingsData::remove_scene_item(const String &key, const String &bkey)
|
||||||
{
|
{
|
||||||
flecs::entity e = ecs().lookup(key.ascii().ptr());
|
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>();
|
CSceneData *d = e.get_mut<CSceneData>();
|
||||||
assert(d);
|
assert(d);
|
||||||
String ename = "bi:" + bkey;
|
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());
|
flecs::entity ce = e.lookup(ename.ascii().ptr());
|
||||||
if (ce.is_valid())
|
if (ce.is_valid())
|
||||||
ce.destruct();
|
ce.destruct();
|
||||||
ce = ecs().entity(ename.ascii().ptr()).child_of(e);
|
ce = ecs().entity(ename.ascii().ptr()).child_of(e);
|
||||||
ce.set<CBuildingInstance>({ bkey, nullptr });
|
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)
|
void BuildingsData::create_scene_data(const String &key, const String &bkey)
|
||||||
{
|
{
|
||||||
if (!has_scene(key)) {
|
if (!has_scene(key)) {
|
||||||
flecs::entity e = ecs().entity(key.ascii().ptr());
|
flecs::entity e = ecs().entity(key.ascii().ptr());
|
||||||
|
// print_line("scene key: " + key);
|
||||||
|
assert(building_data.has(key));
|
||||||
String path = building_data[key];
|
String path = building_data[key];
|
||||||
|
// print_line("path: " + path);
|
||||||
assert(path.length() > 5);
|
assert(path.length() > 5);
|
||||||
print_line("Requesting " + (bkey) + " " + path);
|
print_line("Requesting " + (bkey) + " " + path);
|
||||||
|
assert(!pending_scene.has(path));
|
||||||
struct scene_data sd;
|
struct scene_data sd;
|
||||||
sd.path = path;
|
sd.path = path;
|
||||||
sd.loader = ResourceLoader::load_interactive(
|
sd.loader = ResourceLoader::load_interactive(
|
||||||
path, "PackedScene", true);
|
path, "PackedScene", true);
|
||||||
assert(sd.loader.is_valid());
|
assert(sd.loader.is_valid());
|
||||||
e.set<CSceneData>({ sd });
|
e.set<CSceneData>({ sd });
|
||||||
|
pending_scene.insert(path);
|
||||||
assert(e.get_mut<CSceneData>());
|
assert(e.get_mut<CSceneData>());
|
||||||
String ename = "bi:" + bkey;
|
String ename = "bi:" + bkey;
|
||||||
flecs::entity ce = e.lookup(ename.ascii().ptr());
|
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 = ecs().entity(ename.ascii().ptr());
|
||||||
ce.child_of(e);
|
ce.child_of(e);
|
||||||
ce.set<CBuildingInstance>({ bkey, nullptr });
|
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();
|
it.fini();
|
||||||
});
|
});
|
||||||
// assert(result == d->sd.buildings.size());
|
// assert(result == d->sd.buildings.size());
|
||||||
print_line("scene_get_item_count: " + itos(result));
|
// print_line("scene_get_item_count: " + itos(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
List<String> BuildingsData::scene_get_items(const String &key) const
|
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 =
|
flecs::query<const CBuildingData> q =
|
||||||
ecs().query<const CBuildingData>();
|
ecs().query<const CBuildingData>();
|
||||||
int result;
|
int result;
|
||||||
|
result = q.count();
|
||||||
|
#if 0
|
||||||
q.run([&result](flecs::iter &it) {
|
q.run([&result](flecs::iter &it) {
|
||||||
it.next();
|
it.next();
|
||||||
result = it.count();
|
result = it.count();
|
||||||
it.fini();
|
it.fini();
|
||||||
});
|
});
|
||||||
|
#endif
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -728,6 +926,7 @@ BuildingsData::get_building(const String &building_key)
|
|||||||
|
|
||||||
String BuildingsData::create_building(const Dictionary &dict)
|
String BuildingsData::create_building(const Dictionary &dict)
|
||||||
{
|
{
|
||||||
|
assert(ecs().has<CBuildingStats>());
|
||||||
struct building b;
|
struct building b;
|
||||||
building::from_dict(&b, dict);
|
building::from_dict(&b, dict);
|
||||||
return create_building(b);
|
return create_building(b);
|
||||||
@@ -736,13 +935,29 @@ String BuildingsData::create_building(const Dictionary &dict)
|
|||||||
String BuildingsData::create_building(const struct building &building)
|
String BuildingsData::create_building(const struct building &building)
|
||||||
{
|
{
|
||||||
assert(building.key.length() > 0);
|
assert(building.key.length() > 0);
|
||||||
|
assert(ecs().has<CBuildingStats>());
|
||||||
String ename = "base:" + building.key;
|
String ename = "base:" + building.key;
|
||||||
print_line("create_building: " + ename);
|
// print_line("create_building: " + ename);
|
||||||
flecs::entity e = ecs().lookup(ename.ascii().ptr());
|
flecs::entity e = ecs().lookup(ename.ascii().ptr());
|
||||||
assert(!e.is_valid());
|
assert(!e.is_valid());
|
||||||
e = ecs().entity(ename.ascii().ptr());
|
e = ecs().entity(ename.ascii().ptr());
|
||||||
e.set<CBuildingData>({ building });
|
|
||||||
assert(e.is_valid());
|
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");
|
print_line("create_building: " + ename + " created");
|
||||||
|
|
||||||
return building.key;
|
return building.key;
|
||||||
@@ -779,7 +994,7 @@ bool BuildingsData::destroy_building(const String &key)
|
|||||||
{
|
{
|
||||||
assert(key.length() > 0);
|
assert(key.length() > 0);
|
||||||
String ename = "base:" + key;
|
String ename = "base:" + key;
|
||||||
print_line("destroy_building: " + ename);
|
// print_line("destroy_building: " + ename);
|
||||||
flecs::entity e = ecs().lookup(ename.ascii().ptr());
|
flecs::entity e = ecs().lookup(ename.ascii().ptr());
|
||||||
assert(e.is_valid());
|
assert(e.is_valid());
|
||||||
e.destruct();
|
e.destruct();
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#ifndef BUILDINGS_DATA_H
|
#ifndef BUILDINGS_DATA_H
|
||||||
#define BUILFINGS_DATA_H
|
#define BUILFINGS_DATA_H
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <core/reference.h>
|
#include <core/reference.h>
|
||||||
|
#include <flecs.h>
|
||||||
class PackedScene;
|
class PackedScene;
|
||||||
class ResourceInteractiveLoader;
|
class ResourceInteractiveLoader;
|
||||||
class BuildingsData {
|
class BuildingsData {
|
||||||
@@ -21,10 +23,49 @@ public:
|
|||||||
Dictionary to_dict() const;
|
Dictionary to_dict() const;
|
||||||
String line_name;
|
String line_name;
|
||||||
};
|
};
|
||||||
|
Set<String> pending_scene;
|
||||||
/* Scene objects data */
|
/* Scene objects data */
|
||||||
//private:
|
//private:
|
||||||
// HashMap<String, struct scene_data> scenes;
|
// 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:
|
public:
|
||||||
void get_scene_keys_list(List<String> *keys) const;
|
void get_scene_keys_list(List<String> *keys) const;
|
||||||
bool has_scene(const String &key) const;
|
bool has_scene(const String &key) const;
|
||||||
@@ -113,7 +154,6 @@ public:
|
|||||||
int undo_log_size;
|
int undo_log_size;
|
||||||
BuildingsData();
|
BuildingsData();
|
||||||
virtual ~BuildingsData();
|
virtual ~BuildingsData();
|
||||||
static BuildingsData *singleton;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void read_buildings_json(const String &buildings_path);
|
void read_buildings_json(const String &buildings_path);
|
||||||
@@ -128,8 +168,9 @@ public:
|
|||||||
void update_building_transform(const String &key,
|
void update_building_transform(const String &key,
|
||||||
const Transform &xform);
|
const Transform &xform);
|
||||||
bool has_building(const String &key);
|
bool has_building(const String &key);
|
||||||
String get_closest_building(const Transform &xform);
|
String get_closest_building(const Transform &xform) const;
|
||||||
static BuildingsData *get_singleton();
|
flecs::entity get_closest_building_entity(const Transform &xform) const;
|
||||||
static void cleanup();
|
flecs::entity get_building_entity(const String &key) const;
|
||||||
|
void load_tile(int x, int z);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
@@ -67,6 +67,8 @@ void BuildingsEditor::event_handler(const String &event,
|
|||||||
handle_create_building();
|
handle_create_building();
|
||||||
else if (event == "button:delete_building")
|
else if (event == "button:delete_building")
|
||||||
delete_building_handler();
|
delete_building_handler();
|
||||||
|
else if (event == "button:edit_layout")
|
||||||
|
create_layout_editor();
|
||||||
else if (event == "result:get_closest_building") {
|
else if (event == "result:get_closest_building") {
|
||||||
select_building(args[0], args[3], args[4]);
|
select_building(args[0], args[3], args[4]);
|
||||||
if (get_buildings_editor_mode() == 2 /* rotate */) {
|
if (get_buildings_editor_mode() == 2 /* rotate */) {
|
||||||
@@ -249,8 +251,26 @@ void BuildingsEditor::mouse_press(const Vector2 &position)
|
|||||||
case 0: {
|
case 0: {
|
||||||
/* select */
|
/* select */
|
||||||
Transform xform(Basis(), proj);
|
Transform xform(Basis(), proj);
|
||||||
editor->editor_command("get_closest_building",
|
flecs::entity e =
|
||||||
varray(xform));
|
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;
|
} break;
|
||||||
case 1: {
|
case 1: {
|
||||||
/* move */
|
/* move */
|
||||||
@@ -417,3 +437,8 @@ const Node *BuildingsEditor::scene() const
|
|||||||
const Node *ret = editor->get_tree()->get_current_scene();
|
const Node *ret = editor->get_tree()->get_current_scene();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BuildingsEditor::create_layout_editor()
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,5 +37,6 @@ public:
|
|||||||
template <class T> const T *get_as_node(const String &path) const;
|
template <class T> const T *get_as_node(const String &path) const;
|
||||||
Node *scene();
|
Node *scene();
|
||||||
const Node *scene() const;
|
const Node *scene() const;
|
||||||
|
void create_layout_editor();
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#undef NDEBUG
|
||||||
|
#include <cassert>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <core/os/memory.h>
|
#include <core/os/memory.h>
|
||||||
@@ -14,8 +16,61 @@
|
|||||||
#include "editor_event.h"
|
#include "editor_event.h"
|
||||||
#include "game_event.h"
|
#include "game_event.h"
|
||||||
#include "persistent_data.h"
|
#include "persistent_data.h"
|
||||||
|
#include "buildings_data.h"
|
||||||
#include "npc.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 {
|
class NPCSaveData : public PersistentData::SaveHandler {
|
||||||
public:
|
public:
|
||||||
NPC *npc;
|
NPC *npc;
|
||||||
@@ -39,58 +94,6 @@ struct NPCBase {
|
|||||||
int id;
|
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 {
|
struct module {
|
||||||
module(flecs::world &ecs)
|
module(flecs::world &ecs)
|
||||||
{
|
{
|
||||||
@@ -105,70 +108,12 @@ struct module {
|
|||||||
ecs.component<struct NPCResidence>();
|
ecs.component<struct NPCResidence>();
|
||||||
ecs.component<struct NPCOccupation>();
|
ecs.component<struct NPCOccupation>();
|
||||||
ecs.component<struct NPCLeisure>();
|
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();
|
flecs::world ecs = BaseData::get_singleton()->get();
|
||||||
ecs.import <NPCModule::module>();
|
ecs.import <NPCModule::module>();
|
||||||
@@ -176,10 +121,12 @@ NPC::NPC()
|
|||||||
if (base.is_valid()) {
|
if (base.is_valid()) {
|
||||||
/* create components for top level */
|
/* create components for top level */
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
EditorEvent::get_singleton()->event.add_listener(
|
EditorEvent::get_singleton()->event.add_listener(
|
||||||
this, &NPC::editor_event_handler);
|
this, &NPC::editor_event_handler);
|
||||||
GameEvent::get_singleton()->event.add_listener(
|
GameEvent::get_singleton()->event.add_listener(
|
||||||
this, &NPC::game_event_handler);
|
this, &NPC::game_event_handler);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
NPC *NPC::get_singleton()
|
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)
|
void NPC::editor_event_handler(const String &event, const Vector<Variant> &args)
|
||||||
{
|
{
|
||||||
if (event == "npc_foreground") {
|
/* not implemented */
|
||||||
int npc_id = args[0];
|
|
||||||
foreground_character(npc_id);
|
|
||||||
} else if (event == "npc_background") {
|
|
||||||
int npc_id = args[0];
|
|
||||||
background_character(npc_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NPC::game_event_handler(const String &event, const Vector<Variant> &args)
|
void NPC::game_event_handler(const String &event, const Vector<Variant> &args)
|
||||||
{
|
{
|
||||||
if (event == "npc_foreground") {
|
/* not implemented */
|
||||||
int npc_id = args[0];
|
|
||||||
foreground_character(npc_id);
|
|
||||||
} else if (event == "npc_background") {
|
|
||||||
int npc_id = args[0];
|
|
||||||
background_character(npc_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
@@ -1,23 +1,37 @@
|
|||||||
#ifndef NPC_H_
|
#ifndef NPC_H_
|
||||||
#define NPC_H_
|
#define NPC_H_
|
||||||
class ConfigFile;
|
#include <flecs.h>
|
||||||
class NPC {
|
struct NPC {
|
||||||
static NPC *singleton;
|
NPC(flecs::world &ecs);
|
||||||
NPC();
|
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:
|
public:
|
||||||
static NPC *get_singleton();
|
static void create();
|
||||||
static void cleanup();
|
static void cleanup();
|
||||||
virtual ~NPC();
|
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:
|
private:
|
||||||
void editor_event_handler(const String &event,
|
void editor_event_handler(const String &event,
|
||||||
const Vector<Variant> &args);
|
const Vector<Variant> &args);
|
||||||
void game_event_handler(const String &event,
|
void game_event_handler(const String &event,
|
||||||
const Vector<Variant> &args);
|
const Vector<Variant> &args);
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
@@ -10,6 +10,8 @@
|
|||||||
#include "npc/importer.h"
|
#include "npc/importer.h"
|
||||||
#include "npc/skeleton_data.h"
|
#include "npc/skeleton_data.h"
|
||||||
#include "base_data.h"
|
#include "base_data.h"
|
||||||
|
#include "building_grid_instance.h"
|
||||||
|
#include "buildings/building_layout_instance.h"
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
static void _editor_init()
|
static void _editor_init()
|
||||||
@@ -30,6 +32,8 @@ void register_stream_types()
|
|||||||
ClassDB::register_class<BuildingLayoutEditor>();
|
ClassDB::register_class<BuildingLayoutEditor>();
|
||||||
ClassDB::register_class<MainTabs>();
|
ClassDB::register_class<MainTabs>();
|
||||||
ClassDB::register_class<SkeletonData>();
|
ClassDB::register_class<SkeletonData>();
|
||||||
|
ClassDB::register_class<BuildingGridInstance>();
|
||||||
|
ClassDB::register_class<BuildingLayoutInstance>();
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
ClassDB::APIType prev_api = ClassDB::get_current_api();
|
ClassDB::APIType prev_api = ClassDB::get_current_api();
|
||||||
ClassDB::set_current_api(ClassDB::API_EDITOR);
|
ClassDB::set_current_api(ClassDB::API_EDITOR);
|
||||||
|
|||||||
@@ -431,15 +431,20 @@ void RoadLinesEditor::move_cursor_to_point()
|
|||||||
set_ui_cursor_position(xform.origin);
|
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()
|
void RoadLinesEditor::move_cursor_to_closest_building()
|
||||||
{
|
{
|
||||||
print_line("move_cursor_to_closest_building");
|
print_line("move_cursor_to_closest_building");
|
||||||
Vector3 pt = get_cursor_position();
|
Vector3 pt = get_cursor_position();
|
||||||
const String &key =
|
const String &key = bd()->get_closest_building(Transform(Basis(), pt));
|
||||||
BuildingsData::get_singleton()->get_closest_building(
|
const Transform &xform = bd()->get_building(key).xform;
|
||||||
Transform(Basis(), pt));
|
|
||||||
const Transform &xform =
|
|
||||||
BuildingsData::get_singleton()->get_building(key).xform;
|
|
||||||
set_cursor_position(xform.origin);
|
set_cursor_position(xform.origin);
|
||||||
Spatial *cursor = get_as_node<Spatial>(cursor_name);
|
Spatial *cursor = get_as_node<Spatial>(cursor_name);
|
||||||
if (!cursor->is_visible())
|
if (!cursor->is_visible())
|
||||||
@@ -1120,8 +1125,7 @@ class EdgeEditorHandler {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const AABB &aabb_building =
|
const AABB &aabb_building =
|
||||||
BuildingsData::get_singleton()
|
bd()->building_aabbs[buildings[i].id];
|
||||||
->building_aabbs[buildings[i].id];
|
|
||||||
Transform building_rot(
|
Transform building_rot(
|
||||||
Basis().rotated(
|
Basis().rotated(
|
||||||
Vector3(0, 1, 0),
|
Vector3(0, 1, 0),
|
||||||
@@ -1302,10 +1306,9 @@ class EdgeEditorHandler {
|
|||||||
String lot_id = side.lot_type;
|
String lot_id = side.lot_type;
|
||||||
if (side.buildings.size() > 1) {
|
if (side.buildings.size() > 1) {
|
||||||
const AABB &aabb_lot =
|
const AABB &aabb_lot =
|
||||||
BuildingsData::get_singleton()
|
bd()->building_aabbs
|
||||||
->building_aabbs
|
["lot-" +
|
||||||
["lot-" +
|
lot_id];
|
||||||
lot_id];
|
|
||||||
bool pack_result =
|
bool pack_result =
|
||||||
pack_buildings(
|
pack_buildings(
|
||||||
aabb_lot,
|
aabb_lot,
|
||||||
@@ -1372,10 +1375,9 @@ class EdgeEditorHandler {
|
|||||||
String lot_id = side.lot_type;
|
String lot_id = side.lot_type;
|
||||||
if (side.buildings.size() > 1) {
|
if (side.buildings.size() > 1) {
|
||||||
const AABB &aabb_lot =
|
const AABB &aabb_lot =
|
||||||
BuildingsData::get_singleton()
|
bd()->building_aabbs
|
||||||
->building_aabbs
|
["lot-" +
|
||||||
["lot-" +
|
lot_id];
|
||||||
lot_id];
|
|
||||||
bool pack_result =
|
bool pack_result =
|
||||||
pack_buildings(
|
pack_buildings(
|
||||||
aabb_lot,
|
aabb_lot,
|
||||||
|
|||||||
@@ -487,6 +487,21 @@ struct LotPacker {
|
|||||||
Vector<String> buildings;
|
Vector<String> buildings;
|
||||||
float area;
|
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,
|
Vector<struct config_buildings> lot_buildings_residental,
|
||||||
lot_buildings_commercial, lot_buildings_industrial;
|
lot_buildings_commercial, lot_buildings_industrial;
|
||||||
void get_building_list(const String &varname,
|
void get_building_list(const String &varname,
|
||||||
@@ -502,8 +517,7 @@ struct LotPacker {
|
|||||||
for (j = 0; j < entries.size(); j++) {
|
for (j = 0; j < entries.size(); j++) {
|
||||||
String bname = entries[j];
|
String bname = entries[j];
|
||||||
cb.buildings.push_back(bname);
|
cb.buildings.push_back(bname);
|
||||||
AABB aabb = BuildingsData::get_singleton()
|
AABB aabb = get_building_type_aabb(bname);
|
||||||
->building_aabbs[bname];
|
|
||||||
cb.area += aabb.size.x * aabb.size.z;
|
cb.area += aabb.size.x * aabb.size.z;
|
||||||
print_line("config building: " + bname);
|
print_line("config building: " + bname);
|
||||||
}
|
}
|
||||||
@@ -826,18 +840,22 @@ out_bad:
|
|||||||
}
|
}
|
||||||
bool tmp_found = false;
|
bool tmp_found = false;
|
||||||
int office_count = 0;
|
int office_count = 0;
|
||||||
AABB get_building_aabb(const String &key)
|
AABB get_building_aabb(const String &key) const
|
||||||
{
|
{
|
||||||
const struct BuildingsData::building &b =
|
const struct BuildingsData::building &b =
|
||||||
BuildingsData::get_singleton()->get_building(key);
|
bd()->get_building(key);
|
||||||
const AABB &building_aabb =
|
const AABB &building_aabb = bd()->building_aabbs[b.id];
|
||||||
BuildingsData::get_singleton()->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;
|
return building_aabb;
|
||||||
}
|
}
|
||||||
Transform get_building_transform(const String &key)
|
Transform get_building_transform(const String &key)
|
||||||
{
|
{
|
||||||
const struct BuildingsData::building &b =
|
const struct BuildingsData::building &b =
|
||||||
BuildingsData::get_singleton()->get_building(key);
|
bd()->get_building(key);
|
||||||
return b.xform;
|
return b.xform;
|
||||||
}
|
}
|
||||||
AABB get_aabb_transformed(const String &key)
|
AABB get_aabb_transformed(const String &key)
|
||||||
@@ -863,8 +881,7 @@ out_bad:
|
|||||||
.each([&](flecs::entity e, Lot &lot_) {
|
.each([&](flecs::entity e, Lot &lot_) {
|
||||||
assert(e.get<Lot>()->polygon.points.size() > 0);
|
assert(e.get<Lot>()->polygon.points.size() > 0);
|
||||||
List<String> buildings;
|
List<String> buildings;
|
||||||
BuildingsData::get_singleton()
|
bd()->get_building_keys_list(&buildings);
|
||||||
->get_building_keys_list(&buildings);
|
|
||||||
List<String>::Element *be = buildings.front();
|
List<String>::Element *be = buildings.front();
|
||||||
e.get_mut<Lot>()->polygon.update_aabb();
|
e.get_mut<Lot>()->polygon.update_aabb();
|
||||||
if (e.has<PreOccupied>())
|
if (e.has<PreOccupied>())
|
||||||
@@ -872,8 +889,7 @@ out_bad:
|
|||||||
while (be) {
|
while (be) {
|
||||||
const String &key = be->get();
|
const String &key = be->get();
|
||||||
const struct BuildingsData::building &b =
|
const struct BuildingsData::building &b =
|
||||||
BuildingsData::get_singleton()
|
bd()->get_building(key);
|
||||||
->get_building(key);
|
|
||||||
if (key.begins_with("road__")) {
|
if (key.begins_with("road__")) {
|
||||||
be = be->next();
|
be = be->next();
|
||||||
continue;
|
continue;
|
||||||
@@ -935,8 +951,7 @@ out_bad:
|
|||||||
lb.buildings[i];
|
lb.buildings[i];
|
||||||
const String &key = mp.second;
|
const String &key = mp.second;
|
||||||
const struct BuildingsData::building &b =
|
const struct BuildingsData::building &b =
|
||||||
BuildingsData::get_singleton()
|
bd()->get_building(key);
|
||||||
->get_building(key);
|
|
||||||
Rect2 building_rect =
|
Rect2 building_rect =
|
||||||
get_rect_transformed(key);
|
get_rect_transformed(key);
|
||||||
Rect2 lot_rect =
|
Rect2 lot_rect =
|
||||||
@@ -1096,19 +1111,19 @@ out_bad:
|
|||||||
lot.polygon.update_aabb();
|
lot.polygon.update_aabb();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
float get_required_area(const Vector<String> &buildings) const
|
float get_required_area(const Vector<String> &buildings) const
|
||||||
{
|
{
|
||||||
float ret = 0.0f;
|
float ret = 0.0f;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < (int)buildings.size(); i++) {
|
for (i = 0; i < (int)buildings.size(); i++) {
|
||||||
const String &building = buildings[i];
|
const String &building = buildings[i];
|
||||||
const AABB &building_aabb =
|
const AABB &building_aabb = get_building_aabb(building);
|
||||||
BuildingsData::get_singleton()
|
|
||||||
->building_aabbs[building];
|
|
||||||
ret += building_aabb.size.x * building_aabb.size.z;
|
ret += building_aabb.size.x * building_aabb.size.z;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
int get_selected_building(const Lot &lot,
|
int get_selected_building(const Lot &lot,
|
||||||
Vector<struct config_buildings> &lbs)
|
Vector<struct config_buildings> &lbs)
|
||||||
{
|
{
|
||||||
@@ -1200,9 +1215,8 @@ out_bad:
|
|||||||
const String &building =
|
const String &building =
|
||||||
buildings[i];
|
buildings[i];
|
||||||
const AABB &building_aabb =
|
const AABB &building_aabb =
|
||||||
BuildingsData::get_singleton()
|
get_building_type_aabb(
|
||||||
->building_aabbs
|
building);
|
||||||
[building];
|
|
||||||
AABB result = pack_item(
|
AABB result = pack_item(
|
||||||
e,
|
e,
|
||||||
building_aabb,
|
building_aabb,
|
||||||
|
|||||||
@@ -86,22 +86,27 @@ struct RoadLinesProcessing {
|
|||||||
String road_center_mesh_path, road_mid_mesh_path,
|
String road_center_mesh_path, road_mid_mesh_path,
|
||||||
road_sidewalk_mesh_path;
|
road_sidewalk_mesh_path;
|
||||||
int debug_flags;
|
int debug_flags;
|
||||||
static struct RoadLinesProcessing *singleton;
|
|
||||||
static RoadLinesProcessing *get_singleton()
|
|
||||||
{
|
|
||||||
if (!singleton)
|
|
||||||
singleton = memnew(RoadLinesProcessing);
|
|
||||||
return singleton;
|
|
||||||
}
|
|
||||||
DebugGeo *dbg;
|
DebugGeo *dbg;
|
||||||
ConfigFile config;
|
static ConfigFile config;
|
||||||
RoadLinesProcessing()
|
RoadLinesProcessing()
|
||||||
: dbg(nullptr)
|
: dbg(nullptr)
|
||||||
{
|
{
|
||||||
singleton = this;
|
|
||||||
Error err = config.load("res://config/stream.conf");
|
Error err = config.load("res://config/stream.conf");
|
||||||
assert(err == OK);
|
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)
|
void create_nodes(const std::vector<Vector3> &road_lines_nodes)
|
||||||
{
|
{
|
||||||
@@ -125,23 +130,37 @@ struct RoadLinesProcessing {
|
|||||||
xform = xform * rot;
|
xform = xform * rot;
|
||||||
return xform;
|
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)
|
void create_building_structure(const BuildingsData::building &b)
|
||||||
{
|
{
|
||||||
assert(b.key.begins_with("road__"));
|
assert(b.key.begins_with("road__"));
|
||||||
assert(b.id.length() > 0);
|
assert(b.id.length() > 0);
|
||||||
assert(b.key.length() > 0);
|
assert(b.key.length() > 0);
|
||||||
if (BuildingsData::get_singleton()->has_building(b.key)) {
|
if (bd()->has_building(b.key)) {
|
||||||
BuildingsData::get_singleton()->remove_scene_item(
|
bd()->remove_scene_item(b.id, b.key);
|
||||||
b.id, b.key);
|
bd()->destroy_building(b.key);
|
||||||
BuildingsData::get_singleton()->destroy_building(b.key);
|
|
||||||
}
|
}
|
||||||
BuildingsData::get_singleton()->create_building(b);
|
bd()->create_building(b);
|
||||||
if (!BuildingsData::get_singleton()->has_scene(b.id))
|
if (!bd()->has_scene(b.id))
|
||||||
BuildingsData::get_singleton()->create_scene_data(
|
bd()->create_scene_data(b.id, b.key);
|
||||||
b.id, b.key);
|
|
||||||
else
|
else
|
||||||
BuildingsData::get_singleton()->add_scene_item(b.id,
|
bd()->add_scene_item(b.id, b.key);
|
||||||
b.key);
|
|
||||||
print_line("created building: " + b.key + " " + b.id);
|
print_line("created building: " + b.key + " " + b.id);
|
||||||
print_line("at: " + (b.xform.origin.operator String()));
|
print_line("at: " + (b.xform.origin.operator String()));
|
||||||
print_line("created ok");
|
print_line("created ok");
|
||||||
@@ -414,394 +433,6 @@ out2:;
|
|||||||
/* FIXME: need to generate lots from wedges, not lines (because intersections)
|
/* 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 join lots on the same line segment if they are adjacent and of similar depth
|
||||||
and not too narrow */
|
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()
|
void create_structures()
|
||||||
{
|
{
|
||||||
List<String> keys;
|
List<String> keys;
|
||||||
@@ -852,13 +483,13 @@ out_skip_end:;
|
|||||||
->get()
|
->get()
|
||||||
.query_builder<Lot>()
|
.query_builder<Lot>()
|
||||||
.build()
|
.build()
|
||||||
.each([&](flecs::entity e, Lot &lot) {
|
.each([&](flecs::entity ev, Lot &lot) {
|
||||||
BaseData::get_singleton()
|
BaseData::get_singleton()
|
||||||
->get()
|
->get()
|
||||||
.query_builder<Lot>()
|
.query_builder<Lot>()
|
||||||
.build()
|
.build()
|
||||||
.each([&](flecs::entity we, Lot &wlot) {
|
.each([&](flecs::entity we, Lot &wlot) {
|
||||||
if (e != we) {
|
if (ev != we) {
|
||||||
lot.polygon
|
lot.polygon
|
||||||
.update_aabb();
|
.update_aabb();
|
||||||
wlot.polygon
|
wlot.polygon
|
||||||
@@ -868,7 +499,7 @@ out_skip_end:;
|
|||||||
.length() >
|
.length() >
|
||||||
100000.0f *
|
100000.0f *
|
||||||
1000000.0f)
|
1000000.0f)
|
||||||
e.destruct();
|
ev.destruct();
|
||||||
else if (wlot.polygon
|
else if (wlot.polygon
|
||||||
.aabb
|
.aabb
|
||||||
.size
|
.size
|
||||||
@@ -890,7 +521,7 @@ out_skip_end:;
|
|||||||
.area())
|
.area())
|
||||||
we.destruct();
|
we.destruct();
|
||||||
else
|
else
|
||||||
e.destruct();
|
ev.destruct();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -899,12 +530,11 @@ out_skip_end:;
|
|||||||
->get()
|
->get()
|
||||||
.query_builder<Lot>()
|
.query_builder<Lot>()
|
||||||
.build()
|
.build()
|
||||||
.each([&](flecs::entity e, const Lot &lot) {
|
.each([&](flecs::entity em, const Lot &lot) {
|
||||||
List<Pair<AABB, String> > lot_data;
|
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 =
|
List<Pair<AABB, String> >::Element *lot_e =
|
||||||
lot_data.front();
|
lot_data.front();
|
||||||
int ccount = 0;
|
|
||||||
while (lot_e) {
|
while (lot_e) {
|
||||||
Pair<AABB, String> data = lot_e->get();
|
Pair<AABB, String> data = lot_e->get();
|
||||||
Vector3 center = data.first.position;
|
Vector3 center = data.first.position;
|
||||||
@@ -924,8 +554,8 @@ out_skip_end:;
|
|||||||
data.first.
|
data.first.
|
||||||
operator String());
|
operator String());
|
||||||
for (j = 0;
|
for (j = 0;
|
||||||
j <
|
j < (int)lot.polygon.points
|
||||||
lot.polygon.points.size();
|
.size();
|
||||||
j++)
|
j++)
|
||||||
print_line(
|
print_line(
|
||||||
"polygon: " +
|
"polygon: " +
|
||||||
@@ -942,11 +572,11 @@ out_skip_end:;
|
|||||||
->get()
|
->get()
|
||||||
.query_builder<Lot>()
|
.query_builder<Lot>()
|
||||||
.build()
|
.build()
|
||||||
.each([&](flecs::entity e, const Lot &lot) {
|
.each([&](flecs::entity ev, const Lot &lot) {
|
||||||
List<Pair<AABB, String> > lot_data;
|
List<Pair<AABB, String> > lot_data;
|
||||||
List<Transform> lot_xform;
|
List<Transform> lot_xform;
|
||||||
Lot::get_lot_data(e, &lot_data);
|
Lot::get_lot_data(ev, &lot_data);
|
||||||
Lot::get_lot_rotations(e, &lot_xform);
|
Lot::get_lot_rotations(ev, &lot_xform);
|
||||||
List<Pair<AABB, String> >::Element *lot_e =
|
List<Pair<AABB, String> >::Element *lot_e =
|
||||||
lot_data.front();
|
lot_data.front();
|
||||||
List<Transform>::Element *lotx_e =
|
List<Transform>::Element *lotx_e =
|
||||||
@@ -955,7 +585,7 @@ out_skip_end:;
|
|||||||
while (lot_e) {
|
while (lot_e) {
|
||||||
Pair<AABB, String> data = lot_e->get();
|
Pair<AABB, String> data = lot_e->get();
|
||||||
String key = "road__lot__" +
|
String key = "road__lot__" +
|
||||||
String(e.path()) + "_" +
|
String(ev.path()) + "_" +
|
||||||
itos(ccount);
|
itos(ccount);
|
||||||
key = key.replace("#", "_");
|
key = key.replace("#", "_");
|
||||||
BuildingsData::building b;
|
BuildingsData::building b;
|
||||||
@@ -1290,7 +920,8 @@ out_skip_end:;
|
|||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
Contours *contours = Contours::get_singleton();
|
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)
|
if (r->nodes.size() == 0)
|
||||||
return;
|
return;
|
||||||
struct wedge_data {
|
struct wedge_data {
|
||||||
@@ -1393,13 +1024,6 @@ out_skip_end:;
|
|||||||
~RoadLinesProcessing()
|
~RoadLinesProcessing()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
static void cleanup()
|
|
||||||
{
|
|
||||||
if (singleton) {
|
|
||||||
memfree(singleton);
|
|
||||||
singleton = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void set_debug_flags(int debug_flags)
|
void set_debug_flags(int debug_flags)
|
||||||
{
|
{
|
||||||
this->debug_flags = debug_flags;
|
this->debug_flags = debug_flags;
|
||||||
@@ -1490,11 +1114,11 @@ out_skip_end:;
|
|||||||
}
|
}
|
||||||
d->end();
|
d->end();
|
||||||
}
|
}
|
||||||
RoadLinesProcessing::get_singleton()->create_structures();
|
create_structures();
|
||||||
print_line("ROAD SETUP DONE");
|
print_line("ROAD SETUP DONE");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
RoadLinesProcessing *RoadLinesProcessing::singleton;
|
ConfigFile RoadLinesProcessing::config;
|
||||||
|
|
||||||
class RoadMeshProcessing {
|
class RoadMeshProcessing {
|
||||||
struct mesh_data {
|
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;
|
HashMap<String, struct mesh_data> road_meshes;
|
||||||
MergeGroup *road_mgroup;
|
MergeGroup *road_mgroup;
|
||||||
std::vector<MeshInstance *> nodes_mi;
|
std::vector<MeshInstance *> nodes_mi;
|
||||||
|
|
||||||
public:
|
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,
|
void load_road_mesh(const String &category, const String &name,
|
||||||
const String &path)
|
const String &path)
|
||||||
{
|
{
|
||||||
@@ -1542,10 +1196,6 @@ public:
|
|||||||
}
|
}
|
||||||
road_meshes[category + "/" + name] = md;
|
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)
|
void get_paths(struct wedge_paths &paths, const struct wedge &w)
|
||||||
{
|
{
|
||||||
Vector3 p1 = w.y[0] - w.y[1];
|
Vector3 p1 = w.y[0] - w.y[1];
|
||||||
@@ -1561,16 +1211,6 @@ public:
|
|||||||
paths.path2[1] = p2a;
|
paths.path2[1] = p2a;
|
||||||
paths.path2[2] = p3a;
|
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
|
* @brief transform mesh segment using start rotation @xform1
|
||||||
* ane end rotation @xform2
|
* ane end rotation @xform2
|
||||||
@@ -1599,9 +1239,11 @@ public:
|
|||||||
assert(vertices.size() > 0);
|
assert(vertices.size() > 0);
|
||||||
assert(indices.size() > 0);
|
assert(indices.size() > 0);
|
||||||
float dlen = xform1.origin.distance_to(xform2.origin);
|
float dlen = xform1.origin.distance_to(xform2.origin);
|
||||||
|
#if 0
|
||||||
float offt = 0.0f;
|
float offt = 0.0f;
|
||||||
if (dlen > start_offset)
|
if (dlen > start_offset)
|
||||||
offt = start_offset;
|
offt = start_offset;
|
||||||
|
#endif
|
||||||
int id;
|
int id;
|
||||||
Vector3 dir = xform2.origin - xform1.origin;
|
Vector3 dir = xform2.origin - xform1.origin;
|
||||||
dir = dir.normalized();
|
dir = dir.normalized();
|
||||||
@@ -2004,7 +1646,9 @@ public:
|
|||||||
assert(out_surfaces[h].size() >=
|
assert(out_surfaces[h].size() >=
|
||||||
ArrayMesh::ARRAY_MAX);
|
ArrayMesh::ARRAY_MAX);
|
||||||
float sideroad_l = 3.0f;
|
float sideroad_l = 3.0f;
|
||||||
|
#if 0
|
||||||
float lot_depth1 = mside1.lot_depth;
|
float lot_depth1 = mside1.lot_depth;
|
||||||
|
#endif
|
||||||
if (k == params.nlanes &&
|
if (k == params.nlanes &&
|
||||||
mside1.lot > 0) { /* sidewalk */
|
mside1.lot > 0) { /* sidewalk */
|
||||||
Vector3 dir = lanes[k].xform_m1.origin -
|
Vector3 dir = lanes[k].xform_m1.origin -
|
||||||
@@ -2197,7 +1841,10 @@ public:
|
|||||||
void create_road_meshes(Node *base)
|
void create_road_meshes(Node *base)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
RoadLinesProcessing *r = RoadLinesProcessing::get_singleton();
|
RoadLinesProcessing *r =
|
||||||
|
BaseData::get_singleton()
|
||||||
|
->get()
|
||||||
|
.get_mut<RoadLinesProcessing>();
|
||||||
clear_road_meshes();
|
clear_road_meshes();
|
||||||
road_mgroup = memnew(MergeGroup);
|
road_mgroup = memnew(MergeGroup);
|
||||||
road_mgroup->set_param(MergeGroup::PARAM_GROUP_SIZE, 16);
|
road_mgroup->set_param(MergeGroup::PARAM_GROUP_SIZE, 16);
|
||||||
@@ -2217,38 +1864,33 @@ public:
|
|||||||
nodes_mi.push_back(mi);
|
nodes_mi.push_back(mi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static RoadMeshProcessing *singleton;
|
|
||||||
static RoadMeshProcessing *get_singleton()
|
|
||||||
{
|
|
||||||
if (!singleton)
|
|
||||||
singleton = memnew(RoadMeshProcessing);
|
|
||||||
return singleton;
|
|
||||||
}
|
|
||||||
RoadMeshProcessing()
|
RoadMeshProcessing()
|
||||||
: road_mgroup(nullptr)
|
: road_mgroup(nullptr)
|
||||||
{
|
{
|
||||||
singleton = this;
|
BaseData::get_singleton()->get().ensure<RoadLinesProcessing>();
|
||||||
}
|
|
||||||
static void cleanup()
|
|
||||||
{
|
|
||||||
if (singleton) {
|
|
||||||
memdelete(singleton);
|
|
||||||
singleton = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
RoadMeshProcessing *RoadMeshProcessing::singleton;
|
|
||||||
|
|
||||||
void RoadProcessing::road_setup(Node *target, int debug_flags)
|
void RoadProcessing::road_setup(Node *target, int debug_flags)
|
||||||
{
|
{
|
||||||
RoadLinesProcessing::get_singleton()->set_debug_flags(debug_flags);
|
BaseData::get_singleton()->get().ensure<RoadLinesProcessing>();
|
||||||
RoadLinesProcessing::get_singleton()->road_setup();
|
BaseData::get_singleton()->get().ensure<RoadMeshProcessing>();
|
||||||
RoadMeshProcessing::get_singleton()->create_road_meshes(target);
|
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)
|
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()
|
void RoadProcessing::load_data()
|
||||||
@@ -2258,30 +1900,31 @@ void RoadProcessing::load_data()
|
|||||||
ConfigFile config;
|
ConfigFile config;
|
||||||
Error result = config.load("res://config/stream.conf");
|
Error result = config.load("res://config/stream.conf");
|
||||||
ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
|
ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
|
||||||
RoadMeshProcessing::get_singleton()->load_road_mesh(
|
BaseData::get_singleton()->get().ensure<RoadMeshProcessing>();
|
||||||
"common", "center", config.get_value("road", "center_mesh"));
|
RoadMeshProcessing *rmp =
|
||||||
RoadMeshProcessing::get_singleton()->load_road_mesh(
|
BaseData::get_singleton()->get().get_mut<RoadMeshProcessing>();
|
||||||
"common", "mid", config.get_value("road", "mid_mesh"));
|
assert(rmp);
|
||||||
RoadMeshProcessing::get_singleton()->load_road_mesh(
|
rmp->load_road_mesh("common", "center",
|
||||||
"common", "sidewalk",
|
config.get_value("road", "center_mesh"));
|
||||||
config.get_value("road", "sidewalk_mesh"));
|
rmp->load_road_mesh("common", "mid",
|
||||||
RoadMeshProcessing::get_singleton()->load_road_mesh(
|
config.get_value("road", "mid_mesh"));
|
||||||
"common", "sidewalk_start",
|
rmp->load_road_mesh("common", "sidewalk",
|
||||||
config.get_value("road", "sidewalk_start_mesh"));
|
config.get_value("road", "sidewalk_mesh"));
|
||||||
RoadMeshProcessing::get_singleton()->load_road_mesh(
|
rmp->load_road_mesh("common", "sidewalk_start",
|
||||||
"common", "sidewalk_end",
|
config.get_value("road", "sidewalk_start_mesh"));
|
||||||
config.get_value("road", "sidewalk_end_mesh"));
|
rmp->load_road_mesh("common", "sidewalk_end",
|
||||||
RoadMeshProcessing::get_singleton()->load_road_mesh(
|
config.get_value("road", "sidewalk_end_mesh"));
|
||||||
"common", "sidewalk_sideroad",
|
rmp->load_road_mesh("common", "sidewalk_sideroad",
|
||||||
config.get_value("road", "sidewalk_sideroad_mesh"));
|
config.get_value("road", "sidewalk_sideroad_mesh"));
|
||||||
RoadMeshProcessing::get_singleton()->load_road_mesh(
|
rmp->load_road_mesh("common", "lot",
|
||||||
"common", "lot", config.get_value("road", "lot_mesh"));
|
config.get_value("road", "lot_mesh"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RoadDebug::_notification(int which)
|
void RoadDebug::_notification(int which)
|
||||||
{
|
{
|
||||||
int i, j;
|
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;
|
std::unordered_map<int, RoadLinesProcessing::edgedata>::iterator it;
|
||||||
switch (which) {
|
switch (which) {
|
||||||
case NOTIFICATION_ENTER_TREE:
|
case NOTIFICATION_ENTER_TREE:
|
||||||
@@ -2379,6 +2022,6 @@ void RoadDebug::_notification(int which)
|
|||||||
}
|
}
|
||||||
void RoadProcessing::cleanup()
|
void RoadProcessing::cleanup()
|
||||||
{
|
{
|
||||||
RoadLinesProcessing::cleanup();
|
BaseData::get_singleton()->get().remove<RoadLinesProcessing>();
|
||||||
RoadMeshProcessing::cleanup();
|
BaseData::get_singleton()->get().remove<RoadMeshProcessing>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,17 @@
|
|||||||
#include "base_data.h"
|
#include "base_data.h"
|
||||||
#include "npc/npc.h"
|
#include "npc/npc.h"
|
||||||
#include "stream.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()
|
void StreamWorld::create_tilemap()
|
||||||
{
|
{
|
||||||
tiles.clear();
|
tiles.clear();
|
||||||
@@ -41,6 +49,7 @@ void StreamWorld::create_tilemap()
|
|||||||
nullptr);
|
nullptr);
|
||||||
print_verbose("Tile count: " + itos(tiles.size()));
|
print_verbose("Tile count: " + itos(tiles.size()));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void StreamWorld::update_view()
|
void StreamWorld::update_view()
|
||||||
{
|
{
|
||||||
@@ -80,6 +89,7 @@ void StreamWorld::update_view()
|
|||||||
current_x = world_extent + 1;
|
current_x = world_extent + 1;
|
||||||
current_z = world_extent + 1;
|
current_z = world_extent + 1;
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
eye = viewer->get_global_transform().origin;
|
eye = viewer->get_global_transform().origin;
|
||||||
int tile_x = int(eye.x / tile_size);
|
int tile_x = int(eye.x / tile_size);
|
||||||
int tile_z = int(eye.z / tile_size);
|
int tile_z = int(eye.z / tile_size);
|
||||||
@@ -122,9 +132,10 @@ void StreamWorld::update_view()
|
|||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_x = tile_x;
|
current_x = tile_x;
|
||||||
current_z = tile_z;
|
current_z = tile_z;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamWorld::viewer_dead()
|
void StreamWorld::viewer_dead()
|
||||||
@@ -141,6 +152,7 @@ void StreamWorld::terrain_dead()
|
|||||||
set_process(false);
|
set_process(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
void StreamWorld::load_tile(int tx, int ty)
|
void StreamWorld::load_tile(int tx, int ty)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -151,6 +163,11 @@ void StreamWorld::load_tile(int tx, int ty)
|
|||||||
": " /* + data()->get_building(items[i]).id */);
|
": " /* + data()->get_building(items[i]).id */);
|
||||||
const String &bkey = items[i];
|
const String &bkey = items[i];
|
||||||
load_building(bkey);
|
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] +
|
print_verbose("unload item: " + itos(i) + ": key: " + items[i] +
|
||||||
": " /* + data()->get_building(items[i]).id */);
|
": " /* + data()->get_building(items[i]).id */);
|
||||||
const String &bkey = items[i];
|
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)
|
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)
|
void StreamWorld::unload_building(const String &key)
|
||||||
{
|
{
|
||||||
request_item(1, key);
|
flecs::entity eb = data()->get_building_entity(key);
|
||||||
}
|
// print_line("key: " + bkey);
|
||||||
|
if (!eb.is_valid()) {
|
||||||
void StreamWorld::request_item(int type, const String &bkey)
|
print_error("ERROR: Entity does not exist: " + key);
|
||||||
{
|
|
||||||
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")
|
|
||||||
return;
|
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()
|
void StreamWorld::update_items()
|
||||||
@@ -395,7 +399,9 @@ void StreamWorld::run_command(const String &command,
|
|||||||
RoadProcessing::road_setup(this, args[0]);
|
RoadProcessing::road_setup(this, args[0]);
|
||||||
else
|
else
|
||||||
RoadProcessing::road_setup(this, 0);
|
RoadProcessing::road_setup(this, 0);
|
||||||
|
#if 0
|
||||||
create_tilemap();
|
create_tilemap();
|
||||||
|
#endif
|
||||||
update_view();
|
update_view();
|
||||||
data()->scene_update();
|
data()->scene_update();
|
||||||
update_items();
|
update_items();
|
||||||
@@ -419,7 +425,9 @@ void StreamWorld::run_command(const String &command,
|
|||||||
terrain->set_generator(gen);
|
terrain->set_generator(gen);
|
||||||
update_items();
|
update_items();
|
||||||
RoadProcessing::road_setup(this, 0);
|
RoadProcessing::road_setup(this, 0);
|
||||||
|
#if 0
|
||||||
create_tilemap();
|
create_tilemap();
|
||||||
|
#endif
|
||||||
update_view();
|
update_view();
|
||||||
update_items();
|
update_items();
|
||||||
assert(false);
|
assert(false);
|
||||||
@@ -460,7 +468,9 @@ void StreamWorld::_notification(int which)
|
|||||||
nullptr);
|
nullptr);
|
||||||
assert(false);
|
assert(false);
|
||||||
#endif
|
#endif
|
||||||
|
#if 0
|
||||||
create_tilemap();
|
create_tilemap();
|
||||||
|
#endif
|
||||||
set_process(true);
|
set_process(true);
|
||||||
if (Engine::get_singleton()->is_editor_hint())
|
if (Engine::get_singleton()->is_editor_hint())
|
||||||
break;
|
break;
|
||||||
@@ -516,14 +526,17 @@ StreamWorld::StreamWorld()
|
|||||||
, initialized(false)
|
, initialized(false)
|
||||||
, frame_count(0)
|
, frame_count(0)
|
||||||
{
|
{
|
||||||
|
BaseData::get_singleton()->get().component<BuildingsData>();
|
||||||
Error result = config.load("res://config/stream.conf");
|
Error result = config.load("res://config/stream.conf");
|
||||||
ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
|
ERR_FAIL_COND_MSG(result != OK, "Failed to load config");
|
||||||
|
BaseData::get_singleton()->get().ensure<BuildingsData>();
|
||||||
RoadProcessing::load_data();
|
RoadProcessing::load_data();
|
||||||
world_extent = config.get_value("world", "world_extent");
|
world_extent = config.get_value("world", "world_extent");
|
||||||
tile_size = config.get_value("world", "tile_size");
|
tile_size = config.get_value("world", "tile_size");
|
||||||
ERR_FAIL_COND_MSG(tile_size <= 0 || world_extent <= 0 ||
|
ERR_FAIL_COND_MSG(tile_size <= 0 || world_extent <= 0 ||
|
||||||
world_extent <= tile_size,
|
world_extent <= tile_size,
|
||||||
"Failed to configure world");
|
"Failed to configure world");
|
||||||
|
#if 0
|
||||||
create_tilemap();
|
create_tilemap();
|
||||||
tile_map_t::iterator map_it = tiles.begin();
|
tile_map_t::iterator map_it = tiles.begin();
|
||||||
while (map_it != tiles.end()) {
|
while (map_it != tiles.end()) {
|
||||||
@@ -534,11 +547,11 @@ StreamWorld::StreamWorld()
|
|||||||
itos(tile_buildings.size()));
|
itos(tile_buildings.size()));
|
||||||
map_it++;
|
map_it++;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
view_distance = config.get_value("world", "view_distance");
|
view_distance = config.get_value("world", "view_distance");
|
||||||
NPC *npc = NPC::get_singleton();
|
BaseData::get_singleton()->get().import <NPC>();
|
||||||
if (!npc) {
|
flecs::entity npcctrl = BaseData::get_singleton()->get().entity();
|
||||||
assert(false);
|
npcctrl.set<NPC::NPCControl>({ NPC::NPCControl::CMD_PRESIM });
|
||||||
}
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
void StreamWorld::cleanup()
|
void StreamWorld::cleanup()
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ private:
|
|||||||
VoxelLodTerrain *terrain;
|
VoxelLodTerrain *terrain;
|
||||||
Node *current_scene;
|
Node *current_scene;
|
||||||
ConfigFile config;
|
ConfigFile config;
|
||||||
|
#if 0
|
||||||
using tile_key_t = std::tuple<int, int>;
|
using tile_key_t = std::tuple<int, int>;
|
||||||
struct tile_hash : public std::unary_function<key_t, std::size_t> {
|
struct tile_hash : public std::unary_function<key_t, std::size_t> {
|
||||||
std::size_t operator()(const tile_key_t &k) const
|
std::size_t operator()(const tile_key_t &k) const
|
||||||
@@ -28,6 +29,7 @@ private:
|
|||||||
Vector3 eye;
|
Vector3 eye;
|
||||||
tile_map_t tiles;
|
tile_map_t tiles;
|
||||||
tile_map_t loaded_tiles;
|
tile_map_t loaded_tiles;
|
||||||
|
#endif
|
||||||
|
|
||||||
int world_extent;
|
int world_extent;
|
||||||
int tile_size;
|
int tile_size;
|
||||||
@@ -36,15 +38,14 @@ private:
|
|||||||
int current_x, current_z;
|
int current_x, current_z;
|
||||||
int frame_count;
|
int frame_count;
|
||||||
void _notification(int which);
|
void _notification(int which);
|
||||||
void create_tilemap();
|
// void create_tilemap();
|
||||||
void update_view();
|
void update_view();
|
||||||
void viewer_dead();
|
void viewer_dead();
|
||||||
void terrain_dead();
|
void terrain_dead();
|
||||||
void load_tile(int tx, int ty);
|
// void load_tile(int tx, int ty);
|
||||||
void erase_tile(int tx, int ty);
|
// void erase_tile(int tx, int ty);
|
||||||
void load_building(const String &key);
|
void load_building(const String &key);
|
||||||
void unload_building(const String &key);
|
void unload_building(const String &key);
|
||||||
void request_item(int type, const String &key);
|
|
||||||
void update_items();
|
void update_items();
|
||||||
void remove_building(const String &key);
|
void remove_building(const String &key);
|
||||||
void remove_generated_stuff();
|
void remove_generated_stuff();
|
||||||
|
|||||||
@@ -18,6 +18,14 @@
|
|||||||
#include "signal_handler.h"
|
#include "signal_handler.h"
|
||||||
#include "terrain_editor.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()
|
void TerrainEditor::exit()
|
||||||
{
|
{
|
||||||
if (active)
|
if (active)
|
||||||
@@ -358,15 +366,13 @@ end:;
|
|||||||
case 2001: {
|
case 2001: {
|
||||||
List<String> building_keys;
|
List<String> building_keys;
|
||||||
List<String>::Element *e;
|
List<String>::Element *e;
|
||||||
BuildingsData::get_singleton()->get_building_keys_list(
|
bd()->get_building_keys_list(&building_keys);
|
||||||
&building_keys);
|
bd()->build_building_aabbs();
|
||||||
BuildingsData::get_singleton()->build_building_aabbs();
|
|
||||||
e = building_keys.front();
|
e = building_keys.front();
|
||||||
while (e) {
|
while (e) {
|
||||||
const String &key = e->get();
|
const String &key = e->get();
|
||||||
const BuildingsData::building &b =
|
const BuildingsData::building &b =
|
||||||
BuildingsData::get_singleton()
|
bd()->get_building(key);
|
||||||
->get_building(key);
|
|
||||||
float i, j;
|
float i, j;
|
||||||
print_line("building type: " + b.id);
|
print_line("building type: " + b.id);
|
||||||
print_line("building key: " + b.key);
|
print_line("building key: " + b.key);
|
||||||
@@ -376,8 +382,7 @@ end:;
|
|||||||
"building elevation: " +
|
"building elevation: " +
|
||||||
String::num(imgmapper->get_height_full(
|
String::num(imgmapper->get_height_full(
|
||||||
b.xform.origin)));
|
b.xform.origin)));
|
||||||
AABB aabb = BuildingsData::get_singleton()
|
AABB aabb = bd()->building_aabbs[b.id];
|
||||||
->building_aabbs[b.id];
|
|
||||||
print_line("building AABB: " +
|
print_line("building AABB: " +
|
||||||
(aabb.operator String()));
|
(aabb.operator String()));
|
||||||
float max_elevation_c = -Math_INF,
|
float max_elevation_c = -Math_INF,
|
||||||
@@ -458,9 +463,7 @@ end:;
|
|||||||
// assert(Math::abs(max_elevation2 -
|
// assert(Math::abs(max_elevation2 -
|
||||||
// max_elevation) < 1.0f);
|
// max_elevation) < 1.0f);
|
||||||
#endif
|
#endif
|
||||||
Transform xform = BuildingsData::get_singleton()
|
Transform xform = bd()->get_building(key).xform;
|
||||||
->get_building(key)
|
|
||||||
.xform;
|
|
||||||
xform.origin.y = max_elevation * 1.4998f - 0.5f;
|
xform.origin.y = max_elevation * 1.4998f - 0.5f;
|
||||||
editor->editor_command(
|
editor->editor_command(
|
||||||
"update_building_transform",
|
"update_building_transform",
|
||||||
@@ -474,7 +477,7 @@ end:;
|
|||||||
e = e->next();
|
e = e->next();
|
||||||
}
|
}
|
||||||
imgmapper->save_dirty_tiles();
|
imgmapper->save_dirty_tiles();
|
||||||
BuildingsData::get_singleton()->save_buildings();
|
bd()->save_buildings();
|
||||||
editor->editor_command("nudge_generator", varray());
|
editor->editor_command("nudge_generator", varray());
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -426,19 +426,21 @@ void MainTabs::_notification(int which)
|
|||||||
/* 43 */
|
/* 43 */
|
||||||
"Delete Building", "buildings_delete_building", "delete_building", varray(),
|
"Delete Building", "buildings_delete_building", "delete_building", varray(),
|
||||||
/* 47 */
|
/* 47 */
|
||||||
"Create Building", "buildings_create_building", "create_building", varray(),
|
"Layout", "buildings_edit_layout", "edit_layout", varray(),
|
||||||
/* 51 */
|
/* 51 */
|
||||||
"Save Buildings", "buildings_save", "buildings_save", varray(),
|
"Create Building", "buildings_create_building", "create_building", varray(),
|
||||||
/* 55 */
|
/* 55 */
|
||||||
|
"Save Buildings", "buildings_save", "buildings_save", varray(),
|
||||||
|
/* 59 */
|
||||||
0, Vector2(0, 80), "lines_list_building",
|
0, Vector2(0, 80), "lines_list_building",
|
||||||
/* 58 */
|
/* 62 */
|
||||||
"Assign To Line", "buildings_assign_to_line"
|
"Assign To Line", "buildings_assign_to_line"
|
||||||
/* 60 */
|
/* 64 */
|
||||||
};
|
};
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
ui_field::ui_field_builder(
|
ui_field::ui_field_builder(
|
||||||
this, tab,
|
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.data(),
|
||||||
args_data.size());
|
args_data.size());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user