first impl component creator

This commit is contained in:
2019-05-17 12:03:31 +07:00
parent f87a098424
commit e976840c3d
5 changed files with 235 additions and 28 deletions

View File

@@ -27,9 +27,39 @@ namespace e2d
// component_loader
//
template < typename Component >
template < typename Component = void >
class component_loader;
template <>
class component_loader<> {
public:
struct fill_context {
const str parent_address;
const rapidjson::Value& root;
const asset_group& dependencies;
fill_context(
str nparent_address,
const rapidjson::Value& nroot,
const asset_group& ndependencies)
: parent_address(std::move(nparent_address))
, root(nroot)
, dependencies(ndependencies) {}
};
struct collect_context {
const str parent_address;
const rapidjson::Value& root;
collect_context(
str nparent_address,
const rapidjson::Value& nroot)
: parent_address(std::move(nparent_address))
, root(nroot) {}
};
public:
};
//
// component_creator_base
//
@@ -43,6 +73,14 @@ namespace e2d
public:
component_creator_base() = default;
virtual ~component_creator_base() noexcept = default;
virtual bool fill_prototype(
ecs::prototype& prototype,
const component_loader<>::fill_context& ctx) const = 0;
virtual bool collect_dependencies(
asset_dependencies& dependencies,
const component_loader<>::collect_context& ctx) const = 0;
};
//
@@ -54,6 +92,16 @@ namespace e2d
public:
component_creator() = default;
~component_creator() noexcept override = default;
bool fill_prototype(
ecs::prototype& prototype,
const component_loader<>::fill_context& ctx) const override;
bool collect_dependencies(
asset_dependencies& dependencies,
const component_loader<>::collect_context& ctx) const override;
private:
component_loader<Component> loader_;
};
//
@@ -67,8 +115,20 @@ namespace e2d
template < typename Component >
component_factory& register_component(str_hash type);
bool fill_prototype(
str_hash type,
ecs::prototype& prototype,
const component_loader<>::fill_context& ctx) const;
bool collect_dependencies(
str_hash type,
asset_dependencies& dependencies,
const component_loader<>::collect_context& ctx) const;
private:
std::mutex mutex_;
component_creator_base_iptr find_creator(str_hash type) const;
private:
mutable std::mutex mutex_;
hash_map<str_hash, component_creator_base_iptr> creators_;
};
}

View File

@@ -13,6 +13,35 @@
namespace e2d
{
//
// component_creator
//
template < typename Component >
bool component_creator<Component>::fill_prototype(
ecs::prototype& prototype,
const component_loader<>::fill_context& ctx) const
{
Component component;
if ( !loader_(ctx.parent_address, ctx.root, ctx.dependencies, component) ) {
return false;
}
prototype.component<Component>(component);
return true;
}
template < typename Component >
bool component_creator<Component>::collect_dependencies(
asset_dependencies& dependencies,
const component_loader<>::collect_context& ctx) const
{
return loader_(ctx.parent_address, ctx.root, dependencies);
}
//
// component_factory
//
template < typename Component >
component_factory& component_factory::register_component(str_hash type) {
std::lock_guard<std::mutex> guard(mutex_);

View File

@@ -6,6 +6,7 @@
#include <enduro2d/high/assets/prefab_asset.hpp>
#include <enduro2d/high/component.hpp>
#include <enduro2d/high/assets/json_asset.hpp>
namespace
@@ -65,13 +66,98 @@ namespace
return *schema;
}
stdex::promise<prefab> parse_prefab(
void collect_dependencies(
str_view parent_address,
const rapidjson::Value& root,
asset_dependencies& dependencies)
{
if ( root.HasMember("prototype") ) {
dependencies.add_dependency<prefab_asset>(
path::combine(parent_address, root["prototype"].GetString()));
}
if ( root.HasMember("components") ) {
const rapidjson::Value& components_root = root["components"];
for ( rapidjson::Value::ConstMemberIterator component_root = components_root.MemberBegin();
component_root != components_root.MemberEnd();
++component_root )
{
component_loader<>::collect_context ctx(
parent_address,
component_root->value);
the<component_factory>().collect_dependencies(
component_root->name.GetString(),
dependencies,
ctx);
}
}
if ( root.HasMember("children") ) {
const rapidjson::Value& children_root = root["children"];
for ( rapidjson::SizeType i = 0; i < children_root.Size(); ++i ) {
collect_dependencies(parent_address, children_root[i], dependencies);
}
}
}
stdex::promise<asset_group> collect_dependencies(
const library& library,
str_view parent_address,
const rapidjson::Value& root)
{
E2D_UNUSED(library, parent_address, root);
return stdex::make_resolved_promise(prefab());
asset_dependencies dependencies;
collect_dependencies(parent_address, root, dependencies);
return dependencies.load_async(library);
}
prefab parse_prefab(
str_view parent_address,
const rapidjson::Value& root,
const asset_group& dependencies)
{
prefab content;
if ( root.HasMember("prototype") ) {
auto proto_res = dependencies.find_asset<prefab_asset>(
path::combine(parent_address, root["prototype"].GetString()));
if ( !proto_res ) {
throw prefab_asset_loading_exception();
}
content = proto_res->content();
}
if ( root.HasMember("components") ) {
const rapidjson::Value& components_root = root["components"];
for ( rapidjson::Value::ConstMemberIterator component_root = components_root.MemberBegin();
component_root != components_root.MemberEnd();
++component_root )
{
component_loader<>::fill_context ctx(
parent_address,
component_root->value,
dependencies);
the<component_factory>().fill_prototype(
component_root->name.GetString(),
content.prototype(),
ctx);
}
}
if ( root.HasMember("children") ) {
const rapidjson::Value& children_root = root["children"];
vector<prefab> children;
children.reserve(children_root.Size());
for ( rapidjson::SizeType i = 0; i < children_root.Size(); ++i ) {
children.emplace_back(parse_prefab(
parent_address, children_root[i], dependencies));
}
content.set_children(std::move(children));
}
return content;
}
}
@@ -93,12 +179,12 @@ namespace e2d
}
})
.then([&library, parent_address, prefab_data](){
return parse_prefab(
return collect_dependencies(
library, parent_address, prefab_data->content());
})
.then([](auto&& content){
return prefab_asset::create(
std::forward<decltype(content)>(content));
.then([parent_address, prefab_data](const asset_group& dependencies){
return prefab_asset::create(parse_prefab(
parent_address, prefab_data->content(), dependencies));
});
});
}

View File

@@ -0,0 +1,40 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include <enduro2d/high/component.hpp>
namespace e2d
{
bool component_factory::fill_prototype(
str_hash type,
ecs::prototype& prototype,
const component_loader<>::fill_context& ctx) const
{
auto creator = find_creator(type);
return creator
? creator->fill_prototype(prototype, ctx)
: false;
}
bool component_factory::collect_dependencies(
str_hash type,
asset_dependencies& dependencies,
const component_loader<>::collect_context& ctx) const
{
auto creator = find_creator(type);
return creator
? creator->collect_dependencies(dependencies, ctx)
: false;
}
component_creator_base_iptr component_factory::find_creator(str_hash type) const {
std::lock_guard<std::mutex> guard(mutex_);
const auto iter = creators_.find(type);
return iter != creators_.end()
? iter->second
: nullptr;
}
}

View File

@@ -30,16 +30,12 @@ namespace e2d
gobjects_.emplace(inst->entity().id(), inst);
try {
auto inst_n = node::create(inst);
auto inst_a = inst->get_component<actor>();
if ( !inst_a.exists() ) {
inst_a.assign(node::create(inst));
}
if ( !inst_a.get().node() ) {
inst_a.get().node(node::create(inst));
}
if ( inst_a.get().node()->owner() != inst ) {
inst_a.get().node()->owner(inst);
if ( inst_a && inst_a->node() ) {
inst_n->transform(inst_a->node()->transform());
}
inst_a.assign(inst_n);
} catch (...) {
destroy_instance(inst, true);
throw;
@@ -53,16 +49,12 @@ namespace e2d
gobjects_.emplace(inst->entity().id(), inst);
try {
auto inst_n = node::create(inst);
auto inst_a = inst->get_component<actor>();
if ( !inst_a.exists() ) {
inst_a.assign(node::create(inst));
}
if ( !inst_a.get().node() ) {
inst_a.get().node(node::create(inst));
}
if ( inst_a.get().node()->owner() != inst ) {
inst_a.get().node()->owner(inst);
if ( inst_a && inst_a->node() ) {
inst_n->transform(inst_a->node()->transform());
}
inst_a.assign(inst_n);
} catch (...) {
destroy_instance(inst, true);
throw;
@@ -74,7 +66,7 @@ namespace e2d
try {
auto inst_a = inst->get_component<actor>();
auto child_a = child->get_component<actor>();
inst_a.get().node()->add_child(child_a.get().node());
inst_a->node()->add_child(child_a->node());
} catch (...) {
destroy_instance(child, true);
throw;
@@ -90,8 +82,8 @@ namespace e2d
void world::destroy_instance(const gobject_iptr& inst, bool recursive) noexcept {
if ( recursive ) {
node_iptr inst_n = inst && inst->get_component<actor>().exists()
? inst->get_component<actor>().get().node()
node_iptr inst_n = inst && inst->get_component<actor>()
? inst->get_component<actor>()->node()
: nullptr;
if ( inst_n ) {
inst_n->for_each_child([this](const node_iptr& child_n){