842 lines
23 KiB
C++
842 lines
23 KiB
C++
#undef NDEBUG
|
|
#include <cassert>
|
|
#include "element_data.h"
|
|
ElementData *ElementData::singleton = nullptr;
|
|
const String &ElementData::get_element_type(const String &key) const
|
|
{
|
|
assert(elements.has(key));
|
|
return elements[key].type;
|
|
}
|
|
List<int> ElementData::get_grow_cells_side(const String &key, bool exterior,
|
|
int fl, int cell) const
|
|
{
|
|
List<int> grow_cells;
|
|
int x = cell % grid_size;
|
|
int z = cell / grid_size;
|
|
bool grow_west = true, grow_south = true, grow_east = true,
|
|
grow_north = true;
|
|
int rotation = get_grid_rotation(key, exterior, fl, cell);
|
|
if (x == 0)
|
|
grow_west = false;
|
|
else if (x >= grid_size - 1)
|
|
grow_east = false;
|
|
if (z == 0)
|
|
grow_south = false;
|
|
else if (z >= grid_size - 1)
|
|
grow_north = false;
|
|
if (rotation == 0 || rotation == 2) {
|
|
grow_south = false;
|
|
grow_north = false;
|
|
} else if (rotation == 1 || rotation == 3) {
|
|
grow_west = false;
|
|
grow_east = false;
|
|
}
|
|
if (grow_west) {
|
|
int cell_ = (x - 1) + z * grid_size;
|
|
grow_cells.push_back(cell_);
|
|
}
|
|
if (grow_west && grow_south) {
|
|
int cell_ = (x - 1) + (z - 1) * grid_size;
|
|
grow_cells.push_back(cell_);
|
|
}
|
|
if (grow_south) {
|
|
int cell_ = x + (z - 1) * grid_size;
|
|
grow_cells.push_back(cell_);
|
|
}
|
|
if (grow_south && grow_east) {
|
|
int cell_ = (x + 1) + (z - 1) * grid_size;
|
|
grow_cells.push_back(cell_);
|
|
}
|
|
if (grow_east) {
|
|
int cell_ = (x + 1) + z * grid_size;
|
|
grow_cells.push_back(cell_);
|
|
}
|
|
if (grow_east && grow_north) {
|
|
int cell_ = (x + 1) + (z + 1) * grid_size;
|
|
grow_cells.push_back(cell_);
|
|
}
|
|
if (grow_north) {
|
|
int cell_ = x + (z + 1) * grid_size;
|
|
grow_cells.push_back(cell_);
|
|
}
|
|
if (grow_north && grow_west) {
|
|
int cell_ = (x - 1) + (z + 1) * grid_size;
|
|
grow_cells.push_back(cell_);
|
|
}
|
|
return grow_cells;
|
|
}
|
|
List<int> ElementData::get_grow_cells_normal(const String &key, bool exterior,
|
|
int fl, int cell) const
|
|
{
|
|
List<int> grow_cells;
|
|
int x = cell % grid_size;
|
|
int z = cell / grid_size;
|
|
bool grow_west = true, grow_south = true, grow_east = true,
|
|
grow_north = true;
|
|
if (x == 0)
|
|
grow_west = false;
|
|
else if (x >= grid_size - 1)
|
|
grow_east = false;
|
|
if (z == 0)
|
|
grow_south = false;
|
|
else if (z >= grid_size - 1)
|
|
grow_north = false;
|
|
if (grow_west) {
|
|
int cell_ = (x - 1) + z * grid_size;
|
|
grow_cells.push_back(cell_);
|
|
}
|
|
if (grow_west && grow_south) {
|
|
int cell_ = (x - 1) + (z - 1) * grid_size;
|
|
grow_cells.push_back(cell_);
|
|
}
|
|
if (grow_south) {
|
|
int cell_ = x + (z - 1) * grid_size;
|
|
grow_cells.push_back(cell_);
|
|
}
|
|
if (grow_south && grow_east) {
|
|
int cell_ = (x + 1) + (z - 1) * grid_size;
|
|
grow_cells.push_back(cell_);
|
|
}
|
|
if (grow_east) {
|
|
int cell_ = (x + 1) + z * grid_size;
|
|
grow_cells.push_back(cell_);
|
|
}
|
|
if (grow_east && grow_north) {
|
|
int cell_ = (x + 1) + (z + 1) * grid_size;
|
|
grow_cells.push_back(cell_);
|
|
}
|
|
if (grow_north) {
|
|
int cell_ = x + (z + 1) * grid_size;
|
|
grow_cells.push_back(cell_);
|
|
}
|
|
if (grow_north && grow_west) {
|
|
int cell_ = (x - 1) + (z + 1) * grid_size;
|
|
grow_cells.push_back(cell_);
|
|
}
|
|
return grow_cells;
|
|
}
|
|
List<int> ElementData::get_grow_cells(int type, const String &key,
|
|
bool exterior, int fl, int cell) const
|
|
{
|
|
switch (type) {
|
|
case 0:
|
|
return get_grow_cells_normal(key, exterior, fl, cell);
|
|
break;
|
|
case 1:
|
|
return get_grow_cells_side(key, exterior, fl, cell);
|
|
break;
|
|
default:
|
|
return List<int>();
|
|
break;
|
|
}
|
|
}
|
|
void ElementData::grow_cell(int type, const String &key, bool exterior, int fl,
|
|
int cell)
|
|
{
|
|
List<int> queue;
|
|
List<int> input_cells;
|
|
List<int> output_cells;
|
|
const String &element = get_grid_element(key, exterior, fl, cell);
|
|
print_line("grow_cell: " + element);
|
|
if (element == "empty")
|
|
return;
|
|
int rotation = get_grid_rotation(key, exterior, fl, cell);
|
|
queue.push_back(cell);
|
|
// collect all the same elements adjacent to current one
|
|
while (!queue.empty()) {
|
|
int c = queue.front()->get();
|
|
queue.pop_front();
|
|
const String &el = get_grid_element(key, exterior, fl, c);
|
|
int rot = get_grid_rotation(key, exterior, fl, c);
|
|
if (el == element && rot == rotation) {
|
|
print_line("adding cell: " + itos(c));
|
|
// do not place original cell in inputs
|
|
if (input_cells.find(c) == nullptr)
|
|
input_cells.push_back(c);
|
|
List<int> cells =
|
|
get_grow_cells(type, key, exterior, fl, c);
|
|
while (!cells.empty()) {
|
|
int item = cells.front()->get();
|
|
cells.pop_front();
|
|
if (input_cells.find(item) == nullptr &&
|
|
queue.find(item) == nullptr)
|
|
queue.push_back(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
print_line("input_cells: " + itos(input_cells.size()));
|
|
queue = input_cells;
|
|
while (!queue.empty()) {
|
|
int c = queue.front()->get();
|
|
queue.pop_front();
|
|
const String &el = get_grid_element(key, exterior, fl, c);
|
|
if (el == element) {
|
|
List<int> cells =
|
|
get_grow_cells(type, key, exterior, fl, c);
|
|
while (!cells.empty()) {
|
|
int g = cells.front()->get();
|
|
cells.pop_front();
|
|
const String &em =
|
|
get_grid_element(key, exterior, fl, g);
|
|
if (em == "empty" && queue.find(g) == nullptr)
|
|
queue.push_back(g);
|
|
}
|
|
} else if (el == "empty") {
|
|
if (output_cells.find(c) == nullptr)
|
|
output_cells.push_back(c);
|
|
}
|
|
}
|
|
queue = output_cells;
|
|
while (!queue.empty()) {
|
|
int c = queue.front()->get();
|
|
queue.pop_front();
|
|
const String &cell_element =
|
|
get_grid_element(key, exterior, fl, c);
|
|
assert(cell_element == "empty");
|
|
if (cell_element == "empty") {
|
|
set_grid_element(key, exterior, fl, c, element);
|
|
set_grid_rotation(key, exterior, fl, c, rotation);
|
|
}
|
|
}
|
|
print_line("initial cell: " + itos(cell));
|
|
print_line("input_cells: " + itos(input_cells.size()));
|
|
print_line("output_cells: " + itos(output_cells.size()));
|
|
}
|
|
void ElementData::create_new_layout(const String &key)
|
|
{
|
|
flecs::world ecs = BaseData::get_singleton()->get();
|
|
flecs::entity top = ecs.lookup("grid_layouts");
|
|
assert(top.is_valid());
|
|
flecs::entity layout = ecs.entity(key.ascii().ptr()).child_of(top);
|
|
// one floor by default
|
|
layout.add<struct grid_layout>();
|
|
flecs::entity extr = ecs.entity("exterior").child_of(layout);
|
|
extr.add<grid_layout_exterior>();
|
|
flecs::entity intr = ecs.entity("interior").child_of(layout);
|
|
intr.add<grid_layout_interior>();
|
|
intr.set<grid_layout_base>({ 0 });
|
|
extr.set<grid_layout_base>({ 0 });
|
|
}
|
|
void ElementData::create_new_exterior_floor(const String &key)
|
|
{
|
|
int i;
|
|
flecs::world ecs = BaseData::get_singleton()->get();
|
|
flecs::entity ext = get_base(key, true);
|
|
assert(ext.is_valid());
|
|
struct grid_layout_base *l = ext.get_mut<grid_layout_base>();
|
|
int floor = l->floor_count;
|
|
flecs::entity fl =
|
|
ecs.entity(("floor_" + itos(floor)).ascii().ptr()).child_of(ext);
|
|
assert(fl.is_valid());
|
|
|
|
for (i = 0; i < grid_size * grid_size; i++) {
|
|
flecs::entity item =
|
|
ecs.entity(("item_" + itos(i)).ascii().ptr())
|
|
.child_of(fl);
|
|
item.set<grid_floor_item>({ i, "empty", 0 });
|
|
}
|
|
l->floor_count++;
|
|
}
|
|
void ElementData::create_new_interior_floor(const String &key)
|
|
{
|
|
int i;
|
|
flecs::entity intr = get_base(key, false);
|
|
assert(intr.is_valid());
|
|
struct grid_layout_base *l = intr.get_mut<grid_layout_base>();
|
|
int floor = l->floor_count;
|
|
flecs::world ecs = BaseData::get_singleton()->get();
|
|
flecs::entity fl = ecs.entity(("floor_" + itos(floor)).ascii().ptr())
|
|
.child_of(intr);
|
|
assert(fl.is_valid());
|
|
|
|
for (i = 0; i < grid_size * grid_size; i++) {
|
|
flecs::entity item =
|
|
ecs.entity(("item_" + itos(i)).ascii().ptr())
|
|
.child_of(fl);
|
|
item.set<grid_floor_item>({ i, "empty", 0 });
|
|
}
|
|
l->floor_count++;
|
|
}
|
|
void ElementData::serialize_layouts(Dictionary &store)
|
|
{
|
|
flecs::world ecs = BaseData::get_singleton()->get();
|
|
flecs::entity top = ecs.lookup("grid_layouts");
|
|
assert(top.is_valid());
|
|
top.children([this, &store](flecs::entity l) {
|
|
Dictionary layout, exterior_layout, interior_layout;
|
|
if (l.has<struct grid_layout>()) {
|
|
flecs::entity intr = l.lookup("interior");
|
|
assert(intr.is_valid());
|
|
flecs::entity extr = l.lookup("exterior");
|
|
assert(extr.is_valid());
|
|
intr.children([this, &interior_layout](
|
|
flecs::entity intr_fl) {
|
|
if (intr_fl.has<struct grid_floor>()) {
|
|
Array items;
|
|
intr_fl.children([&items](
|
|
flecs::entity
|
|
floor_item) {
|
|
if (floor_item.has<
|
|
struct grid_floor_item>()) {
|
|
const struct grid_floor_item *item =
|
|
floor_item.get<
|
|
struct grid_floor_item>();
|
|
Dictionary sitem;
|
|
sitem["index"] =
|
|
item->index;
|
|
sitem["element"] =
|
|
item->element;
|
|
sitem["rotation"] =
|
|
item->rotation;
|
|
items.push_back(sitem);
|
|
}
|
|
});
|
|
String floor_key(intr_fl.name());
|
|
interior_layout[floor_key] = items;
|
|
}
|
|
});
|
|
extr.children([this, &exterior_layout](
|
|
flecs::entity extr_fl) {
|
|
Array items;
|
|
extr_fl.children([&items](flecs::entity
|
|
floor_item) {
|
|
if (floor_item.has<
|
|
struct grid_floor_item>()) {
|
|
const struct grid_floor_item
|
|
*item = floor_item.get<
|
|
struct grid_floor_item>();
|
|
Dictionary sitem;
|
|
sitem["index"] = item->index;
|
|
sitem["element"] =
|
|
item->element;
|
|
sitem["rotation"] =
|
|
item->rotation;
|
|
items.push_back(sitem);
|
|
}
|
|
});
|
|
String floor_key(extr_fl.name());
|
|
exterior_layout[floor_key] = items;
|
|
});
|
|
layout["interior"] = interior_layout;
|
|
layout["exterior"] = exterior_layout;
|
|
}
|
|
String layout_name(l.name());
|
|
store[layout_name] = layout;
|
|
});
|
|
}
|
|
void ElementData::unserialize_layouts(const Dictionary &store)
|
|
{
|
|
int i;
|
|
flecs::world ecs = BaseData::get_singleton()->get();
|
|
flecs::entity top = ecs.lookup("grid_layouts");
|
|
assert(top.is_valid());
|
|
// delete all layouts
|
|
top.children([this](flecs::entity l) { l.destruct(); });
|
|
List<Variant> layout_keys;
|
|
store.get_key_list(&layout_keys);
|
|
List<Variant>::Element *e;
|
|
e = layout_keys.front();
|
|
while (e) {
|
|
String layout_name = e->get();
|
|
flecs::entity layout =
|
|
ecs.entity(layout_name.ascii().ptr()).child_of(top);
|
|
layout.add<grid_layout>();
|
|
flecs::entity extr = ecs.entity("exterior").child_of(layout);
|
|
extr.add<grid_layout_exterior>();
|
|
extr.set<grid_layout_base>({ 0 });
|
|
flecs::entity intr = ecs.entity("interior").child_of(layout);
|
|
intr.add<grid_layout_interior>();
|
|
intr.set<grid_layout_base>({ 0 });
|
|
Dictionary store_layout = store[e->get()];
|
|
Dictionary store_interior = store_layout["interior"];
|
|
Dictionary store_exterior = store_layout["exterior"];
|
|
List<Variant>::Element *ve;
|
|
List<Variant> interior_keys;
|
|
List<Variant> exterior_keys;
|
|
store_interior.get_key_list(&interior_keys);
|
|
store_exterior.get_key_list(&exterior_keys);
|
|
for (ve = interior_keys.front(); ve; ve = ve->next()) {
|
|
String floor_key = ve->get();
|
|
if (floor_key.begins_with("floor_")) {
|
|
flecs::entity floor_e =
|
|
ecs.entity(floor_key.ascii().ptr())
|
|
.child_of(intr);
|
|
assert(floor_e.is_valid());
|
|
floor_e.set<struct grid_floor>({ true });
|
|
const Array &floor_interior =
|
|
store_interior[floor_key];
|
|
for (i = 0; i < floor_interior.size(); i++) {
|
|
const Dictionary &item =
|
|
floor_interior[i];
|
|
int index = item["index"];
|
|
String element = item["element"];
|
|
int rotation = item["rotation"];
|
|
String item_key = "item_" + itos(index);
|
|
flecs::entity item_e =
|
|
ecs.entity(item_key.ascii()
|
|
.ptr())
|
|
.child_of(floor_e);
|
|
item_e.set<grid_floor_item>(
|
|
{ index, element, rotation });
|
|
}
|
|
struct grid_layout_base *l =
|
|
intr.get_mut<struct grid_layout_base>();
|
|
l->floor_count++;
|
|
}
|
|
}
|
|
for (ve = exterior_keys.front(); ve; ve = ve->next()) {
|
|
String floor_key = ve->get();
|
|
if (floor_key.begins_with("floor_")) {
|
|
flecs::entity floor_e =
|
|
ecs.entity(floor_key.ascii().ptr())
|
|
.child_of(extr);
|
|
assert(floor_e.is_valid());
|
|
floor_e.add<struct grid_floor>();
|
|
const Array &floor_exterior =
|
|
store_exterior[floor_key];
|
|
for (i = 0; i < floor_exterior.size(); i++) {
|
|
const Dictionary &item =
|
|
floor_exterior[i];
|
|
int index = item["index"];
|
|
String element = item["element"];
|
|
int rotation = item["rotation"];
|
|
String item_key = "item_" + itos(index);
|
|
flecs::entity item_e =
|
|
ecs.entity(item_key.ascii()
|
|
.ptr())
|
|
.child_of(floor_e);
|
|
item_e.set<grid_floor_item>(
|
|
{ index, element, rotation });
|
|
}
|
|
struct grid_layout_base *l =
|
|
extr.get_mut<struct grid_layout_base>();
|
|
l->floor_count++;
|
|
}
|
|
}
|
|
e = e->next();
|
|
}
|
|
}
|
|
void ElementData::ensure_floor(const String &key, bool exterior, int fl)
|
|
{
|
|
int i;
|
|
if (has_floor(key, exterior, fl))
|
|
return;
|
|
flecs::world ecs = BaseData::get_singleton()->get();
|
|
flecs::entity base = get_base(key, exterior);
|
|
flecs::entity floor_e =
|
|
ecs.entity(("floor_" + itos(fl)).ascii().ptr()).child_of(base);
|
|
assert(floor_e.is_valid());
|
|
if (!floor_e.has<struct grid_floor>())
|
|
floor_e.set<struct grid_floor>({ true });
|
|
for (i = 0; i < grid_size * grid_size; i++) {
|
|
flecs::entity item =
|
|
ecs.entity(("item_" + itos(i)).ascii().ptr())
|
|
.child_of(floor_e);
|
|
item.set<grid_floor_item>({ i, "empty", 0 });
|
|
}
|
|
assert(has_floor(key, exterior, fl));
|
|
print_line("ensured floor: " + itos(fl));
|
|
}
|
|
void ElementData::load_data()
|
|
{
|
|
int i;
|
|
ConfigFile config;
|
|
ConfigFile automata_conf;
|
|
Dictionary conf_element_types;
|
|
Dictionary conf_elements;
|
|
Dictionary conf_grid_layouts;
|
|
List<Variant> keys;
|
|
List<Variant>::Element *e;
|
|
elements.clear();
|
|
element_type.clear();
|
|
config.load("res://astream/blayout.conf");
|
|
conf_element_types = config.get_value("buildings_layout",
|
|
"element_types", Dictionary());
|
|
conf_elements =
|
|
config.get_value("buildings_layout", "elements", Dictionary());
|
|
conf_grid_layouts = config.get_value("buildings_layout", "grid_layouts",
|
|
Dictionary());
|
|
conf_element_types.get_key_list(&keys);
|
|
e = keys.front();
|
|
while (e) {
|
|
String key = e->get();
|
|
Dictionary item = conf_element_types[key];
|
|
assert(item.has("sockets"));
|
|
create_element_type(key);
|
|
Array sockets = item["sockets"];
|
|
for (i = 0; i < sockets.size(); i++)
|
|
set_element_type_socket(key, i, sockets[i]);
|
|
e = e->next();
|
|
}
|
|
keys.clear();
|
|
conf_elements.get_key_list(&keys);
|
|
e = keys.front();
|
|
while (e) {
|
|
String key = e->get();
|
|
Dictionary item = conf_elements[key];
|
|
assert(item.has("type"));
|
|
assert(item.has("mesh_names"));
|
|
String type = item["type"];
|
|
String base = item.get("base", "");
|
|
print_line("loading element: " + key + " type: " + type);
|
|
if (key == "empty") {
|
|
e = e->next();
|
|
continue;
|
|
}
|
|
create_element(key, type);
|
|
Array mesh_names = item["mesh_names"];
|
|
for (i = 0; i < mesh_names.size(); i++)
|
|
set_element_mesh_name(key, i, mesh_names[i]);
|
|
set_element_base(key, base);
|
|
e = e->next();
|
|
}
|
|
unserialize_layouts(conf_grid_layouts);
|
|
{
|
|
Error err = automata_conf.load("res://astream/automata.conf");
|
|
assert(err == OK);
|
|
Dictionary automata_dict = automata_conf.get_value(
|
|
"automata", "automata", Dictionary());
|
|
assert(automata_dict.size() > 0);
|
|
List<Variant> pkeys;
|
|
List<Variant>::Element *pe;
|
|
automata_dict.get_key_list(&pkeys);
|
|
pe = pkeys.front();
|
|
automata.clear();
|
|
while (pe) {
|
|
String name = pe->get();
|
|
print_line("automata: " + name);
|
|
assert(automata_dict.has(name));
|
|
Array at = automata_dict[name];
|
|
assert(at.size() > 0);
|
|
for (i = 0; i < at.size(); i++)
|
|
add_automata_from_dict(name, at[i]);
|
|
assert(automata.has(name));
|
|
pe = pe->next();
|
|
}
|
|
}
|
|
assert(automata.size() > 0);
|
|
EditorEvent::get_singleton()->event.emit("elements_update_all",
|
|
varray());
|
|
}
|
|
void ElementData::add_automata(const String &name,
|
|
const struct ElementData::match_field *match,
|
|
const struct ElementData::match_field &cell)
|
|
{
|
|
struct ElementData::automata_data data;
|
|
int i;
|
|
for (i = 0; i < 9; i++)
|
|
data.match[i] = match[i];
|
|
data.cell = cell;
|
|
automata[name].push_back(data);
|
|
}
|
|
void ElementData::add_automata_from_dict(const String &name,
|
|
const Dictionary &d)
|
|
{
|
|
int i;
|
|
assert(d.has("match"));
|
|
assert(d.has("cell"));
|
|
Array cell = d["cell"];
|
|
Array matches = d["match"];
|
|
assert(matches.size() == 9);
|
|
if (cell.size() == 2) {
|
|
struct ElementData::automata_data data;
|
|
for (i = 0; i < matches.size(); i++) {
|
|
Array match = matches[i];
|
|
assert(match.size() == 2);
|
|
String entry = match[0];
|
|
int rotation = match[1];
|
|
data.match[i] = { entry, rotation };
|
|
}
|
|
String n = cell[0];
|
|
int r = cell[1];
|
|
data.cell = { n, r };
|
|
if (automata.has(name))
|
|
automata[name].push_back(data);
|
|
else {
|
|
Vector<struct ElementData::automata_data> l;
|
|
l.push_back(data);
|
|
automata[name] = l;
|
|
}
|
|
} else if (cell.size() == 5) {
|
|
/*******************************************
|
|
* 0 1 2
|
|
* 3 4 5 0
|
|
* 6 7 8
|
|
*
|
|
* 2 5 8
|
|
* 1 4 7 90
|
|
* 0 3 6
|
|
*
|
|
* 8 7 6
|
|
* 5 4 3 180
|
|
* 2 1 0
|
|
*
|
|
* 6 3 0
|
|
* 7 4 1 270
|
|
* 8 5 2
|
|
*/
|
|
/* clang-format off */
|
|
int remap[9][9] = {
|
|
{
|
|
/* 0 */
|
|
0, 1, 2, /* a */
|
|
3, 4, 5, /* b */
|
|
6, 7, 8, /* c */
|
|
},
|
|
{
|
|
/* 90 */
|
|
2, 5, 8,
|
|
1, 4, 7,
|
|
0, 3, 6,
|
|
},
|
|
{
|
|
/* 180 */
|
|
8, 7, 6,
|
|
5, 4, 3,
|
|
2, 1, 0,
|
|
},
|
|
{
|
|
/* 270 */
|
|
6, 3, 0,
|
|
7, 4, 1,
|
|
8, 5, 2,
|
|
},
|
|
};
|
|
/* clang-format on */
|
|
int j;
|
|
struct ElementData::automata_data data[4];
|
|
for (j = 0; j < 4; j++) {
|
|
for (i = 0; i < matches.size(); i++) {
|
|
Array match = matches[remap[j][i]];
|
|
assert(match.size() == 2);
|
|
String entry = match[0];
|
|
int rotation = match[1];
|
|
if (rotation >= 0)
|
|
rotation = (rotation + j) % 4;
|
|
data[j].match[i] = { entry, rotation };
|
|
|
|
String n = cell[0];
|
|
int r = cell[1 + j];
|
|
data[j].cell = { n, r };
|
|
}
|
|
}
|
|
if (!automata.has(name)) {
|
|
Vector<struct ElementData::automata_data> l;
|
|
automata[name] = l;
|
|
}
|
|
for (j = 0; j < 4; j++)
|
|
automata[name].push_back(data[j]);
|
|
}
|
|
}
|
|
void ElementData::run_cellular_automata(const String &name, const String &key,
|
|
bool exterior, int fl)
|
|
{
|
|
int i, j, k;
|
|
print_line("automata: " + name);
|
|
assert(automata.size() > 0);
|
|
assert(automata.has(name));
|
|
flecs::entity base = get_base(key, exterior);
|
|
flecs::entity floor_e =
|
|
base.lookup(("floor_" + itos(fl)).ascii().ptr());
|
|
assert(floor_e.is_valid());
|
|
bool changed = true;
|
|
while (changed) {
|
|
changed = false;
|
|
for (k = 0; k < automata[name].size(); k++) {
|
|
for (i = 0; i < grid_size * grid_size; i++) {
|
|
flecs::entity item = floor_e.lookup(
|
|
("item_" + itos(i)).ascii().ptr());
|
|
const struct grid_floor_item *floor_item =
|
|
item.get<struct grid_floor_item>();
|
|
int index = floor_item->index;
|
|
// print_line("automata: processing: " + itos(index));
|
|
assert(index == i);
|
|
int neighbor_indices[9] = {
|
|
/* a */ index - grid_size - 1,
|
|
index - grid_size,
|
|
index - grid_size + 1,
|
|
/* b */ index - 1,
|
|
index,
|
|
index + 1,
|
|
/* c */ index + grid_size - 1,
|
|
index + grid_size,
|
|
index + grid_size + 1
|
|
};
|
|
struct ElementData::match_field match[9];
|
|
for (j = 0; j < 9; j++) {
|
|
int idx = neighbor_indices[j];
|
|
if (idx < 0 ||
|
|
idx >= grid_size * grid_size) {
|
|
match[j].entry = "empty";
|
|
match[j].rotation = -1;
|
|
} else {
|
|
flecs::entity mitem =
|
|
floor_e.lookup(
|
|
("item_" +
|
|
itos(idx))
|
|
.ascii()
|
|
.ptr());
|
|
const struct ElementData::grid_floor_item
|
|
*fl_item = mitem.get<
|
|
struct ElementData::
|
|
grid_floor_item>();
|
|
match[j].entry =
|
|
fl_item->element;
|
|
match[j].rotation =
|
|
fl_item->rotation;
|
|
}
|
|
// print_line("automata: processing: " +
|
|
// itos(index) + " " + match[j].entry +
|
|
// " " + itos(match[j].rotation));
|
|
}
|
|
// print_line("match created: " +
|
|
// itos(automata[name].size()));
|
|
bool matched = true;
|
|
for (j = 0; j < 9; j++) {
|
|
if (match[j].entry !=
|
|
automata[name][k].match[j].entry) {
|
|
matched = false;
|
|
break;
|
|
}
|
|
if (automata[name][k].match[j].rotation >=
|
|
0 &&
|
|
match[j].rotation >= 0 &&
|
|
match[j].rotation !=
|
|
automata[name][k]
|
|
.match[j]
|
|
.rotation) {
|
|
matched = false;
|
|
break;
|
|
}
|
|
}
|
|
if (matched) {
|
|
for (j = 0; j < 9; j++) {
|
|
print_line(
|
|
"matched: " +
|
|
match[j].entry + " " +
|
|
itos(match[j].rotation) +
|
|
" => " +
|
|
automata[name][k]
|
|
.match[j]
|
|
.entry +
|
|
" " +
|
|
itos(automata[name][k]
|
|
.match[j]
|
|
.rotation));
|
|
}
|
|
}
|
|
if (matched) {
|
|
struct grid_floor_item *floor_item_rw =
|
|
item.get_mut<
|
|
struct grid_floor_item>();
|
|
assert(has_element(
|
|
automata[name][k].cell.entry));
|
|
floor_item_rw->element =
|
|
automata[name][k].cell.entry;
|
|
changed = true;
|
|
print_line("matched, " +
|
|
floor_item->element);
|
|
if (automata[name][k].cell.rotation >=
|
|
0)
|
|
floor_item_rw->rotation =
|
|
automata[name][k]
|
|
.cell.rotation;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void ElementData::save_data()
|
|
{
|
|
int i;
|
|
ConfigFile config;
|
|
Dictionary conf_element_types;
|
|
Dictionary conf_elements;
|
|
Dictionary conf_exterior_grid;
|
|
List<String> keys;
|
|
List<String>::Element *e;
|
|
element_type.get_key_list(&keys);
|
|
e = keys.front();
|
|
while (e) {
|
|
Dictionary item;
|
|
const struct grid_element_type &g = element_type[e->get()];
|
|
if (e->get() == "empty") {
|
|
e = e->next();
|
|
continue;
|
|
}
|
|
item["name"] = e->get();
|
|
Array sockets;
|
|
sockets.resize(ELEMENT_SOCKETS);
|
|
for (i = 0; i < ELEMENT_SOCKETS; i++)
|
|
sockets[i] = g.sockets[i];
|
|
item["sockets"] = sockets;
|
|
|
|
conf_element_types[e->get()] = item;
|
|
e = e->next();
|
|
}
|
|
keys.clear();
|
|
elements.get_key_list(&keys);
|
|
e = keys.front();
|
|
while (e) {
|
|
Dictionary item;
|
|
const struct grid_element &g = elements[e->get()];
|
|
if (e->get() == "empty") {
|
|
e = e->next();
|
|
continue;
|
|
}
|
|
item["name"] = e->get();
|
|
item["type"] = g.type;
|
|
Array mesh_names;
|
|
mesh_names.resize(ELEMENT_SOCKETS);
|
|
for (i = 0; i < ELEMENT_SOCKETS; i++)
|
|
mesh_names[i] = g.mesh_names[i];
|
|
item["mesh_names"] = mesh_names;
|
|
item["base"] = g.base;
|
|
|
|
conf_elements[e->get()] = item;
|
|
e = e->next();
|
|
}
|
|
// TODO: support multiple layouts;
|
|
serialize_layouts(conf_exterior_grid);
|
|
|
|
config.set_value("buildings_layout", "element_types",
|
|
conf_element_types);
|
|
config.set_value("buildings_layout", "elements", conf_elements);
|
|
config.set_value("buildings_layout", "grid_layouts",
|
|
conf_exterior_grid);
|
|
config.save("res://astream/blayout.conf");
|
|
}
|
|
Spatial *ElementData::get_grid_node(const String &key, bool exterior, int fl,
|
|
int i)
|
|
{
|
|
assert(has_floor(key, exterior, fl));
|
|
flecs::entity item_data = get_grid_entity(key, exterior, fl, i);
|
|
if (!item_data.has<struct grid_floor_item_node>()) {
|
|
Spatial *sp = memnew(Spatial);
|
|
get_as_node<Spatial>("%bg_floor")
|
|
->call_deferred("add_child", sp);
|
|
item_data.set<struct grid_floor_item_node>({ sp });
|
|
int x = i % grid_size;
|
|
int z = i / grid_size;
|
|
int rotation = get_grid_rotation(key, exterior, fl, i);
|
|
sp->set_transform(Transform(
|
|
Basis().rotated(Vector3(0, 1, 0),
|
|
Math_PI * rotation / 2.0f),
|
|
Vector3((x - 4) * 4, 1 + 5 * fl, (z - 4) * 4) -
|
|
get_as_node<Spatial>("%bg_floor")
|
|
->get_transform()
|
|
.origin));
|
|
} else {
|
|
int rotation = get_grid_rotation(key, exterior, fl, i);
|
|
const struct grid_floor_item_node *item =
|
|
item_data.get<struct grid_floor_item_node>();
|
|
Spatial *node = item->node;
|
|
assert(node);
|
|
Transform xform = node->get_transform();
|
|
xform.basis = Basis().rotated(Vector3(0, 1, 0),
|
|
rotation * Math_PI / 2.0f);
|
|
node->set_transform(xform);
|
|
}
|
|
return item_data.get<struct grid_floor_item_node>()->node;
|
|
} |