Buildings refactoring

This commit is contained in:
2024-09-27 15:40:28 +03:00
parent 8f36415891
commit 5778c79bba
7 changed files with 201 additions and 48 deletions

View File

@@ -104,7 +104,7 @@ void BuildingsData::cleanup()
} }
} }
int BuildingsData::get_building_by_key(const String &key) int BuildingsData::get_building_by_key(const String &key) const
{ {
int i, index = -1; int i, index = -1;
uint64_t key_hash = key.hash64(); uint64_t key_hash = key.hash64();
@@ -393,3 +393,62 @@ func fill_door_locations():
e = e->next(); e = e->next();
} }
} }
int BuildingsData::get_building_count() const
{
return buildings.size();
}
const struct BuildingsData::building &
BuildingsData::get_building(int index) const
{
assert(index >= 0 && index < buildings.size());
return buildings[index];
}
const struct BuildingsData::building &
BuildingsData::get_building(const String &building_key) const
{
int index = get_building_by_key(building_key);
assert(index >= 0 && index < buildings.size());
return buildings[index];
}
struct BuildingsData::building &BuildingsData::get_building(int index)
{
assert(index >= 0 && index < buildings.size());
return buildings[index];
}
struct BuildingsData::building *BuildingsData::get_building_ptr(int index)
{
assert(index >= 0 && index < buildings.size());
return &buildings[index];
}
int BuildingsData::create_building(const Dictionary &dict)
{
struct building b;
building::from_dict(&b, dict);
return create_building(b);
}
int BuildingsData::create_building(const struct building &building)
{
int index = buildings.size();
buildings.push_back(building);
return index;
}
int BuildingsData::create_building(const building *building)
{
assert(building);
return create_building(*building);
}
bool BuildingsData::destroy_building(int index)
{
assert(index >= 0 && index < buildings.size());
buildings.erase(buildings.begin() + index);
return true;
}

View File

@@ -34,7 +34,19 @@ public:
HashMap<String, Vector<Transform> > building_doors; HashMap<String, Vector<Transform> > building_doors;
HashMap<String, AABB> building_aabbs; HashMap<String, AABB> building_aabbs;
/* Data for each building in a world */ /* Data for each building in a world */
private:
std::vector<struct building> buildings; std::vector<struct building> buildings;
public:
int get_building_count() const;
const struct building &get_building(int index) const;
const struct building &get_building(const String &building_key) const;
struct building &get_building(int index);
struct building *get_building_ptr(int index);
int create_building(const Dictionary &dict);
int create_building(const struct building &building);
int create_building(const struct building *building);
bool destroy_building(int index);
struct checkpoint_data { struct checkpoint_data {
HashMap<String, String> building_data; HashMap<String, String> building_data;
std::vector<struct building> buildings; std::vector<struct building> buildings;
@@ -59,6 +71,6 @@ public:
int get_closest_building(const Transform &xform); int get_closest_building(const Transform &xform);
static BuildingsData *get_singleton(); static BuildingsData *get_singleton();
static void cleanup(); static void cleanup();
int get_building_by_key(const String &key); int get_building_by_key(const String &key) const;
}; };
#endif #endif

View File

@@ -5,10 +5,11 @@ def can_build(env, platform):
def configure(env): def configure(env):
pass pass
def get_icons_path():
return "icons"
def get_doc_classes(): def get_doc_classes():
return [] return []
def get_doc_path(): def get_doc_path():
return "doc_classes" return "doc_classes"

View File

@@ -12,6 +12,7 @@
#include <scene/main/viewport.h> #include <scene/main/viewport.h>
#include "from_string.h" #include "from_string.h"
#include "buildings_data.h" #include "buildings_data.h"
#include "editor_event.h"
#include "road_lines_data.h" #include "road_lines_data.h"
ImmediateGeometry *RoadLinesData::debug_im = nullptr; ImmediateGeometry *RoadLinesData::debug_im = nullptr;
@@ -533,7 +534,7 @@ void RoadLinesData::line_add_building(const String &line, const String &key,
lb.y_rotation = y_rotation; lb.y_rotation = y_rotation;
lines[line].buildings.push_back(lb); lines[line].buildings.push_back(lb);
// TODO: save/load // TODO: save/load
BuildingsData::get_singleton()->buildings[index].line_name = line; BuildingsData::get_singleton()->get_building(index).line_name = line;
} }
void RoadLinesData::assign_close_buildings(const String &line) void RoadLinesData::assign_close_buildings(const String &line)
@@ -550,22 +551,24 @@ void RoadLinesData::assign_close_buildings(const String &line)
if (lines[line].segments.size() == 0) if (lines[line].segments.size() == 0)
return; return;
print_line("assign_close_buildings: processing: " + print_line("assign_close_buildings: processing: " +
itos(BuildingsData::get_singleton()->buildings.size()) + itos(BuildingsData::get_singleton()->get_building_count()) +
" buildings"); " buildings");
for (i = 0; i < (int)BuildingsData::get_singleton()->buildings.size(); for (i = 0;
i < (int)BuildingsData::get_singleton()->get_building_count();
i++) { i++) {
float dst = Math_INF; float dst = Math_INF;
float result_offset = 0.0f; float result_offset = 0.0f;
float side = 0.0f; float side = 0.0f;
String building_key; String building_key;
struct BuildingsData::building &data = struct BuildingsData::building &data =
BuildingsData::get_singleton()->buildings[i]; BuildingsData::get_singleton()->get_building(i);
// manually placed // manually placed
if (!data.generated) if (!data.generated)
continue; continue;
// already assigned to another line // already assigned to another line
const String &building_line = const String &building_line = BuildingsData::get_singleton()
BuildingsData::get_singleton()->buildings[i].line_name; ->get_building(i)
.line_name;
if (building_line != line && building_line != "") if (building_line != line && building_line != "")
continue; continue;
if (line_has_building(line, data.key)) if (line_has_building(line, data.key))
@@ -670,14 +673,91 @@ Vector3 RoadLinesData::get_point_by_offsets(const String &line,
} }
n_offset -= segment->length; n_offset -= segment->length;
} }
print_line("offset: " + String::num(n_offset)); print_verbose("offset: " + String::num(n_offset));
ret = lines[line].segments[selected_segment].p1 + ret = lines[line].segments[selected_segment].p1 +
lines[line].segments[selected_segment].dir * n_offset + lines[line].segments[selected_segment].dir * n_offset +
lines[line].segments[selected_segment].tangent * normal_offset; lines[line].segments[selected_segment].tangent * normal_offset;
print_line("data: " + (ret.operator String())); print_verbose("data: " + (ret.operator String()));
return ret; return ret;
} }
void RoadLinesData::update_buildings_from_lines()
{
BuildingsData *bd = BuildingsData::get_singleton();
List<String> keys;
lines.get_key_list(&keys);
List<String>::Element *e = keys.front();
while (e) {
int i, j;
const String &line = e->get();
for (i = 0; i < (int)lines[line].buildings.size(); i++) {
const uint64_t &building_key_hash =
lines[line].buildings[i].building_key_hash;
bool found = false;
int index = -1;
for (j = 0; j < (int)bd->get_building_count(); j++) {
if (bd->get_building(j).key_hash ==
building_key_hash) {
found = true;
index = j;
break;
}
struct BuildingsData::building &b =
bd->get_building(index);
if (found) {
Vector3 pt = get_point_by_offsets(
line,
lines[line]
.buildings[i]
.line_offset,
lines[line]
.buildings[i]
.normal_offset);
Basis basis = Basis().rotated(
Vector3(0, 1, 0),
lines[line]
.buildings[i]
.y_rotation);
b.xform.origin = pt;
b.xform.basis = basis;
Array args;
args.push_back(index);
EditorEvent::get_singleton()->event.emit(
"building_updated", args);
} else {
Vector3 pt = get_point_by_offsets(
line,
lines[line]
.buildings[i]
.line_offset,
lines[line]
.buildings[i]
.normal_offset);
Basis basis = Basis().rotated(
Vector3(0, 1, 0),
lines[line]
.buildings[i]
.y_rotation);
struct BuildingsData::building nb;
Dictionary data;
data["id"] =
lines[line].buildings[i].id;
data["xform"] = Transform(basis, pt);
BuildingsData::building::from_dict(
&nb, data);
index = bd->get_building_count();
bd->create_building(nb);
Array args;
args.push_back(index);
EditorEvent::get_singleton()->event.emit(
"building_created", args);
}
}
}
e = e->next();
}
}
void RoadLinesData::line_building_data::from_dict(line_building_data *b, void RoadLinesData::line_building_data::from_dict(line_building_data *b,
const Dictionary &from) const Dictionary &from)
{ {

View File

@@ -15,6 +15,7 @@ protected:
public: public:
struct line_building_data { struct line_building_data {
String id;
String building_key; String building_key;
uint64_t building_key_hash; uint64_t building_key_hash;
float line_offset; float line_offset;
@@ -66,6 +67,7 @@ public:
bool line_has_building(const String &line, const String &building_key); bool line_has_building(const String &line, const String &building_key);
Vector3 get_point_by_offsets(const String &line, float dir_offset, Vector3 get_point_by_offsets(const String &line, float dir_offset,
float normal_offset); float normal_offset);
void update_buildings_from_lines();
private: private:
void create_segments_from_lines(); void create_segments_from_lines();

View File

@@ -799,7 +799,7 @@ void RoadLinesEditor::move_cursor_to_closest_building()
int index = BuildingsData::get_singleton()->get_closest_building( int index = BuildingsData::get_singleton()->get_closest_building(
Transform(Basis(), pt)); Transform(Basis(), pt));
const Transform &xform = const Transform &xform =
BuildingsData::get_singleton()->buildings[index].xform; BuildingsData::get_singleton()->get_building(index).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())

View File

@@ -17,9 +17,9 @@
void StreamWorld::create_tilemap() void StreamWorld::create_tilemap()
{ {
int i; int i;
for (i = 0; i < (int)data()->buildings.size(); i++) { for (i = 0; i < (int)data()->get_building_count(); i++) {
int tile_x = data()->buildings[i].xform.origin.x / tile_size; int tile_x = data()->get_building(i).xform.origin.x / tile_size;
int tile_z = data()->buildings[i].xform.origin.z / tile_size; int tile_z = data()->get_building(i).xform.origin.z / tile_size;
std::tuple<int, int> key = std::make_tuple(tile_x, tile_z); std::tuple<int, int> key = std::make_tuple(tile_x, tile_z);
if (tiles.find(key) != tiles.end()) if (tiles.find(key) != tiles.end())
tiles[key].push_back(i); tiles[key].push_back(i);
@@ -137,7 +137,7 @@ void StreamWorld::load_tile(int tx, int ty)
const std::vector<int> &items = tiles[key]; const std::vector<int> &items = tiles[key];
for (i = 0; i < (int)items.size(); i++) { for (i = 0; i < (int)items.size(); i++) {
print_line("load item: " + itos(i) + ": " + itos(items[i]) + print_line("load item: " + itos(i) + ": " + itos(items[i]) +
": " + data()->buildings[items[i]].id); ": " + data()->get_building(items[i]).id);
load_building(items[i]); load_building(items[i]);
} }
} }
@@ -149,7 +149,7 @@ void StreamWorld::erase_tile(int tx, int ty)
const std::vector<int> &items = tiles[key]; const std::vector<int> &items = tiles[key];
for (i = 0; i < (int)items.size(); i++) { for (i = 0; i < (int)items.size(); i++) {
print_line("unload item: " + itos(i) + ": " + itos(items[i]) + print_line("unload item: " + itos(i) + ": " + itos(items[i]) +
": " + data()->buildings[items[i]].id); ": " + data()->get_building(items[i]).id);
unload_building(items[i]); unload_building(items[i]);
} }
} }
@@ -166,7 +166,7 @@ void StreamWorld::unload_building(int id)
void StreamWorld::request_item(int type, int item) void StreamWorld::request_item(int type, int item)
{ {
String id = data()->buildings[item].id; String id = data()->get_building(item).id;
if (id == "empty") if (id == "empty")
return; return;
String path = data()->building_data[id]; String path = data()->building_data[id];
@@ -230,8 +230,8 @@ void StreamWorld::update_items()
item_nodes[data()->scenes[*key].buildings[i]] = psc; item_nodes[data()->scenes[*key].buildings[i]] = psc;
current_scene->add_child(psp); current_scene->add_child(psp);
psp->set_global_transform( psp->set_global_transform(
data()->buildings[data()->scenes[*key] data()->get_building(
.buildings[i]] data()->scenes[*key].buildings[i])
.xform); .xform);
} }
key = data()->scenes.next(key); key = data()->scenes.next(key);
@@ -243,11 +243,11 @@ void StreamWorld::remove_building(int index)
// TODO: implement // TODO: implement
int i; int i;
unload_building(index); unload_building(index);
data()->buildings.erase(data()->buildings.begin() + index); data()->destroy_building(index);
for (i = index; i < (int)data()->buildings.size(); i++) { for (i = index; i < (int)data()->get_building_count(); i++) {
item_nodes[i] = item_nodes[i + 1]; item_nodes[i] = item_nodes[i + 1];
} }
item_nodes.erase(data()->buildings.size()); item_nodes.erase(data()->get_building_count());
update_items(); update_items();
} }
@@ -262,12 +262,12 @@ void StreamWorld::run_command(const String &command, const Array &args)
int id = data()->get_closest_building(xform); int id = data()->get_closest_building(xform);
Array ret_data; Array ret_data;
ret_data.resize(5); ret_data.resize(5);
ret_data[0] = data()->buildings[id].xform; ret_data[0] = data()->get_building(id).xform;
ret_data[1] = xform.origin.distance_squared_to( ret_data[1] = xform.origin.distance_squared_to(
data()->buildings[id].xform.origin); data()->get_building(id).xform.origin);
ret_data[2] = data()->buildings[id].key; ret_data[2] = data()->get_building(id).key;
ret_data[3] = id; ret_data[3] = id;
ret_data[4] = data()->buildings[id].id; ret_data[4] = data()->get_building(id).id;
emit_signal("command_result", command, ret_data); emit_signal("command_result", command, ret_data);
} else if (command == "get_building_id_for_key") { } else if (command == "get_building_id_for_key") {
if (args.size() == 0) { if (args.size() == 0) {
@@ -279,8 +279,8 @@ void StreamWorld::run_command(const String &command, const Array &args)
Array ret_data; Array ret_data;
ret_data.resize(1); ret_data.resize(1);
int id = -1, i; int id = -1, i;
for (i = 0; i < (int)data()->buildings.size(); i++) for (i = 0; i < (int)data()->get_building_count(); i++)
if (data()->buildings[i].key.hash64() == khash) { if (data()->get_building(i).key.hash64() == khash) {
id = i; id = i;
break; break;
} }
@@ -292,7 +292,7 @@ void StreamWorld::run_command(const String &command, const Array &args)
return; return;
} }
int id = args[0]; int id = args[0];
if (id < 0 || id >= (int)data()->buildings.size()) if (id < 0 || id >= (int)data()->get_building_count())
return; return;
data()->update_building_transform(id, args[1]); data()->update_building_transform(id, args[1]);
if (item_nodes.has(id)) { if (item_nodes.has(id)) {
@@ -327,9 +327,9 @@ void StreamWorld::run_command(const String &command, const Array &args)
print_error("unknown building type: " + new_type); print_error("unknown building type: " + new_type);
return; return;
} }
String old_type = data()->buildings[id].id; String old_type = data()->get_building(id).id;
unload_building(id); unload_building(id);
data()->buildings[id].id = new_type; data()->get_building(id).id = new_type;
load_building(id); load_building(id);
update_items(); update_items();
print_line("changed building: " + itos(id) + print_line("changed building: " + itos(id) +
@@ -344,8 +344,8 @@ void StreamWorld::run_command(const String &command, const Array &args)
// TODO: check that key is valid // TODO: check that key is valid
print_verbose("DICT: " + (JSON::print(building_dict, "\t"))); print_verbose("DICT: " + (JSON::print(building_dict, "\t")));
BuildingsData::building::from_dict(&b, building_dict); BuildingsData::building::from_dict(&b, building_dict);
data()->buildings.push_back(b); data()->create_building(b);
load_building(data()->buildings.size() - 1); load_building(data()->get_building_count() - 1);
} else if (command == "remove_building") { } else if (command == "remove_building") {
if (args.size() == 0) { if (args.size() == 0) {
print_error("bad command: not enough args: " + command); print_error("bad command: not enough args: " + command);
@@ -359,11 +359,11 @@ void StreamWorld::run_command(const String &command, const Array &args)
return; return;
} }
std::vector<int> erased_indices; std::vector<int> erased_indices;
erased_indices.reserve(data()->buildings.size()); erased_indices.reserve(data()->get_building_count());
String prefix = args[0]; String prefix = args[0];
int i, j; int i, j;
for (i = 0; i < (int)data()->buildings.size(); i++) { for (i = 0; i < (int)data()->get_building_count(); i++) {
if (data()->buildings[i].id.begins_with(prefix)) if (data()->get_building(i).id.begins_with(prefix))
erased_indices.push_back(i); erased_indices.push_back(i);
} }
print_line("delete buildings: " + itos(erased_indices.size()) + print_line("delete buildings: " + itos(erased_indices.size()) +
@@ -371,11 +371,10 @@ void StreamWorld::run_command(const String &command, const Array &args)
for (i = erased_indices.size() - 1; i >= 0; i--) { for (i = erased_indices.size() - 1; i >= 0; i--) {
int index = erased_indices[i]; int index = erased_indices[i];
unload_building(index); unload_building(index);
data()->buildings.erase(data()->buildings.begin() + data()->destroy_building(index);
index); for (j = index; j < data()->get_building_count(); j++)
for (j = index; j < (int)data()->buildings.size(); j++)
item_nodes[j] = item_nodes[j + 1]; item_nodes[j] = item_nodes[j + 1];
item_nodes.erase(data()->buildings.size()); item_nodes.erase(data()->get_building_count());
} }
update_items(); update_items();
} else if (command == "remove_generated_stuff") { } else if (command == "remove_generated_stuff") {
@@ -505,19 +504,19 @@ StreamWorld::~StreamWorld()
void StreamWorld::remove_generated_stuff() void StreamWorld::remove_generated_stuff()
{ {
std::vector<int> erased_indices; std::vector<int> erased_indices;
erased_indices.reserve(data()->buildings.size()); erased_indices.reserve(data()->get_building_count());
int i, j; int i, j;
for (i = 0; i < (int)data()->buildings.size(); i++) { for (i = 0; i < data()->get_building_count(); i++) {
if (data()->buildings[i].generated) if (data()->get_building(i).generated)
erased_indices.push_back(i); erased_indices.push_back(i);
} }
for (i = erased_indices.size() - 1; i >= 0; i--) { for (i = erased_indices.size() - 1; i >= 0; i--) {
int index = erased_indices[i]; int index = erased_indices[i];
unload_building(index); unload_building(index);
data()->buildings.erase(data()->buildings.begin() + index); data()->destroy_building(index);
for (j = index; j < (int)data()->buildings.size(); j++) for (j = index; j < (int)data()->get_building_count(); j++)
item_nodes[j] = item_nodes[j + 1]; item_nodes[j] = item_nodes[j + 1];
item_nodes.erase(data()->buildings.size()); item_nodes.erase(data()->get_building_count());
} }
update_items(); update_items();
} }
@@ -525,7 +524,7 @@ void StreamWorld::remove_generated_stuff()
void StreamWorld::undo() void StreamWorld::undo()
{ {
int id; int id;
for (id = 0; id < (int)data()->buildings.size(); id++) for (id = 0; id < (int)data()->get_building_count(); id++)
unload_building(id); unload_building(id);
data()->undo(); data()->undo();
update_view(); update_view();