|
|
@@ -1,487 +0,0 @@
|
|
|
-#ifndef ENTT_ENTITY_PROTOTYPE_HPP
|
|
|
-#define ENTT_ENTITY_PROTOTYPE_HPP
|
|
|
-
|
|
|
-
|
|
|
-#include <tuple>
|
|
|
-#include <utility>
|
|
|
-#include <cstddef>
|
|
|
-#include <type_traits>
|
|
|
-#include <unordered_map>
|
|
|
-#include "../config/config.h"
|
|
|
-#include "registry.hpp"
|
|
|
-#include "entity.hpp"
|
|
|
-#include "fwd.hpp"
|
|
|
-
|
|
|
-
|
|
|
-namespace entt {
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * @brief Prototype container for _concepts_.
|
|
|
- *
|
|
|
- * @deprecated
|
|
|
- * This class will be wiped out in a future version of the library.<br/>
|
|
|
- * Use a prototype registry and the new `registry::stomp` functionality to
|
|
|
- * achieve the same result in a more idiomatic way.
|
|
|
- *
|
|
|
- * A prototype is used to define a _concept_ in terms of components.<br/>
|
|
|
- * Prototypes act as templates for those specific types of an application which
|
|
|
- * users would otherwise define through a series of component assignments to
|
|
|
- * entities. In other words, prototypes can be used to assign components to
|
|
|
- * entities of a registry at once.
|
|
|
- *
|
|
|
- * @note
|
|
|
- * Components used along with prototypes must be copy constructible. Prototypes
|
|
|
- * wrap component types with custom types, so they do not interfere with other
|
|
|
- * users of the registry they were built with.
|
|
|
- *
|
|
|
- * @warning
|
|
|
- * Prototypes directly use their underlying registries to store entities and
|
|
|
- * components for their purposes. Users must ensure that the lifetime of a
|
|
|
- * registry and its contents exceed that of the prototypes that use it.
|
|
|
- *
|
|
|
- * @tparam Entity A valid entity type (see entt_traits for more details).
|
|
|
- */
|
|
|
-template<typename Entity>
|
|
|
-class basic_prototype {
|
|
|
- using basic_fn_type = void(const basic_prototype &, basic_registry<Entity> &, const Entity);
|
|
|
-
|
|
|
- template<typename Component>
|
|
|
- struct component_wrapper { Component component; };
|
|
|
-
|
|
|
- struct component_handler {
|
|
|
- basic_fn_type *assign_or_replace;
|
|
|
- basic_fn_type *assign;
|
|
|
- };
|
|
|
-
|
|
|
- void release() {
|
|
|
- if(reg->valid(entity)) {
|
|
|
- reg->destroy(entity);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-public:
|
|
|
- /*! @brief Registry type. */
|
|
|
- using registry_type = basic_registry<Entity>;
|
|
|
- /*! @brief Underlying entity identifier. */
|
|
|
- using entity_type = Entity;
|
|
|
- /*! @brief Unsigned integer type. */
|
|
|
- using size_type = std::size_t;
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Constructs a prototype that is bound to a given registry.
|
|
|
- * @param ref A valid reference to a registry.
|
|
|
- */
|
|
|
- explicit basic_prototype(registry_type &ref)
|
|
|
- : reg{&ref},
|
|
|
- entity{ref.create()}
|
|
|
- {}
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Releases all its resources.
|
|
|
- */
|
|
|
- ~basic_prototype() {
|
|
|
- release();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Move constructor.
|
|
|
- *
|
|
|
- * After prototype move construction, instances that have been moved from
|
|
|
- * are placed in a valid but unspecified state. It's highly discouraged to
|
|
|
- * continue using them.
|
|
|
- *
|
|
|
- * @param other The instance to move from.
|
|
|
- */
|
|
|
- basic_prototype(basic_prototype &&other)
|
|
|
- : handlers{std::move(other.handlers)},
|
|
|
- reg{other.reg},
|
|
|
- entity{other.entity}
|
|
|
- {
|
|
|
- other.entity = null;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Move assignment operator.
|
|
|
- *
|
|
|
- * After prototype move assignment, instances that have been moved from are
|
|
|
- * placed in a valid but unspecified state. It's highly discouraged to
|
|
|
- * continue using them.
|
|
|
- *
|
|
|
- * @param other The instance to move from.
|
|
|
- * @return This prototype.
|
|
|
- */
|
|
|
- basic_prototype & operator=(basic_prototype &&other) {
|
|
|
- if(this != &other) {
|
|
|
- auto tmp{std::move(other)};
|
|
|
- handlers.swap(tmp.handlers);
|
|
|
- std::swap(reg, tmp.reg);
|
|
|
- std::swap(entity, tmp.entity);
|
|
|
- }
|
|
|
-
|
|
|
- return *this;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Assigns to or replaces the given component of a prototype.
|
|
|
- * @tparam Component Type of component to assign or replace.
|
|
|
- * @tparam Args Types of arguments to use to construct the component.
|
|
|
- * @param args Parameters to use to initialize the component.
|
|
|
- * @return A reference to the newly created component.
|
|
|
- */
|
|
|
- template<typename Component, typename... Args>
|
|
|
- Component & set(Args &&... args) {
|
|
|
- component_handler handler;
|
|
|
-
|
|
|
- handler.assign_or_replace = [](const basic_prototype &proto, registry_type &other, const Entity dst) {
|
|
|
- const auto &wrapper = proto.reg->template get<component_wrapper<Component>>(proto.entity);
|
|
|
- other.template assign_or_replace<Component>(dst, wrapper.component);
|
|
|
- };
|
|
|
-
|
|
|
- handler.assign = [](const basic_prototype &proto, registry_type &other, const Entity dst) {
|
|
|
- if(!other.template has<Component>(dst)) {
|
|
|
- const auto &wrapper = proto.reg->template get<component_wrapper<Component>>(proto.entity);
|
|
|
- other.template assign<Component>(dst, wrapper.component);
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- handlers[reg->template type<Component>()] = handler;
|
|
|
- auto &wrapper = reg->template assign_or_replace<component_wrapper<Component>>(entity, Component{std::forward<Args>(args)...});
|
|
|
- return wrapper.component;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Removes the given component from a prototype.
|
|
|
- * @tparam Component Type of component to remove.
|
|
|
- */
|
|
|
- template<typename Component>
|
|
|
- void unset() ENTT_NOEXCEPT {
|
|
|
- reg->template reset<component_wrapper<Component>>(entity);
|
|
|
- handlers.erase(reg->template type<Component>());
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Checks if a prototype owns all the given components.
|
|
|
- * @tparam Component Components for which to perform the check.
|
|
|
- * @return True if the prototype owns all the components, false otherwise.
|
|
|
- */
|
|
|
- template<typename... Component>
|
|
|
- bool has() const ENTT_NOEXCEPT {
|
|
|
- return reg->template has<component_wrapper<Component>...>(entity);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Returns references to the given components.
|
|
|
- *
|
|
|
- * @warning
|
|
|
- * Attempting to get a component from a prototype that doesn't own it
|
|
|
- * results in undefined behavior.<br/>
|
|
|
- * An assertion will abort the execution at runtime in debug mode if the
|
|
|
- * prototype doesn't own an instance of the given component.
|
|
|
- *
|
|
|
- * @tparam Component Types of components to get.
|
|
|
- * @return References to the components owned by the prototype.
|
|
|
- */
|
|
|
- template<typename... Component>
|
|
|
- decltype(auto) get() const ENTT_NOEXCEPT {
|
|
|
- if constexpr(sizeof...(Component) == 1) {
|
|
|
- return (std::as_const(*reg).template get<component_wrapper<Component...>>(entity).component);
|
|
|
- } else {
|
|
|
- return std::tuple<std::add_const_t<Component> &...>{get<Component>()...};
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /*! @copydoc get */
|
|
|
- template<typename... Component>
|
|
|
- decltype(auto) get() ENTT_NOEXCEPT {
|
|
|
- if constexpr(sizeof...(Component) == 1) {
|
|
|
- return (const_cast<Component &>(std::as_const(*this).template get<Component>()), ...);
|
|
|
- } else {
|
|
|
- return std::tuple<Component &...>{get<Component>()...};
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Returns pointers to the given components.
|
|
|
- * @tparam Component Types of components to get.
|
|
|
- * @return Pointers to the components owned by the prototype.
|
|
|
- */
|
|
|
- template<typename... Component>
|
|
|
- auto try_get() const ENTT_NOEXCEPT {
|
|
|
- if constexpr(sizeof...(Component) == 1) {
|
|
|
- const auto *wrapper = reg->template try_get<component_wrapper<Component...>>(entity);
|
|
|
- return wrapper ? &wrapper->component : nullptr;
|
|
|
- } else {
|
|
|
- return std::tuple<std::add_const_t<Component> *...>{try_get<Component>()...};
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /*! @copydoc try_get */
|
|
|
- template<typename... Component>
|
|
|
- auto try_get() ENTT_NOEXCEPT {
|
|
|
- if constexpr(sizeof...(Component) == 1) {
|
|
|
- return (const_cast<Component *>(std::as_const(*this).template try_get<Component>()), ...);
|
|
|
- } else {
|
|
|
- return std::tuple<Component *...>{try_get<Component>()...};
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Creates a new entity using a given prototype.
|
|
|
- *
|
|
|
- * Utility shortcut, equivalent to the following snippet:
|
|
|
- *
|
|
|
- * @code{.cpp}
|
|
|
- * const auto entity = registry.create();
|
|
|
- * prototype(registry, entity);
|
|
|
- * @endcode
|
|
|
- *
|
|
|
- * @note
|
|
|
- * The registry may or may not be different from the one already used by
|
|
|
- * the prototype. There is also an overload that directly uses the
|
|
|
- * underlying registry.
|
|
|
- *
|
|
|
- * @param other A valid reference to a registry.
|
|
|
- * @return A valid entity identifier.
|
|
|
- */
|
|
|
- entity_type create(registry_type &other) const {
|
|
|
- const auto entt = other.create();
|
|
|
- assign(other, entt);
|
|
|
- return entt;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Creates a new entity using a given prototype.
|
|
|
- *
|
|
|
- * Utility shortcut, equivalent to the following snippet:
|
|
|
- *
|
|
|
- * @code{.cpp}
|
|
|
- * const auto entity = registry.create();
|
|
|
- * prototype(entity);
|
|
|
- * @endcode
|
|
|
- *
|
|
|
- * @note
|
|
|
- * This overload directly uses the underlying registry as a working space.
|
|
|
- * Therefore, the components of the prototype and of the entity will share
|
|
|
- * the same registry.
|
|
|
- *
|
|
|
- * @return A valid entity identifier.
|
|
|
- */
|
|
|
- entity_type create() const {
|
|
|
- return create(*reg);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Assigns the components of a prototype to a given entity.
|
|
|
- *
|
|
|
- * Assigning a prototype to an entity won't overwrite existing components
|
|
|
- * under any circumstances.<br/>
|
|
|
- * In other words, only those components that the entity doesn't own yet are
|
|
|
- * copied over. All the other components remain unchanged.
|
|
|
- *
|
|
|
- * @note
|
|
|
- * The registry may or may not be different from the one already used by
|
|
|
- * the prototype. There is also an overload that directly uses the
|
|
|
- * underlying registry.
|
|
|
- *
|
|
|
- * @warning
|
|
|
- * Attempting to use an invalid entity results in undefined behavior.<br/>
|
|
|
- * An assertion will abort the execution at runtime in debug mode in case of
|
|
|
- * invalid entity.
|
|
|
- *
|
|
|
- * @param other A valid reference to a registry.
|
|
|
- * @param dst A valid entity identifier.
|
|
|
- */
|
|
|
- void assign(registry_type &other, const entity_type dst) const {
|
|
|
- for(auto &handler: handlers) {
|
|
|
- handler.second.assign(*this, other, dst);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Assigns the components of a prototype to a given entity.
|
|
|
- *
|
|
|
- * Assigning a prototype to an entity won't overwrite existing components
|
|
|
- * under any circumstances.<br/>
|
|
|
- * In other words, only those components that the entity doesn't own yet are
|
|
|
- * copied over. All the other components remain unchanged.
|
|
|
- *
|
|
|
- * @note
|
|
|
- * This overload directly uses the underlying registry as a working space.
|
|
|
- * Therefore, the components of the prototype and of the entity will share
|
|
|
- * the same registry.
|
|
|
- *
|
|
|
- * @warning
|
|
|
- * Attempting to use an invalid entity results in undefined behavior.<br/>
|
|
|
- * An assertion will abort the execution at runtime in debug mode in case of
|
|
|
- * invalid entity.
|
|
|
- *
|
|
|
- * @param dst A valid entity identifier.
|
|
|
- */
|
|
|
- void assign(const entity_type dst) const {
|
|
|
- assign(*reg, dst);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Assigns or replaces the components of a prototype for an entity.
|
|
|
- *
|
|
|
- * Existing components are overwritten, if any. All the other components
|
|
|
- * will be copied over to the target entity.
|
|
|
- *
|
|
|
- * @note
|
|
|
- * The registry may or may not be different from the one already used by
|
|
|
- * the prototype. There is also an overload that directly uses the
|
|
|
- * underlying registry.
|
|
|
- *
|
|
|
- * @warning
|
|
|
- * Attempting to use an invalid entity results in undefined behavior.<br/>
|
|
|
- * An assertion will abort the execution at runtime in debug mode in case of
|
|
|
- * invalid entity.
|
|
|
- *
|
|
|
- * @param other A valid reference to a registry.
|
|
|
- * @param dst A valid entity identifier.
|
|
|
- */
|
|
|
- void assign_or_replace(registry_type &other, const entity_type dst) const {
|
|
|
- for(auto &handler: handlers) {
|
|
|
- handler.second.assign_or_replace(*this, other, dst);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Assigns or replaces the components of a prototype for an entity.
|
|
|
- *
|
|
|
- * Existing components are overwritten, if any. All the other components
|
|
|
- * will be copied over to the target entity.
|
|
|
- *
|
|
|
- * @note
|
|
|
- * This overload directly uses the underlying registry as a working space.
|
|
|
- * Therefore, the components of the prototype and of the entity will share
|
|
|
- * the same registry.
|
|
|
- *
|
|
|
- * @warning
|
|
|
- * Attempting to use an invalid entity results in undefined behavior.<br/>
|
|
|
- * An assertion will abort the execution at runtime in debug mode in case of
|
|
|
- * invalid entity.
|
|
|
- *
|
|
|
- * @param dst A valid entity identifier.
|
|
|
- */
|
|
|
- void assign_or_replace(const entity_type dst) const {
|
|
|
- assign_or_replace(*reg, dst);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Assigns the components of a prototype to an entity.
|
|
|
- *
|
|
|
- * Assigning a prototype to an entity won't overwrite existing components
|
|
|
- * under any circumstances.<br/>
|
|
|
- * In other words, only the components that the entity doesn't own yet are
|
|
|
- * copied over. All the other components remain unchanged.
|
|
|
- *
|
|
|
- * @note
|
|
|
- * The registry may or may not be different from the one already used by
|
|
|
- * the prototype. There is also an overload that directly uses the
|
|
|
- * underlying registry.
|
|
|
- *
|
|
|
- * @warning
|
|
|
- * Attempting to use an invalid entity results in undefined behavior.<br/>
|
|
|
- * An assertion will abort the execution at runtime in debug mode in case of
|
|
|
- * invalid entity.
|
|
|
- *
|
|
|
- * @param other A valid reference to a registry.
|
|
|
- * @param dst A valid entity identifier.
|
|
|
- */
|
|
|
- void operator()(registry_type &other, const entity_type dst) const ENTT_NOEXCEPT {
|
|
|
- assign(other, dst);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Assigns the components of a prototype to an entity.
|
|
|
- *
|
|
|
- * Assigning a prototype to an entity won't overwrite existing components
|
|
|
- * under any circumstances.<br/>
|
|
|
- * In other words, only the components that the entity doesn't own yet are
|
|
|
- * copied over. All the other components remain unchanged.
|
|
|
- *
|
|
|
- * @note
|
|
|
- * This overload directly uses the underlying registry as a working space.
|
|
|
- * Therefore, the components of the prototype and of the entity will share
|
|
|
- * the same registry.
|
|
|
- *
|
|
|
- * @warning
|
|
|
- * Attempting to use an invalid entity results in undefined behavior.<br/>
|
|
|
- * An assertion will abort the execution at runtime in debug mode in case of
|
|
|
- * invalid entity.
|
|
|
- *
|
|
|
- * @param dst A valid entity identifier.
|
|
|
- */
|
|
|
- void operator()(const entity_type dst) const ENTT_NOEXCEPT {
|
|
|
- assign(*reg, dst);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Creates a new entity using a given prototype.
|
|
|
- *
|
|
|
- * Utility shortcut, equivalent to the following snippet:
|
|
|
- *
|
|
|
- * @code{.cpp}
|
|
|
- * const auto entity = registry.create();
|
|
|
- * prototype(registry, entity);
|
|
|
- * @endcode
|
|
|
- *
|
|
|
- * @note
|
|
|
- * The registry may or may not be different from the one already used by
|
|
|
- * the prototype. There is also an overload that directly uses the
|
|
|
- * underlying registry.
|
|
|
- *
|
|
|
- * @param other A valid reference to a registry.
|
|
|
- * @return A valid entity identifier.
|
|
|
- */
|
|
|
- entity_type operator()(registry_type &other) const ENTT_NOEXCEPT {
|
|
|
- return create(other);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Creates a new entity using a given prototype.
|
|
|
- *
|
|
|
- * Utility shortcut, equivalent to the following snippet:
|
|
|
- *
|
|
|
- * @code{.cpp}
|
|
|
- * const auto entity = registry.create();
|
|
|
- * prototype(entity);
|
|
|
- * @endcode
|
|
|
- *
|
|
|
- * @note
|
|
|
- * This overload directly uses the underlying registry as a working space.
|
|
|
- * Therefore, the components of the prototype and of the entity will share
|
|
|
- * the same registry.
|
|
|
- *
|
|
|
- * @return A valid entity identifier.
|
|
|
- */
|
|
|
- entity_type operator()() const ENTT_NOEXCEPT {
|
|
|
- return create(*reg);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @brief Returns a reference to the underlying registry.
|
|
|
- * @return A reference to the underlying registry.
|
|
|
- */
|
|
|
- const registry_type & backend() const ENTT_NOEXCEPT {
|
|
|
- return *reg;
|
|
|
- }
|
|
|
-
|
|
|
- /*! @copydoc backend */
|
|
|
- registry_type & backend() ENTT_NOEXCEPT {
|
|
|
- return const_cast<registry_type &>(std::as_const(*this).backend());
|
|
|
- }
|
|
|
-
|
|
|
-private:
|
|
|
- std::unordered_map<component, component_handler> handlers;
|
|
|
- registry_type *reg;
|
|
|
- entity_type entity;
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-#endif // ENTT_ENTITY_PROTOTYPE_HPP
|