Skip to content
Snippets Groups Projects
Commit c963ab32 authored by Joseph Walton-Rivers's avatar Joseph Walton-Rivers
Browse files

add hexboard-style inheritance to prototypes

parent 7308b0f6
No related branches found
No related tags found
No related merge requests found
---
prefabs:
- name: "environment"
components:
gfx::material:
ambient: [0.0215, 0.1754, 0.0215]
diffuse: [1, 1, 1]
specular: [0.0633, 0.727811, 0.633]
shininess: 16
- name: "wallX"
parent: "environment"
components:
Transform:
StaticMesh:
......@@ -8,11 +16,6 @@ prefabs:
shape:
type: box
scale: [1.0, 5.0, 41]
gfx::material:
ambient: [0.0215, 0.1754, 0.0215]
diffuse: [1, 1, 1]
specular: [0.0633, 0.727811, 0.633]
shininess: 16
phys::Body:
type: static
shape:
......@@ -20,6 +23,7 @@ prefabs:
extents: [0.5, 2.5, 20.5]
# Wall Z shorter to avoid z-fighting
- name: "wallZ"
parent: "environment"
components:
Transform:
StaticMesh:
......@@ -27,17 +31,13 @@ prefabs:
shape:
type: box
scale: [39, 5, 1]
gfx::material:
ambient: [0.0215, 0.1754, 0.0215]
diffuse: [1, 1, 1]
specular: [0.0633, 0.727811, 0.633]
shininess: 16
phys::Body:
type: static
shape:
type: box
extents: [ 19.5, 2.5, 0.5 ]
- name: "floor"
parent: "environment"
components:
Transform:
StaticMesh:
......@@ -45,11 +45,6 @@ prefabs:
shape:
type: box # we don't (currently) support planes...
scale: [39, 0.5, 39]
gfx::material:
ambient: [0.0215, 0.1754, 0.0215]
diffuse: [1, 1, 1]
specular: [0.0633, 0.727811, 0.633]
shininess: 16
phys::Body:
type: static
shape:
......
......@@ -28,6 +28,7 @@ namespace fggl::entity {
auto nodes = YAML::LoadAllFromFile( filePath->c_str() );
for (const auto& node : nodes) {
auto prefabs = node["prefabs"];
for ( const auto& prefab : prefabs ) {
auto name = prefab["name"].as<fggl::util::GUID>();
......@@ -35,8 +36,10 @@ namespace fggl::entity {
debug::info("found prefab: {}", fggl::util::guidToString(name) );
#endif
// setup the components
// set up the components
EntitySpec entity{};
entity.parent = prefab["parent"].as<fggl::util::GUID>(NO_PARENT);
for (const auto& compEntry : prefab["components"]) {
auto compId = compEntry.first.as<fggl::util::GUID>();
......
......@@ -33,12 +33,8 @@ namespace fggl::entity {
constexpr auto PROTOTYPE_ASSET = assets::AssetType::make("entity_prototype");
using FactoryFunc = std::function<void(const ComponentSpec& config, EntityManager&, const EntityID&)>;
using CustomiseFunc = std::function<void(EntityManager&, const EntityID&)>;
using ComponentID = util::GUID;
using EntityType = util::GUID;
struct FactoryInfo {
FactoryFunc factory;
CustomiseFunc finalise = nullptr;
......@@ -50,36 +46,21 @@ namespace fggl::entity {
EntityID create(const EntityType& spec, EntityManager& manager, const CustomiseFunc& customise = nullptr) {
try {
auto &prototype = m_prototypes.at(spec);
std::vector<CustomiseFunc> finishers;
// invoke each component factory as required
auto entity = manager.create();
for ( auto& component : prototype.ordering ) {
try {
auto& data = prototype.components.at(component);
auto& info = m_factories.at(component);
info.factory(data, manager, entity);
if ( info.finalise != nullptr ) {
finishers.push_back(info.finalise);
}
} catch (std::out_of_range& ex) {
#ifndef NDEBUG
debug::log(debug::Level::error, "EntityFactory: Unknown component factory type '{}'", fggl::util::guidToString(component));
#endif
manager.destroy(entity);
return fggl::entity::INVALID;
}
// set up the components for the entity
auto entity = setupComponents(spec, manager, finishers);
if ( entity == entity::INVALID ) {
debug::error("Error attempting to create entity with type {}", std::to_string(spec.get()) );
return entity::INVALID;
}
// allow the caller to perform any setup needed
if (customise != nullptr) {
customise(manager, entity);
}
// finalise the entities
// finally, we run any cleanup/init setups required by the component factories
for( auto& finisher : finishers ) {
finisher(manager, entity);
}
......@@ -110,6 +91,56 @@ namespace fggl::entity {
private:
std::map<ComponentID, FactoryInfo> m_factories;
std::map<EntityType, EntitySpec> m_prototypes;
entity::EntityID setupComponents(EntityType entityType, EntityManager& manager, std::vector<CustomiseFunc>& finishers) {
auto entity = manager.create();
std::vector<ComponentID> loadedComps;
auto currentType = entityType;
while ( currentType != NO_PARENT ) {
auto& entitySpec = m_prototypes.at(currentType);
for ( auto& component : entitySpec.ordering ) {
// skip comps loaded by children
if (std::find(loadedComps.begin(), loadedComps.end(), component) != loadedComps.end()) {
continue;
}
try {
auto& data = getComponent(entitySpec, component);
loadedComps.push_back(component);
auto& info = m_factories.at(component);
info.factory(data, manager, entity);
if ( info.finalise != nullptr ) {
finishers.push_back(info.finalise);
}
} catch (std::out_of_range& ex) {
#ifndef NDEBUG
debug::log(debug::Level::error, "EntityFactory: Unknown component factory type '{}'", fggl::util::guidToString(component));
#endif
manager.destroy(entity);
return entity::INVALID;
}
}
currentType = entitySpec.parent;
}
return entity;
}
ComponentSpec& getComponent(EntitySpec& prototype, util::GUID compToken) {
auto compItr = prototype.components.find(compToken);
if ( compItr != prototype.components.end() ) {
return compItr->second;
}
if ( prototype.parent == NO_PARENT ) {
throw std::out_of_range("EntityFactory: no such component!");
}
return getComponent(m_prototypes.at(prototype.parent), compToken);
}
};
assets::AssetRefRaw load_prototype(EntityFactory* factory, const assets::AssetGUID& guid, assets::AssetData data);
......
......@@ -26,6 +26,10 @@
namespace fggl::entity {
using ComponentID = util::GUID;
using EntityType = util::GUID;
constexpr EntityType NO_PARENT = util::make_guid("FGGL_NULL_PARENT");
struct ComponentSpec {
template<typename T>
......@@ -46,8 +50,9 @@ namespace fggl::entity {
};
struct EntitySpec {
std::vector<util::GUID> ordering;
std::map<util::GUID, ComponentSpec> components;
EntityType parent = NO_PARENT;
std::vector<ComponentID> ordering;
std::map<ComponentID, ComponentSpec> components;
};
} // namespace fggl::entity
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment