mirror of
https://github.com/enduro2d/enduro2d.git
synced 2025-12-14 16:09:06 +07:00
Merge branch 'feature/safe_gobject' into feature/scripting
This commit is contained in:
@@ -74,11 +74,6 @@ namespace e2d
|
||||
|
||||
class atlas;
|
||||
class flipbook;
|
||||
class gobject;
|
||||
template < typename T >
|
||||
class gcomponent;
|
||||
template < typename T >
|
||||
class const_gcomponent;
|
||||
class model;
|
||||
class node;
|
||||
class prefab;
|
||||
@@ -89,6 +84,12 @@ namespace e2d
|
||||
class luasol;
|
||||
class starter;
|
||||
class world;
|
||||
|
||||
class gobject;
|
||||
template < typename T >
|
||||
class gcomponent;
|
||||
template < typename T >
|
||||
class const_gcomponent;
|
||||
}
|
||||
|
||||
namespace sol
|
||||
|
||||
@@ -8,17 +8,6 @@
|
||||
|
||||
#include "_high.hpp"
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
class gobject;
|
||||
|
||||
template < typename T >
|
||||
class gcomponent;
|
||||
|
||||
template < typename T >
|
||||
class const_gcomponent;
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
class gobject final {
|
||||
@@ -33,6 +22,8 @@ namespace e2d
|
||||
bool valid() const noexcept;
|
||||
explicit operator bool() const noexcept;
|
||||
|
||||
void destroy() noexcept;
|
||||
|
||||
template < typename T >
|
||||
gcomponent<T> component() noexcept;
|
||||
|
||||
@@ -110,31 +101,23 @@ namespace e2d
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
class gobject_destroying_state_ilist_tag;
|
||||
using gobject_destroying_states = intrusive_list<
|
||||
gobject::state,
|
||||
gobject_destroying_state_ilist_tag>;
|
||||
|
||||
class gobject::state
|
||||
: private noncopyable
|
||||
, public ref_counter<state> {
|
||||
, public ref_counter<state>
|
||||
, public intrusive_list_hook<gobject_destroying_state_ilist_tag> {
|
||||
public:
|
||||
virtual ~state() noexcept {}
|
||||
virtual bool valid() const noexcept = 0;
|
||||
virtual void destroy() noexcept = 0;
|
||||
virtual bool invalided() const noexcept = 0;
|
||||
virtual ecs::entity raw_entity() noexcept = 0;
|
||||
virtual ecs::const_entity raw_entity() const noexcept = 0;
|
||||
};
|
||||
|
||||
inline const gobject::state_iptr& gobject::internal_state() const noexcept {
|
||||
return state_;
|
||||
}
|
||||
|
||||
inline gobject::gobject(state_iptr state)
|
||||
: state_(std::move(state)) {}
|
||||
|
||||
inline bool gobject::valid() const noexcept {
|
||||
return state_ && state_->valid();
|
||||
}
|
||||
|
||||
inline gobject::operator bool() const noexcept {
|
||||
return valid();
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
gcomponent<T> gobject::component() noexcept {
|
||||
return gcomponent<T>(*this);
|
||||
@@ -145,16 +128,6 @@ namespace e2d
|
||||
return const_gcomponent<T>(*this);
|
||||
}
|
||||
|
||||
inline ecs::entity gobject::raw_entity() noexcept {
|
||||
E2D_ASSERT(valid());
|
||||
return state_->raw_entity();
|
||||
}
|
||||
|
||||
inline ecs::const_entity gobject::raw_entity() const noexcept {
|
||||
E2D_ASSERT(valid());
|
||||
return state_->raw_entity();
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
ecs::component<T> gobject::raw_component() noexcept {
|
||||
E2D_ASSERT(valid());
|
||||
|
||||
@@ -42,6 +42,8 @@ namespace e2d
|
||||
static node_iptr create(gobject owner, const node_iptr& parent, const t3f& transform);
|
||||
|
||||
void owner(gobject owner) noexcept;
|
||||
|
||||
gobject& owner() noexcept;
|
||||
const gobject& owner() const noexcept;
|
||||
|
||||
void transform(const t3f& transform) noexcept;
|
||||
|
||||
@@ -51,12 +51,17 @@ namespace e2d
|
||||
gobject instantiate(const prefab& prefab, const gobject& parent, const t3f& transform);
|
||||
gobject instantiate(const prefab& prefab, const node_iptr& parent, const t3f& transform);
|
||||
|
||||
void destroy_instance(const gobject& inst) noexcept;
|
||||
void destroy_instance(gobject& inst) noexcept;
|
||||
void finalize_instances() noexcept;
|
||||
|
||||
gobject resolve(ecs::entity_id ent) const noexcept;
|
||||
gobject resolve(const ecs::const_entity& ent) const noexcept;
|
||||
private:
|
||||
void destroy_instances_() noexcept;
|
||||
void finalize_instance_(gobject& inst) noexcept;
|
||||
private:
|
||||
ecs::registry registry_;
|
||||
hash_map<ecs::entity_id, gobject> gobjects_;
|
||||
gobject_destroying_states destroying_states_;
|
||||
};
|
||||
}
|
||||
|
||||
41
sources/enduro2d/high/gobject.cpp
Normal file
41
sources/enduro2d/high/gobject.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/*******************************************************************************
|
||||
* 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/gobject.hpp>
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
const gobject::state_iptr& gobject::internal_state() const noexcept {
|
||||
return state_;
|
||||
}
|
||||
|
||||
gobject::gobject(state_iptr state)
|
||||
: state_(std::move(state)) {}
|
||||
|
||||
bool gobject::valid() const noexcept {
|
||||
return state_ && !state_->invalided();
|
||||
}
|
||||
|
||||
gobject::operator bool() const noexcept {
|
||||
return valid();
|
||||
}
|
||||
|
||||
void gobject::destroy() noexcept {
|
||||
if ( valid() ) {
|
||||
state_->destroy();
|
||||
}
|
||||
}
|
||||
|
||||
ecs::entity gobject::raw_entity() noexcept {
|
||||
E2D_ASSERT(valid());
|
||||
return state_->raw_entity();
|
||||
}
|
||||
|
||||
ecs::const_entity gobject::raw_entity() const noexcept {
|
||||
E2D_ASSERT(valid());
|
||||
return state_->raw_entity();
|
||||
}
|
||||
}
|
||||
@@ -69,6 +69,10 @@ namespace e2d
|
||||
owner_ = std::move(owner);
|
||||
}
|
||||
|
||||
gobject& node::owner() noexcept {
|
||||
return owner_;
|
||||
}
|
||||
|
||||
const gobject& node::owner() const noexcept {
|
||||
return owner_;
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ namespace
|
||||
the<world>().registry().process_systems_in_range(
|
||||
world::priority_update_section_begin,
|
||||
world::priority_update_section_end);
|
||||
the<world>().finalize_instances();
|
||||
return !the<window>().should_close()
|
||||
|| (application_ && !application_->on_should_close());
|
||||
}
|
||||
|
||||
@@ -13,49 +13,58 @@ namespace
|
||||
using namespace e2d;
|
||||
|
||||
class gobject_state final : public gobject::state {
|
||||
private:
|
||||
enum flag_masks : u32 {
|
||||
fm_invalided = 1u << 0,
|
||||
fm_destroying = 1u << 1,
|
||||
};
|
||||
public:
|
||||
gobject_state(ecs::registry& registry)
|
||||
: entity_(registry.create_entity()) {}
|
||||
gobject_state(world& w, ecs::entity e)
|
||||
: world_(w)
|
||||
, entity_(std::move(e)) {}
|
||||
|
||||
gobject_state(ecs::registry& registry, const ecs::prototype& proto)
|
||||
: entity_(registry.create_entity(proto)) {}
|
||||
|
||||
~gobject_state() final {
|
||||
destroy();
|
||||
void mark_invalided() noexcept {
|
||||
math::set_flags_inplace(flags_, fm_invalided);
|
||||
}
|
||||
|
||||
void destroy() noexcept {
|
||||
if ( valid() ) {
|
||||
entity_.destroy();
|
||||
valid_ = false;
|
||||
}
|
||||
void mark_destroying() noexcept {
|
||||
math::set_flags_inplace(flags_, fm_destroying);
|
||||
}
|
||||
|
||||
bool valid() const noexcept final {
|
||||
return valid_;
|
||||
bool destroying() const noexcept {
|
||||
return math::check_any_flags(flags_, fm_destroying);
|
||||
}
|
||||
public:
|
||||
void destroy() noexcept final {
|
||||
gobject go{this};
|
||||
world_.destroy_instance(go);
|
||||
}
|
||||
|
||||
bool invalided() const noexcept final {
|
||||
return math::check_any_flags(flags_, fm_invalided);
|
||||
}
|
||||
|
||||
ecs::entity raw_entity() noexcept final {
|
||||
E2D_ASSERT(valid());
|
||||
E2D_ASSERT(!invalided());
|
||||
return entity_;
|
||||
}
|
||||
|
||||
ecs::const_entity raw_entity() const noexcept final {
|
||||
E2D_ASSERT(valid());
|
||||
E2D_ASSERT(!invalided());
|
||||
return entity_;
|
||||
}
|
||||
private:
|
||||
bool valid_{true};
|
||||
world& world_;
|
||||
ecs::entity entity_;
|
||||
u32 flags_{0u};
|
||||
};
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
world::~world() noexcept {
|
||||
while ( !gobjects_.empty() ) {
|
||||
destroy_instance(gobjects_.begin()->second);
|
||||
}
|
||||
destroy_instances_();
|
||||
finalize_instances();
|
||||
}
|
||||
|
||||
ecs::registry& world::registry() noexcept {
|
||||
@@ -67,7 +76,9 @@ namespace e2d
|
||||
}
|
||||
|
||||
gobject world::instantiate() {
|
||||
gobject inst{make_intrusive<gobject_state>(registry_)};
|
||||
gobject inst{make_intrusive<gobject_state>(
|
||||
*this,
|
||||
registry_.create_entity())};
|
||||
gobjects_.emplace(inst.raw_entity().id(), inst);
|
||||
|
||||
try {
|
||||
@@ -78,7 +89,7 @@ namespace e2d
|
||||
}
|
||||
inst_a.assign(n);
|
||||
} catch (...) {
|
||||
destroy_instance(inst);
|
||||
finalize_instance_(inst);
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -86,7 +97,9 @@ namespace e2d
|
||||
}
|
||||
|
||||
gobject world::instantiate(const prefab& prefab) {
|
||||
gobject inst{make_intrusive<gobject_state>(registry_, prefab.prototype())};
|
||||
gobject inst{make_intrusive<gobject_state>(
|
||||
*this,
|
||||
registry_.create_entity(prefab.prototype()))};
|
||||
gobjects_.emplace(inst.raw_entity().id(), inst);
|
||||
|
||||
try {
|
||||
@@ -97,7 +110,7 @@ namespace e2d
|
||||
}
|
||||
inst_a.assign(n);
|
||||
} catch (...) {
|
||||
destroy_instance(inst);
|
||||
finalize_instance_(inst);
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -109,12 +122,12 @@ namespace e2d
|
||||
gcomponent<actor> child_a{child};
|
||||
inst_a->node()->add_child(child_a->node());
|
||||
} catch (...) {
|
||||
destroy_instance(child);
|
||||
finalize_instance_(child);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
destroy_instance(inst);
|
||||
finalize_instance_(inst);
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -124,6 +137,7 @@ namespace e2d
|
||||
gobject world::instantiate(const gobject& parent) {
|
||||
gobject go = instantiate();
|
||||
if ( go && parent ) {
|
||||
try {
|
||||
gcomponent<actor> parent_a{parent};
|
||||
if ( !parent_a ) {
|
||||
parent_a.assign(node::create(parent));
|
||||
@@ -132,6 +146,10 @@ namespace e2d
|
||||
parent_a->node(node::create(parent));
|
||||
}
|
||||
parent_a->node()->add_child(gcomponent<actor>{go}->node());
|
||||
} catch (...) {
|
||||
finalize_instance_(go);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return go;
|
||||
}
|
||||
@@ -147,6 +165,7 @@ namespace e2d
|
||||
gobject world::instantiate(const prefab& prefab, const gobject& parent) {
|
||||
gobject go = instantiate(prefab);
|
||||
if ( go && parent ) {
|
||||
try {
|
||||
gcomponent<actor> parent_a{parent};
|
||||
if ( !parent_a ) {
|
||||
parent_a.assign(node::create(parent));
|
||||
@@ -155,6 +174,10 @@ namespace e2d
|
||||
parent_a->node(node::create(parent));
|
||||
}
|
||||
parent_a->node()->add_child(gcomponent<actor>{go}->node());
|
||||
} catch (...) {
|
||||
finalize_instance_(go);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return go;
|
||||
}
|
||||
@@ -199,19 +222,21 @@ namespace e2d
|
||||
return go;
|
||||
}
|
||||
|
||||
void world::destroy_instance(const gobject& inst) noexcept {
|
||||
gcomponent<actor> inst_a{inst};
|
||||
auto inst_n = inst_a ? inst_a->node() : nullptr;
|
||||
|
||||
if ( inst_n ) {
|
||||
inst_n->for_each_child([this](const const_node_iptr& child_n){
|
||||
destroy_instance(child_n->owner());
|
||||
});
|
||||
void world::destroy_instance(gobject& inst) noexcept {
|
||||
auto gstate = inst
|
||||
? dynamic_pointer_cast<gobject_state>(inst.internal_state())
|
||||
: nullptr;
|
||||
if ( gstate && !gstate->destroying() ) {
|
||||
gstate->mark_destroying();
|
||||
destroying_states_.push_back(*gstate);
|
||||
}
|
||||
}
|
||||
|
||||
if ( inst ) {
|
||||
gobjects_.erase(inst.raw_entity().id());
|
||||
dynamic_pointer_cast<gobject_state>(inst.internal_state())->destroy();
|
||||
void world::finalize_instances() noexcept {
|
||||
while ( !destroying_states_.empty() ) {
|
||||
gobject inst{&destroying_states_.front()};
|
||||
destroying_states_.pop_front();
|
||||
finalize_instance_(inst);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,4 +255,27 @@ namespace e2d
|
||||
? iter->second
|
||||
: gobject();
|
||||
}
|
||||
|
||||
void world::destroy_instances_() noexcept {
|
||||
for ( auto& [_, go] : gobjects_ ) {
|
||||
destroy_instance(go);
|
||||
}
|
||||
}
|
||||
|
||||
void world::finalize_instance_(gobject& inst) noexcept {
|
||||
gcomponent<actor> inst_a{inst};
|
||||
auto inst_n = inst_a ? inst_a->node() : nullptr;
|
||||
|
||||
if ( inst_n ) {
|
||||
inst_n->for_each_child([this](const node_iptr& child_n){
|
||||
destroy_instance(child_n->owner());
|
||||
});
|
||||
}
|
||||
|
||||
if ( inst ) {
|
||||
inst.raw_entity().destroy();
|
||||
gobjects_.erase(inst.raw_entity().id());
|
||||
dynamic_pointer_cast<gobject_state>(inst.internal_state())->mark_invalided();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user