Properly link flecs library
This commit is contained in:
210
engine/libs/flecs/include/flecs/addons/alerts.h
Normal file
210
engine/libs/flecs/include/flecs/addons/alerts.h
Normal file
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* @file addons/alerts.h
|
||||
* @brief Alerts module.
|
||||
*
|
||||
* The alerts module enables applications to register alerts for when certain
|
||||
* conditions are met. Alerts are registered as queries, and automatically
|
||||
* become active when entities match the alert query.
|
||||
*/
|
||||
|
||||
#ifdef FLECS_ALERTS
|
||||
|
||||
/**
|
||||
* @defgroup c_addons_alerts Alerts
|
||||
* @brief Create alerts from monitoring queries.
|
||||
*
|
||||
* \ingroup c_addons
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef FLECS_ALERTS_H
|
||||
#define FLECS_ALERTS_H
|
||||
|
||||
#ifndef FLECS_RULES
|
||||
#define FLECS_RULES
|
||||
#endif
|
||||
|
||||
#ifndef FLECS_PIPELINE
|
||||
#define FLECS_PIPELINE
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ECS_ALERT_MAX_SEVERITY_FILTERS (4)
|
||||
|
||||
/* Module id */
|
||||
FLECS_API extern ECS_COMPONENT_DECLARE(FlecsAlerts);
|
||||
|
||||
/* Module components */
|
||||
|
||||
/** Tag added to alert, and used as first element of alert severity pair */
|
||||
FLECS_API extern ECS_COMPONENT_DECLARE(EcsAlert);
|
||||
FLECS_API extern ECS_COMPONENT_DECLARE(EcsAlertInstance);
|
||||
FLECS_API extern ECS_COMPONENT_DECLARE(EcsAlertsActive);
|
||||
FLECS_API extern ECS_COMPONENT_DECLARE(EcsAlertTimeout);
|
||||
|
||||
/* Alert severity tags */
|
||||
FLECS_API extern ECS_TAG_DECLARE(EcsAlertInfo);
|
||||
FLECS_API extern ECS_TAG_DECLARE(EcsAlertWarning);
|
||||
FLECS_API extern ECS_TAG_DECLARE(EcsAlertError);
|
||||
FLECS_API extern ECS_TAG_DECLARE(EcsAlertCritical);
|
||||
|
||||
/** Alert information. Added to each alert instance */
|
||||
typedef struct EcsAlertInstance {
|
||||
char *message;
|
||||
} EcsAlertInstance;
|
||||
|
||||
/** Map with active alerts for entity. */
|
||||
typedef struct EcsAlertsActive {
|
||||
int32_t info_count;
|
||||
int32_t warning_count;
|
||||
int32_t error_count;
|
||||
ecs_map_t alerts;
|
||||
} EcsAlertsActive;
|
||||
|
||||
typedef struct ecs_alert_severity_filter_t {
|
||||
ecs_entity_t severity; /* Severity kind */
|
||||
ecs_id_t with; /* Component to match */
|
||||
const char *var; /* Variable to match component on. Do not include the
|
||||
* '$' character. Leave to NULL for $this. */
|
||||
int32_t _var_index; /* Index of variable in filter (do not set) */
|
||||
} ecs_alert_severity_filter_t;
|
||||
|
||||
typedef struct ecs_alert_desc_t {
|
||||
int32_t _canary;
|
||||
|
||||
/** Entity associated with alert */
|
||||
ecs_entity_t entity;
|
||||
|
||||
/** Alert query. An alert will be created for each entity that matches the
|
||||
* specified query. The query must have at least one term that uses the
|
||||
* $this variable (default). */
|
||||
ecs_filter_desc_t filter;
|
||||
|
||||
/** Template for alert message. This string is used to generate the alert
|
||||
* message and may refer to variables in the query result. The format for
|
||||
* the template expressions is as specified by ecs_interpolate_string.
|
||||
*
|
||||
* Examples:
|
||||
* "$this has Position but not Velocity"
|
||||
* "$this has a parent entity $parent without Position"
|
||||
*/
|
||||
const char *message;
|
||||
|
||||
/** User friendly name. Will only be set if FLECS_DOC addon is enabled. */
|
||||
const char *doc_name;
|
||||
|
||||
/** Description of alert. Will only be set if FLECS_DOC addon is enabled */
|
||||
const char *brief;
|
||||
|
||||
/** Metric kind. Must be EcsAlertInfo, EcsAlertWarning, EcsAlertError or
|
||||
* EcsAlertCritical. Defaults to EcsAlertError. */
|
||||
ecs_entity_t severity;
|
||||
|
||||
/** Severity filters can be used to assign different severities to the same
|
||||
* alert. This prevents having to create multiple alerts, and allows
|
||||
* entities to transition between severities without resetting the
|
||||
* alert duration (optional). */
|
||||
ecs_alert_severity_filter_t severity_filters[ECS_ALERT_MAX_SEVERITY_FILTERS];
|
||||
|
||||
/** The retain period specifies how long an alert must be inactive before it
|
||||
* is cleared. This makes it easier to track noisy alerts. While an alert is
|
||||
* inactive its duration won't increase.
|
||||
* When the retain period is 0, the alert will clear immediately after it no
|
||||
* longer matches the alert query. */
|
||||
ecs_ftime_t retain_period;
|
||||
|
||||
/** Alert when member value is out of range. Uses the warning/error ranges
|
||||
* assigned to the member in the MemberRanges component (optional). */
|
||||
ecs_entity_t member;
|
||||
|
||||
/** (Component) id of member to monitor. If left to 0 this will be set to
|
||||
* the parent entity of the member (optional). */
|
||||
ecs_id_t id;
|
||||
|
||||
/** Variable from which to fetch the member (optional). When left to NULL
|
||||
* 'id' will be obtained from $this. */
|
||||
const char *var;
|
||||
} ecs_alert_desc_t;
|
||||
|
||||
/** Create a new alert.
|
||||
* An alert is a query that is evaluated periodically and creates alert
|
||||
* instances for each entity that matches the query. Alerts can be used to
|
||||
* automate detection of errors in an application.
|
||||
*
|
||||
* Alerts are automatically cleared when a query is no longer true for an alert
|
||||
* instance. At most one alert instance will be created per matched entity.
|
||||
*
|
||||
* Alert instances have three components:
|
||||
* - AlertInstance: contains the alert message for the instance
|
||||
* - MetricSource: contains the entity that triggered the alert
|
||||
* - MetricValue: contains how long the alert has been active
|
||||
*
|
||||
* Alerts reuse components from the metrics addon so that alert instances can be
|
||||
* tracked and discovered as metrics. Just like metrics, alert instances are
|
||||
* created as children of the alert.
|
||||
*
|
||||
* When an entity has active alerts, it will have the EcsAlertsActive component
|
||||
* which contains a map with active alerts for the entity. This component
|
||||
* will be automatically removed once all alerts are cleared for the entity.
|
||||
*
|
||||
* @param world The world.
|
||||
* @param desc Alert description.
|
||||
* @return The alert entity.
|
||||
*/
|
||||
FLECS_API
|
||||
ecs_entity_t ecs_alert_init(
|
||||
ecs_world_t *world,
|
||||
const ecs_alert_desc_t *desc);
|
||||
|
||||
#define ecs_alert(world, ...)\
|
||||
ecs_alert_init(world, &(ecs_alert_desc_t)__VA_ARGS__)
|
||||
|
||||
/** Return number of active alerts for entity.
|
||||
* When a valid alert entity is specified for the alert parameter, the operation
|
||||
* will return whether the specified alert is active for the entity. When no
|
||||
* alert is specified, the operation will return the total number of active
|
||||
* alerts for the entity.
|
||||
*
|
||||
* @param world The world.
|
||||
* @param entity The entity.
|
||||
* @param alert The alert to test for (optional).
|
||||
* @return The number of active alerts for the entity.
|
||||
*/
|
||||
FLECS_API
|
||||
int32_t ecs_get_alert_count(
|
||||
const ecs_world_t *world,
|
||||
ecs_entity_t entity,
|
||||
ecs_entity_t alert);
|
||||
|
||||
/** Return alert instance for specified alert.
|
||||
* This operation returns the alert instance for the specified alert. If the
|
||||
* alert is not active for the entity, the operation will return 0.
|
||||
*
|
||||
* @param world The world.
|
||||
* @param entity The entity.
|
||||
* @param alert The alert to test for.
|
||||
* @return The alert instance for the specified alert.
|
||||
*/
|
||||
FLECS_API
|
||||
ecs_entity_t ecs_get_alert(
|
||||
const ecs_world_t *world,
|
||||
ecs_entity_t entity,
|
||||
ecs_entity_t alert);
|
||||
|
||||
/* Module import */
|
||||
FLECS_API
|
||||
void FlecsAlertsImport(
|
||||
ecs_world_t *world);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif
|
||||
117
engine/libs/flecs/include/flecs/addons/app.h
Normal file
117
engine/libs/flecs/include/flecs/addons/app.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* @file addons/app.h
|
||||
* @brief App addon.
|
||||
*
|
||||
* The app addon is a wrapper around the application's main loop. Its main
|
||||
* purpose is to provide a hook to modules that need to take control of the
|
||||
* main loop, as is for example the case with native applications that use
|
||||
* emscripten with webGL.
|
||||
*/
|
||||
|
||||
#ifdef FLECS_APP
|
||||
|
||||
#ifndef FLECS_PIPELINE
|
||||
#define FLECS_PIPELINE
|
||||
#endif
|
||||
|
||||
#ifndef FLECS_APP_H
|
||||
#define FLECS_APP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup c_addons_app App
|
||||
* @brief Optional addon for running the main application loop.
|
||||
*
|
||||
* \ingroup c_addons
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Callback type for init action. */
|
||||
typedef int(*ecs_app_init_action_t)(
|
||||
ecs_world_t *world);
|
||||
|
||||
/** Used with ecs_app_run. */
|
||||
typedef struct ecs_app_desc_t {
|
||||
ecs_ftime_t target_fps; /**< Target FPS. */
|
||||
ecs_ftime_t delta_time; /**< Frame time increment (0 for measured values) */
|
||||
int32_t threads; /**< Number of threads. */
|
||||
int32_t frames; /**< Number of frames to run (0 for infinite) */
|
||||
bool enable_rest; /**< Enables ECS access over HTTP, necessary for explorer */
|
||||
bool enable_monitor; /**< Periodically collect statistics */
|
||||
uint16_t port; /**< HTTP port used by REST API */
|
||||
|
||||
ecs_app_init_action_t init; /**< If set, function is ran before starting the
|
||||
* main loop. */
|
||||
|
||||
void *ctx; /**< Reserved for custom run/frame actions */
|
||||
} ecs_app_desc_t;
|
||||
|
||||
/** Callback type for run action. */
|
||||
typedef int(*ecs_app_run_action_t)(
|
||||
ecs_world_t *world,
|
||||
ecs_app_desc_t *desc);
|
||||
|
||||
/** Callback type for frame action. */
|
||||
typedef int(*ecs_app_frame_action_t)(
|
||||
ecs_world_t *world,
|
||||
const ecs_app_desc_t *desc);
|
||||
|
||||
/** Run application.
|
||||
* This will run the application with the parameters specified in desc. After
|
||||
* the application quits (ecs_quit is called) the world will be cleaned up.
|
||||
*
|
||||
* If a custom run action is set, it will be invoked by this operation. The
|
||||
* default run action calls the frame action in a loop until it returns a
|
||||
* non-zero value.
|
||||
*
|
||||
* @param world The world.
|
||||
* @param desc Application parameters.
|
||||
*/
|
||||
FLECS_API
|
||||
int ecs_app_run(
|
||||
ecs_world_t *world,
|
||||
ecs_app_desc_t *desc);
|
||||
|
||||
/** Default frame callback.
|
||||
* This operation will run a single frame. By default this operation will invoke
|
||||
* ecs_progress directly, unless a custom frame action is set.
|
||||
*
|
||||
* @param world The world.
|
||||
* @param desc The desc struct passed to ecs_app_run.
|
||||
* @return value returned by ecs_progress
|
||||
*/
|
||||
FLECS_API
|
||||
int ecs_app_run_frame(
|
||||
ecs_world_t *world,
|
||||
const ecs_app_desc_t *desc);
|
||||
|
||||
/** Set custom run action.
|
||||
* See ecs_app_run.
|
||||
*
|
||||
* @param callback The run action.
|
||||
*/
|
||||
FLECS_API
|
||||
int ecs_app_set_run_action(
|
||||
ecs_app_run_action_t callback);
|
||||
|
||||
/** Set custom frame action.
|
||||
* See ecs_app_run_frame.
|
||||
*
|
||||
* @param callback The frame action.
|
||||
*/
|
||||
FLECS_API
|
||||
int ecs_app_set_frame_action(
|
||||
ecs_app_frame_action_t callback);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif // FLECS_APP
|
||||
48
engine/libs/flecs/include/flecs/addons/coredoc.h
Normal file
48
engine/libs/flecs/include/flecs/addons/coredoc.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @file addons/coredoc.h
|
||||
* @brief Core doc module.
|
||||
*
|
||||
* The core doc module imports documentation and reflection data for core
|
||||
* components, tags and systems.
|
||||
*/
|
||||
|
||||
#ifdef FLECS_COREDOC
|
||||
|
||||
#ifndef FLECS_DOC
|
||||
#define FLECS_DOC
|
||||
#endif
|
||||
|
||||
#ifndef FLECS_META
|
||||
#define FLECS_META
|
||||
#endif
|
||||
|
||||
#ifndef FLECS_COREDOC_H
|
||||
#define FLECS_COREDOC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup c_addons_coredoc Coredoc
|
||||
* @brief Module that adds documentation and reflection to core entities.
|
||||
*
|
||||
* \ingroup c_addons
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Module import */
|
||||
|
||||
FLECS_API
|
||||
void FlecsCoreDocImport(
|
||||
ecs_world_t *world);
|
||||
|
||||
/* @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
155
engine/libs/flecs/include/flecs/addons/cpp/c_types.hpp
Normal file
155
engine/libs/flecs/include/flecs/addons/cpp/c_types.hpp
Normal file
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* @file addons/cpp/c_types.hpp
|
||||
* @brief Aliases for types/constants from C API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/**
|
||||
* @defgroup cpp_globals API Types & Globals
|
||||
* @brief Types & constants bridged from C API.
|
||||
*
|
||||
* \ingroup cpp_core
|
||||
* @{
|
||||
*/
|
||||
|
||||
using world_t = ecs_world_t;
|
||||
using world_info_t = ecs_world_info_t;
|
||||
using query_group_info_t = ecs_query_group_info_t;
|
||||
using id_t = ecs_id_t;
|
||||
using entity_t = ecs_entity_t;
|
||||
using type_t = ecs_type_t;
|
||||
using table_t = ecs_table_t;
|
||||
using filter_t = ecs_filter_t;
|
||||
using observer_t = ecs_observer_t;
|
||||
using query_t = ecs_query_t;
|
||||
using rule_t = ecs_rule_t;
|
||||
using ref_t = ecs_ref_t;
|
||||
using iter_t = ecs_iter_t;
|
||||
using type_info_t = ecs_type_info_t;
|
||||
using type_hooks_t = ecs_type_hooks_t;
|
||||
using flags32_t = ecs_flags32_t;
|
||||
|
||||
enum inout_kind_t {
|
||||
InOutDefault = EcsInOutDefault,
|
||||
InOutNone = EcsInOutNone,
|
||||
InOut = EcsInOut,
|
||||
In = EcsIn,
|
||||
Out = EcsOut
|
||||
};
|
||||
|
||||
enum oper_kind_t {
|
||||
And = EcsAnd,
|
||||
Or = EcsOr,
|
||||
Not = EcsNot,
|
||||
Optional = EcsOptional,
|
||||
AndFrom = EcsAndFrom,
|
||||
OrFrom = EcsOrFrom,
|
||||
NotFrom = EcsNotFrom
|
||||
};
|
||||
|
||||
/** Id flags */
|
||||
static const flecs::entity_t Pair = ECS_PAIR;
|
||||
static const flecs::entity_t Override = ECS_OVERRIDE;
|
||||
static const flecs::entity_t Toggle = ECS_TOGGLE;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Builtin components and tags
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* Builtin components */
|
||||
using Component = EcsComponent;
|
||||
using Identifier = EcsIdentifier;
|
||||
using Poly = EcsPoly;
|
||||
using Target = EcsTarget;
|
||||
|
||||
/* Builtin tags */
|
||||
static const flecs::entity_t Query = EcsQuery;
|
||||
static const flecs::entity_t Observer = EcsObserver;
|
||||
static const flecs::entity_t Private = EcsPrivate;
|
||||
static const flecs::entity_t Module = EcsModule;
|
||||
static const flecs::entity_t Prefab = EcsPrefab;
|
||||
static const flecs::entity_t Disabled = EcsDisabled;
|
||||
static const flecs::entity_t Empty = EcsEmpty;
|
||||
static const flecs::entity_t Monitor = EcsMonitor;
|
||||
static const flecs::entity_t System = EcsSystem;
|
||||
static const flecs::entity_t Pipeline = ecs_id(EcsPipeline);
|
||||
static const flecs::entity_t Phase = EcsPhase;
|
||||
|
||||
/* Builtin event tags */
|
||||
static const flecs::entity_t OnAdd = EcsOnAdd;
|
||||
static const flecs::entity_t OnRemove = EcsOnRemove;
|
||||
static const flecs::entity_t OnSet = EcsOnSet;
|
||||
static const flecs::entity_t UnSet = EcsUnSet;
|
||||
static const flecs::entity_t OnTableCreate = EcsOnTableCreate;
|
||||
static const flecs::entity_t OnTableDelete = EcsOnTableDelete;
|
||||
|
||||
/* Builtin term flags */
|
||||
static const uint32_t Self = EcsSelf;
|
||||
static const uint32_t Up = EcsUp;
|
||||
static const uint32_t Down = EcsDown;
|
||||
static const uint32_t Cascade = EcsCascade;
|
||||
static const uint32_t Desc = EcsDesc;
|
||||
static const uint32_t Parent = EcsParent;
|
||||
static const uint32_t IsVariable = EcsIsVariable;
|
||||
static const uint32_t IsEntity = EcsIsEntity;
|
||||
static const uint32_t Filter = EcsFilter;
|
||||
static const uint32_t TraverseFlags = EcsTraverseFlags;
|
||||
|
||||
/* Builtin entity ids */
|
||||
static const flecs::entity_t Flecs = EcsFlecs;
|
||||
static const flecs::entity_t FlecsCore = EcsFlecsCore;
|
||||
static const flecs::entity_t World = EcsWorld;
|
||||
|
||||
/* Relationship properties */
|
||||
static const flecs::entity_t Wildcard = EcsWildcard;
|
||||
static const flecs::entity_t Any = EcsAny;
|
||||
static const flecs::entity_t This = EcsThis;
|
||||
static const flecs::entity_t Transitive = EcsTransitive;
|
||||
static const flecs::entity_t Reflexive = EcsReflexive;
|
||||
static const flecs::entity_t Final = EcsFinal;
|
||||
static const flecs::entity_t DontInherit = EcsDontInherit;
|
||||
static const flecs::entity_t Tag = EcsTag;
|
||||
static const flecs::entity_t Union = EcsUnion;
|
||||
static const flecs::entity_t Exclusive = EcsExclusive;
|
||||
static const flecs::entity_t Acyclic = EcsAcyclic;
|
||||
static const flecs::entity_t Traversable = EcsTraversable;
|
||||
static const flecs::entity_t Symmetric = EcsSymmetric;
|
||||
static const flecs::entity_t With = EcsWith;
|
||||
static const flecs::entity_t OneOf = EcsOneOf;
|
||||
|
||||
/* Builtin relationships */
|
||||
static const flecs::entity_t IsA = EcsIsA;
|
||||
static const flecs::entity_t ChildOf = EcsChildOf;
|
||||
static const flecs::entity_t DependsOn = EcsDependsOn;
|
||||
static const flecs::entity_t SlotOf = EcsSlotOf;
|
||||
|
||||
/* Builtin identifiers */
|
||||
static const flecs::entity_t Name = EcsName;
|
||||
static const flecs::entity_t Symbol = EcsSymbol;
|
||||
|
||||
/* Cleanup policies */
|
||||
static const flecs::entity_t OnDelete = EcsOnDelete;
|
||||
static const flecs::entity_t OnDeleteTarget = EcsOnDeleteTarget;
|
||||
static const flecs::entity_t Remove = EcsRemove;
|
||||
static const flecs::entity_t Delete = EcsDelete;
|
||||
static const flecs::entity_t Panic = EcsPanic;
|
||||
|
||||
/* Misc */
|
||||
static const flecs::entity_t Flatten = EcsFlatten;
|
||||
static const flecs::entity_t DefaultChildComponent = EcsDefaultChildComponent;
|
||||
|
||||
/* Builtin predicates for comparing entity ids in queries. Only supported by rules */
|
||||
static const flecs::entity_t PredEq = EcsPredEq;
|
||||
static const flecs::entity_t PredMatch = EcsPredMatch;
|
||||
static const flecs::entity_t PredLookup = EcsPredLookup;
|
||||
|
||||
/* Builtin marker entities for query scopes */
|
||||
static const flecs::entity_t ScopeOpen = EcsScopeOpen;
|
||||
static const flecs::entity_t ScopeClose = EcsScopeClose;
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
546
engine/libs/flecs/include/flecs/addons/cpp/component.hpp
Normal file
546
engine/libs/flecs/include/flecs/addons/cpp/component.hpp
Normal file
@@ -0,0 +1,546 @@
|
||||
/**
|
||||
* @file addons/cpp/component.hpp
|
||||
* @brief Registering/obtaining info from components.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* @defgroup cpp_components Components
|
||||
* @brief Registering and working with components.
|
||||
*
|
||||
* \ingroup cpp_core
|
||||
* @{
|
||||
*/
|
||||
|
||||
namespace flecs {
|
||||
|
||||
namespace _ {
|
||||
|
||||
// Trick to obtain typename from type, as described here
|
||||
// https://blog.molecular-matters.com/2015/12/11/getting-the-type-of-a-template-argument-as-string-without-rtti/
|
||||
//
|
||||
// The code from the link has been modified to work with more types, and across
|
||||
// multiple compilers. The resulting string should be the same on all platforms
|
||||
// for all compilers.
|
||||
//
|
||||
|
||||
#if defined(__GNUC__) || defined(_WIN32)
|
||||
template <typename T>
|
||||
inline static const char* type_name() {
|
||||
static const size_t len = ECS_FUNC_TYPE_LEN(const char*, type_name, ECS_FUNC_NAME);
|
||||
static char result[len + 1] = {};
|
||||
static const size_t front_len = ECS_FUNC_NAME_FRONT(const char*, type_name);
|
||||
return ecs_cpp_get_type_name(result, ECS_FUNC_NAME, len, front_len);
|
||||
}
|
||||
#else
|
||||
#error "implicit component registration not supported"
|
||||
#endif
|
||||
|
||||
// Translate a typename into a language-agnostic identifier. This allows for
|
||||
// registration of components/modules across language boundaries.
|
||||
template <typename T>
|
||||
inline static const char* symbol_name() {
|
||||
static const size_t len = ECS_FUNC_TYPE_LEN(const char*, symbol_name, ECS_FUNC_NAME);
|
||||
static char result[len + 1] = {};
|
||||
return ecs_cpp_get_symbol_name(result, type_name<T>(), len);
|
||||
}
|
||||
|
||||
template <> inline const char* symbol_name<uint8_t>() {
|
||||
return "u8";
|
||||
}
|
||||
template <> inline const char* symbol_name<uint16_t>() {
|
||||
return "u16";
|
||||
}
|
||||
template <> inline const char* symbol_name<uint32_t>() {
|
||||
return "u32";
|
||||
}
|
||||
template <> inline const char* symbol_name<uint64_t>() {
|
||||
return "u64";
|
||||
}
|
||||
template <> inline const char* symbol_name<int8_t>() {
|
||||
return "i8";
|
||||
}
|
||||
template <> inline const char* symbol_name<int16_t>() {
|
||||
return "i16";
|
||||
}
|
||||
template <> inline const char* symbol_name<int32_t>() {
|
||||
return "i32";
|
||||
}
|
||||
template <> inline const char* symbol_name<int64_t>() {
|
||||
return "i64";
|
||||
}
|
||||
template <> inline const char* symbol_name<float>() {
|
||||
return "f32";
|
||||
}
|
||||
template <> inline const char* symbol_name<double>() {
|
||||
return "f64";
|
||||
}
|
||||
|
||||
// If type is trivial, don't register lifecycle actions. While the functions
|
||||
// that obtain the lifecycle callback do detect whether the callback is required
|
||||
// adding a special case for trivial types eases the burden a bit on the
|
||||
// compiler as it reduces the number of templates to evaluate.
|
||||
template<typename T, enable_if_t<
|
||||
std::is_trivial<T>::value == true
|
||||
>* = nullptr>
|
||||
void register_lifecycle_actions(ecs_world_t*, ecs_entity_t) { }
|
||||
|
||||
// If the component is non-trivial, register component lifecycle actions.
|
||||
// Depending on the type not all callbacks may be available.
|
||||
template<typename T, enable_if_t<
|
||||
std::is_trivial<T>::value == false
|
||||
>* = nullptr>
|
||||
void register_lifecycle_actions(
|
||||
ecs_world_t *world,
|
||||
ecs_entity_t component)
|
||||
{
|
||||
ecs_type_hooks_t cl{};
|
||||
cl.ctor = ctor<T>();
|
||||
cl.dtor = dtor<T>();
|
||||
|
||||
cl.copy = copy<T>();
|
||||
cl.copy_ctor = copy_ctor<T>();
|
||||
cl.move = move<T>();
|
||||
cl.move_ctor = move_ctor<T>();
|
||||
|
||||
cl.ctor_move_dtor = ctor_move_dtor<T>();
|
||||
cl.move_dtor = move_dtor<T>();
|
||||
|
||||
ecs_set_hooks_id( world, component, &cl);
|
||||
}
|
||||
|
||||
// Class that manages component ids across worlds & binaries.
|
||||
// The cpp_type class stores the component id for a C++ type in a static global
|
||||
// variable that is shared between worlds. Whenever a component is used this
|
||||
// class will check if it already has been registered (has the global id been
|
||||
// set), and if not, register the component with the world.
|
||||
//
|
||||
// If the id has been set, the class will ensure it is known by the world. If it
|
||||
// is not known the component has been registered by another world and will be
|
||||
// registered with the world using the same id. If the id does exist, the class
|
||||
// will register it as a component, and verify whether the input is consistent.
|
||||
template <typename T>
|
||||
struct cpp_type_impl {
|
||||
// Initialize component identifier
|
||||
static void init(
|
||||
entity_t entity,
|
||||
bool allow_tag = true)
|
||||
{
|
||||
if (s_reset_count != ecs_cpp_reset_count_get()) {
|
||||
reset();
|
||||
}
|
||||
|
||||
// If an identifier was already set, check for consistency
|
||||
if (s_id) {
|
||||
ecs_assert(s_id == entity, ECS_INCONSISTENT_COMPONENT_ID,
|
||||
type_name<T>());
|
||||
ecs_assert(allow_tag == s_allow_tag, ECS_INVALID_PARAMETER, NULL);
|
||||
|
||||
// Component was already registered and data is consistent with new
|
||||
// identifier, so nothing else to be done.
|
||||
return;
|
||||
}
|
||||
|
||||
// Component wasn't registered yet, set the values. Register component
|
||||
// name as the fully qualified flecs path.
|
||||
s_id = entity;
|
||||
s_allow_tag = allow_tag;
|
||||
s_size = sizeof(T);
|
||||
s_alignment = alignof(T);
|
||||
if (is_empty<T>::value && allow_tag) {
|
||||
s_size = 0;
|
||||
s_alignment = 0;
|
||||
}
|
||||
|
||||
s_reset_count = ecs_cpp_reset_count_get();
|
||||
}
|
||||
|
||||
// Obtain a component identifier for explicit component registration.
|
||||
static entity_t id_explicit(world_t *world = nullptr,
|
||||
const char *name = nullptr, bool allow_tag = true, flecs::id_t id = 0,
|
||||
bool is_component = true, bool *existing = nullptr)
|
||||
{
|
||||
if (!s_id) {
|
||||
// If no world was provided the component cannot be registered
|
||||
ecs_assert(world != nullptr, ECS_COMPONENT_NOT_REGISTERED, name);
|
||||
} else {
|
||||
ecs_assert(!id || s_id == id, ECS_INCONSISTENT_COMPONENT_ID, NULL);
|
||||
}
|
||||
|
||||
// If no id has been registered yet for the component (indicating the
|
||||
// component has not yet been registered, or the component is used
|
||||
// across more than one binary), or if the id does not exists in the
|
||||
// world (indicating a multi-world application), register it. */
|
||||
if (!s_id || (world && !ecs_exists(world, s_id))) {
|
||||
init(s_id ? s_id : id, allow_tag);
|
||||
|
||||
ecs_assert(!id || s_id == id, ECS_INTERNAL_ERROR, NULL);
|
||||
|
||||
const char *symbol = nullptr;
|
||||
if (id) {
|
||||
symbol = ecs_get_symbol(world, id);
|
||||
}
|
||||
if (!symbol) {
|
||||
symbol = symbol_name<T>();
|
||||
}
|
||||
|
||||
entity_t entity = ecs_cpp_component_register_explicit(
|
||||
world, s_id, id, name, type_name<T>(), symbol,
|
||||
s_size, s_alignment, is_component, existing);
|
||||
|
||||
s_id = entity;
|
||||
|
||||
// If component is enum type, register constants
|
||||
#if FLECS_CPP_ENUM_REFLECTION_SUPPORT
|
||||
_::init_enum<T>(world, entity);
|
||||
#endif
|
||||
}
|
||||
|
||||
// By now the identifier must be valid and known with the world.
|
||||
ecs_assert(s_id != 0 && ecs_exists(world, s_id),
|
||||
ECS_INTERNAL_ERROR, NULL);
|
||||
|
||||
return s_id;
|
||||
}
|
||||
|
||||
// Obtain a component identifier for implicit component registration. This
|
||||
// is almost the same as id_explicit, except that this operation
|
||||
// automatically registers lifecycle callbacks.
|
||||
// Additionally, implicit registration temporarily resets the scope & with
|
||||
// state of the world, so that the component is not implicitly created with
|
||||
// the scope/with of the code it happens to be first used by.
|
||||
static id_t id(world_t *world = nullptr, const char *name = nullptr,
|
||||
bool allow_tag = true)
|
||||
{
|
||||
// If no id has been registered yet, do it now.
|
||||
if (!registered(world)) {
|
||||
ecs_entity_t prev_scope = 0;
|
||||
ecs_id_t prev_with = 0;
|
||||
|
||||
if (world) {
|
||||
prev_scope = ecs_set_scope(world, 0);
|
||||
prev_with = ecs_set_with(world, 0);
|
||||
}
|
||||
|
||||
// This will register a component id, but will not register
|
||||
// lifecycle callbacks.
|
||||
bool existing;
|
||||
id_explicit(world, name, allow_tag, 0, true, &existing);
|
||||
|
||||
// Register lifecycle callbacks, but only if the component has a
|
||||
// size. Components that don't have a size are tags, and tags don't
|
||||
// require construction/destruction/copy/move's. */
|
||||
if (size() && !existing) {
|
||||
register_lifecycle_actions<T>(world, s_id);
|
||||
}
|
||||
|
||||
if (prev_with) {
|
||||
ecs_set_with(world, prev_with);
|
||||
}
|
||||
if (prev_scope) {
|
||||
ecs_set_scope(world, prev_scope);
|
||||
}
|
||||
}
|
||||
|
||||
// By now we should have a valid identifier
|
||||
ecs_assert(s_id != 0, ECS_INTERNAL_ERROR, NULL);
|
||||
|
||||
return s_id;
|
||||
}
|
||||
|
||||
// Return the size of a component.
|
||||
static size_t size() {
|
||||
ecs_assert(s_id != 0, ECS_INTERNAL_ERROR, NULL);
|
||||
return s_size;
|
||||
}
|
||||
|
||||
// Return the alignment of a component.
|
||||
static size_t alignment() {
|
||||
ecs_assert(s_id != 0, ECS_INTERNAL_ERROR, NULL);
|
||||
return s_alignment;
|
||||
}
|
||||
|
||||
// Was the component already registered.
|
||||
static bool registered(flecs::world_t *world) {
|
||||
if (s_reset_count != ecs_cpp_reset_count_get()) {
|
||||
reset();
|
||||
}
|
||||
if (s_id == 0) {
|
||||
return false;
|
||||
}
|
||||
if (world && !ecs_exists(world, s_id)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// This function is only used to test cross-translation unit features. No
|
||||
// code other than test cases should invoke this function.
|
||||
static void reset() {
|
||||
s_id = 0;
|
||||
s_size = 0;
|
||||
s_alignment = 0;
|
||||
s_allow_tag = true;
|
||||
}
|
||||
|
||||
static entity_t s_id;
|
||||
static size_t s_size;
|
||||
static size_t s_alignment;
|
||||
static bool s_allow_tag;
|
||||
static int32_t s_reset_count;
|
||||
};
|
||||
|
||||
// Global templated variables that hold component identifier and other info
|
||||
template <typename T> entity_t cpp_type_impl<T>::s_id;
|
||||
template <typename T> size_t cpp_type_impl<T>::s_size;
|
||||
template <typename T> size_t cpp_type_impl<T>::s_alignment;
|
||||
template <typename T> bool cpp_type_impl<T>::s_allow_tag( true );
|
||||
template <typename T> int32_t cpp_type_impl<T>::s_reset_count;
|
||||
|
||||
// Front facing class for implicitly registering a component & obtaining
|
||||
// static component data
|
||||
|
||||
// Regular type
|
||||
template <typename T>
|
||||
struct cpp_type<T, if_not_t< is_pair<T>::value >>
|
||||
: cpp_type_impl<base_type_t<T>> { };
|
||||
|
||||
// Pair type
|
||||
template <typename T>
|
||||
struct cpp_type<T, if_t< is_pair<T>::value >>
|
||||
{
|
||||
// Override id method to return id of pair
|
||||
static id_t id(world_t *world = nullptr) {
|
||||
return ecs_pair(
|
||||
cpp_type< pair_first_t<T> >::id(world),
|
||||
cpp_type< pair_second_t<T> >::id(world));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace _
|
||||
|
||||
/** Untyped component class.
|
||||
* Generic base class for flecs::component.
|
||||
*
|
||||
* \ingroup cpp_components
|
||||
*/
|
||||
struct untyped_component : entity {
|
||||
using entity::entity;
|
||||
|
||||
# ifdef FLECS_META
|
||||
# include "mixins/meta/untyped_component.inl"
|
||||
# endif
|
||||
# ifdef FLECS_METRICS
|
||||
# include "mixins/metrics/untyped_component.inl"
|
||||
# endif
|
||||
};
|
||||
|
||||
/** Component class.
|
||||
* Class used to register components and component metadata.
|
||||
*
|
||||
* \ingroup cpp_components
|
||||
*/
|
||||
template <typename T>
|
||||
struct component : untyped_component {
|
||||
/** Register a component.
|
||||
* If the component was already registered, this operation will return a handle
|
||||
* to the existing component.
|
||||
*
|
||||
* @param world The world for which to register the component.
|
||||
* @param name Optional name (overrides typename).
|
||||
* @param allow_tag If true, empty types will be registered with size 0.
|
||||
* @param id Optional id to register component with.
|
||||
*/
|
||||
component(
|
||||
flecs::world_t *world,
|
||||
const char *name = nullptr,
|
||||
bool allow_tag = true,
|
||||
flecs::id_t id = 0)
|
||||
{
|
||||
const char *n = name;
|
||||
bool implicit_name = false;
|
||||
if (!n) {
|
||||
n = _::type_name<T>();
|
||||
|
||||
/* Keep track of whether name was explicitly set. If not, and the
|
||||
* component was already registered, just use the registered name.
|
||||
*
|
||||
* The registered name may differ from the typename as the registered
|
||||
* name includes the flecs scope. This can in theory be different from
|
||||
* the C++ namespace though it is good practice to keep them the same */
|
||||
implicit_name = true;
|
||||
}
|
||||
|
||||
if (_::cpp_type<T>::registered(world)) {
|
||||
/* Obtain component id. Because the component is already registered,
|
||||
* this operation does nothing besides returning the existing id */
|
||||
id = _::cpp_type<T>::id_explicit(world, name, allow_tag, id);
|
||||
|
||||
ecs_cpp_component_validate(world, id, n, _::symbol_name<T>(),
|
||||
_::cpp_type<T>::size(),
|
||||
_::cpp_type<T>::alignment(),
|
||||
implicit_name);
|
||||
} else {
|
||||
/* If component is registered from an existing scope, ignore the
|
||||
* namespace in the name of the component. */
|
||||
if (implicit_name && (ecs_get_scope(world) != 0)) {
|
||||
/* If the type is a template type, make sure to ignore ':'
|
||||
* inside the template parameter list. */
|
||||
const char *start = strchr(n, '<'), *last_elem = NULL;
|
||||
if (start) {
|
||||
const char *ptr = start;
|
||||
while (ptr[0] && (ptr[0] != ':') && (ptr > n)) {
|
||||
ptr --;
|
||||
}
|
||||
if (ptr[0] == ':') {
|
||||
last_elem = ptr;
|
||||
}
|
||||
} else {
|
||||
last_elem = strrchr(n, ':');
|
||||
}
|
||||
if (last_elem) {
|
||||
name = last_elem + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find or register component */
|
||||
bool existing;
|
||||
id = ecs_cpp_component_register(world, id, n, _::symbol_name<T>(),
|
||||
ECS_SIZEOF(T), ECS_ALIGNOF(T), implicit_name, &existing);
|
||||
|
||||
/* Initialize static component data */
|
||||
id = _::cpp_type<T>::id_explicit(world, name, allow_tag, id);
|
||||
|
||||
/* Initialize lifecycle actions (ctor, dtor, copy, move) */
|
||||
if (_::cpp_type<T>::size() && !existing) {
|
||||
_::register_lifecycle_actions<T>(world, id);
|
||||
}
|
||||
}
|
||||
|
||||
m_world = world;
|
||||
m_id = id;
|
||||
}
|
||||
|
||||
/** Register on_add hook. */
|
||||
template <typename Func>
|
||||
component<T>& on_add(Func&& func) {
|
||||
using Delegate = typename _::each_delegate<
|
||||
typename std::decay<Func>::type, T>;
|
||||
flecs::type_hooks_t h = get_hooks();
|
||||
ecs_assert(h.on_add == nullptr, ECS_INVALID_OPERATION,
|
||||
"on_add hook is already set");
|
||||
BindingCtx *ctx = get_binding_ctx(h);
|
||||
h.on_add = Delegate::run_add;
|
||||
ctx->on_add = FLECS_NEW(Delegate)(FLECS_FWD(func));
|
||||
ctx->free_on_add = reinterpret_cast<ecs_ctx_free_t>(
|
||||
_::free_obj<Delegate>);
|
||||
ecs_set_hooks_id(m_world, m_id, &h);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Register on_remove hook. */
|
||||
template <typename Func>
|
||||
component<T>& on_remove(Func&& func) {
|
||||
using Delegate = typename _::each_delegate<
|
||||
typename std::decay<Func>::type, T>;
|
||||
flecs::type_hooks_t h = get_hooks();
|
||||
ecs_assert(h.on_remove == nullptr, ECS_INVALID_OPERATION,
|
||||
"on_remove hook is already set");
|
||||
BindingCtx *ctx = get_binding_ctx(h);
|
||||
h.on_remove = Delegate::run_remove;
|
||||
ctx->on_remove = FLECS_NEW(Delegate)(FLECS_FWD(func));
|
||||
ctx->free_on_remove = reinterpret_cast<ecs_ctx_free_t>(
|
||||
_::free_obj<Delegate>);
|
||||
ecs_set_hooks_id(m_world, m_id, &h);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Register on_set hook. */
|
||||
template <typename Func>
|
||||
component<T>& on_set(Func&& func) {
|
||||
using Delegate = typename _::each_delegate<
|
||||
typename std::decay<Func>::type, T>;
|
||||
flecs::type_hooks_t h = get_hooks();
|
||||
ecs_assert(h.on_set == nullptr, ECS_INVALID_OPERATION,
|
||||
"on_set hook is already set");
|
||||
BindingCtx *ctx = get_binding_ctx(h);
|
||||
h.on_set = Delegate::run_set;
|
||||
ctx->on_set = FLECS_NEW(Delegate)(FLECS_FWD(func));
|
||||
ctx->free_on_set = reinterpret_cast<ecs_ctx_free_t>(
|
||||
_::free_obj<Delegate>);
|
||||
ecs_set_hooks_id(m_world, m_id, &h);
|
||||
return *this;
|
||||
}
|
||||
|
||||
# ifdef FLECS_META
|
||||
# include "mixins/meta/component.inl"
|
||||
# endif
|
||||
|
||||
private:
|
||||
using BindingCtx = _::component_binding_ctx;
|
||||
|
||||
BindingCtx* get_binding_ctx(flecs::type_hooks_t& h){
|
||||
BindingCtx *result = static_cast<BindingCtx*>(h.binding_ctx);
|
||||
if (!result) {
|
||||
result = FLECS_NEW(BindingCtx);
|
||||
h.binding_ctx = result;
|
||||
h.binding_ctx_free = reinterpret_cast<ecs_ctx_free_t>(
|
||||
_::free_obj<BindingCtx>);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
flecs::type_hooks_t get_hooks() {
|
||||
const flecs::type_hooks_t* h = ecs_get_hooks_id(m_world, m_id);
|
||||
if (h) {
|
||||
return *h;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** Get id currently assigned to component. If no world has registered the
|
||||
* component yet, this operation will return 0. */
|
||||
template <typename T>
|
||||
flecs::entity_t type_id() {
|
||||
if (_::cpp_type<T>::s_reset_count == ecs_cpp_reset_count_get()) {
|
||||
return _::cpp_type<T>::s_id;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Reset static component ids.
|
||||
* When components are registered their component ids are stored in a static
|
||||
* type specific variable. This stored id is passed into component registration
|
||||
* functions to ensure consistent ids across worlds.
|
||||
*
|
||||
* In some cases this can be undesirable, like when a process repeatedly creates
|
||||
* worlds with different components. A typical example where this can happen is
|
||||
* when running multiple tests in a single process, where each test registers
|
||||
* its own set of components.
|
||||
*
|
||||
* This operation can be used to prevent reusing of component ids and force
|
||||
* generating a new ids upon registration.
|
||||
*
|
||||
* Note that this operation should *never* be called while there are still
|
||||
* alive worlds in a process. Doing so results in undefined behavior.
|
||||
*
|
||||
* Also note that this operation does not actually change the static component
|
||||
* variables. It only ensures that the next time a component id is requested, a
|
||||
* new id will be generated.
|
||||
*
|
||||
* \ingroup cpp_components
|
||||
*/
|
||||
inline void reset() {
|
||||
ecs_cpp_reset_count_inc();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** @} */
|
||||
886
engine/libs/flecs/include/flecs/addons/cpp/delegate.hpp
Normal file
886
engine/libs/flecs/include/flecs/addons/cpp/delegate.hpp
Normal file
@@ -0,0 +1,886 @@
|
||||
/**
|
||||
* @file addons/cpp/delegate.hpp
|
||||
* @brief Wrappers around C++ functions that provide callbacks for C APIs.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs
|
||||
{
|
||||
|
||||
namespace _
|
||||
{
|
||||
|
||||
// Binding ctx for component hooks
|
||||
struct component_binding_ctx {
|
||||
void *on_add = nullptr;
|
||||
void *on_remove = nullptr;
|
||||
void *on_set = nullptr;
|
||||
ecs_ctx_free_t free_on_add = nullptr;
|
||||
ecs_ctx_free_t free_on_remove = nullptr;
|
||||
ecs_ctx_free_t free_on_set = nullptr;
|
||||
|
||||
~component_binding_ctx() {
|
||||
if (on_add && free_on_add) {
|
||||
free_on_add(on_add);
|
||||
}
|
||||
if (on_remove && free_on_remove) {
|
||||
free_on_remove(on_remove);
|
||||
}
|
||||
if (on_set && free_on_set) {
|
||||
free_on_set(on_set);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Utility to convert template argument pack to array of term ptrs
|
||||
struct term_ptr {
|
||||
void *ptr;
|
||||
bool is_ref;
|
||||
};
|
||||
|
||||
template <typename ... Components>
|
||||
struct term_ptrs {
|
||||
using array = flecs::array<_::term_ptr, sizeof...(Components)>;
|
||||
|
||||
bool populate(const ecs_iter_t *iter) {
|
||||
return populate(iter, 0, static_cast<
|
||||
remove_reference_t<
|
||||
remove_pointer_t<Components>>
|
||||
*>(nullptr)...);
|
||||
}
|
||||
|
||||
array m_terms;
|
||||
|
||||
private:
|
||||
/* Populate terms array without checking for references */
|
||||
bool populate(const ecs_iter_t*, size_t) { return false; }
|
||||
|
||||
template <typename T, typename... Targs>
|
||||
bool populate(const ecs_iter_t *iter, size_t index, T, Targs... comps) {
|
||||
m_terms[index].ptr = iter->ptrs[index];
|
||||
bool is_ref = iter->sources && iter->sources[index] != 0;
|
||||
m_terms[index].is_ref = is_ref;
|
||||
is_ref |= populate(iter, index + 1, comps ...);
|
||||
return is_ref;
|
||||
}
|
||||
};
|
||||
|
||||
struct delegate { };
|
||||
|
||||
// Template that figures out from the template parameters of a query/system
|
||||
// how to pass the value to the each callback
|
||||
template <typename T, typename = int>
|
||||
struct each_column { };
|
||||
|
||||
// Base class
|
||||
struct each_column_base {
|
||||
each_column_base(const _::term_ptr& term, size_t row)
|
||||
: m_term(term), m_row(row) { }
|
||||
|
||||
protected:
|
||||
const _::term_ptr& m_term;
|
||||
size_t m_row;
|
||||
};
|
||||
|
||||
// If type is not a pointer, return a reference to the type (default case)
|
||||
template <typename T>
|
||||
struct each_column<T, if_t< !is_pointer<T>::value &&
|
||||
!is_empty<actual_type_t<T>>::value && is_actual<T>::value > >
|
||||
: each_column_base
|
||||
{
|
||||
each_column(const _::term_ptr& term, size_t row)
|
||||
: each_column_base(term, row) { }
|
||||
|
||||
T& get_row() {
|
||||
return static_cast<T*>(this->m_term.ptr)[this->m_row];
|
||||
}
|
||||
};
|
||||
|
||||
// If argument type is not the same as actual component type, return by value.
|
||||
// This requires that the actual type can be converted to the type.
|
||||
// A typical scenario where this happens is when using flecs::pair types.
|
||||
template <typename T>
|
||||
struct each_column<T, if_t< !is_pointer<T>::value &&
|
||||
!is_empty<actual_type_t<T>>::value && !is_actual<T>::value> >
|
||||
: each_column_base
|
||||
{
|
||||
each_column(const _::term_ptr& term, size_t row)
|
||||
: each_column_base(term, row) { }
|
||||
|
||||
T get_row() {
|
||||
return static_cast<actual_type_t<T>*>(this->m_term.ptr)[this->m_row];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// If type is empty (indicating a tag) the query will pass a nullptr. To avoid
|
||||
// returning nullptr to reference arguments, return a temporary value.
|
||||
template <typename T>
|
||||
struct each_column<T, if_t< is_empty<actual_type_t<T>>::value &&
|
||||
!is_pointer<T>::value > >
|
||||
: each_column_base
|
||||
{
|
||||
each_column(const _::term_ptr& term, size_t row)
|
||||
: each_column_base(term, row) { }
|
||||
|
||||
T get_row() {
|
||||
return actual_type_t<T>();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// If type is a pointer (indicating an optional value) return the type as is
|
||||
template <typename T>
|
||||
struct each_column<T, if_t< is_pointer<T>::value &&
|
||||
!is_empty<actual_type_t<T>>::value > >
|
||||
: each_column_base
|
||||
{
|
||||
each_column(const _::term_ptr& term, size_t row)
|
||||
: each_column_base(term, row) { }
|
||||
|
||||
actual_type_t<T> get_row() {
|
||||
if (this->m_term.ptr) {
|
||||
return &static_cast<actual_type_t<T>>(this->m_term.ptr)[this->m_row];
|
||||
} else {
|
||||
// optional argument doesn't hava a value
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// If the query contains component references to other entities, check if the
|
||||
// current argument is one.
|
||||
template <typename T, typename = int>
|
||||
struct each_ref_column : public each_column<T> {
|
||||
each_ref_column(const _::term_ptr& term, size_t row)
|
||||
: each_column<T>(term, row) {
|
||||
|
||||
if (term.is_ref) {
|
||||
// If this is a reference, set the row to 0 as a ref always is a
|
||||
// single value, not an array. This prevents the application from
|
||||
// having to do an if-check on whether the column is owned.
|
||||
//
|
||||
// This check only happens when the current table being iterated
|
||||
// over caused the query to match a reference. The check is
|
||||
// performed once per iterated table.
|
||||
this->m_row = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Func, typename ... Components>
|
||||
struct each_delegate : public delegate {
|
||||
// If the number of arguments in the function signature is one more than the
|
||||
// number of components in the query, an extra entity arg is required.
|
||||
static constexpr bool PassEntity =
|
||||
(sizeof...(Components) + 1) == (arity<Func>::value);
|
||||
|
||||
// If the number of arguments in the function is two more than the number of
|
||||
// components in the query, extra iter + index arguments are required.
|
||||
static constexpr bool PassIter =
|
||||
(sizeof...(Components) + 2) == (arity<Func>::value);
|
||||
|
||||
static_assert(arity<Func>::value > 0,
|
||||
"each() must have at least one argument");
|
||||
|
||||
using Terms = typename term_ptrs<Components ...>::array;
|
||||
|
||||
template < if_not_t< is_same< decay_t<Func>, decay_t<Func>& >::value > = 0>
|
||||
explicit each_delegate(Func&& func) noexcept
|
||||
: m_func(FLECS_MOV(func)) { }
|
||||
|
||||
explicit each_delegate(const Func& func) noexcept
|
||||
: m_func(func) { }
|
||||
|
||||
// Invoke object directly. This operation is useful when the calling
|
||||
// function has just constructed the delegate, such as what happens when
|
||||
// iterating a query.
|
||||
void invoke(ecs_iter_t *iter) const {
|
||||
term_ptrs<Components...> terms;
|
||||
|
||||
if (terms.populate(iter)) {
|
||||
invoke_callback< each_ref_column >(iter, m_func, 0, terms.m_terms);
|
||||
} else {
|
||||
invoke_callback< each_column >(iter, m_func, 0, terms.m_terms);
|
||||
}
|
||||
}
|
||||
|
||||
// Static function that can be used as callback for systems/triggers
|
||||
static void run(ecs_iter_t *iter) {
|
||||
auto self = static_cast<const each_delegate*>(iter->binding_ctx);
|
||||
ecs_assert(self != nullptr, ECS_INTERNAL_ERROR, NULL);
|
||||
self->invoke(iter);
|
||||
}
|
||||
|
||||
// Static function to call for component on_add hook
|
||||
static void run_add(ecs_iter_t *iter) {
|
||||
component_binding_ctx *ctx = reinterpret_cast<component_binding_ctx*>(
|
||||
iter->binding_ctx);
|
||||
iter->binding_ctx = ctx->on_add;
|
||||
run(iter);
|
||||
}
|
||||
|
||||
// Static function to call for component on_remove hook
|
||||
static void run_remove(ecs_iter_t *iter) {
|
||||
component_binding_ctx *ctx = reinterpret_cast<component_binding_ctx*>(
|
||||
iter->binding_ctx);
|
||||
iter->binding_ctx = ctx->on_remove;
|
||||
run(iter);
|
||||
}
|
||||
|
||||
// Static function to call for component on_set hook
|
||||
static void run_set(ecs_iter_t *iter) {
|
||||
component_binding_ctx *ctx = reinterpret_cast<component_binding_ctx*>(
|
||||
iter->binding_ctx);
|
||||
iter->binding_ctx = ctx->on_set;
|
||||
run(iter);
|
||||
}
|
||||
|
||||
// Each delegates always use instanced iterators
|
||||
static bool instanced() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// Number of function arguments is one more than number of components, pass
|
||||
// entity as argument.
|
||||
template <template<typename X, typename = int> class ColumnType,
|
||||
typename... Args, if_t<
|
||||
sizeof...(Components) == sizeof...(Args) && PassEntity> = 0>
|
||||
static void invoke_callback(
|
||||
ecs_iter_t *iter, const Func& func, size_t, Terms&, Args... comps)
|
||||
{
|
||||
ECS_TABLE_LOCK(iter->world, iter->table);
|
||||
|
||||
ecs_world_t *world = iter->world;
|
||||
size_t count = static_cast<size_t>(iter->count);
|
||||
|
||||
ecs_assert(count > 0, ECS_INVALID_OPERATION,
|
||||
"no entities returned, use each() without flecs::entity argument");
|
||||
|
||||
for (size_t i = 0; i < count; i ++) {
|
||||
func(flecs::entity(world, iter->entities[i]),
|
||||
(ColumnType< remove_reference_t<Components> >(comps, i)
|
||||
.get_row())...);
|
||||
}
|
||||
|
||||
ECS_TABLE_UNLOCK(iter->world, iter->table);
|
||||
}
|
||||
|
||||
// Number of function arguments is two more than number of components, pass
|
||||
// iter + index as argument.
|
||||
template <template<typename X, typename = int> class ColumnType,
|
||||
typename... Args, int Enabled = PassIter, if_t<
|
||||
sizeof...(Components) == sizeof...(Args) && Enabled> = 0>
|
||||
static void invoke_callback(
|
||||
ecs_iter_t *iter, const Func& func, size_t, Terms&, Args... comps)
|
||||
{
|
||||
size_t count = static_cast<size_t>(iter->count);
|
||||
if (count == 0) {
|
||||
// If query has no This terms, count can be 0. Since each does not
|
||||
// have an entity parameter, just pass through components
|
||||
count = 1;
|
||||
}
|
||||
|
||||
flecs::iter it(iter);
|
||||
|
||||
ECS_TABLE_LOCK(iter->world, iter->table);
|
||||
|
||||
for (size_t i = 0; i < count; i ++) {
|
||||
func(it, i, (ColumnType< remove_reference_t<Components> >(comps, i)
|
||||
.get_row())...);
|
||||
}
|
||||
|
||||
ECS_TABLE_UNLOCK(iter->world, iter->table);
|
||||
}
|
||||
|
||||
// Number of function arguments is equal to number of components, no entity
|
||||
template <template<typename X, typename = int> class ColumnType,
|
||||
typename... Args, if_t<
|
||||
sizeof...(Components) == sizeof...(Args) && !PassEntity && !PassIter> = 0>
|
||||
static void invoke_callback(
|
||||
ecs_iter_t *iter, const Func& func, size_t, Terms&, Args... comps)
|
||||
{
|
||||
size_t count = static_cast<size_t>(iter->count);
|
||||
if (count == 0) {
|
||||
// If query has no This terms, count can be 0. Since each does not
|
||||
// have an entity parameter, just pass through components
|
||||
count = 1;
|
||||
}
|
||||
|
||||
flecs::iter it(iter);
|
||||
|
||||
ECS_TABLE_LOCK(iter->world, iter->table);
|
||||
|
||||
for (size_t i = 0; i < count; i ++) {
|
||||
func( (ColumnType< remove_reference_t<Components> >(comps, i)
|
||||
.get_row())...);
|
||||
}
|
||||
|
||||
ECS_TABLE_UNLOCK(iter->world, iter->table);
|
||||
}
|
||||
|
||||
template <template<typename X, typename = int> class ColumnType,
|
||||
typename... Args, if_t< sizeof...(Components) != sizeof...(Args) > = 0>
|
||||
static void invoke_callback(ecs_iter_t *iter, const Func& func,
|
||||
size_t index, Terms& columns, Args... comps)
|
||||
{
|
||||
invoke_callback<ColumnType>(
|
||||
iter, func, index + 1, columns, comps..., columns[index]);
|
||||
}
|
||||
|
||||
Func m_func;
|
||||
};
|
||||
|
||||
template <typename Func, typename ... Components>
|
||||
struct find_delegate : public delegate {
|
||||
// If the number of arguments in the function signature is one more than the
|
||||
// number of components in the query, an extra entity arg is required.
|
||||
static constexpr bool PassEntity =
|
||||
(sizeof...(Components) + 1) == (arity<Func>::value);
|
||||
|
||||
// If the number of arguments in the function is two more than the number of
|
||||
// components in the query, extra iter + index arguments are required.
|
||||
static constexpr bool PassIter =
|
||||
(sizeof...(Components) + 2) == (arity<Func>::value);
|
||||
|
||||
static_assert(arity<Func>::value > 0,
|
||||
"each() must have at least one argument");
|
||||
|
||||
using Terms = typename term_ptrs<Components ...>::array;
|
||||
|
||||
template < if_not_t< is_same< decay_t<Func>, decay_t<Func>& >::value > = 0>
|
||||
explicit find_delegate(Func&& func) noexcept
|
||||
: m_func(FLECS_MOV(func)) { }
|
||||
|
||||
explicit find_delegate(const Func& func) noexcept
|
||||
: m_func(func) { }
|
||||
|
||||
// Invoke object directly. This operation is useful when the calling
|
||||
// function has just constructed the delegate, such as what happens when
|
||||
// iterating a query.
|
||||
flecs::entity invoke(ecs_iter_t *iter) const {
|
||||
term_ptrs<Components...> terms;
|
||||
|
||||
if (terms.populate(iter)) {
|
||||
return invoke_callback< each_ref_column >(iter, m_func, 0, terms.m_terms);
|
||||
} else {
|
||||
return invoke_callback< each_column >(iter, m_func, 0, terms.m_terms);
|
||||
}
|
||||
}
|
||||
|
||||
// Find delegates always use instanced iterators
|
||||
static bool instanced() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// Number of function arguments is one more than number of components, pass
|
||||
// entity as argument.
|
||||
template <template<typename X, typename = int> class ColumnType,
|
||||
typename... Args, if_t<
|
||||
sizeof...(Components) == sizeof...(Args) && PassEntity> = 0>
|
||||
static flecs::entity invoke_callback(
|
||||
ecs_iter_t *iter, const Func& func, size_t, Terms&, Args... comps)
|
||||
{
|
||||
ECS_TABLE_LOCK(iter->world, iter->table);
|
||||
|
||||
ecs_world_t *world = iter->world;
|
||||
size_t count = static_cast<size_t>(iter->count);
|
||||
flecs::entity result;
|
||||
|
||||
ecs_assert(count > 0, ECS_INVALID_OPERATION,
|
||||
"no entities returned, use find() without flecs::entity argument");
|
||||
|
||||
for (size_t i = 0; i < count; i ++) {
|
||||
if (func(flecs::entity(world, iter->entities[i]),
|
||||
(ColumnType< remove_reference_t<Components> >(comps, i)
|
||||
.get_row())...))
|
||||
{
|
||||
result = flecs::entity(world, iter->entities[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ECS_TABLE_UNLOCK(iter->world, iter->table);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Number of function arguments is two more than number of components, pass
|
||||
// iter + index as argument.
|
||||
template <template<typename X, typename = int> class ColumnType,
|
||||
typename... Args, int Enabled = PassIter, if_t<
|
||||
sizeof...(Components) == sizeof...(Args) && Enabled> = 0>
|
||||
static flecs::entity invoke_callback(
|
||||
ecs_iter_t *iter, const Func& func, size_t, Terms&, Args... comps)
|
||||
{
|
||||
size_t count = static_cast<size_t>(iter->count);
|
||||
if (count == 0) {
|
||||
// If query has no This terms, count can be 0. Since each does not
|
||||
// have an entity parameter, just pass through components
|
||||
count = 1;
|
||||
}
|
||||
|
||||
flecs::iter it(iter);
|
||||
flecs::entity result;
|
||||
|
||||
ECS_TABLE_LOCK(iter->world, iter->table);
|
||||
|
||||
for (size_t i = 0; i < count; i ++) {
|
||||
if (func(it, i, (ColumnType< remove_reference_t<Components> >(comps, i)
|
||||
.get_row())...))
|
||||
{
|
||||
result = flecs::entity(iter->world, iter->entities[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ECS_TABLE_UNLOCK(iter->world, iter->table);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Number of function arguments is equal to number of components, no entity
|
||||
template <template<typename X, typename = int> class ColumnType,
|
||||
typename... Args, if_t<
|
||||
sizeof...(Components) == sizeof...(Args) && !PassEntity && !PassIter> = 0>
|
||||
static flecs::entity invoke_callback(
|
||||
ecs_iter_t *iter, const Func& func, size_t, Terms&, Args... comps)
|
||||
{
|
||||
size_t count = static_cast<size_t>(iter->count);
|
||||
if (count == 0) {
|
||||
// If query has no This terms, count can be 0. Since each does not
|
||||
// have an entity parameter, just pass through components
|
||||
count = 1;
|
||||
}
|
||||
|
||||
flecs::iter it(iter);
|
||||
flecs::entity result;
|
||||
|
||||
ECS_TABLE_LOCK(iter->world, iter->table);
|
||||
|
||||
for (size_t i = 0; i < count; i ++) {
|
||||
if (func( (ColumnType< remove_reference_t<Components> >(comps, i)
|
||||
.get_row())...))
|
||||
{
|
||||
result = flecs::entity(iter->world, iter->entities[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ECS_TABLE_UNLOCK(iter->world, iter->table);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <template<typename X, typename = int> class ColumnType,
|
||||
typename... Args, if_t< sizeof...(Components) != sizeof...(Args) > = 0>
|
||||
static flecs::entity invoke_callback(ecs_iter_t *iter, const Func& func,
|
||||
size_t index, Terms& columns, Args... comps)
|
||||
{
|
||||
return invoke_callback<ColumnType>(
|
||||
iter, func, index + 1, columns, comps..., columns[index]);
|
||||
}
|
||||
|
||||
Func m_func;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Utility class to invoke a system iterate action
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Func, typename ... Components>
|
||||
struct iter_delegate : delegate {
|
||||
private:
|
||||
static constexpr bool IterOnly = arity<Func>::value == 1;
|
||||
|
||||
using Terms = typename term_ptrs<Components ...>::array;
|
||||
|
||||
public:
|
||||
template < if_not_t< is_same< decay_t<Func>, decay_t<Func>& >::value > = 0>
|
||||
explicit iter_delegate(Func&& func) noexcept
|
||||
: m_func(FLECS_MOV(func)) { }
|
||||
|
||||
explicit iter_delegate(const Func& func) noexcept
|
||||
: m_func(func) { }
|
||||
|
||||
// Invoke object directly. This operation is useful when the calling
|
||||
// function has just constructed the delegate, such as what happens when
|
||||
// iterating a query.
|
||||
void invoke(ecs_iter_t *iter) const {
|
||||
term_ptrs<Components...> terms;
|
||||
terms.populate(iter);
|
||||
invoke_callback(iter, m_func, 0, terms.m_terms);
|
||||
}
|
||||
|
||||
// Static function that can be used as callback for systems/triggers
|
||||
static void run(ecs_iter_t *iter) {
|
||||
auto self = static_cast<const iter_delegate*>(iter->binding_ctx);
|
||||
ecs_assert(self != nullptr, ECS_INTERNAL_ERROR, NULL);
|
||||
self->invoke(iter);
|
||||
}
|
||||
|
||||
// Instancing needs to be enabled explicitly for iter delegates
|
||||
static bool instanced() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename... Args, if_t<!sizeof...(Args) && IterOnly> = 0>
|
||||
static void invoke_callback(ecs_iter_t *iter, const Func& func,
|
||||
size_t, Terms&, Args...)
|
||||
{
|
||||
flecs::iter it(iter);
|
||||
|
||||
ECS_TABLE_LOCK(iter->world, iter->table);
|
||||
|
||||
func(it);
|
||||
|
||||
ECS_TABLE_UNLOCK(iter->world, iter->table);
|
||||
}
|
||||
|
||||
template <typename... Targs, if_t<!IterOnly &&
|
||||
(sizeof...(Targs) == sizeof...(Components))> = 0>
|
||||
static void invoke_callback(ecs_iter_t *iter, const Func& func, size_t,
|
||||
Terms&, Targs... comps)
|
||||
{
|
||||
flecs::iter it(iter);
|
||||
|
||||
ECS_TABLE_LOCK(iter->world, iter->table);
|
||||
|
||||
func(it, ( static_cast<
|
||||
remove_reference_t<
|
||||
remove_pointer_t<
|
||||
actual_type_t<Components> > >* >
|
||||
(comps.ptr))...);
|
||||
|
||||
ECS_TABLE_UNLOCK(iter->world, iter->table);
|
||||
}
|
||||
|
||||
template <typename... Targs, if_t<!IterOnly &&
|
||||
(sizeof...(Targs) != sizeof...(Components)) > = 0>
|
||||
static void invoke_callback(ecs_iter_t *iter, const Func& func,
|
||||
size_t index, Terms& columns, Targs... comps)
|
||||
{
|
||||
invoke_callback(iter, func, index + 1, columns, comps...,
|
||||
columns[index]);
|
||||
}
|
||||
|
||||
Func m_func;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Utility class to invoke an entity observer delegate
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Func>
|
||||
struct entity_observer_delegate : delegate {
|
||||
explicit entity_observer_delegate(Func&& func) noexcept
|
||||
: m_func(FLECS_MOV(func)) { }
|
||||
|
||||
// Static function that can be used as callback for systems/triggers
|
||||
static void run(ecs_iter_t *iter) {
|
||||
invoke<Func>(iter);
|
||||
}
|
||||
private:
|
||||
template <typename F, if_t<arity<F>::value == 1> = 0>
|
||||
static void invoke(ecs_iter_t *iter) {
|
||||
auto self = static_cast<const entity_observer_delegate*>(iter->binding_ctx);
|
||||
ecs_assert(self != nullptr, ECS_INTERNAL_ERROR, NULL);
|
||||
self->m_func(flecs::entity(iter->world, ecs_field_src(iter, 1)));
|
||||
}
|
||||
|
||||
template <typename F, if_t<arity<F>::value == 0> = 0>
|
||||
static void invoke(ecs_iter_t *iter) {
|
||||
auto self = static_cast<const entity_observer_delegate*>(iter->binding_ctx);
|
||||
ecs_assert(self != nullptr, ECS_INTERNAL_ERROR, NULL);
|
||||
self->m_func();
|
||||
}
|
||||
|
||||
Func m_func;
|
||||
};
|
||||
|
||||
template <typename Func, typename Event>
|
||||
struct entity_payload_observer_delegate : delegate {
|
||||
explicit entity_payload_observer_delegate(Func&& func) noexcept
|
||||
: m_func(FLECS_MOV(func)) { }
|
||||
|
||||
// Static function that can be used as callback for systems/triggers
|
||||
static void run(ecs_iter_t *iter) {
|
||||
invoke<Func>(iter);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename F, if_t<arity<F>::value == 1> = 0>
|
||||
static void invoke(ecs_iter_t *iter) {
|
||||
auto self = static_cast<const entity_payload_observer_delegate*>(
|
||||
iter->binding_ctx);
|
||||
ecs_assert(self != nullptr, ECS_INTERNAL_ERROR, NULL);
|
||||
ecs_assert(iter->param != nullptr, ECS_INVALID_OPERATION,
|
||||
"entity observer invoked without payload");
|
||||
|
||||
Event *data = static_cast<Event*>(iter->param);
|
||||
self->m_func(*data);
|
||||
}
|
||||
|
||||
template <typename F, if_t<arity<F>::value == 2> = 0>
|
||||
static void invoke(ecs_iter_t *iter) {
|
||||
auto self = static_cast<const entity_payload_observer_delegate*>(
|
||||
iter->binding_ctx);
|
||||
ecs_assert(self != nullptr, ECS_INTERNAL_ERROR, NULL);
|
||||
ecs_assert(iter->param != nullptr, ECS_INVALID_OPERATION,
|
||||
"entity observer invoked without payload");
|
||||
|
||||
Event *data = static_cast<Event*>(iter->param);
|
||||
self->m_func(flecs::entity(iter->world, ecs_field_src(iter, 1)), *data);
|
||||
}
|
||||
|
||||
Func m_func;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Utility to invoke callback on entity if it has components in signature
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename ... Args>
|
||||
struct entity_with_delegate_impl;
|
||||
|
||||
template<typename ... Args>
|
||||
struct entity_with_delegate_impl<arg_list<Args ...>> {
|
||||
using ColumnArray = flecs::array<int32_t, sizeof...(Args)>;
|
||||
using ArrayType = flecs::array<void*, sizeof...(Args)>;
|
||||
using DummyArray = flecs::array<int, sizeof...(Args)>;
|
||||
using IdArray = flecs::array<id_t, sizeof...(Args)>;
|
||||
|
||||
static bool const_args() {
|
||||
static flecs::array<bool, sizeof...(Args)> is_const_args ({
|
||||
flecs::is_const<flecs::remove_reference_t<Args>>::value...
|
||||
});
|
||||
|
||||
for (auto is_const : is_const_args) {
|
||||
if (!is_const) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
bool get_ptrs(world_t *world, const ecs_record_t *r, ecs_table_t *table,
|
||||
ArrayType& ptrs)
|
||||
{
|
||||
ecs_assert(table != NULL, ECS_INTERNAL_ERROR, NULL);
|
||||
if (!ecs_table_column_count(table)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* table_index_of needs real world */
|
||||
const flecs::world_t *real_world = ecs_get_world(world);
|
||||
|
||||
/* Get column indices for components */
|
||||
ColumnArray columns ({
|
||||
ecs_table_get_column_index(real_world, table,
|
||||
_::cpp_type<Args>().id(world))...
|
||||
});
|
||||
|
||||
/* Get pointers for columns for entity */
|
||||
size_t i = 0;
|
||||
for (int32_t column : columns) {
|
||||
if (column == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ptrs[i ++] = ecs_record_get_column(r, column, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool get_mut_ptrs(world_t *world, ecs_entity_t e, ArrayType& ptrs) {
|
||||
/* Get pointers w/get_mut */
|
||||
size_t i = 0;
|
||||
DummyArray dummy ({
|
||||
(ptrs[i ++] = ecs_get_mut_id(world, e,
|
||||
_::cpp_type<Args>().id(world)), 0)...
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
static bool invoke_read(world_t *world, entity_t e, const Func& func) {
|
||||
const ecs_record_t *r = ecs_read_begin(world, e);
|
||||
if (!r) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ecs_table_t *table = r->table;
|
||||
if (!table) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ArrayType ptrs;
|
||||
bool has_components;
|
||||
if ((has_components = get_ptrs(world, r, table, ptrs))) {
|
||||
invoke_callback(func, 0, ptrs);
|
||||
}
|
||||
|
||||
ecs_read_end(r);
|
||||
|
||||
return has_components;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
static bool invoke_write(world_t *world, entity_t e, const Func& func) {
|
||||
ecs_record_t *r = ecs_write_begin(world, e);
|
||||
if (!r) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ecs_table_t *table = r->table;
|
||||
if (!table) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ArrayType ptrs;
|
||||
bool has_components;
|
||||
if ((has_components = get_ptrs(world, r, table, ptrs))) {
|
||||
invoke_callback(func, 0, ptrs);
|
||||
}
|
||||
|
||||
ecs_write_end(r);
|
||||
|
||||
return has_components;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
static bool invoke_get(world_t *world, entity_t e, const Func& func) {
|
||||
if (const_args()) {
|
||||
return invoke_read(world, e, func);
|
||||
} else {
|
||||
return invoke_write(world, e, func);
|
||||
}
|
||||
}
|
||||
|
||||
// Utility for storing id in array in pack expansion
|
||||
static size_t store_added(IdArray& added, size_t elem, ecs_table_t *prev,
|
||||
ecs_table_t *next, id_t id)
|
||||
{
|
||||
// Array should only contain ids for components that are actually added,
|
||||
// so check if the prev and next tables are different.
|
||||
if (prev != next) {
|
||||
added[elem] = id;
|
||||
elem ++;
|
||||
}
|
||||
return elem;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
static bool invoke_get_mut(world_t *world, entity_t id, const Func& func) {
|
||||
flecs::world w(world);
|
||||
|
||||
ArrayType ptrs;
|
||||
ecs_table_t *table = NULL;
|
||||
|
||||
// When not deferred take the fast path.
|
||||
if (!w.is_deferred()) {
|
||||
// Bit of low level code so we only do at most one table move & one
|
||||
// entity lookup for the entire operation.
|
||||
|
||||
// Make sure the object is not a stage. Operations on a stage are
|
||||
// only allowed when the stage is in deferred mode, which is when
|
||||
// the world is in readonly mode.
|
||||
ecs_assert(!w.is_stage(), ECS_INVALID_PARAMETER, NULL);
|
||||
|
||||
// Find table for entity
|
||||
ecs_record_t *r = ecs_record_find(world, id);
|
||||
if (r) {
|
||||
table = r->table;
|
||||
}
|
||||
|
||||
// Find destination table that has all components
|
||||
ecs_table_t *prev = table, *next;
|
||||
size_t elem = 0;
|
||||
IdArray added;
|
||||
|
||||
// Iterate components, only store added component ids in added array
|
||||
DummyArray dummy_before ({ (
|
||||
next = ecs_table_add_id(world, prev, w.id<Args>()),
|
||||
elem = store_added(added, elem, prev, next, w.id<Args>()),
|
||||
prev = next, 0
|
||||
)... });
|
||||
(void)dummy_before;
|
||||
|
||||
// If table is different, move entity straight to it
|
||||
if (table != next) {
|
||||
ecs_type_t ids;
|
||||
ids.array = added.ptr();
|
||||
ids.count = static_cast<ecs_size_t>(elem);
|
||||
ecs_commit(world, id, r, next, &ids, NULL);
|
||||
table = next;
|
||||
}
|
||||
|
||||
if (!get_ptrs(w, r, table, ptrs)) {
|
||||
ecs_abort(ECS_INTERNAL_ERROR, NULL);
|
||||
}
|
||||
|
||||
ECS_TABLE_LOCK(world, table);
|
||||
|
||||
// When deferred, obtain pointers with regular get_mut
|
||||
} else {
|
||||
get_mut_ptrs(world, id, ptrs);
|
||||
}
|
||||
|
||||
invoke_callback(func, 0, ptrs);
|
||||
|
||||
if (!w.is_deferred()) {
|
||||
ECS_TABLE_UNLOCK(world, table);
|
||||
}
|
||||
|
||||
// Call modified on each component
|
||||
DummyArray dummy_after ({
|
||||
( ecs_modified_id(world, id, w.id<Args>()), 0)...
|
||||
});
|
||||
(void)dummy_after;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Func, typename ... TArgs,
|
||||
if_t<sizeof...(TArgs) == sizeof...(Args)> = 0>
|
||||
static void invoke_callback(
|
||||
const Func& f, size_t, ArrayType&, TArgs&& ... comps)
|
||||
{
|
||||
f(*static_cast<typename base_arg_type<Args>::type*>(comps)...);
|
||||
}
|
||||
|
||||
template <typename Func, typename ... TArgs,
|
||||
if_t<sizeof...(TArgs) != sizeof...(Args)> = 0>
|
||||
static void invoke_callback(const Func& f, size_t arg, ArrayType& ptrs,
|
||||
TArgs&& ... comps)
|
||||
{
|
||||
invoke_callback(f, arg + 1, ptrs, comps..., ptrs[arg]);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Func, typename U = int>
|
||||
struct entity_with_delegate {
|
||||
static_assert(function_traits<Func>::value, "type is not callable");
|
||||
};
|
||||
|
||||
template <typename Func>
|
||||
struct entity_with_delegate<Func, if_t< is_callable<Func>::value > >
|
||||
: entity_with_delegate_impl< arg_list_t<Func> >
|
||||
{
|
||||
static_assert(function_traits<Func>::arity > 0,
|
||||
"function must have at least one argument");
|
||||
};
|
||||
|
||||
} // namespace _
|
||||
|
||||
} // namespace flecs
|
||||
310
engine/libs/flecs/include/flecs/addons/cpp/entity.hpp
Normal file
310
engine/libs/flecs/include/flecs/addons/cpp/entity.hpp
Normal file
@@ -0,0 +1,310 @@
|
||||
/**
|
||||
* @file addons/cpp/entity.hpp
|
||||
* @brief Entity class.
|
||||
*
|
||||
* This class provides read/write access to entities.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "entity_view.hpp"
|
||||
#include "mixins/entity/builder.hpp"
|
||||
|
||||
/**
|
||||
* @defgroup cpp_entities Entities
|
||||
* @brief Entity operations.
|
||||
*
|
||||
* \ingroup cpp_core
|
||||
* @{
|
||||
*/
|
||||
|
||||
namespace flecs
|
||||
{
|
||||
|
||||
/** Entity.
|
||||
* Class with read/write operations for entities.
|
||||
*
|
||||
* \ingroup cpp_entities
|
||||
*/
|
||||
struct entity : entity_builder<entity>
|
||||
{
|
||||
entity() : entity_builder<entity>() { }
|
||||
|
||||
/** Create entity.
|
||||
*
|
||||
* @param world The world in which to create the entity.
|
||||
*/
|
||||
explicit entity(world_t *world)
|
||||
: entity_builder()
|
||||
{
|
||||
m_world = world;
|
||||
m_id = ecs_new(world, 0);
|
||||
}
|
||||
|
||||
/** Wrap an existing entity id.
|
||||
*
|
||||
* @param world The world in which the entity is created.
|
||||
* @param id The entity id.
|
||||
*/
|
||||
explicit entity(const flecs::world_t *world, flecs::id_t id) {
|
||||
m_world = const_cast<flecs::world_t*>(world);
|
||||
m_id = id;
|
||||
}
|
||||
|
||||
/** Create a named entity.
|
||||
* Named entities can be looked up with the lookup functions. Entity names
|
||||
* may be scoped, where each element in the name is separated by "::".
|
||||
* For example: "Foo::Bar". If parts of the hierarchy in the scoped name do
|
||||
* not yet exist, they will be automatically created.
|
||||
*
|
||||
* @param world The world in which to create the entity.
|
||||
* @param name The entity name.
|
||||
*/
|
||||
explicit entity(world_t *world, const char *name)
|
||||
: entity_builder()
|
||||
{
|
||||
m_world = world;
|
||||
|
||||
ecs_entity_desc_t desc = {};
|
||||
desc.name = name;
|
||||
desc.sep = "::";
|
||||
desc.root_sep = "::";
|
||||
m_id = ecs_entity_init(world, &desc);
|
||||
}
|
||||
|
||||
/** Conversion from flecs::entity_t to flecs::entity.
|
||||
*
|
||||
* @param id The entity_t value to convert.
|
||||
*/
|
||||
explicit entity(entity_t id)
|
||||
: entity_builder( nullptr, id ) { }
|
||||
|
||||
/** Get mutable component value.
|
||||
* This operation returns a mutable pointer to the component. If the entity
|
||||
* did not yet have the component, it will be added. If a base entity had
|
||||
* the component, it will be overridden, and the value of the base component
|
||||
* will be copied to the entity before this function returns.
|
||||
*
|
||||
* @tparam T The component to get.
|
||||
* @return Pointer to the component value.
|
||||
*/
|
||||
template <typename T>
|
||||
T* get_mut() const {
|
||||
auto comp_id = _::cpp_type<T>::id(m_world);
|
||||
ecs_assert(_::cpp_type<T>::size() != 0, ECS_INVALID_PARAMETER, NULL);
|
||||
return static_cast<T*>(ecs_get_mut_id(m_world, m_id, comp_id));
|
||||
}
|
||||
|
||||
/** Get mutable component value (untyped).
|
||||
* This operation returns a mutable pointer to the component. If the entity
|
||||
* did not yet have the component, it will be added. If a base entity had
|
||||
* the component, it will be overridden, and the value of the base component
|
||||
* will be copied to the entity before this function returns.
|
||||
*
|
||||
* @param comp The component to get.
|
||||
* @return Pointer to the component value.
|
||||
*/
|
||||
void* get_mut(entity_t comp) const {
|
||||
return ecs_get_mut_id(m_world, m_id, comp);
|
||||
}
|
||||
|
||||
/** Get mutable pointer for a pair.
|
||||
* This operation gets the value for a pair from the entity.
|
||||
*
|
||||
* @tparam First The first part of the pair.
|
||||
* @tparam Second the second part of the pair.
|
||||
*/
|
||||
template <typename First, typename Second, typename P = pair<First, Second>,
|
||||
typename A = actual_type_t<P>, if_not_t< flecs::is_pair<First>::value> = 0>
|
||||
A* get_mut() const {
|
||||
return static_cast<A*>(ecs_get_mut_id(m_world, m_id, ecs_pair(
|
||||
_::cpp_type<First>::id(m_world),
|
||||
_::cpp_type<Second>::id(m_world))));
|
||||
}
|
||||
|
||||
/** Get mutable pointer for the first element of a pair.
|
||||
* This operation gets the value for a pair from the entity.
|
||||
*
|
||||
* @tparam First The first part of the pair.
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
template <typename First>
|
||||
First* get_mut(entity_t second) const {
|
||||
auto comp_id = _::cpp_type<First>::id(m_world);
|
||||
ecs_assert(_::cpp_type<First>::size() != 0, ECS_INVALID_PARAMETER, NULL);
|
||||
return static_cast<First*>(
|
||||
ecs_get_mut_id(m_world, m_id, ecs_pair(comp_id, second)));
|
||||
}
|
||||
|
||||
/** Get mutable pointer for a pair (untyped).
|
||||
* This operation gets the value for a pair from the entity. If neither the
|
||||
* first nor second element of the pair is a component, the operation will
|
||||
* fail.
|
||||
*
|
||||
* @param first The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
void* get_mut(entity_t first, entity_t second) const {
|
||||
return ecs_get_mut_id(m_world, m_id, ecs_pair(first, second));
|
||||
}
|
||||
|
||||
/** Get mutable pointer for the second element of a pair.
|
||||
* This operation gets the value for a pair from the entity.
|
||||
*
|
||||
* @tparam Second The second element of the pair.
|
||||
* @param first The first element of the pair.
|
||||
*/
|
||||
template <typename Second>
|
||||
Second* get_mut_second(entity_t first) const {
|
||||
auto second = _::cpp_type<Second>::id(m_world);
|
||||
ecs_assert(_::cpp_type<Second>::size() != 0, ECS_INVALID_PARAMETER, NULL);
|
||||
return static_cast<Second*>(
|
||||
ecs_get_mut_id(m_world, m_id, ecs_pair(first, second)));
|
||||
}
|
||||
|
||||
/** Signal that component was modified.
|
||||
*
|
||||
* @tparam T component that was modified.
|
||||
*/
|
||||
template <typename T>
|
||||
void modified() const {
|
||||
auto comp_id = _::cpp_type<T>::id(m_world);
|
||||
ecs_assert(_::cpp_type<T>::size() != 0, ECS_INVALID_PARAMETER, NULL);
|
||||
this->modified(comp_id);
|
||||
}
|
||||
|
||||
/** Signal that the first element of a pair was modified.
|
||||
*
|
||||
* @tparam First The first part of the pair.
|
||||
* @tparam Second the second part of the pair.
|
||||
*/
|
||||
template <typename First, typename Second>
|
||||
void modified() const {
|
||||
this->modified<First>(_::cpp_type<Second>::id(m_world));
|
||||
}
|
||||
|
||||
/** Signal that the first part of a pair was modified.
|
||||
*
|
||||
* @tparam First The first part of the pair.
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
template <typename First>
|
||||
void modified(entity_t second) const {
|
||||
auto first = _::cpp_type<First>::id(m_world);
|
||||
ecs_assert(_::cpp_type<First>::size() != 0, ECS_INVALID_PARAMETER, NULL);
|
||||
this->modified(first, second);
|
||||
}
|
||||
|
||||
/** Signal that a pair has modified (untyped).
|
||||
* If neither the first or second element of the pair are a component, the
|
||||
* operation will fail.
|
||||
*
|
||||
* @param first The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
void modified(entity_t first, entity_t second) const {
|
||||
this->modified(ecs_pair(first, second));
|
||||
}
|
||||
|
||||
/** Signal that component was modified.
|
||||
*
|
||||
* @param comp component that was modified.
|
||||
*/
|
||||
void modified(entity_t comp) const {
|
||||
ecs_modified_id(m_world, m_id, comp);
|
||||
}
|
||||
|
||||
/** Get reference to component.
|
||||
* A reference allows for quick and safe access to a component value, and is
|
||||
* a faster alternative to repeatedly calling 'get' for the same component.
|
||||
*
|
||||
* @tparam T component for which to get a reference.
|
||||
* @return The reference.
|
||||
*/
|
||||
template <typename T>
|
||||
ref<T> get_ref() const {
|
||||
return ref<T>(m_world, m_id, _::cpp_type<T>::id(m_world));
|
||||
}
|
||||
|
||||
template <typename First, typename Second, typename P = flecs::pair<First, Second>,
|
||||
typename A = actual_type_t<P>>
|
||||
ref<A> get_ref() const {
|
||||
return ref<A>(m_world, m_id,
|
||||
ecs_pair(_::cpp_type<First>::id(m_world),
|
||||
_::cpp_type<Second>::id(m_world)));
|
||||
}
|
||||
|
||||
template <typename First>
|
||||
ref<First> get_ref(flecs::entity_t second) const {
|
||||
return ref<First>(m_world, m_id,
|
||||
ecs_pair(_::cpp_type<First>::id(m_world), second));
|
||||
}
|
||||
|
||||
template <typename Second>
|
||||
ref<Second> get_ref_second(flecs::entity_t first) const {
|
||||
return ref<Second>(m_world, m_id,
|
||||
ecs_pair(first, _::cpp_type<Second>::id(m_world)));
|
||||
}
|
||||
|
||||
/** Recursively flatten relationship.
|
||||
* @see ecs_flatten
|
||||
*/
|
||||
void flatten(flecs::entity_t r, const ecs_flatten_desc_t *desc = nullptr) {
|
||||
ecs_flatten(m_world, ecs_pair(r, m_id), desc);
|
||||
}
|
||||
|
||||
/** Clear an entity.
|
||||
* This operation removes all components from an entity without recycling
|
||||
* the entity id.
|
||||
*/
|
||||
void clear() const {
|
||||
ecs_clear(m_world, m_id);
|
||||
}
|
||||
|
||||
/** Delete an entity.
|
||||
* Entities have to be deleted explicitly, and are not deleted when the
|
||||
* entity object goes out of scope.
|
||||
*/
|
||||
void destruct() const {
|
||||
ecs_delete(m_world, m_id);
|
||||
}
|
||||
|
||||
/** Return entity as entity_view.
|
||||
* This returns an entity_view instance for the entity which is a readonly
|
||||
* version of the entity class.
|
||||
*
|
||||
* This is similar to a regular upcast, except that this method ensures that
|
||||
* the entity_view instance is instantiated with a world vs. a stage, which
|
||||
* a regular upcast does not guarantee.
|
||||
*/
|
||||
flecs::entity_view view() const {
|
||||
return flecs::entity_view(
|
||||
const_cast<flecs::world_t*>(ecs_get_world(m_world)), m_id);
|
||||
}
|
||||
|
||||
/** Entity id 0.
|
||||
* This function is useful when the API must provide an entity that
|
||||
* belongs to a world, but the entity id is 0.
|
||||
*
|
||||
* @param world The world.
|
||||
*/
|
||||
static
|
||||
flecs::entity null(const flecs::world_t *world) {
|
||||
flecs::entity result;
|
||||
result.m_world = const_cast<flecs::world_t*>(world);
|
||||
return result;
|
||||
}
|
||||
|
||||
static
|
||||
flecs::entity null() {
|
||||
return flecs::entity();
|
||||
}
|
||||
|
||||
# ifdef FLECS_JSON
|
||||
# include "mixins/json/entity.inl"
|
||||
# endif
|
||||
};
|
||||
|
||||
} // namespace flecs
|
||||
|
||||
/** @} */
|
||||
755
engine/libs/flecs/include/flecs/addons/cpp/entity_view.hpp
Normal file
755
engine/libs/flecs/include/flecs/addons/cpp/entity_view.hpp
Normal file
@@ -0,0 +1,755 @@
|
||||
/**
|
||||
* @file addons/cpp/entity_view.hpp
|
||||
* @brief Entity class with only readonly operations.
|
||||
*
|
||||
* This class provides readonly access to entities. Using this class to store
|
||||
* entities in components ensures valid handles, as this class will always store
|
||||
* the actual world vs. a stage. The constructors of this class will never
|
||||
* create a new entity.
|
||||
*
|
||||
* To obtain a mutable handle to the entity, use the "mut" function.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* \ingroup cpp_entities
|
||||
* @{
|
||||
*/
|
||||
|
||||
namespace flecs
|
||||
{
|
||||
|
||||
/** Entity view.
|
||||
* Class with read operations for entities. Base for flecs::entity.
|
||||
*
|
||||
* \ingroup cpp_entities
|
||||
*/
|
||||
struct entity_view : public id {
|
||||
|
||||
entity_view() : flecs::id() { }
|
||||
|
||||
/** Wrap an existing entity id.
|
||||
*
|
||||
* @param world The world in which the entity is created.
|
||||
* @param id The entity id.
|
||||
*/
|
||||
explicit entity_view(flecs::world_t *world, flecs::id_t id)
|
||||
: flecs::id(world
|
||||
? const_cast<flecs::world_t*>(ecs_get_world(world))
|
||||
: nullptr
|
||||
, id ) { }
|
||||
|
||||
/** Implicit conversion from flecs::entity_t to flecs::entity_view. */
|
||||
entity_view(entity_t id)
|
||||
: flecs::id( nullptr, id ) { }
|
||||
|
||||
/** Get entity id.
|
||||
* @return The integer entity id.
|
||||
*/
|
||||
entity_t id() const {
|
||||
return m_id;
|
||||
}
|
||||
|
||||
/** Check if entity is valid.
|
||||
*
|
||||
* @return True if the entity is alive, false otherwise.
|
||||
*/
|
||||
bool is_valid() const {
|
||||
return m_world && ecs_is_valid(m_world, m_id);
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return is_valid();
|
||||
}
|
||||
|
||||
/** Check if entity is alive.
|
||||
*
|
||||
* @return True if the entity is alive, false otherwise.
|
||||
*/
|
||||
bool is_alive() const {
|
||||
return m_world && ecs_is_alive(m_world, m_id);
|
||||
}
|
||||
|
||||
/** Return the entity name.
|
||||
*
|
||||
* @return The entity name.
|
||||
*/
|
||||
flecs::string_view name() const {
|
||||
return flecs::string_view(ecs_get_name(m_world, m_id));
|
||||
}
|
||||
|
||||
/** Return the entity symbol.
|
||||
*
|
||||
* @return The entity symbol.
|
||||
*/
|
||||
flecs::string_view symbol() const {
|
||||
return flecs::string_view(ecs_get_symbol(m_world, m_id));
|
||||
}
|
||||
|
||||
/** Return the entity path.
|
||||
*
|
||||
* @return The hierarchical entity path.
|
||||
*/
|
||||
flecs::string path(const char *sep = "::", const char *init_sep = "::") const {
|
||||
return path_from(0, sep, init_sep);
|
||||
}
|
||||
|
||||
/** Return the entity path relative to a parent.
|
||||
*
|
||||
* @return The relative hierarchical entity path.
|
||||
*/
|
||||
flecs::string path_from(flecs::entity_t parent, const char *sep = "::", const char *init_sep = "::") const {
|
||||
char *path = ecs_get_path_w_sep(m_world, parent, m_id, sep, init_sep);
|
||||
return flecs::string(path);
|
||||
}
|
||||
|
||||
/** Return the entity path relative to a parent.
|
||||
*
|
||||
* @return The relative hierarchical entity path.
|
||||
*/
|
||||
template <typename Parent>
|
||||
flecs::string path_from(const char *sep = "::", const char *init_sep = "::") const {
|
||||
return path_from(_::cpp_type<Parent>::id(m_world), sep, init_sep);
|
||||
}
|
||||
|
||||
bool enabled() const {
|
||||
return !ecs_has_id(m_world, m_id, flecs::Disabled);
|
||||
}
|
||||
|
||||
/** Get the entity's type.
|
||||
*
|
||||
* @return The entity's type.
|
||||
*/
|
||||
flecs::type type() const;
|
||||
|
||||
/** Get the entity's table.
|
||||
*
|
||||
* @return Returns the entity's table.
|
||||
*/
|
||||
flecs::table table() const;
|
||||
|
||||
/** Get table range for the entity.
|
||||
* Returns a range with the entity's row as offset and count set to 1. If
|
||||
* the entity is not stored in a table, the function returns a range with
|
||||
* count 0.
|
||||
*
|
||||
* @return Returns the entity's table range.
|
||||
*/
|
||||
flecs::table_range range() const;
|
||||
|
||||
/** Iterate (component) ids of an entity.
|
||||
* The function parameter must match the following signature:
|
||||
* void(*)(flecs::id id)
|
||||
*
|
||||
* @param func The function invoked for each id.
|
||||
*/
|
||||
template <typename Func>
|
||||
void each(const Func& func) const;
|
||||
|
||||
/** Iterate matching pair ids of an entity.
|
||||
* The function parameter must match the following signature:
|
||||
* void(*)(flecs::id id)
|
||||
*
|
||||
* @param func The function invoked for each id.
|
||||
*/
|
||||
template <typename Func>
|
||||
void each(flecs::id_t first, flecs::id_t second, const Func& func) const;
|
||||
|
||||
/** Iterate targets for a given relationship.
|
||||
* The function parameter must match the following signature:
|
||||
* void(*)(flecs::entity target)
|
||||
*
|
||||
* @param rel The relationship for which to iterate the targets.
|
||||
* @param func The function invoked for each target.
|
||||
*/
|
||||
template <typename Func>
|
||||
void each(const flecs::entity_view& rel, const Func& func) const;
|
||||
|
||||
/** Iterate targets for a given relationship.
|
||||
* The function parameter must match the following signature:
|
||||
* void(*)(flecs::entity target)
|
||||
*
|
||||
* @tparam First The relationship for which to iterate the targets.
|
||||
* @param func The function invoked for each target.
|
||||
*/
|
||||
template <typename First, typename Func>
|
||||
void each(const Func& func) const {
|
||||
return each(_::cpp_type<First>::id(m_world), func);
|
||||
}
|
||||
|
||||
/** Iterate children for entity.
|
||||
* The function parameter must match the following signature:
|
||||
* void(*)(flecs::entity target)
|
||||
*
|
||||
* @param rel The relationship to follow.
|
||||
* @param func The function invoked for each child.
|
||||
*/
|
||||
template <typename Func>
|
||||
void children(flecs::entity_t rel, Func&& func) const {
|
||||
/* When the entity is a wildcard, this would attempt to query for all
|
||||
* entities with (ChildOf, *) or (ChildOf, _) instead of querying for
|
||||
* the children of the wildcard entity. */
|
||||
if (m_id == flecs::Wildcard || m_id == flecs::Any) {
|
||||
/* This is correct, wildcard entities don't have children */
|
||||
return;
|
||||
}
|
||||
|
||||
flecs::world world(m_world);
|
||||
|
||||
ecs_term_t terms[2];
|
||||
ecs_filter_t f = ECS_FILTER_INIT;
|
||||
f.terms = terms;
|
||||
f.term_count = 2;
|
||||
|
||||
ecs_filter_desc_t desc = {};
|
||||
desc.terms[0].first.id = rel;
|
||||
desc.terms[0].second.id = m_id;
|
||||
desc.terms[0].second.flags = EcsIsEntity;
|
||||
desc.terms[1].id = flecs::Prefab;
|
||||
desc.terms[1].oper = EcsOptional;
|
||||
desc.storage = &f;
|
||||
if (ecs_filter_init(m_world, &desc) != nullptr) {
|
||||
ecs_iter_t it = ecs_filter_iter(m_world, &f);
|
||||
while (ecs_filter_next(&it)) {
|
||||
_::each_delegate<Func>(FLECS_MOV(func)).invoke(&it);
|
||||
}
|
||||
|
||||
ecs_filter_fini(&f);
|
||||
}
|
||||
}
|
||||
|
||||
/** Iterate children for entity.
|
||||
* The function parameter must match the following signature:
|
||||
* void(*)(flecs::entity target)
|
||||
*
|
||||
* @tparam Rel The relationship to follow.
|
||||
* @param func The function invoked for each child.
|
||||
*/
|
||||
template <typename Rel, typename Func>
|
||||
void children(Func&& func) const {
|
||||
children(_::cpp_type<Rel>::id(m_world), FLECS_MOV(func));
|
||||
}
|
||||
|
||||
/** Iterate children for entity.
|
||||
* The function parameter must match the following signature:
|
||||
* void(*)(flecs::entity target)
|
||||
*
|
||||
* This operation follows the ChildOf relationship.
|
||||
*
|
||||
* @param func The function invoked for each child.
|
||||
*/
|
||||
template <typename Func>
|
||||
void children(Func&& func) const {
|
||||
children(flecs::ChildOf, FLECS_MOV(func));
|
||||
}
|
||||
|
||||
/** Get component value.
|
||||
*
|
||||
* @tparam T The component to get.
|
||||
* @return Pointer to the component value, nullptr if the entity does not
|
||||
* have the component.
|
||||
*/
|
||||
template <typename T, if_t< is_actual<T>::value > = 0>
|
||||
const T* get() const {
|
||||
auto comp_id = _::cpp_type<T>::id(m_world);
|
||||
ecs_assert(_::cpp_type<T>::size() != 0, ECS_INVALID_PARAMETER, NULL);
|
||||
return static_cast<const T*>(ecs_get_id(m_world, m_id, comp_id));
|
||||
}
|
||||
|
||||
/** Get component value.
|
||||
* Overload for when T is not the same as the actual type, which happens
|
||||
* when using pair types.
|
||||
*
|
||||
* @tparam T The component to get.
|
||||
* @return Pointer to the component value, nullptr if the entity does not
|
||||
* have the component.
|
||||
*/
|
||||
template <typename T, typename A = actual_type_t<T>,
|
||||
if_t< flecs::is_pair<T>::value > = 0>
|
||||
const A* get() const {
|
||||
auto comp_id = _::cpp_type<T>::id(m_world);
|
||||
ecs_assert(_::cpp_type<A>::size() != 0, ECS_INVALID_PARAMETER, NULL);
|
||||
return static_cast<const A*>(ecs_get_id(m_world, m_id, comp_id));
|
||||
}
|
||||
|
||||
/** Get a pair.
|
||||
* This operation gets the value for a pair from the entity.
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @tparam Second the second element of a pair.
|
||||
*/
|
||||
template <typename First, typename Second, typename P = pair<First, Second>,
|
||||
typename A = actual_type_t<P>, if_not_t< flecs::is_pair<First>::value > = 0>
|
||||
const A* get() const {
|
||||
return this->get<P>();
|
||||
}
|
||||
|
||||
/** Get a pair.
|
||||
* This operation gets the value for a pair from the entity.
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
template<typename First, typename Second, if_not_t< is_enum<Second>::value> = 0>
|
||||
const First* get(Second second) const {
|
||||
auto comp_id = _::cpp_type<First>::id(m_world);
|
||||
ecs_assert(_::cpp_type<First>::size() != 0, ECS_INVALID_PARAMETER, NULL);
|
||||
return static_cast<const First*>(
|
||||
ecs_get_id(m_world, m_id, ecs_pair(comp_id, second)));
|
||||
}
|
||||
|
||||
/** Get a pair.
|
||||
* This operation gets the value for a pair from the entity.
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @param constant the enum constant.
|
||||
*/
|
||||
template<typename First, typename Second, if_t<is_enum<Second>::value> = 0>
|
||||
const First* get(Second constant) const {
|
||||
const auto& et = enum_type<Second>(this->m_world);
|
||||
flecs::entity_t target = et.entity(constant);
|
||||
return get<First>(target);
|
||||
}
|
||||
|
||||
/** Get component value (untyped).
|
||||
*
|
||||
* @param comp The component to get.
|
||||
* @return Pointer to the component value, nullptr if the entity does not
|
||||
* have the component.
|
||||
*/
|
||||
const void* get(flecs::id_t comp) const {
|
||||
return ecs_get_id(m_world, m_id, comp);
|
||||
}
|
||||
|
||||
/** Get a pair (untyped).
|
||||
* This operation gets the value for a pair from the entity. If neither the
|
||||
* first nor the second part of the pair are components, the operation
|
||||
* will fail.
|
||||
*
|
||||
* @param first The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
const void* get(flecs::entity_t first, flecs::entity_t second) const {
|
||||
return ecs_get_id(m_world, m_id, ecs_pair(first, second));
|
||||
}
|
||||
|
||||
/** Get 1..N components.
|
||||
* This operation accepts a callback with as arguments the components to
|
||||
* retrieve. The callback will only be invoked when the entity has all
|
||||
* the components.
|
||||
*
|
||||
* This operation is faster than individually calling get for each component
|
||||
* as it only obtains entity metadata once.
|
||||
*
|
||||
* While the callback is invoked the table in which the components are
|
||||
* stored is locked, which prevents mutations that could cause invalidation
|
||||
* of the component references. Note that this is not an actual lock:
|
||||
* invalid access causes a runtime panic and so it is still up to the
|
||||
* application to ensure access is protected.
|
||||
*
|
||||
* The component arguments must be references and can be either const or
|
||||
* non-const. When all arguments are const, the function will read-lock the
|
||||
* table (see ecs_read_begin). If one or more arguments are non-const the
|
||||
* function will write-lock the table (see ecs_write_begin).
|
||||
*
|
||||
* Example:
|
||||
* e.get([](Position& p, Velocity& v) { // write lock
|
||||
* p.x += v.x;
|
||||
* });
|
||||
*
|
||||
* e.get([](const Position& p) { // read lock
|
||||
* std::cout << p.x << std::endl;
|
||||
* });
|
||||
*
|
||||
* @param func The callback to invoke.
|
||||
* @return True if the entity has all components, false if not.
|
||||
*/
|
||||
template <typename Func, if_t< is_callable<Func>::value > = 0>
|
||||
bool get(const Func& func) const;
|
||||
|
||||
/** Get enum constant.
|
||||
*
|
||||
* @tparam T The enum type for which to get the constant
|
||||
* @return Constant entity if found, 0 entity if not.
|
||||
*/
|
||||
template <typename T, if_t< is_enum<T>::value > = 0>
|
||||
const T* get() const;
|
||||
|
||||
/** Get the second part for a pair.
|
||||
* This operation gets the value for a pair from the entity. The first
|
||||
* part of the pair should not be a component.
|
||||
*
|
||||
* @tparam Second the second element of a pair.
|
||||
* @param first The first part of the pair.
|
||||
*/
|
||||
template<typename Second>
|
||||
const Second* get_second(flecs::entity_t first) const {
|
||||
auto second = _::cpp_type<Second>::id(m_world);
|
||||
ecs_assert(_::cpp_type<Second>::size() != 0, ECS_INVALID_PARAMETER, NULL);
|
||||
return static_cast<const Second*>(
|
||||
ecs_get_id(m_world, m_id, ecs_pair(first, second)));
|
||||
}
|
||||
|
||||
/** Get the second part for a pair.
|
||||
* This operation gets the value for a pair from the entity. The first
|
||||
* part of the pair should not be a component.
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @tparam Second the second element of a pair.
|
||||
*/
|
||||
template<typename First, typename Second>
|
||||
const Second* get_second() const {
|
||||
return get<pair_object<First, Second>>();
|
||||
}
|
||||
|
||||
/** Get target for a given pair.
|
||||
* This operation returns the target for a given pair. The optional
|
||||
* index can be used to iterate through targets, in case the entity has
|
||||
* multiple instances for the same relationship.
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @param index The index (0 for the first instance of the relationship).
|
||||
*/
|
||||
template<typename First>
|
||||
flecs::entity target(int32_t index = 0) const;
|
||||
|
||||
/** Get target for a given pair.
|
||||
* This operation returns the target for a given pair. The optional
|
||||
* index can be used to iterate through targets, in case the entity has
|
||||
* multiple instances for the same relationship.
|
||||
*
|
||||
* @param first The first element of the pair for which to retrieve the target.
|
||||
* @param index The index (0 for the first instance of the relationship).
|
||||
*/
|
||||
flecs::entity target(flecs::entity_t first, int32_t index = 0) const;
|
||||
|
||||
/** Get the target of a pair for a given relationship id.
|
||||
* This operation returns the first entity that has the provided id by following
|
||||
* the specified relationship. If the entity itself has the id then entity will
|
||||
* be returned. If the id cannot be found on the entity or by following the
|
||||
* relationship, the operation will return 0.
|
||||
*
|
||||
* This operation can be used to lookup, for example, which prefab is providing
|
||||
* a component by specifying the IsA pair:
|
||||
*
|
||||
* // Is Position provided by the entity or one of its base entities?
|
||||
* ecs_get_target_for_id(world, entity, EcsIsA, ecs_id(Position))
|
||||
*
|
||||
* @param relationship The relationship to follow.
|
||||
* @param id The id to lookup.
|
||||
* @return The entity for which the target has been found.
|
||||
*/
|
||||
flecs::entity target_for(flecs::entity_t relationship, flecs::id_t id) const;
|
||||
|
||||
template <typename T>
|
||||
flecs::entity target_for(flecs::entity_t relationship) const;
|
||||
|
||||
template <typename First, typename Second>
|
||||
flecs::entity target_for(flecs::entity_t relationship) const;
|
||||
|
||||
/** Get depth for given relationship.
|
||||
*
|
||||
* @param rel The relationship.
|
||||
* @return The depth.
|
||||
*/
|
||||
int32_t depth(flecs::entity_t rel) const {
|
||||
return ecs_get_depth(m_world, m_id, rel);
|
||||
}
|
||||
|
||||
/** Get depth for given relationship.
|
||||
*
|
||||
* @tparam Rel The relationship.
|
||||
* @return The depth.
|
||||
*/
|
||||
template<typename Rel>
|
||||
int32_t depth() const {
|
||||
return this->depth(_::cpp_type<Rel>::id(m_world));
|
||||
}
|
||||
|
||||
/** Get parent of entity.
|
||||
* Short for target(flecs::ChildOf).
|
||||
*
|
||||
* @return The parent of the entity.
|
||||
*/
|
||||
flecs::entity parent() const;
|
||||
|
||||
/** Lookup an entity by name.
|
||||
* Lookup an entity in the scope of this entity. The provided path may
|
||||
* contain double colons as scope separators, for example: "Foo::Bar".
|
||||
*
|
||||
* @param path The name of the entity to lookup.
|
||||
* @param search_path When false, only the entity's scope is searched.
|
||||
* @return The found entity, or entity::null if no entity matched.
|
||||
*/
|
||||
flecs::entity lookup(const char *path, bool search_path = false) const;
|
||||
|
||||
/** Check if entity has the provided entity.
|
||||
*
|
||||
* @param e The entity to check.
|
||||
* @return True if the entity has the provided entity, false otherwise.
|
||||
*/
|
||||
bool has(flecs::id_t e) const {
|
||||
return ecs_has_id(m_world, m_id, e);
|
||||
}
|
||||
|
||||
/** Check if entity has the provided component.
|
||||
*
|
||||
* @tparam T The component to check.
|
||||
* @return True if the entity has the provided component, false otherwise.
|
||||
*/
|
||||
template <typename T>
|
||||
bool has() const {
|
||||
flecs::id_t cid = _::cpp_type<T>::id(m_world);
|
||||
bool result = ecs_has_id(m_world, m_id, cid);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (is_enum<T>::value) {
|
||||
return ecs_has_pair(m_world, m_id, cid, flecs::Wildcard);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Check if entity has the provided enum constant.
|
||||
*
|
||||
* @tparam E The enum type (can be deduced).
|
||||
* @param value The enum constant to check.
|
||||
* @return True if the entity has the provided constant, false otherwise.
|
||||
*/
|
||||
template <typename E, if_t< is_enum<E>::value > = 0>
|
||||
bool has(E value) const {
|
||||
auto r = _::cpp_type<E>::id(m_world);
|
||||
auto o = enum_type<E>(m_world).entity(value);
|
||||
return ecs_has_pair(m_world, m_id, r, o);
|
||||
}
|
||||
|
||||
/** Check if entity has the provided pair.
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @tparam Second The second element of the pair.
|
||||
* @return True if the entity has the provided component, false otherwise.
|
||||
*/
|
||||
template <typename First, typename Second>
|
||||
bool has() const {
|
||||
return this->has<First>(_::cpp_type<Second>::id(m_world));
|
||||
}
|
||||
|
||||
/** Check if entity has the provided pair.
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
* @return True if the entity has the provided component, false otherwise.
|
||||
*/
|
||||
template<typename First, typename Second, if_not_t< is_enum<Second>::value > = 0>
|
||||
bool has(Second second) const {
|
||||
auto comp_id = _::cpp_type<First>::id(m_world);
|
||||
return ecs_has_id(m_world, m_id, ecs_pair(comp_id, second));
|
||||
}
|
||||
|
||||
/** Check if entity has the provided pair.
|
||||
*
|
||||
* @tparam Second The second element of the pair.
|
||||
* @param first The first element of the pair.
|
||||
* @return True if the entity has the provided component, false otherwise.
|
||||
*/
|
||||
template <typename Second>
|
||||
bool has_second(flecs::entity_t first) const {
|
||||
return this->has(first, _::cpp_type<Second>::id(m_world));
|
||||
}
|
||||
|
||||
/** Check if entity has the provided pair.
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @param value The enum constant.
|
||||
* @return True if the entity has the provided component, false otherwise.
|
||||
*/
|
||||
template<typename First, typename E, if_t< is_enum<E>::value > = 0>
|
||||
bool has(E value) const {
|
||||
const auto& et = enum_type<E>(this->m_world);
|
||||
flecs::entity_t second = et.entity(value);
|
||||
return has<First>(second);
|
||||
}
|
||||
|
||||
/** Check if entity has the provided pair.
|
||||
*
|
||||
* @param first The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
* @return True if the entity has the provided component, false otherwise.
|
||||
*/
|
||||
bool has(flecs::id_t first, flecs::id_t second) const {
|
||||
return ecs_has_id(m_world, m_id, ecs_pair(first, second));
|
||||
}
|
||||
|
||||
/** Check if entity owns the provided entity.
|
||||
* An entity is owned if it is not shared from a base entity.
|
||||
*
|
||||
* @param e The entity to check.
|
||||
* @return True if the entity owns the provided entity, false otherwise.
|
||||
*/
|
||||
bool owns(flecs::id_t e) const {
|
||||
return ecs_owns_id(m_world, m_id, e);
|
||||
}
|
||||
|
||||
/** Check if entity owns the provided pair.
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
* @return True if the entity owns the provided component, false otherwise.
|
||||
*/
|
||||
template <typename First>
|
||||
bool owns(flecs::id_t second) const {
|
||||
auto comp_id = _::cpp_type<First>::id(m_world);
|
||||
return owns(ecs_pair(comp_id, second));
|
||||
}
|
||||
|
||||
/** Check if entity owns the provided pair.
|
||||
*
|
||||
* @param first The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
* @return True if the entity owns the provided component, false otherwise.
|
||||
*/
|
||||
bool owns(flecs::id_t first, flecs::id_t second) const {
|
||||
return owns(ecs_pair(first, second));
|
||||
}
|
||||
|
||||
/** Check if entity owns the provided component.
|
||||
* An component is owned if it is not shared from a base entity.
|
||||
*
|
||||
* @tparam T The component to check.
|
||||
* @return True if the entity owns the provided component, false otherwise.
|
||||
*/
|
||||
template <typename T>
|
||||
bool owns() const {
|
||||
return owns(_::cpp_type<T>::id(m_world));
|
||||
}
|
||||
|
||||
/** Check if entity owns the provided pair.
|
||||
* An pair is owned if it is not shared from a base entity.
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @tparam Second The second element of the pair.
|
||||
* @return True if the entity owns the provided pair, false otherwise.
|
||||
*/
|
||||
template <typename First, typename Second>
|
||||
bool owns() const {
|
||||
return owns(
|
||||
_::cpp_type<First>::id(m_world),
|
||||
_::cpp_type<Second>::id(m_world));
|
||||
}
|
||||
|
||||
/** Test if id is enabled.
|
||||
*
|
||||
* @param id The id to test.
|
||||
* @return True if enabled, false if not.
|
||||
*/
|
||||
bool enabled(flecs::id_t id) const {
|
||||
return ecs_is_enabled_id(m_world, m_id, id);
|
||||
}
|
||||
|
||||
/** Test if component is enabled.
|
||||
*
|
||||
* @tparam T The component to test.
|
||||
* @return True if enabled, false if not.
|
||||
*/
|
||||
template<typename T>
|
||||
bool enabled() const {
|
||||
return this->enabled(_::cpp_type<T>::id(m_world));
|
||||
}
|
||||
|
||||
/** Test if pair is enabled.
|
||||
*
|
||||
* @param first The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
* @return True if enabled, false if not.
|
||||
*/
|
||||
bool enabled(flecs::id_t first, flecs::id_t second) const {
|
||||
return this->enabled(ecs_pair(first, second));
|
||||
}
|
||||
|
||||
/** Test if pair is enabled.
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
* @return True if enabled, false if not.
|
||||
*/
|
||||
template <typename First>
|
||||
bool enabled(flecs::id_t second) const {
|
||||
return this->enabled(_::cpp_type<First>::id(m_world), second);
|
||||
}
|
||||
|
||||
/** Test if pair is enabled.
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @tparam Second The second element of the pair.
|
||||
* @return True if enabled, false if not.
|
||||
*/
|
||||
template <typename First, typename Second>
|
||||
bool enabled() const {
|
||||
return this->enabled<First>(_::cpp_type<Second>::id(m_world));
|
||||
}
|
||||
|
||||
flecs::entity clone(bool clone_value = true, flecs::entity_t dst_id = 0) const;
|
||||
|
||||
/** Return mutable entity handle for current stage
|
||||
* When an entity handle created from the world is used while the world is
|
||||
* in staged mode, it will only allow for readonly operations since
|
||||
* structural changes are not allowed on the world while in staged mode.
|
||||
*
|
||||
* To do mutations on the entity, this operation provides a handle to the
|
||||
* entity that uses the stage instead of the actual world.
|
||||
*
|
||||
* Note that staged entity handles should never be stored persistently, in
|
||||
* components or elsewhere. An entity handle should always point to the
|
||||
* main world.
|
||||
*
|
||||
* Also note that this operation is not necessary when doing mutations on an
|
||||
* entity outside of a system. It is allowed to do entity operations
|
||||
* directly on the world, as long as the world is not in staged mode.
|
||||
*
|
||||
* @param stage The current stage.
|
||||
* @return An entity handle that allows for mutations in the current stage.
|
||||
*/
|
||||
flecs::entity mut(const flecs::world& stage) const;
|
||||
|
||||
/** Same as mut(world), but for iterator.
|
||||
* This operation allows for the construction of a mutable entity handle
|
||||
* from an iterator.
|
||||
*
|
||||
* @param it An iterator that contains a reference to the world or stage.
|
||||
* @return An entity handle that allows for mutations in the current stage.
|
||||
*/
|
||||
flecs::entity mut(const flecs::iter& it) const;
|
||||
|
||||
/** Same as mut(world), but for entity.
|
||||
* This operation allows for the construction of a mutable entity handle
|
||||
* from another entity. This is useful in each() functions, which only
|
||||
* provide a handle to the entity being iterated over.
|
||||
*
|
||||
* @param e Another mutable entity.
|
||||
* @return An entity handle that allows for mutations in the current stage.
|
||||
*/
|
||||
flecs::entity mut(const flecs::entity_view& e) const;
|
||||
|
||||
# ifdef FLECS_JSON
|
||||
# include "mixins/json/entity_view.inl"
|
||||
# endif
|
||||
# ifdef FLECS_DOC
|
||||
# include "mixins/doc/entity_view.inl"
|
||||
# endif
|
||||
# ifdef FLECS_ALERTS
|
||||
# include "mixins/alerts/entity_view.inl"
|
||||
# endif
|
||||
|
||||
# include "mixins/enum/entity_view.inl"
|
||||
# include "mixins/event/entity_view.inl"
|
||||
|
||||
private:
|
||||
flecs::entity set_stage(world_t *stage);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/** @} */
|
||||
184
engine/libs/flecs/include/flecs/addons/cpp/flecs.hpp
Normal file
184
engine/libs/flecs/include/flecs/addons/cpp/flecs.hpp
Normal file
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
* @file addons/cpp/flecs.hpp
|
||||
* @brief Flecs C++11 API.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// STL includes
|
||||
#include <type_traits>
|
||||
|
||||
/**
|
||||
* @defgroup cpp C++ API
|
||||
* @{
|
||||
*/
|
||||
|
||||
namespace flecs
|
||||
{
|
||||
|
||||
struct world;
|
||||
struct world_async_stage;
|
||||
struct iter;
|
||||
struct entity_view;
|
||||
struct entity;
|
||||
struct type;
|
||||
struct table;
|
||||
struct table_range;
|
||||
struct untyped_component;
|
||||
|
||||
template <typename T>
|
||||
struct component;
|
||||
|
||||
namespace _
|
||||
{
|
||||
template <typename T, typename U = int>
|
||||
struct cpp_type;
|
||||
|
||||
template <typename Func, typename ... Components>
|
||||
struct each_delegate;
|
||||
|
||||
} // namespace _
|
||||
} // namespace flecs
|
||||
|
||||
// Types imported from C API
|
||||
#include "c_types.hpp"
|
||||
|
||||
// C++ utilities
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
// Mixin forward declarations
|
||||
#include "mixins/id/decl.hpp"
|
||||
#include "mixins/term/decl.hpp"
|
||||
#include "mixins/filter/decl.hpp"
|
||||
#include "mixins/event/decl.hpp"
|
||||
#include "mixins/query/decl.hpp"
|
||||
#include "mixins/observer/decl.hpp"
|
||||
#ifdef FLECS_SYSTEM
|
||||
#include "mixins/system/decl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_PIPELINE
|
||||
#include "mixins/pipeline/decl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_TIMER
|
||||
#include "mixins/timer/decl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_SNAPSHOT
|
||||
#include "mixins/snapshot/decl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_DOC
|
||||
#include "mixins/doc/decl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_REST
|
||||
#include "mixins/rest/decl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_RULES
|
||||
#include "mixins/rule/decl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_META
|
||||
#include "mixins/meta/decl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_UNITS
|
||||
#include "mixins/units/decl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_MONITOR
|
||||
#include "mixins/monitor/decl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_METRICS
|
||||
#include "mixins/metrics/decl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_ALERTS
|
||||
#include "mixins/alerts/decl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_JSON
|
||||
#include "mixins/json/decl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_APP
|
||||
#include "mixins/app/decl.hpp"
|
||||
#endif
|
||||
|
||||
#include "log.hpp"
|
||||
#include "pair.hpp"
|
||||
#include "lifecycle_traits.hpp"
|
||||
#include "ref.hpp"
|
||||
#include "world.hpp"
|
||||
#include "iter.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "delegate.hpp"
|
||||
#include "utils/iterable.hpp"
|
||||
#include "component.hpp"
|
||||
#include "type.hpp"
|
||||
#include "table.hpp"
|
||||
|
||||
// Mixin implementations
|
||||
#include "mixins/id/impl.hpp"
|
||||
#include "mixins/entity/impl.hpp"
|
||||
#include "mixins/component/impl.hpp"
|
||||
#include "mixins/term/impl.hpp"
|
||||
#include "mixins/filter/impl.hpp"
|
||||
#include "mixins/query/impl.hpp"
|
||||
#include "mixins/observer/impl.hpp"
|
||||
#include "mixins/event/impl.hpp"
|
||||
#include "mixins/enum/impl.hpp"
|
||||
#ifdef FLECS_MODULE
|
||||
#include "mixins/module/impl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_SYSTEM
|
||||
#include "mixins/system/impl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_PIPELINE
|
||||
#include "mixins/pipeline/impl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_TIMER
|
||||
#include "mixins/timer/impl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_SNAPSHOT
|
||||
#include "mixins/snapshot/impl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_DOC
|
||||
#include "mixins/doc/impl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_DOC
|
||||
#include "mixins/doc/impl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_REST
|
||||
#include "mixins/rest/impl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_RULES
|
||||
#include "mixins/rule/impl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_META
|
||||
#include "mixins/meta/impl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_UNITS
|
||||
#include "mixins/units/impl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_MONITOR
|
||||
#include "mixins/monitor/impl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_METRICS
|
||||
#include "mixins/metrics/impl.hpp"
|
||||
#endif
|
||||
#ifdef FLECS_ALERTS
|
||||
#include "mixins/alerts/impl.hpp"
|
||||
#endif
|
||||
|
||||
#include "impl/iter.hpp"
|
||||
#include "impl/world.hpp"
|
||||
|
||||
/**
|
||||
* @defgroup cpp_core Core
|
||||
* @brief Core ECS functionality (entities, storage, queries)
|
||||
*
|
||||
* @{
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup cpp_addons Addons
|
||||
* @brief C++ APIs for addons.
|
||||
*
|
||||
* @{
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @} */
|
||||
85
engine/libs/flecs/include/flecs/addons/cpp/impl/iter.hpp
Normal file
85
engine/libs/flecs/include/flecs/addons/cpp/impl/iter.hpp
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* @file addons/cpp/impl/iter.hpp
|
||||
* @brief Iterator implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs
|
||||
{
|
||||
|
||||
inline flecs::entity iter::system() const {
|
||||
return flecs::entity(m_iter->world, m_iter->system);
|
||||
}
|
||||
|
||||
inline flecs::entity iter::event() const {
|
||||
return flecs::entity(m_iter->world, m_iter->event);
|
||||
}
|
||||
|
||||
inline flecs::id iter::event_id() const {
|
||||
return flecs::id(m_iter->world, m_iter->event_id);
|
||||
}
|
||||
|
||||
inline flecs::world iter::world() const {
|
||||
return flecs::world(m_iter->world);
|
||||
}
|
||||
|
||||
inline flecs::entity iter::entity(size_t row) const {
|
||||
ecs_assert(row < static_cast<size_t>(m_iter->count),
|
||||
ECS_COLUMN_INDEX_OUT_OF_RANGE, NULL);
|
||||
return flecs::entity(m_iter->world, m_iter->entities[row]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline column<T>::column(iter &iter, int32_t index) {
|
||||
*this = iter.field<T>(index);
|
||||
}
|
||||
|
||||
inline flecs::entity iter::src(int32_t index) const {
|
||||
return flecs::entity(m_iter->world, ecs_field_src(m_iter, index));
|
||||
}
|
||||
|
||||
inline flecs::id iter::id(int32_t index) const {
|
||||
return flecs::id(m_iter->world, ecs_field_id(m_iter, index));
|
||||
}
|
||||
|
||||
inline flecs::id iter::pair(int32_t index) const {
|
||||
flecs::id_t id = ecs_field_id(m_iter, index);
|
||||
ecs_check(ECS_HAS_ID_FLAG(id, PAIR), ECS_INVALID_PARAMETER, NULL);
|
||||
return flecs::id(m_iter->world, id);
|
||||
error:
|
||||
return flecs::id();
|
||||
}
|
||||
|
||||
inline flecs::type iter::type() const {
|
||||
return flecs::type(m_iter->world, ecs_table_get_type(m_iter->table));
|
||||
}
|
||||
|
||||
inline flecs::table iter::table() const {
|
||||
return flecs::table(m_iter->real_world, m_iter->table);
|
||||
}
|
||||
|
||||
inline flecs::table_range iter::range() const {
|
||||
return flecs::table_range(m_iter->real_world, m_iter->table,
|
||||
m_iter->offset, m_iter->count);
|
||||
}
|
||||
|
||||
#ifdef FLECS_RULES
|
||||
inline flecs::entity iter::get_var(int var_id) const {
|
||||
ecs_assert(var_id != -1, ECS_INVALID_PARAMETER, 0);
|
||||
return flecs::entity(m_iter->world, ecs_iter_get_var(m_iter, var_id));
|
||||
}
|
||||
|
||||
/** Get value of variable by name.
|
||||
* Get value of a query variable for current result.
|
||||
*/
|
||||
inline flecs::entity iter::get_var(const char *name) const {
|
||||
ecs_rule_iter_t *rit = &m_iter->priv.iter.rule;
|
||||
const flecs::rule_t *r = rit->rule;
|
||||
int var_id = ecs_rule_find_var(r, name);
|
||||
ecs_assert(var_id != -1, ECS_INVALID_PARAMETER, name);
|
||||
return flecs::entity(m_iter->world, ecs_iter_get_var(m_iter, var_id));
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace flecs
|
||||
287
engine/libs/flecs/include/flecs/addons/cpp/impl/world.hpp
Normal file
287
engine/libs/flecs/include/flecs/addons/cpp/impl/world.hpp
Normal file
@@ -0,0 +1,287 @@
|
||||
/**
|
||||
* @file addons/cpp/impl/world.hpp
|
||||
* @brief World implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs
|
||||
{
|
||||
|
||||
inline void world::init_builtin_components() {
|
||||
# ifdef FLECS_SYSTEM
|
||||
_::system_init(*this);
|
||||
# endif
|
||||
# ifdef FLECS_TIMER
|
||||
_::timer_init(*this);
|
||||
# endif
|
||||
# ifdef FLECS_DOC
|
||||
doc::_::init(*this);
|
||||
# endif
|
||||
# ifdef FLECS_REST
|
||||
rest::_::init(*this);
|
||||
# endif
|
||||
# ifdef FLECS_META
|
||||
meta::_::init(*this);
|
||||
# endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline flecs::entity world::use(const char *alias) const {
|
||||
entity_t e = _::cpp_type<T>::id(m_world);
|
||||
const char *name = alias;
|
||||
if (!name) {
|
||||
// If no name is defined, use the entity name without the scope
|
||||
name = ecs_get_name(m_world, e);
|
||||
}
|
||||
ecs_set_alias(m_world, e, name);
|
||||
return flecs::entity(m_world, e);
|
||||
}
|
||||
|
||||
inline flecs::entity world::use(const char *name, const char *alias) const {
|
||||
entity_t e = ecs_lookup_path_w_sep(m_world, 0, name, "::", "::", true);
|
||||
ecs_assert(e != 0, ECS_INVALID_PARAMETER, NULL);
|
||||
|
||||
ecs_set_alias(m_world, e, alias);
|
||||
return flecs::entity(m_world, e);
|
||||
}
|
||||
|
||||
inline void world::use(flecs::entity e, const char *alias) const {
|
||||
entity_t eid = e.id();
|
||||
const char *name = alias;
|
||||
if (!name) {
|
||||
// If no name is defined, use the entity name without the scope
|
||||
name = ecs_get_name(m_world, eid);
|
||||
}
|
||||
ecs_set_alias(m_world, eid, name);
|
||||
}
|
||||
|
||||
inline flecs::entity world::set_scope(const flecs::entity_t s) const {
|
||||
return flecs::entity(ecs_set_scope(m_world, s));
|
||||
}
|
||||
|
||||
inline flecs::entity world::get_scope() const {
|
||||
return flecs::entity(m_world, ecs_get_scope(m_world));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline flecs::entity world::set_scope() const {
|
||||
return set_scope( _::cpp_type<T>::id(m_world) );
|
||||
}
|
||||
|
||||
inline entity world::lookup(const char *name, bool search_path) const {
|
||||
auto e = ecs_lookup_path_w_sep(m_world, 0, name, "::", "::", search_path);
|
||||
return flecs::entity(*this, e);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T* world::get_mut() const {
|
||||
flecs::entity e(m_world, _::cpp_type<T>::id(m_world));
|
||||
return e.get_mut<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void world::modified() const {
|
||||
flecs::entity e(m_world, _::cpp_type<T>::id(m_world));
|
||||
e.modified<T>();
|
||||
}
|
||||
|
||||
template <typename First, typename Second>
|
||||
inline void world::set(Second second, const First& value) const {
|
||||
flecs::entity e(m_world, _::cpp_type<First>::id(m_world));
|
||||
e.set<First>(second, value);
|
||||
}
|
||||
|
||||
template <typename First, typename Second>
|
||||
inline void world::set(Second second, First&& value) const {
|
||||
flecs::entity e(m_world, _::cpp_type<First>::id(m_world));
|
||||
e.set<First>(second, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline ref<T> world::get_ref() const {
|
||||
flecs::entity e(m_world, _::cpp_type<T>::id(m_world));
|
||||
return e.get_ref<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline const T* world::get() const {
|
||||
flecs::entity e(m_world, _::cpp_type<T>::id(m_world));
|
||||
return e.get<T>();
|
||||
}
|
||||
|
||||
template <typename First, typename Second, typename P, typename A>
|
||||
const A* world::get() const {
|
||||
flecs::entity e(m_world, _::cpp_type<First>::id(m_world));
|
||||
return e.get<First, Second>();
|
||||
}
|
||||
|
||||
template <typename First, typename Second>
|
||||
const First* world::get(Second second) const {
|
||||
flecs::entity e(m_world, _::cpp_type<First>::id(m_world));
|
||||
return e.get<First>(second);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool world::has() const {
|
||||
flecs::entity e(m_world, _::cpp_type<T>::id(m_world));
|
||||
return e.has<T>();
|
||||
}
|
||||
|
||||
template <typename First, typename Second>
|
||||
inline bool world::has() const {
|
||||
flecs::entity e(m_world, _::cpp_type<First>::id(m_world));
|
||||
return e.has<First, Second>();
|
||||
}
|
||||
|
||||
template <typename First>
|
||||
inline bool world::has(flecs::id_t second) const {
|
||||
flecs::entity e(m_world, _::cpp_type<First>::id(m_world));
|
||||
return e.has<First>(second);
|
||||
}
|
||||
|
||||
inline bool world::has(flecs::id_t first, flecs::id_t second) const {
|
||||
flecs::entity e(m_world, first);
|
||||
return e.has(first, second);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void world::add() const {
|
||||
flecs::entity e(m_world, _::cpp_type<T>::id(m_world));
|
||||
e.add<T>();
|
||||
}
|
||||
|
||||
template <typename First, typename Second>
|
||||
inline void world::add() const {
|
||||
flecs::entity e(m_world, _::cpp_type<First>::id(m_world));
|
||||
e.add<First, Second>();
|
||||
}
|
||||
|
||||
template <typename First>
|
||||
inline void world::add(flecs::entity_t second) const {
|
||||
flecs::entity e(m_world, _::cpp_type<First>::id(m_world));
|
||||
e.add<First>(second);
|
||||
}
|
||||
|
||||
inline void world::add(flecs::entity_t first, flecs::entity_t second) const {
|
||||
flecs::entity e(m_world, first);
|
||||
e.add(first, second);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void world::remove() const {
|
||||
flecs::entity e(m_world, _::cpp_type<T>::id(m_world));
|
||||
e.remove<T>();
|
||||
}
|
||||
|
||||
template <typename First, typename Second>
|
||||
inline void world::remove() const {
|
||||
flecs::entity e(m_world, _::cpp_type<First>::id(m_world));
|
||||
e.remove<First, Second>();
|
||||
}
|
||||
|
||||
template <typename First>
|
||||
inline void world::remove(flecs::entity_t second) const {
|
||||
flecs::entity e(m_world, _::cpp_type<First>::id(m_world));
|
||||
e.remove<First>(second);
|
||||
}
|
||||
|
||||
inline void world::remove(flecs::entity_t first, flecs::entity_t second) const {
|
||||
flecs::entity e(m_world, first);
|
||||
e.remove(first, second);
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
inline void world::children(Func&& f) const {
|
||||
this->entity(0).children(FLECS_FWD(f));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline flecs::entity world::singleton() const {
|
||||
return flecs::entity(m_world, _::cpp_type<T>::id(m_world));
|
||||
}
|
||||
|
||||
template <typename First>
|
||||
inline flecs::entity world::target(int32_t index) const
|
||||
{
|
||||
return flecs::entity(m_world,
|
||||
ecs_get_target(m_world, _::cpp_type<First>::id(m_world), _::cpp_type<First>::id(m_world), index));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline flecs::entity world::target(
|
||||
flecs::entity_t relationship,
|
||||
int32_t index) const
|
||||
{
|
||||
return flecs::entity(m_world,
|
||||
ecs_get_target(m_world, _::cpp_type<T>::id(m_world), relationship, index));
|
||||
}
|
||||
|
||||
inline flecs::entity world::target(
|
||||
flecs::entity_t relationship,
|
||||
int32_t index) const
|
||||
{
|
||||
return flecs::entity(m_world,
|
||||
ecs_get_target(m_world, relationship, relationship, index));
|
||||
}
|
||||
|
||||
template <typename Func, if_t< is_callable<Func>::value > >
|
||||
inline void world::get(const Func& func) const {
|
||||
static_assert(arity<Func>::value == 1, "singleton component must be the only argument");
|
||||
_::entity_with_delegate<Func>::invoke_get(
|
||||
this->m_world, this->singleton<first_arg_t<Func>>(), func);
|
||||
}
|
||||
|
||||
template <typename Func, if_t< is_callable<Func>::value > >
|
||||
inline void world::set(const Func& func) const {
|
||||
static_assert(arity<Func>::value == 1, "singleton component must be the only argument");
|
||||
_::entity_with_delegate<Func>::invoke_get_mut(
|
||||
this->m_world, this->singleton<first_arg_t<Func>>(), func);
|
||||
}
|
||||
|
||||
inline flecs::entity world::get_alive(flecs::entity_t e) const {
|
||||
e = ecs_get_alive(m_world, e);
|
||||
return flecs::entity(m_world, e);
|
||||
}
|
||||
/* Prevent clashing with Unreal define. Unreal applications will have to use
|
||||
* ecs_ensure. */
|
||||
#ifndef ensure
|
||||
inline flecs::entity world::ensure(flecs::entity_t e) const {
|
||||
ecs_ensure(m_world, e);
|
||||
return flecs::entity(m_world, e);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename E>
|
||||
inline flecs::entity enum_data<E>::entity() const {
|
||||
return flecs::entity(world_, impl_.id);
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
inline flecs::entity enum_data<E>::entity(int value) const {
|
||||
return flecs::entity(world_, impl_.constants[value].id);
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
inline flecs::entity enum_data<E>::entity(E value) const {
|
||||
return flecs::entity(world_, impl_.constants[static_cast<int>(value)].id);
|
||||
}
|
||||
|
||||
/** Use provided scope for operations ran on returned world.
|
||||
* Operations need to be ran in a single statement.
|
||||
*/
|
||||
inline flecs::scoped_world world::scope(id_t parent) const {
|
||||
return scoped_world(m_world, parent);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline flecs::scoped_world world::scope() const {
|
||||
flecs::id_t parent = _::cpp_type<T>::id(m_world);
|
||||
return scoped_world(m_world, parent);
|
||||
}
|
||||
|
||||
inline flecs::scoped_world world::scope(const char* name) const {
|
||||
return scope(entity(name));
|
||||
}
|
||||
|
||||
} // namespace flecs
|
||||
477
engine/libs/flecs/include/flecs/addons/cpp/iter.hpp
Normal file
477
engine/libs/flecs/include/flecs/addons/cpp/iter.hpp
Normal file
@@ -0,0 +1,477 @@
|
||||
/**
|
||||
* @file addons/cpp/iter.hpp
|
||||
* @brief Wrapper classes for ecs_iter_t and component arrays.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @defgroup cpp_iterator Iterators
|
||||
* @brief Iterator operations.
|
||||
*
|
||||
* \ingroup cpp_core
|
||||
* @{
|
||||
*/
|
||||
|
||||
namespace flecs
|
||||
{
|
||||
|
||||
/** Unsafe wrapper class around a column.
|
||||
* This class can be used when a system does not know the type of a column at
|
||||
* compile time.
|
||||
*
|
||||
* \ingroup cpp_iterator
|
||||
*/
|
||||
struct untyped_column {
|
||||
untyped_column(void* array, size_t size, size_t count, bool is_shared = false)
|
||||
: m_array(array)
|
||||
, m_size(size)
|
||||
, m_count(count)
|
||||
, m_is_shared(is_shared) {}
|
||||
|
||||
/** Return element in component array.
|
||||
* This operator may only be used if the column is not shared.
|
||||
*
|
||||
* @param index Index of element.
|
||||
* @return Reference to element.
|
||||
*/
|
||||
void* operator[](size_t index) const {
|
||||
ecs_assert(index < m_count, ECS_COLUMN_INDEX_OUT_OF_RANGE, NULL);
|
||||
ecs_assert(!m_is_shared, ECS_INVALID_PARAMETER, NULL);
|
||||
return ECS_OFFSET(m_array, m_size * index);
|
||||
}
|
||||
|
||||
protected:
|
||||
void* m_array;
|
||||
size_t m_size;
|
||||
size_t m_count;
|
||||
bool m_is_shared;
|
||||
};
|
||||
|
||||
/** Wrapper class around a column.
|
||||
*
|
||||
* @tparam T component type of the column.
|
||||
*
|
||||
* \ingroup cpp_iterator
|
||||
*/
|
||||
template <typename T>
|
||||
struct column {
|
||||
static_assert(std::is_empty<T>::value == false,
|
||||
"invalid type for column, cannot iterate empty type");
|
||||
|
||||
/** Create column from component array.
|
||||
*
|
||||
* @param array Pointer to the component array.
|
||||
* @param count Number of elements in component array.
|
||||
* @param is_shared Is the component shared or not.
|
||||
*/
|
||||
column(T* array, size_t count, bool is_shared = false)
|
||||
: m_array(array)
|
||||
, m_count(count)
|
||||
, m_is_shared(is_shared) {}
|
||||
|
||||
/** Create column from iterator.
|
||||
*
|
||||
* @param iter Iterator object.
|
||||
* @param column Index of the signature of the query being iterated over.
|
||||
*/
|
||||
column(iter &iter, int column);
|
||||
|
||||
/** Return element in component array.
|
||||
* This operator may only be used if the column is not shared.
|
||||
*
|
||||
* @param index Index of element.
|
||||
* @return Reference to element.
|
||||
*/
|
||||
T& operator[](size_t index) const {
|
||||
ecs_assert(index < m_count, ECS_COLUMN_INDEX_OUT_OF_RANGE, NULL);
|
||||
ecs_assert(!index || !m_is_shared, ECS_INVALID_PARAMETER, NULL);
|
||||
ecs_assert(m_array != nullptr, ECS_COLUMN_INDEX_OUT_OF_RANGE, NULL);
|
||||
return m_array[index];
|
||||
}
|
||||
|
||||
/** Return first element of component array.
|
||||
* This operator is typically used when the column is shared.
|
||||
*
|
||||
* @return Reference to the first element.
|
||||
*/
|
||||
T& operator*() const {
|
||||
ecs_assert(m_array != nullptr, ECS_COLUMN_INDEX_OUT_OF_RANGE, NULL);
|
||||
return *m_array;
|
||||
}
|
||||
|
||||
/** Return first element of component array.
|
||||
* This operator is typically used when the column is shared.
|
||||
*
|
||||
* @return Pointer to the first element.
|
||||
*/
|
||||
T* operator->() const {
|
||||
ecs_assert(m_array != nullptr, ECS_COLUMN_INDEX_OUT_OF_RANGE, NULL);
|
||||
return m_array;
|
||||
}
|
||||
|
||||
protected:
|
||||
T* m_array;
|
||||
size_t m_count;
|
||||
bool m_is_shared;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace _ {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** Iterate over an integer range (used to iterate over entity range).
|
||||
*
|
||||
* @tparam T of the iterator
|
||||
*/
|
||||
template <typename T>
|
||||
struct range_iterator
|
||||
{
|
||||
explicit range_iterator(T value)
|
||||
: m_value(value){}
|
||||
|
||||
bool operator!=(range_iterator const& other) const
|
||||
{
|
||||
return m_value != other.m_value;
|
||||
}
|
||||
|
||||
T const& operator*() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
range_iterator& operator++()
|
||||
{
|
||||
++m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
T m_value;
|
||||
};
|
||||
|
||||
} // namespace _
|
||||
|
||||
} // namespace flecs
|
||||
|
||||
namespace flecs
|
||||
{
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** Class for iterating over query results.
|
||||
*
|
||||
* \ingroup cpp_iterator
|
||||
*/
|
||||
struct iter {
|
||||
private:
|
||||
using row_iterator = _::range_iterator<size_t>;
|
||||
|
||||
public:
|
||||
/** Construct iterator from C iterator object.
|
||||
* This operation is typically not invoked directly by the user.
|
||||
*
|
||||
* @param it Pointer to C iterator.
|
||||
*/
|
||||
iter(ecs_iter_t *it) : m_iter(it) {
|
||||
m_begin = 0;
|
||||
m_end = static_cast<std::size_t>(it->count);
|
||||
}
|
||||
|
||||
row_iterator begin() const {
|
||||
return row_iterator(m_begin);
|
||||
}
|
||||
|
||||
row_iterator end() const {
|
||||
return row_iterator(m_end);
|
||||
}
|
||||
|
||||
flecs::entity system() const;
|
||||
|
||||
flecs::entity event() const;
|
||||
|
||||
flecs::id event_id() const;
|
||||
|
||||
flecs::world world() const;
|
||||
|
||||
const flecs::iter_t* c_ptr() const {
|
||||
return m_iter;
|
||||
}
|
||||
|
||||
size_t count() const {
|
||||
return static_cast<size_t>(m_iter->count);
|
||||
}
|
||||
|
||||
ecs_ftime_t delta_time() const {
|
||||
return m_iter->delta_time;
|
||||
}
|
||||
|
||||
ecs_ftime_t delta_system_time() const {
|
||||
return m_iter->delta_system_time;
|
||||
}
|
||||
|
||||
flecs::type type() const;
|
||||
|
||||
flecs::table table() const;
|
||||
|
||||
flecs::table_range range() const;
|
||||
|
||||
/** Access ctx.
|
||||
* ctx contains the context pointer assigned to a system.
|
||||
*/
|
||||
void* ctx() {
|
||||
return m_iter->ctx;
|
||||
}
|
||||
|
||||
/** Access ctx.
|
||||
* ctx contains the context pointer assigned to a system.
|
||||
*/
|
||||
template <typename T>
|
||||
T* ctx() {
|
||||
return static_cast<T*>(m_iter->ctx);
|
||||
}
|
||||
|
||||
/** Access param.
|
||||
* param contains the pointer passed to the param argument of system::run
|
||||
*/
|
||||
void* param() {
|
||||
return m_iter->param;
|
||||
}
|
||||
|
||||
/** Access param.
|
||||
* param contains the pointer passed to the param argument of system::run
|
||||
*/
|
||||
template <typename T>
|
||||
T* param() {
|
||||
/* TODO: type check */
|
||||
return static_cast<T*>(m_iter->param);
|
||||
}
|
||||
|
||||
/** Obtain mutable handle to entity being iterated over.
|
||||
*
|
||||
* @param row Row being iterated over.
|
||||
*/
|
||||
flecs::entity entity(size_t row) const;
|
||||
|
||||
/** Returns whether field is matched on self.
|
||||
*
|
||||
* @param index The field index.
|
||||
*/
|
||||
bool is_self(int32_t index) const {
|
||||
return ecs_field_is_self(m_iter, index);
|
||||
}
|
||||
|
||||
/** Returns whether field is set.
|
||||
*
|
||||
* @param index The field index.
|
||||
*/
|
||||
bool is_set(int32_t index) const {
|
||||
return ecs_field_is_set(m_iter, index);
|
||||
}
|
||||
|
||||
/** Returns whether field is readonly.
|
||||
*
|
||||
* @param index The field index.
|
||||
*/
|
||||
bool is_readonly(int32_t index) const {
|
||||
return ecs_field_is_readonly(m_iter, index);
|
||||
}
|
||||
|
||||
/** Number of fields in iteator.
|
||||
*/
|
||||
int32_t field_count() const {
|
||||
return m_iter->field_count;
|
||||
}
|
||||
|
||||
/** Size of field data type.
|
||||
*
|
||||
* @param index The field id.
|
||||
*/
|
||||
size_t size(int32_t index) const {
|
||||
return ecs_field_size(m_iter, index);
|
||||
}
|
||||
|
||||
/** Obtain field source (0 if This).
|
||||
*
|
||||
* @param index The field index.
|
||||
*/
|
||||
flecs::entity src(int32_t index) const;
|
||||
|
||||
/** Obtain id matched for field.
|
||||
*
|
||||
* @param index The field index.
|
||||
*/
|
||||
flecs::id id(int32_t index) const;
|
||||
|
||||
/** Obtain pair id matched for field.
|
||||
* This operation will fail if the id is not a pair.
|
||||
*
|
||||
* @param index The field index.
|
||||
*/
|
||||
flecs::id pair(int32_t index) const;
|
||||
|
||||
/** Obtain column index for field.
|
||||
*
|
||||
* @param index The field index.
|
||||
*/
|
||||
int32_t column_index(int32_t index) const {
|
||||
return ecs_field_column_index(m_iter, index);
|
||||
}
|
||||
|
||||
/** Convert current iterator result to string.
|
||||
*/
|
||||
flecs::string str() const {
|
||||
char *s = ecs_iter_str(m_iter);
|
||||
return flecs::string(s);
|
||||
}
|
||||
|
||||
/** Get readonly access to field data.
|
||||
* If the specified field index does not match with the provided type, the
|
||||
* function will assert.
|
||||
*
|
||||
* @tparam T Type of the field.
|
||||
* @param index The field index.
|
||||
* @return The field data.
|
||||
*/
|
||||
template <typename T, typename A = actual_type_t<T>,
|
||||
typename std::enable_if<std::is_const<T>::value, void>::type* = nullptr>
|
||||
flecs::column<A> field(int32_t index) const {
|
||||
return get_field<A>(index);
|
||||
}
|
||||
|
||||
/** Get read/write access to field data.
|
||||
* If the matched id for the specified field does not match with the provided
|
||||
* type or if the field is readonly, the function will assert.
|
||||
*
|
||||
* @tparam T Type of the field.
|
||||
* @param index The field index.
|
||||
* @return The field data.
|
||||
*/
|
||||
template <typename T, typename A = actual_type_t<T>,
|
||||
typename std::enable_if<
|
||||
std::is_const<T>::value == false, void>::type* = nullptr>
|
||||
flecs::column<A> field(int32_t index) const {
|
||||
ecs_assert(!ecs_field_is_readonly(m_iter, index),
|
||||
ECS_ACCESS_VIOLATION, NULL);
|
||||
return get_field<A>(index);
|
||||
}
|
||||
|
||||
/** Get unchecked access to field data.
|
||||
* Unchecked access is required when a system does not know the type of a
|
||||
* field at compile time.
|
||||
*
|
||||
* @param index The field index.
|
||||
*/
|
||||
flecs::untyped_column field(int32_t index) const {
|
||||
return get_unchecked_field(index);
|
||||
}
|
||||
|
||||
/** Get readonly access to entity ids.
|
||||
*
|
||||
* @return The entity ids.
|
||||
*/
|
||||
flecs::column<const flecs::entity_t> entities() const {
|
||||
return flecs::column<const flecs::entity_t>(m_iter->entities, static_cast<size_t>(m_iter->count), false);
|
||||
}
|
||||
|
||||
/** Obtain the total number of tables the iterator will iterate over. */
|
||||
int32_t table_count() const {
|
||||
return m_iter->table_count;
|
||||
}
|
||||
|
||||
/** Check if the current table has changed since the last iteration.
|
||||
* Can only be used when iterating queries and/or systems. */
|
||||
bool changed() {
|
||||
return ecs_query_changed(nullptr, m_iter);
|
||||
}
|
||||
|
||||
/** Skip current table.
|
||||
* This indicates to the query that the data in the current table is not
|
||||
* modified. By default, iterating a table with a query will mark the
|
||||
* iterated components as dirty if they are annotated with InOut or Out.
|
||||
*
|
||||
* When this operation is invoked, the components of the current table will
|
||||
* not be marked dirty. */
|
||||
void skip() {
|
||||
ecs_query_skip(m_iter);
|
||||
}
|
||||
|
||||
/* Return group id for current table (grouped queries only) */
|
||||
uint64_t group_id() const {
|
||||
return m_iter->group_id;
|
||||
}
|
||||
|
||||
#ifdef FLECS_RULES
|
||||
/** Get value of variable by id.
|
||||
* Get value of a query variable for current result.
|
||||
*/
|
||||
flecs::entity get_var(int var_id) const;
|
||||
|
||||
/** Get value of variable by name.
|
||||
* Get value of a query variable for current result.
|
||||
*/
|
||||
flecs::entity get_var(const char *name) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
/* Get field, check if correct type is used */
|
||||
template <typename T, typename A = actual_type_t<T>>
|
||||
flecs::column<T> get_field(int32_t index) const {
|
||||
|
||||
#ifndef FLECS_NDEBUG
|
||||
ecs_entity_t term_id = ecs_field_id(m_iter, index);
|
||||
ecs_assert(ECS_HAS_ID_FLAG(term_id, PAIR) ||
|
||||
term_id == _::cpp_type<T>::id(m_iter->world),
|
||||
ECS_COLUMN_TYPE_MISMATCH, NULL);
|
||||
#endif
|
||||
|
||||
size_t count;
|
||||
bool is_shared = !ecs_field_is_self(m_iter, index);
|
||||
|
||||
/* If a shared column is retrieved with 'column', there will only be a
|
||||
* single value. Ensure that the application does not accidentally read
|
||||
* out of bounds. */
|
||||
if (is_shared) {
|
||||
count = 1;
|
||||
} else {
|
||||
/* If column is owned, there will be as many values as there are
|
||||
* entities. */
|
||||
count = static_cast<size_t>(m_iter->count);
|
||||
}
|
||||
|
||||
return flecs::column<A>(
|
||||
static_cast<T*>(ecs_field_w_size(m_iter, sizeof(A), index)),
|
||||
count, is_shared);
|
||||
}
|
||||
|
||||
flecs::untyped_column get_unchecked_field(int32_t index) const {
|
||||
size_t count;
|
||||
size_t size = ecs_field_size(m_iter, index);
|
||||
bool is_shared = !ecs_field_is_self(m_iter, index);
|
||||
|
||||
/* If a shared column is retrieved with 'column', there will only be a
|
||||
* single value. Ensure that the application does not accidentally read
|
||||
* out of bounds. */
|
||||
if (is_shared) {
|
||||
count = 1;
|
||||
} else {
|
||||
/* If column is owned, there will be as many values as there are
|
||||
* entities. */
|
||||
count = static_cast<size_t>(m_iter->count);
|
||||
}
|
||||
|
||||
return flecs::untyped_column(
|
||||
ecs_field_w_size(m_iter, 0, index), size, count, is_shared);
|
||||
}
|
||||
|
||||
flecs::iter_t *m_iter;
|
||||
std::size_t m_begin;
|
||||
std::size_t m_end;
|
||||
};
|
||||
|
||||
} // namespace flecs
|
||||
|
||||
/** @} */
|
||||
382
engine/libs/flecs/include/flecs/addons/cpp/lifecycle_traits.hpp
Normal file
382
engine/libs/flecs/include/flecs/addons/cpp/lifecycle_traits.hpp
Normal file
@@ -0,0 +1,382 @@
|
||||
/**
|
||||
* @file addons/cpp/lifecycle_traits.hpp
|
||||
* @brief Utilities for discovering and registering component lifecycle hooks.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs
|
||||
{
|
||||
|
||||
namespace _
|
||||
{
|
||||
|
||||
inline void ecs_ctor_illegal(void *, int32_t, const ecs_type_info_t *ti) {
|
||||
ecs_abort(ECS_INVALID_OPERATION, "invalid constructor for %s", ti->name);
|
||||
}
|
||||
|
||||
inline void ecs_dtor_illegal(void *, int32_t, const ecs_type_info_t *ti) {
|
||||
ecs_abort(ECS_INVALID_OPERATION, "invalid destructor for %s", ti->name);
|
||||
}
|
||||
|
||||
inline void ecs_copy_illegal(
|
||||
void *, const void *, int32_t, const ecs_type_info_t *ti)
|
||||
{
|
||||
ecs_abort(ECS_INVALID_OPERATION, "invalid copy assignment for %s", ti->name);
|
||||
}
|
||||
|
||||
inline void ecs_move_illegal(void *, void *, int32_t, const ecs_type_info_t *ti) {
|
||||
ecs_abort(ECS_INVALID_OPERATION, "invalid move assignment for %s", ti->name);
|
||||
}
|
||||
|
||||
inline void ecs_copy_ctor_illegal(
|
||||
void *, const void *, int32_t, const ecs_type_info_t *ti)
|
||||
{
|
||||
ecs_abort(ECS_INVALID_OPERATION, "invalid copy construct for %s", ti->name);
|
||||
}
|
||||
|
||||
inline void ecs_move_ctor_illegal(
|
||||
void *, void *, int32_t, const ecs_type_info_t *ti)
|
||||
{
|
||||
ecs_abort(ECS_INVALID_OPERATION, "invalid move construct for %s", ti->name);
|
||||
}
|
||||
|
||||
|
||||
// T()
|
||||
// Can't coexist with T(flecs::entity) or T(flecs::world, flecs::entity)
|
||||
template <typename T>
|
||||
void ctor_impl(void *ptr, int32_t count, const ecs_type_info_t *info) {
|
||||
(void)info; ecs_assert(info->size == ECS_SIZEOF(T),
|
||||
ECS_INTERNAL_ERROR, NULL);
|
||||
T *arr = static_cast<T*>(ptr);
|
||||
for (int i = 0; i < count; i ++) {
|
||||
FLECS_PLACEMENT_NEW(&arr[i], T);
|
||||
}
|
||||
}
|
||||
|
||||
// ~T()
|
||||
template <typename T>
|
||||
void dtor_impl(void *ptr, int32_t count, const ecs_type_info_t *info) {
|
||||
(void)info; ecs_assert(info->size == ECS_SIZEOF(T),
|
||||
ECS_INTERNAL_ERROR, NULL);
|
||||
T *arr = static_cast<T*>(ptr);
|
||||
for (int i = 0; i < count; i ++) {
|
||||
arr[i].~T();
|
||||
}
|
||||
}
|
||||
|
||||
// T& operator=(const T&)
|
||||
template <typename T>
|
||||
void copy_impl(void *dst_ptr, const void *src_ptr, int32_t count,
|
||||
const ecs_type_info_t *info)
|
||||
{
|
||||
(void)info; ecs_assert(info->size == ECS_SIZEOF(T),
|
||||
ECS_INTERNAL_ERROR, NULL);
|
||||
T *dst_arr = static_cast<T*>(dst_ptr);
|
||||
const T *src_arr = static_cast<const T*>(src_ptr);
|
||||
for (int i = 0; i < count; i ++) {
|
||||
dst_arr[i] = src_arr[i];
|
||||
}
|
||||
}
|
||||
|
||||
// T& operator=(T&&)
|
||||
template <typename T>
|
||||
void move_impl(void *dst_ptr, void *src_ptr, int32_t count,
|
||||
const ecs_type_info_t *info)
|
||||
{
|
||||
(void)info; ecs_assert(info->size == ECS_SIZEOF(T),
|
||||
ECS_INTERNAL_ERROR, NULL);
|
||||
T *dst_arr = static_cast<T*>(dst_ptr);
|
||||
T *src_arr = static_cast<T*>(src_ptr);
|
||||
for (int i = 0; i < count; i ++) {
|
||||
dst_arr[i] = FLECS_MOV(src_arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// T(T&)
|
||||
template <typename T>
|
||||
void copy_ctor_impl(void *dst_ptr, const void *src_ptr, int32_t count,
|
||||
const ecs_type_info_t *info)
|
||||
{
|
||||
(void)info; ecs_assert(info->size == ECS_SIZEOF(T),
|
||||
ECS_INTERNAL_ERROR, NULL);
|
||||
T *dst_arr = static_cast<T*>(dst_ptr);
|
||||
const T *src_arr = static_cast<const T*>(src_ptr);
|
||||
for (int i = 0; i < count; i ++) {
|
||||
FLECS_PLACEMENT_NEW(&dst_arr[i], T(src_arr[i]));
|
||||
}
|
||||
}
|
||||
|
||||
// T(T&&)
|
||||
template <typename T>
|
||||
void move_ctor_impl(void *dst_ptr, void *src_ptr, int32_t count,
|
||||
const ecs_type_info_t *info)
|
||||
{
|
||||
(void)info; ecs_assert(info->size == ECS_SIZEOF(T),
|
||||
ECS_INTERNAL_ERROR, NULL);
|
||||
T *dst_arr = static_cast<T*>(dst_ptr);
|
||||
T *src_arr = static_cast<T*>(src_ptr);
|
||||
for (int i = 0; i < count; i ++) {
|
||||
FLECS_PLACEMENT_NEW(&dst_arr[i], T(FLECS_MOV(src_arr[i])));
|
||||
}
|
||||
}
|
||||
|
||||
// T(T&&), ~T()
|
||||
// Typically used when moving to a new table, and removing from the old table
|
||||
template <typename T>
|
||||
void ctor_move_dtor_impl(void *dst_ptr, void *src_ptr, int32_t count,
|
||||
const ecs_type_info_t *info)
|
||||
{
|
||||
(void)info; ecs_assert(info->size == ECS_SIZEOF(T),
|
||||
ECS_INTERNAL_ERROR, NULL);
|
||||
T *dst_arr = static_cast<T*>(dst_ptr);
|
||||
T *src_arr = static_cast<T*>(src_ptr);
|
||||
for (int i = 0; i < count; i ++) {
|
||||
FLECS_PLACEMENT_NEW(&dst_arr[i], T(FLECS_MOV(src_arr[i])));
|
||||
src_arr[i].~T();
|
||||
}
|
||||
}
|
||||
|
||||
// Move assign + dtor (non-trivial move assigmnment)
|
||||
// Typically used when moving a component to a deleted component
|
||||
template <typename T, if_not_t<
|
||||
std::is_trivially_move_assignable<T>::value > = 0>
|
||||
void move_dtor_impl(void *dst_ptr, void *src_ptr, int32_t count,
|
||||
const ecs_type_info_t *info)
|
||||
{
|
||||
(void)info; ecs_assert(info->size == ECS_SIZEOF(T),
|
||||
ECS_INTERNAL_ERROR, NULL);
|
||||
T *dst_arr = static_cast<T*>(dst_ptr);
|
||||
T *src_arr = static_cast<T*>(src_ptr);
|
||||
for (int i = 0; i < count; i ++) {
|
||||
// Move assignment should free dst & assign dst to src
|
||||
dst_arr[i] = FLECS_MOV(src_arr[i]);
|
||||
// Destruct src. Move should have left object in a state where it no
|
||||
// longer holds resources, but it still needs to be destructed.
|
||||
src_arr[i].~T();
|
||||
}
|
||||
}
|
||||
|
||||
// Move assign + dtor (trivial move assigmnment)
|
||||
// Typically used when moving a component to a deleted component
|
||||
template <typename T, if_t<
|
||||
std::is_trivially_move_assignable<T>::value > = 0>
|
||||
void move_dtor_impl(void *dst_ptr, void *src_ptr, int32_t count,
|
||||
const ecs_type_info_t *info)
|
||||
{
|
||||
(void)info; ecs_assert(info->size == ECS_SIZEOF(T),
|
||||
ECS_INTERNAL_ERROR, NULL);
|
||||
T *dst_arr = static_cast<T*>(dst_ptr);
|
||||
T *src_arr = static_cast<T*>(src_ptr);
|
||||
for (int i = 0; i < count; i ++) {
|
||||
// Cleanup resources of dst
|
||||
dst_arr[i].~T();
|
||||
// Copy src to dst
|
||||
dst_arr[i] = FLECS_MOV(src_arr[i]);
|
||||
// No need to destruct src. Since this is a trivial move the code
|
||||
// should be agnostic to the address of the component which means we
|
||||
// can pretend nothing got destructed.
|
||||
}
|
||||
}
|
||||
|
||||
} // _
|
||||
|
||||
// Trait to test if type is constructible by flecs
|
||||
template <typename T>
|
||||
struct is_flecs_constructible {
|
||||
static constexpr bool value =
|
||||
std::is_default_constructible<actual_type_t<T>>::value;
|
||||
};
|
||||
|
||||
namespace _
|
||||
{
|
||||
|
||||
// Trivially constructible
|
||||
template <typename T, if_t< std::is_trivially_constructible<T>::value > = 0>
|
||||
ecs_xtor_t ctor() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Not constructible by flecs
|
||||
template <typename T, if_t<
|
||||
! std::is_default_constructible<T>::value > = 0>
|
||||
ecs_xtor_t ctor() {
|
||||
return ecs_ctor_illegal;
|
||||
}
|
||||
|
||||
// Default constructible
|
||||
template <typename T, if_t<
|
||||
! std::is_trivially_constructible<T>::value &&
|
||||
std::is_default_constructible<T>::value > = 0>
|
||||
ecs_xtor_t ctor() {
|
||||
return ctor_impl<T>;
|
||||
}
|
||||
|
||||
// No dtor
|
||||
template <typename T, if_t< std::is_trivially_destructible<T>::value > = 0>
|
||||
ecs_xtor_t dtor() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Dtor
|
||||
template <typename T, if_t<
|
||||
std::is_destructible<T>::value &&
|
||||
! std::is_trivially_destructible<T>::value > = 0>
|
||||
ecs_xtor_t dtor() {
|
||||
return dtor_impl<T>;
|
||||
}
|
||||
|
||||
// Assert when the type cannot be destructed
|
||||
template <typename T, if_not_t< std::is_destructible<T>::value > = 0>
|
||||
ecs_xtor_t dtor() {
|
||||
flecs_static_assert(always_false<T>::value,
|
||||
"component type must be destructible");
|
||||
return ecs_dtor_illegal;
|
||||
}
|
||||
|
||||
// Trivially copyable
|
||||
template <typename T, if_t< std::is_trivially_copyable<T>::value > = 0>
|
||||
ecs_copy_t copy() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Not copyable
|
||||
template <typename T, if_t<
|
||||
! std::is_trivially_copyable<T>::value &&
|
||||
! std::is_copy_assignable<T>::value > = 0>
|
||||
ecs_copy_t copy() {
|
||||
return ecs_copy_illegal;
|
||||
}
|
||||
|
||||
// Copy assignment
|
||||
template <typename T, if_t<
|
||||
std::is_copy_assignable<T>::value &&
|
||||
! std::is_trivially_copyable<T>::value > = 0>
|
||||
ecs_copy_t copy() {
|
||||
return copy_impl<T>;
|
||||
}
|
||||
|
||||
// Trivially move assignable
|
||||
template <typename T, if_t< std::is_trivially_move_assignable<T>::value > = 0>
|
||||
ecs_move_t move() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Component types must be move assignable
|
||||
template <typename T, if_not_t< std::is_move_assignable<T>::value > = 0>
|
||||
ecs_move_t move() {
|
||||
flecs_static_assert(always_false<T>::value,
|
||||
"component type must be move assignable");
|
||||
return ecs_move_illegal;
|
||||
}
|
||||
|
||||
// Move assignment
|
||||
template <typename T, if_t<
|
||||
std::is_move_assignable<T>::value &&
|
||||
! std::is_trivially_move_assignable<T>::value > = 0>
|
||||
ecs_move_t move() {
|
||||
return move_impl<T>;
|
||||
}
|
||||
|
||||
// Trivially copy constructible
|
||||
template <typename T, if_t<
|
||||
std::is_trivially_copy_constructible<T>::value > = 0>
|
||||
ecs_copy_t copy_ctor() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// No copy ctor
|
||||
template <typename T, if_t< ! std::is_copy_constructible<T>::value > = 0>
|
||||
ecs_copy_t copy_ctor() {
|
||||
return ecs_copy_ctor_illegal;
|
||||
}
|
||||
|
||||
// Copy ctor
|
||||
template <typename T, if_t<
|
||||
std::is_copy_constructible<T>::value &&
|
||||
! std::is_trivially_copy_constructible<T>::value > = 0>
|
||||
ecs_copy_t copy_ctor() {
|
||||
return copy_ctor_impl<T>;
|
||||
}
|
||||
|
||||
// Trivially move constructible
|
||||
template <typename T, if_t<
|
||||
std::is_trivially_move_constructible<T>::value > = 0>
|
||||
ecs_move_t move_ctor() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Component types must be move constructible
|
||||
template <typename T, if_not_t< std::is_move_constructible<T>::value > = 0>
|
||||
ecs_move_t move_ctor() {
|
||||
flecs_static_assert(always_false<T>::value,
|
||||
"component type must be move constructible");
|
||||
return ecs_move_ctor_illegal;
|
||||
}
|
||||
|
||||
// Move ctor
|
||||
template <typename T, if_t<
|
||||
std::is_move_constructible<T>::value &&
|
||||
! std::is_trivially_move_constructible<T>::value > = 0>
|
||||
ecs_move_t move_ctor() {
|
||||
return move_ctor_impl<T>;
|
||||
}
|
||||
|
||||
// Trivial merge (move assign + dtor)
|
||||
template <typename T, if_t<
|
||||
std::is_trivially_move_constructible<T>::value &&
|
||||
std::is_trivially_destructible<T>::value > = 0>
|
||||
ecs_move_t ctor_move_dtor() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Component types must be move constructible and destructible
|
||||
template <typename T, if_t<
|
||||
! std::is_move_constructible<T>::value ||
|
||||
! std::is_destructible<T>::value > = 0>
|
||||
ecs_move_t ctor_move_dtor() {
|
||||
flecs_static_assert(always_false<T>::value,
|
||||
"component type must be move constructible and destructible");
|
||||
return ecs_move_ctor_illegal;
|
||||
}
|
||||
|
||||
// Merge ctor + dtor
|
||||
template <typename T, if_t<
|
||||
!(std::is_trivially_move_constructible<T>::value &&
|
||||
std::is_trivially_destructible<T>::value) &&
|
||||
std::is_move_constructible<T>::value &&
|
||||
std::is_destructible<T>::value > = 0>
|
||||
ecs_move_t ctor_move_dtor() {
|
||||
return ctor_move_dtor_impl<T>;
|
||||
}
|
||||
|
||||
// Trivial merge (move assign + dtor)
|
||||
template <typename T, if_t<
|
||||
std::is_trivially_move_assignable<T>::value &&
|
||||
std::is_trivially_destructible<T>::value > = 0>
|
||||
ecs_move_t move_dtor() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Component types must be move constructible and destructible
|
||||
template <typename T, if_t<
|
||||
! std::is_move_assignable<T>::value ||
|
||||
! std::is_destructible<T>::value > = 0>
|
||||
ecs_move_t move_dtor() {
|
||||
flecs_static_assert(always_false<T>::value,
|
||||
"component type must be move constructible and destructible");
|
||||
return ecs_move_ctor_illegal;
|
||||
}
|
||||
|
||||
// Merge assign + dtor
|
||||
template <typename T, if_t<
|
||||
!(std::is_trivially_move_assignable<T>::value &&
|
||||
std::is_trivially_destructible<T>::value) &&
|
||||
std::is_move_assignable<T>::value &&
|
||||
std::is_destructible<T>::value > = 0>
|
||||
ecs_move_t move_dtor() {
|
||||
return move_dtor_impl<T>;
|
||||
}
|
||||
|
||||
} // _
|
||||
} // flecs
|
||||
97
engine/libs/flecs/include/flecs/addons/cpp/log.hpp
Normal file
97
engine/libs/flecs/include/flecs/addons/cpp/log.hpp
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* @file addons/cpp/log.hpp
|
||||
* @brief Logging functions.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
namespace log {
|
||||
|
||||
/**
|
||||
* @defgroup cpp_log Logging
|
||||
* @brief Logging functions.
|
||||
*
|
||||
* \ingroup cpp_addons
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Set log level */
|
||||
inline void set_level(int level) {
|
||||
ecs_log_set_level(level);
|
||||
}
|
||||
|
||||
inline int get_level(void) {
|
||||
return ecs_log_get_level();
|
||||
}
|
||||
|
||||
/** Enable colors in logging */
|
||||
inline void enable_colors(bool enabled = true) {
|
||||
ecs_log_enable_colors(enabled);
|
||||
}
|
||||
|
||||
/** Enable timestamps in logging */
|
||||
inline void enable_timestamp(bool enabled = true) {
|
||||
ecs_log_enable_timestamp(enabled);
|
||||
}
|
||||
|
||||
/** Enable time delta in logging */
|
||||
inline void enable_timedelta(bool enabled = true) {
|
||||
ecs_log_enable_timedelta(enabled);
|
||||
}
|
||||
|
||||
/** Debug trace (level 1) */
|
||||
inline void dbg(const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ecs_logv(1, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/** Trace (level 0) */
|
||||
inline void trace(const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ecs_logv(0, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/** Trace (level -2) */
|
||||
inline void warn(const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ecs_logv(-2, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/** Trace (level -3) */
|
||||
inline void err(const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ecs_logv(-3, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/** Increase log indentation */
|
||||
inline void push(const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ecs_logv(0, fmt, args);
|
||||
va_end(args);
|
||||
ecs_log_push();
|
||||
}
|
||||
|
||||
/** Increase log indentation */
|
||||
inline void push() {
|
||||
ecs_log_push();
|
||||
}
|
||||
|
||||
/** Increase log indentation */
|
||||
inline void pop() {
|
||||
ecs_log_pop();
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/alerts/builder.hpp
|
||||
* @brief Alert builder.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../utils/builder.hpp"
|
||||
#include "builder_i.hpp"
|
||||
|
||||
namespace flecs {
|
||||
namespace _ {
|
||||
template <typename ... Components>
|
||||
using alert_builder_base = builder<
|
||||
alert, ecs_alert_desc_t, alert_builder<Components...>,
|
||||
alert_builder_i, Components ...>;
|
||||
}
|
||||
|
||||
/** Alert builder.
|
||||
*
|
||||
* \ingroup cpp_addons_alerts
|
||||
*/
|
||||
template <typename ... Components>
|
||||
struct alert_builder final : _::alert_builder_base<Components...> {
|
||||
alert_builder(flecs::world_t* world, const char *name = nullptr)
|
||||
: _::alert_builder_base<Components...>(world)
|
||||
{
|
||||
_::sig<Components...>(world).populate(this);
|
||||
if (name != nullptr) {
|
||||
ecs_entity_desc_t entity_desc = {};
|
||||
entity_desc.name = name;
|
||||
entity_desc.sep = "::";
|
||||
entity_desc.root_sep = "::";
|
||||
this->m_desc.entity = ecs_entity_init(world, &entity_desc);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/alerts/builder_i.hpp
|
||||
* @brief Alert builder interface.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../filter/builder_i.hpp"
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/** Alert builder interface.
|
||||
*
|
||||
* \ingroup cpp_addons_alerts
|
||||
*/
|
||||
template<typename Base, typename ... Components>
|
||||
struct alert_builder_i : filter_builder_i<Base, Components ...> {
|
||||
private:
|
||||
using BaseClass = filter_builder_i<Base, Components ...>;
|
||||
|
||||
public:
|
||||
alert_builder_i()
|
||||
: BaseClass(nullptr)
|
||||
, m_desc(nullptr) { }
|
||||
|
||||
alert_builder_i(ecs_alert_desc_t *desc, int32_t term_index = 0)
|
||||
: BaseClass(&desc->filter, term_index)
|
||||
, m_desc(desc) { }
|
||||
|
||||
/** Alert message.
|
||||
*
|
||||
* @see ecs_alert_desc_t::message
|
||||
*/
|
||||
Base& message(const char *message) {
|
||||
m_desc->message = message;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set brief description for alert.
|
||||
*
|
||||
* @see ecs_alert_desc_t::brief
|
||||
*/
|
||||
Base& brief(const char *brief) {
|
||||
m_desc->brief = brief;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set doc name for alert.
|
||||
*
|
||||
* @see ecs_alert_desc_t::doc_name
|
||||
*/
|
||||
Base& doc_name(const char *doc_name) {
|
||||
m_desc->doc_name = doc_name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set severity of alert (default is Error)
|
||||
*
|
||||
* @see ecs_alert_desc_t::severity
|
||||
*/
|
||||
Base& severity(flecs::entity_t kind) {
|
||||
m_desc->severity = kind;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* Set retain period of alert.
|
||||
*
|
||||
* @see ecs_alert_desc_t::retain_period
|
||||
*/
|
||||
Base& retain_period(ecs_ftime_t period) {
|
||||
m_desc->retain_period = period;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set severity of alert (default is Error)
|
||||
*
|
||||
* @see ecs_alert_desc_t::severity
|
||||
*/
|
||||
template <typename Severity>
|
||||
Base& severity() {
|
||||
return severity(_::cpp_type<Severity>::id(world_v()));
|
||||
}
|
||||
|
||||
/** Add severity filter */
|
||||
Base& severity_filter(flecs::entity_t kind, flecs::id_t with, const char *var = nullptr) {
|
||||
ecs_assert(severity_filter_count < ECS_ALERT_MAX_SEVERITY_FILTERS,
|
||||
ECS_INVALID_PARAMETER, "Maxium number of severity filters reached");
|
||||
|
||||
ecs_alert_severity_filter_t *filter =
|
||||
&m_desc->severity_filters[severity_filter_count ++];
|
||||
|
||||
filter->severity = kind;
|
||||
filter->with = with;
|
||||
filter->var = var;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Add severity filter */
|
||||
template <typename Severity>
|
||||
Base& severity_filter(flecs::id_t with, const char *var = nullptr) {
|
||||
return severity_filter(_::cpp_type<Severity>::id(world_v()), with, var);
|
||||
}
|
||||
|
||||
/** Add severity filter */
|
||||
template <typename Severity, typename T, if_not_t< is_enum<T>::value > = 0>
|
||||
Base& severity_filter(const char *var = nullptr) {
|
||||
return severity_filter(_::cpp_type<Severity>::id(world_v()),
|
||||
_::cpp_type<T>::id(world_v()), var);
|
||||
}
|
||||
|
||||
/** Add severity filter */
|
||||
template <typename Severity, typename T, if_t< is_enum<T>::value > = 0 >
|
||||
Base& severity_filter(T with, const char *var = nullptr) {
|
||||
flecs::world w(world_v());
|
||||
flecs::entity constant = w.to_entity<T>(with);
|
||||
return severity_filter(_::cpp_type<Severity>::id(world_v()),
|
||||
w.pair<T>(constant), var);
|
||||
}
|
||||
|
||||
/** Set member to create an alert for out of range values */
|
||||
Base& member(flecs::entity_t m) {
|
||||
m_desc->member = m;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set (component) id for member (optional). If .member() is set and id
|
||||
* is not set, the id will default to the member parent. */
|
||||
Base& id(flecs::id_t id) {
|
||||
m_desc->id = id;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set member to create an alert for out of range values */
|
||||
template <typename T>
|
||||
Base& member(const char *m, const char *v = nullptr) {
|
||||
flecs::entity_t id = _::cpp_type<T>::id(world_v());
|
||||
flecs::entity_t mid = ecs_lookup_path_w_sep(
|
||||
world_v(), id, m, "::", "::", false);
|
||||
ecs_assert(m != 0, ECS_INVALID_PARAMETER, NULL);
|
||||
m_desc->var = v;
|
||||
return this->member(mid);
|
||||
}
|
||||
|
||||
/** Set source variable for member (optional, defaults to $this) */
|
||||
Base& var(const char *v) {
|
||||
m_desc->var = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual flecs::world_t* world_v() = 0;
|
||||
|
||||
private:
|
||||
operator Base&() {
|
||||
return *static_cast<Base*>(this);
|
||||
}
|
||||
|
||||
ecs_alert_desc_t *m_desc;
|
||||
int32_t severity_filter_count = 0;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/alerts/decl.hpp
|
||||
* @brief Alert declarations.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/**
|
||||
* @defgroup cpp_addons_alerts Alerts
|
||||
* @brief Alert implementation.
|
||||
*
|
||||
* \ingroup cpp_addons
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Module */
|
||||
struct alerts {
|
||||
using AlertsActive = EcsAlertsActive;
|
||||
using Instance = EcsAlertInstance;
|
||||
|
||||
struct Alert { };
|
||||
struct Info { };
|
||||
struct Warning { };
|
||||
struct Error { };
|
||||
|
||||
alerts(flecs::world& world);
|
||||
};
|
||||
|
||||
template <typename ... Components>
|
||||
struct alert;
|
||||
|
||||
template <typename ... Components>
|
||||
struct alert_builder;
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/alerts/entity_view.inl
|
||||
* @brief Alerts entity mixin.
|
||||
*/
|
||||
|
||||
/** Return number of alerts for entity.
|
||||
*
|
||||
* \memberof flecs::entity_view
|
||||
* \ingroup cpp_addons_alerts
|
||||
*/
|
||||
int32_t alert_count(flecs::entity_t alert = 0) const {
|
||||
return ecs_get_alert_count(m_world, m_id, alert);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/alerts/impl.hpp
|
||||
* @brief Alerts module implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "builder.hpp"
|
||||
|
||||
namespace flecs {
|
||||
|
||||
template <typename ... Components>
|
||||
struct alert final : entity
|
||||
{
|
||||
using entity::entity;
|
||||
|
||||
explicit alert() {
|
||||
m_id = 0;
|
||||
m_world = nullptr;
|
||||
}
|
||||
|
||||
explicit alert(flecs::world_t *world, ecs_alert_desc_t *desc)
|
||||
{
|
||||
m_world = world;
|
||||
m_id = ecs_alert_init(world, desc);
|
||||
|
||||
if (desc->filter.terms_buffer) {
|
||||
ecs_os_free(desc->filter.terms_buffer);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline alerts::alerts(flecs::world& world) {
|
||||
/* Import C module */
|
||||
FlecsAlertsImport(world);
|
||||
|
||||
world.entity<alerts::Alert>("::flecs::alerts::Alert");
|
||||
world.entity<alerts::Info>("::flecs::alerts::Info");
|
||||
world.entity<alerts::Warning>("::flecs::alerts::Warning");
|
||||
world.entity<alerts::Error>("::flecs::alerts::Error");
|
||||
}
|
||||
|
||||
template <typename... Comps, typename... Args>
|
||||
inline flecs::alert_builder<Comps...> world::alert(Args &&... args) const {
|
||||
return flecs::alert_builder<Comps...>(m_world, FLECS_FWD(args)...);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
/** Create alert.
|
||||
*
|
||||
* \ingroup cpp_addons_alerts
|
||||
* \memberof flecs::world
|
||||
*/
|
||||
template <typename... Comps, typename... Args>
|
||||
flecs::alert_builder<Comps...> alert(Args &&... args) const;
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/app/builder.hpp
|
||||
* @brief App builder.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/**
|
||||
* @defgroup cpp_addons_app App
|
||||
* @brief Optional addon for running the main application loop.
|
||||
* \ingroup cpp_addons
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** App builder interface */
|
||||
struct app_builder {
|
||||
app_builder(flecs::world_t *world)
|
||||
: m_world(world)
|
||||
, m_desc{}
|
||||
{
|
||||
const ecs_world_info_t *stats = ecs_get_world_info(world);
|
||||
m_desc.target_fps = stats->target_fps;
|
||||
ecs_ftime_t t_zero = 0.0;
|
||||
if (ECS_EQ(m_desc.target_fps, t_zero)) {
|
||||
m_desc.target_fps = 60;
|
||||
}
|
||||
}
|
||||
|
||||
app_builder& target_fps(ecs_ftime_t value) {
|
||||
m_desc.target_fps = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
app_builder& delta_time(ecs_ftime_t value) {
|
||||
m_desc.delta_time = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
app_builder& threads(int32_t value) {
|
||||
m_desc.threads = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
app_builder& frames(int32_t value) {
|
||||
m_desc.frames = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
app_builder& enable_rest(uint16_t port = 0) {
|
||||
m_desc.enable_rest = true;
|
||||
m_desc.port = port;
|
||||
return *this;
|
||||
}
|
||||
|
||||
app_builder& enable_monitor(bool value = true) {
|
||||
m_desc.enable_monitor = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
app_builder& init(ecs_app_init_action_t value) {
|
||||
m_desc.init = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
app_builder& ctx(void *value) {
|
||||
m_desc.ctx = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int run() {
|
||||
int result = ecs_app_run(m_world, &m_desc);
|
||||
if (ecs_should_quit(m_world)) {
|
||||
// Only free world if quit flag is set. This ensures that we won't
|
||||
// try to cleanup the world if the app is used in an environment
|
||||
// that takes over the main loop, like with emscripten.
|
||||
ecs_fini(m_world);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
flecs::world_t *m_world;
|
||||
ecs_app_desc_t m_desc;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/app/decl.hpp
|
||||
* @brief App addon declarations.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "builder.hpp"
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/app/mixin.inl
|
||||
* @brief App world addon mixin.
|
||||
*/
|
||||
|
||||
/** Return app builder.
|
||||
* The app builder is a convenience wrapper around a loop that runs
|
||||
* world::progress. An app allows for writing platform agnostic code,
|
||||
* as it provides hooks to modules for overtaking the main loop which is
|
||||
* required for frameworks like emscripten.
|
||||
*
|
||||
* \ingroup cpp_addons_app
|
||||
* \memberof flecs::world
|
||||
*/
|
||||
flecs::app_builder app() {
|
||||
m_owned = false; // App takes ownership of world
|
||||
return flecs::app_builder(m_world);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/component/impl.hpp
|
||||
* @brief Component mixin implementation
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
template <typename T, typename... Args>
|
||||
inline flecs::component<T> world::component(Args &&... args) const {
|
||||
return flecs::component<T>(m_world, FLECS_FWD(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline flecs::untyped_component world::component(Args &&... args) const {
|
||||
return flecs::untyped_component(m_world, FLECS_FWD(args)...);
|
||||
}
|
||||
|
||||
} // namespace flecs
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/component/mixin.inl
|
||||
* @brief Component mixin.
|
||||
*/
|
||||
|
||||
/** Find or register component.
|
||||
*
|
||||
* \ingroup cpp_components
|
||||
* \memberof flecs::world
|
||||
*/
|
||||
template <typename T, typename... Args>
|
||||
flecs::component<T> component(Args &&... args) const;
|
||||
|
||||
/** Find or register untyped component.
|
||||
* Method available on flecs::world class.
|
||||
*
|
||||
* \ingroup cpp_components
|
||||
* \memberof flecs::world
|
||||
*/
|
||||
template <typename... Args>
|
||||
flecs::untyped_component component(Args &&... args) const;
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/doc/decl.hpp
|
||||
* @brief Doc mixin declarations.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
namespace doc {
|
||||
|
||||
/**
|
||||
* @defgroup cpp_addons_doc Doc
|
||||
* @brief Utilities for documenting entities, components and systems.
|
||||
*
|
||||
* \ingroup cpp_addons
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** flecs.doc.Description component */
|
||||
using Description = EcsDocDescription;
|
||||
|
||||
/** flecs.doc.Brief component */
|
||||
static const flecs::entity_t Brief = EcsDocBrief;
|
||||
|
||||
/** flecs.doc.Detail component */
|
||||
static const flecs::entity_t Detail = EcsDocDetail;
|
||||
|
||||
/** flecs.doc.Link component */
|
||||
static const flecs::entity_t Link = EcsDocLink;
|
||||
|
||||
/** flecs.doc.Color component */
|
||||
static const flecs::entity_t Color = EcsDocColor;
|
||||
|
||||
namespace _ {
|
||||
void init(flecs::world& world);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/doc/entity_builder.inl
|
||||
* @brief Doc entity builder mixin.
|
||||
*/
|
||||
|
||||
/** Set doc name.
|
||||
* This adds (flecs.doc.Description, flecs.Name) to the entity.
|
||||
*
|
||||
* \memberof flecs::entity_builder
|
||||
* \ingroup cpp_addons_doc
|
||||
*/
|
||||
Self& set_doc_name(const char *name) {
|
||||
ecs_doc_set_name(m_world, m_id, name);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Set doc brief.
|
||||
* This adds (flecs.doc.Description, flecs.doc.Brief) to the entity.
|
||||
*
|
||||
* \memberof flecs::entity_builder
|
||||
* \ingroup cpp_addons_doc
|
||||
*/
|
||||
Self& set_doc_brief(const char *brief) {
|
||||
ecs_doc_set_brief(m_world, m_id, brief);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Set doc detailed description.
|
||||
* This adds (flecs.doc.Description, flecs.doc.Detail) to the entity.
|
||||
*
|
||||
* \memberof flecs::entity_builder
|
||||
* \ingroup cpp_addons_doc
|
||||
*/
|
||||
Self& set_doc_detail(const char *detail) {
|
||||
ecs_doc_set_detail(m_world, m_id, detail);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Set doc link.
|
||||
* This adds (flecs.doc.Description, flecs.doc.Link) to the entity.
|
||||
*
|
||||
* \memberof flecs::entity_builder
|
||||
* \ingroup cpp_addons_doc
|
||||
*/
|
||||
Self& set_doc_link(const char *link) {
|
||||
ecs_doc_set_link(m_world, m_id, link);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Set doc color.
|
||||
* This adds (flecs.doc.Description, flecs.doc.Color) to the entity.
|
||||
*
|
||||
* \memberof flecs::entity_builder
|
||||
* \ingroup cpp_addons_doc
|
||||
*/
|
||||
Self& set_doc_color(const char *link) {
|
||||
ecs_doc_set_color(m_world, m_id, link);
|
||||
return to_base();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/doc/entity_view.inl
|
||||
* @brief Doc entity view mixin.
|
||||
*/
|
||||
|
||||
const char* doc_name() {
|
||||
return ecs_doc_get_name(m_world, m_id);
|
||||
}
|
||||
|
||||
const char* doc_brief() {
|
||||
return ecs_doc_get_brief(m_world, m_id);
|
||||
}
|
||||
|
||||
const char* doc_detail() {
|
||||
return ecs_doc_get_detail(m_world, m_id);
|
||||
}
|
||||
|
||||
const char* doc_link() {
|
||||
return ecs_doc_get_link(m_world, m_id);
|
||||
}
|
||||
|
||||
const char* doc_color() {
|
||||
return ecs_doc_get_color(m_world, m_id);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/doc/impl.hpp
|
||||
* @brief Doc mixin implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
namespace doc {
|
||||
|
||||
inline const char* get_name(const flecs::entity_view& e) {
|
||||
return ecs_doc_get_name(e.world(), e);
|
||||
}
|
||||
|
||||
inline const char* get_brief(const flecs::entity_view& e) {
|
||||
return ecs_doc_get_brief(e.world(), e);
|
||||
}
|
||||
|
||||
inline const char* get_detail(const flecs::entity_view& e) {
|
||||
return ecs_doc_get_detail(e.world(), e);
|
||||
}
|
||||
|
||||
inline const char* get_link(const flecs::entity_view& e) {
|
||||
return ecs_doc_get_link(e.world(), e);
|
||||
}
|
||||
|
||||
inline void set_name(flecs::entity& e, const char *name) {
|
||||
ecs_doc_set_name(e.world(), e, name);
|
||||
}
|
||||
|
||||
inline void set_brief(flecs::entity& e, const char *description) {
|
||||
ecs_doc_set_brief(e.world(), e, description);
|
||||
}
|
||||
|
||||
inline void set_detail(flecs::entity& e, const char *description) {
|
||||
ecs_doc_set_detail(e.world(), e, description);
|
||||
}
|
||||
|
||||
inline void set_link(flecs::entity& e, const char *description) {
|
||||
ecs_doc_set_link(e.world(), e, description);
|
||||
}
|
||||
|
||||
namespace _ {
|
||||
|
||||
inline void init(flecs::world& world) {
|
||||
world.component<doc::Description>("flecs::doc::Description");
|
||||
}
|
||||
|
||||
} // namespace _
|
||||
} // namespace doc
|
||||
} // namespace flecs
|
||||
@@ -0,0 +1,971 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/entity/builder.hpp
|
||||
* @brief Entity builder.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs
|
||||
{
|
||||
|
||||
/** Entity builder.
|
||||
* \ingroup cpp_entities
|
||||
*/
|
||||
template <typename Self>
|
||||
struct entity_builder : entity_view {
|
||||
|
||||
using entity_view::entity_view;
|
||||
|
||||
/** Add a component to an entity.
|
||||
* To ensure the component is initialized, it should have a constructor.
|
||||
*
|
||||
* @tparam T the component type to add.
|
||||
*/
|
||||
template <typename T>
|
||||
Self& add() {
|
||||
flecs_static_assert(is_flecs_constructible<T>::value,
|
||||
"cannot default construct type: add T::T() or use emplace<T>()");
|
||||
ecs_add_id(this->m_world, this->m_id, _::cpp_type<T>::id(this->m_world));
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Add pair for enum constant.
|
||||
* This operation will add a pair to the entity where the first element is
|
||||
* the enumeration type, and the second element the enumeration constant.
|
||||
*
|
||||
* The operation may be used with regular (C style) enumerations as well as
|
||||
* enum classes.
|
||||
*
|
||||
* @param value The enumeration value.
|
||||
*/
|
||||
template <typename E, if_t< is_enum<E>::value > = 0>
|
||||
Self& add(E value) {
|
||||
flecs::entity_t first = _::cpp_type<E>::id(this->m_world);
|
||||
const auto& et = enum_type<E>(this->m_world);
|
||||
flecs::entity_t second = et.entity(value);
|
||||
return this->add(first, second);
|
||||
}
|
||||
|
||||
/** Add an entity to an entity.
|
||||
* Add an entity to the entity. This is typically used for tagging.
|
||||
*
|
||||
* @param component The component to add.
|
||||
*/
|
||||
Self& add(id_t component) {
|
||||
ecs_add_id(this->m_world, this->m_id, component);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Add a pair.
|
||||
* This operation adds a pair to the entity.
|
||||
*
|
||||
* @param first The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
Self& add(entity_t first, entity_t second) {
|
||||
ecs_add_pair(this->m_world, this->m_id, first, second);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Add a pair.
|
||||
* This operation adds a pair to the entity.
|
||||
*
|
||||
* @tparam First The first element of the pair
|
||||
* @tparam Second The second element of the pair
|
||||
*/
|
||||
template<typename First, typename Second>
|
||||
Self& add() {
|
||||
return this->add<First>(_::cpp_type<Second>::id(this->m_world));
|
||||
}
|
||||
|
||||
/** Add a pair.
|
||||
* This operation adds a pair to the entity.
|
||||
*
|
||||
* @tparam First The first element of the pair
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
template<typename First, typename Second, if_not_t< is_enum<Second>::value > = 0>
|
||||
Self& add(Second second) {
|
||||
flecs_static_assert(is_flecs_constructible<First>::value,
|
||||
"cannot default construct type: add T::T() or use emplace<T>()");
|
||||
return this->add(_::cpp_type<First>::id(this->m_world), second);
|
||||
}
|
||||
|
||||
/** Add a pair.
|
||||
* This operation adds a pair to the entity that consists out of a tag
|
||||
* combined with an enum constant.
|
||||
*
|
||||
* @tparam First The first element of the pair
|
||||
* @param constant the enum constant.
|
||||
*/
|
||||
template<typename First, typename Second, if_t< is_enum<Second>::value > = 0>
|
||||
Self& add(Second constant) {
|
||||
flecs_static_assert(is_flecs_constructible<First>::value,
|
||||
"cannot default construct type: add T::T() or use emplace<T>()");
|
||||
const auto& et = enum_type<Second>(this->m_world);
|
||||
return this->add<First>(et.entity(constant));
|
||||
}
|
||||
|
||||
/** Add a pair.
|
||||
* This operation adds a pair to the entity.
|
||||
*
|
||||
* @param first The first element of the pair
|
||||
* @tparam Second The second element of the pair
|
||||
*/
|
||||
template<typename Second>
|
||||
Self& add_second(flecs::entity_t first) {
|
||||
return this->add(first, _::cpp_type<Second>::id(this->m_world));
|
||||
}
|
||||
|
||||
/** Conditional add.
|
||||
* This operation adds if condition is true, removes if condition is false.
|
||||
*
|
||||
* @param cond The condition to evaluate.
|
||||
* @param component The component to add.
|
||||
*/
|
||||
Self& add_if(bool cond, flecs::id_t component) {
|
||||
if (cond) {
|
||||
return this->add(component);
|
||||
} else {
|
||||
return this->remove(component);
|
||||
}
|
||||
}
|
||||
|
||||
/** Conditional add.
|
||||
* This operation adds if condition is true, removes if condition is false.
|
||||
*
|
||||
* @tparam T The component to add.
|
||||
* @param cond The condition to evaluate.
|
||||
*/
|
||||
template <typename T>
|
||||
Self& add_if(bool cond) {
|
||||
if (cond) {
|
||||
return this->add<T>();
|
||||
} else {
|
||||
return this->remove<T>();
|
||||
}
|
||||
}
|
||||
|
||||
/** Conditional add.
|
||||
* This operation adds if condition is true, removes if condition is false.
|
||||
*
|
||||
* @param cond The condition to evaluate.
|
||||
* @param first The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
Self& add_if(bool cond, flecs::entity_t first, flecs::entity_t second) {
|
||||
if (cond) {
|
||||
return this->add(first, second);
|
||||
} else {
|
||||
/* If second is 0 or if relationship is exclusive, use wildcard for
|
||||
* second which will remove all instances of the relationship.
|
||||
* Replacing 0 with Wildcard will make it possible to use the second
|
||||
* as the condition. */
|
||||
if (!second || ecs_has_id(this->m_world, first, flecs::Exclusive)) {
|
||||
second = flecs::Wildcard;
|
||||
}
|
||||
return this->remove(first, second);
|
||||
}
|
||||
}
|
||||
|
||||
/** Conditional add.
|
||||
* This operation adds if condition is true, removes if condition is false.
|
||||
*
|
||||
* @tparam First The first element of the pair
|
||||
* @param cond The condition to evaluate.
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
template <typename First>
|
||||
Self& add_if(bool cond, flecs::entity_t second) {
|
||||
return this->add_if(cond, _::cpp_type<First>::id(this->m_world), second);
|
||||
}
|
||||
|
||||
/** Conditional add.
|
||||
* This operation adds if condition is true, removes if condition is false.
|
||||
*
|
||||
* @tparam First The first element of the pair
|
||||
* @tparam Second The second element of the pair
|
||||
* @param cond The condition to evaluate.
|
||||
*/
|
||||
template <typename First, typename Second>
|
||||
Self& add_if(bool cond) {
|
||||
return this->add_if<First>(cond, _::cpp_type<Second>::id(this->m_world));
|
||||
}
|
||||
|
||||
/** Conditional add.
|
||||
* This operation adds if condition is true, removes if condition is false.
|
||||
*
|
||||
* @param cond The condition to evaluate.
|
||||
* @param constant The enumeration constant.
|
||||
*/
|
||||
template <typename E, if_t< is_enum<E>::value > = 0>
|
||||
Self& add_if(bool cond, E constant) {
|
||||
const auto& et = enum_type<E>(this->m_world);
|
||||
return this->add_if<E>(cond, et.entity(constant));
|
||||
}
|
||||
|
||||
/** Shortcut for add(IsA, entity).
|
||||
*
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
Self& is_a(entity_t second) {
|
||||
return this->add(flecs::IsA, second);
|
||||
}
|
||||
|
||||
/** Shortcut for add(IsA, entity).
|
||||
*
|
||||
* @tparam T the type associated with the entity.
|
||||
*/
|
||||
template <typename T>
|
||||
Self& is_a() {
|
||||
return this->add(flecs::IsA, _::cpp_type<T>::id(this->m_world));
|
||||
}
|
||||
|
||||
/** Shortcut for add(ChildOf, entity).
|
||||
*
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
Self& child_of(entity_t second) {
|
||||
return this->add(flecs::ChildOf, second);
|
||||
}
|
||||
|
||||
/** Shortcut for add(DependsOn, entity).
|
||||
*
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
Self& depends_on(entity_t second) {
|
||||
return this->add(flecs::DependsOn, second);
|
||||
}
|
||||
|
||||
/** Shortcut for add(SlotOf, entity).
|
||||
*
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
Self& slot_of(entity_t second) {
|
||||
return this->add(flecs::SlotOf, second);
|
||||
}
|
||||
|
||||
/** Shortcut for add(SlotOf, target(ChildOf)).
|
||||
*/
|
||||
Self& slot() {
|
||||
ecs_check(ecs_get_target(m_world, m_id, flecs::ChildOf, 0),
|
||||
ECS_INVALID_PARAMETER, "add ChildOf pair before using slot()");
|
||||
return this->slot_of(this->target(flecs::ChildOf));
|
||||
error:
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Shortcut for add(ChildOf, entity).
|
||||
*
|
||||
* @tparam T the type associated with the entity.
|
||||
*/
|
||||
template <typename T>
|
||||
Self& child_of() {
|
||||
return this->child_of(_::cpp_type<T>::id(this->m_world));
|
||||
}
|
||||
|
||||
/** Shortcut for add(DependsOn, entity).
|
||||
*
|
||||
* @tparam T the type associated with the entity.
|
||||
*/
|
||||
template <typename T>
|
||||
Self& depends_on() {
|
||||
return this->depends_on(_::cpp_type<T>::id(this->m_world));
|
||||
}
|
||||
|
||||
/** Shortcut for add(SlotOf, entity).
|
||||
*
|
||||
* @tparam T the type associated with the entity.
|
||||
*/
|
||||
template <typename T>
|
||||
Self& slot_of() {
|
||||
return this->slot_of(_::cpp_type<T>::id(this->m_world));
|
||||
}
|
||||
|
||||
/** Remove a component from an entity.
|
||||
*
|
||||
* @tparam T the type of the component to remove.
|
||||
*/
|
||||
template <typename T, if_not_t< is_enum<T>::value > = 0>
|
||||
Self& remove() {
|
||||
ecs_remove_id(this->m_world, this->m_id, _::cpp_type<T>::id(this->m_world));
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Remove pair for enum.
|
||||
* This operation will remove any (Enum, *) pair from the entity.
|
||||
*
|
||||
* @tparam E The enumeration type.
|
||||
*/
|
||||
template <typename E, if_t< is_enum<E>::value > = 0>
|
||||
Self& remove() {
|
||||
flecs::entity_t first = _::cpp_type<E>::id(this->m_world);
|
||||
return this->remove(first, flecs::Wildcard);
|
||||
}
|
||||
|
||||
/** Remove an entity from an entity.
|
||||
*
|
||||
* @param entity The entity to remove.
|
||||
*/
|
||||
Self& remove(entity_t entity) {
|
||||
ecs_remove_id(this->m_world, this->m_id, entity);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Remove a pair.
|
||||
* This operation removes a pair from the entity.
|
||||
*
|
||||
* @param first The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
Self& remove(entity_t first, entity_t second) {
|
||||
ecs_remove_pair(this->m_world, this->m_id, first, second);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Removes a pair.
|
||||
* This operation removes a pair from the entity.
|
||||
*
|
||||
* @tparam First The first element of the pair
|
||||
* @tparam Second The second element of the pair
|
||||
*/
|
||||
template<typename First, typename Second>
|
||||
Self& remove() {
|
||||
return this->remove<First>(_::cpp_type<Second>::id(this->m_world));
|
||||
}
|
||||
|
||||
/** Remove a pair.
|
||||
* This operation removes the pair from the entity.
|
||||
*
|
||||
* @tparam First The first element of the pair
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
template<typename First, typename Second, if_not_t< is_enum<Second>::value > = 0>
|
||||
Self& remove(Second second) {
|
||||
return this->remove(_::cpp_type<First>::id(this->m_world), second);
|
||||
}
|
||||
|
||||
/** Removes a pair.
|
||||
* This operation removes a pair from the entity.
|
||||
*
|
||||
* @tparam Second The second element of the pair
|
||||
* @param first The first element of the pair
|
||||
*/
|
||||
template<typename Second>
|
||||
Self& remove_second(flecs::entity_t first) {
|
||||
return this->remove(first, _::cpp_type<Second>::id(this->m_world));
|
||||
}
|
||||
|
||||
/** Remove a pair.
|
||||
* This operation removes the pair from the entity.
|
||||
*
|
||||
* @tparam First The first element of the pair
|
||||
* @param constant the enum constant.
|
||||
*/
|
||||
template<typename First, typename Second, if_t< is_enum<Second>::value > = 0>
|
||||
Self& remove(Second constant) {
|
||||
const auto& et = enum_type<Second>(this->m_world);
|
||||
flecs::entity_t second = et.entity(constant);
|
||||
return this->remove<First>(second);
|
||||
}
|
||||
|
||||
/** Mark id for auto-overriding.
|
||||
* When an entity inherits from a base entity (using the IsA relationship)
|
||||
* any ids marked for auto-overriding on the base will be overridden
|
||||
* automatically by the entity.
|
||||
*
|
||||
* @param id The id to mark for overriding.
|
||||
*/
|
||||
Self& override(flecs::id_t id) {
|
||||
return this->add(ECS_OVERRIDE | id);
|
||||
}
|
||||
|
||||
/** Mark pair for auto-overriding.
|
||||
* @see override(flecs::id_t id)
|
||||
*
|
||||
* @param first The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
Self& override(flecs::entity_t first, flecs::entity_t second) {
|
||||
return this->override(ecs_pair(first, second));
|
||||
}
|
||||
|
||||
/** Mark component for auto-overriding.
|
||||
* @see override(flecs::id_t id)
|
||||
*
|
||||
* @tparam T The component to mark for overriding.
|
||||
*/
|
||||
template <typename T>
|
||||
Self& override() {
|
||||
return this->override(_::cpp_type<T>::id(this->m_world));
|
||||
}
|
||||
|
||||
/** Mark pair for auto-overriding.
|
||||
* @see override(flecs::id_t id)
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
template <typename First>
|
||||
Self& override(flecs::entity_t second) {
|
||||
return this->override(_::cpp_type<First>::id(this->m_world), second);
|
||||
}
|
||||
|
||||
/** Mark pair for auto-overriding.
|
||||
* @see override(flecs::id_t id)
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @tparam Second The second element of the pair.
|
||||
*/
|
||||
template <typename First, typename Second>
|
||||
Self& override() {
|
||||
return this->override<First>(_::cpp_type<Second>::id(this->m_world));
|
||||
}
|
||||
|
||||
/** Set component, mark component for auto-overriding.
|
||||
* @see override(flecs::id_t id)
|
||||
*
|
||||
* @tparam T The component to set and for which to add the OVERRIDE flag
|
||||
*/
|
||||
template <typename T>
|
||||
Self& set_override(const T& val) {
|
||||
this->override<T>();
|
||||
return this->set<T>(val);
|
||||
}
|
||||
|
||||
/** Set component, mark component for auto-overriding.
|
||||
* @see override(flecs::id_t id)
|
||||
*
|
||||
* @tparam T The component to set and for which to add the OVERRIDE flag
|
||||
*/
|
||||
template <typename T>
|
||||
Self& set_override(T&& val) {
|
||||
this->override<T>();
|
||||
return this->set<T>(FLECS_FWD(val));
|
||||
}
|
||||
|
||||
/** Set pair, mark component for auto-overriding.
|
||||
* @see override(flecs::id_t id)
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
template <typename First>
|
||||
Self& set_override(flecs::entity_t second, const First& val) {
|
||||
this->override<First>(second);
|
||||
return this->set<First>(second, val);
|
||||
}
|
||||
|
||||
/** Set pair, mark component for auto-overriding.
|
||||
* @see override(flecs::id_t id)
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
template <typename First>
|
||||
Self& set_override(flecs::entity_t second, First&& val) {
|
||||
this->override<First>(second);
|
||||
return this->set<First>(second, FLECS_FWD(val));
|
||||
}
|
||||
|
||||
/** Set component, mark component for auto-overriding.
|
||||
* @see override(flecs::id_t id)
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @tparam Second The second element of the pair.
|
||||
*/
|
||||
template <typename First, typename Second, typename P = pair<First, Second>,
|
||||
typename A = actual_type_t<P>, if_not_t< flecs::is_pair<First>::value> = 0>
|
||||
Self& set_override(const A& val) {
|
||||
this->override<First, Second>();
|
||||
return this->set<First, Second>(val);
|
||||
}
|
||||
|
||||
/** Set component, mark component for auto-overriding.
|
||||
* @see override(flecs::id_t id)
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @tparam Second The second element of the pair.
|
||||
*/
|
||||
template <typename First, typename Second, typename P = pair<First, Second>,
|
||||
typename A = actual_type_t<P>, if_not_t< flecs::is_pair<First>::value> = 0>
|
||||
Self& set_override(A&& val) {
|
||||
this->override<First, Second>();
|
||||
return this->set<First, Second>(FLECS_FWD(val));
|
||||
}
|
||||
|
||||
/** Emplace component, mark component for auto-overriding.
|
||||
* @see override(flecs::id_t id)
|
||||
*
|
||||
* @tparam T The component to emplace and override.
|
||||
*/
|
||||
template <typename T, typename ... Args>
|
||||
Self& emplace_override(Args&&... args) {
|
||||
this->override<T>();
|
||||
|
||||
flecs::emplace<T>(this->m_world, this->m_id,
|
||||
_::cpp_type<T>::id(this->m_world), FLECS_FWD(args)...);
|
||||
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Emplace pair, mark pair for auto-overriding.
|
||||
* @see override(flecs::id_t id)
|
||||
*
|
||||
* @tparam First The first element of the pair to emplace and override.
|
||||
* @tparam Second The second element of the pair to emplace and override.
|
||||
*/
|
||||
template <typename First, typename Second, typename P = pair<First, Second>,
|
||||
typename A = actual_type_t<P>, if_not_t< flecs::is_pair<First>::value> = 0,
|
||||
typename ... Args>
|
||||
Self& emplace_override(Args&&... args) {
|
||||
this->override<First, Second>();
|
||||
|
||||
flecs::emplace<A>(this->m_world, this->m_id,
|
||||
ecs_pair(_::cpp_type<First>::id(this->m_world),
|
||||
_::cpp_type<Second>::id(this->m_world)),
|
||||
FLECS_FWD(args)...);
|
||||
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Enable an entity.
|
||||
* Enabled entities are matched with systems and can be searched with
|
||||
* queries.
|
||||
*/
|
||||
Self& enable() {
|
||||
ecs_enable(this->m_world, this->m_id, true);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Disable an entity.
|
||||
* Disabled entities are not matched with systems and cannot be searched
|
||||
* with queries, unless explicitly specified in the query expression.
|
||||
*/
|
||||
Self& disable() {
|
||||
ecs_enable(this->m_world, this->m_id, false);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Enable an id.
|
||||
* This sets the enabled bit for this component. If this is the first time
|
||||
* the component is enabled or disabled, the bitset is added.
|
||||
*
|
||||
* @param id The id to enable.
|
||||
* @param toggle True to enable, false to disable (default = true).
|
||||
*/
|
||||
Self& enable(flecs::id_t id, bool toggle = true) {
|
||||
ecs_enable_id(this->m_world, this->m_id, id, toggle);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Enable a component.
|
||||
* @see enable(flecs::id_t id)
|
||||
*
|
||||
* @tparam T The component to enable.
|
||||
*/
|
||||
template<typename T>
|
||||
Self& enable() {
|
||||
return this->enable(_::cpp_type<T>::id(this->m_world));
|
||||
}
|
||||
|
||||
/** Enable a pair.
|
||||
* @see enable(flecs::id_t id)
|
||||
*
|
||||
* @param first The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
Self& enable(flecs::id_t first, flecs::id_t second) {
|
||||
return this->enable(ecs_pair(first, second));
|
||||
}
|
||||
|
||||
/** Enable a pair.
|
||||
* @see enable(flecs::id_t id)
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
template<typename First>
|
||||
Self& enable(flecs::id_t second) {
|
||||
return this->enable(_::cpp_type<First>::id(), second);
|
||||
}
|
||||
|
||||
/** Enable a pair.
|
||||
* @see enable(flecs::id_t id)
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @tparam Second The second element of the pair.
|
||||
*/
|
||||
template<typename First, typename Second>
|
||||
Self& enable() {
|
||||
return this->enable<First>(_::cpp_type<Second>::id());
|
||||
}
|
||||
|
||||
/** Disable an id.
|
||||
* This sets the enabled bit for this id. If this is the first time
|
||||
* the id is enabled or disabled, the bitset is added.
|
||||
*
|
||||
* @param id The id to disable.
|
||||
*/
|
||||
Self& disable(flecs::id_t id) {
|
||||
return this->enable(id, false);
|
||||
}
|
||||
|
||||
/** Disable a component.
|
||||
* @see disable(flecs::id_t id)
|
||||
*
|
||||
* @tparam T The component to enable.
|
||||
*/
|
||||
template<typename T>
|
||||
Self& disable() {
|
||||
return this->disable(_::cpp_type<T>::id());
|
||||
}
|
||||
|
||||
/** Disable a pair.
|
||||
* @see disable(flecs::id_t id)
|
||||
*
|
||||
* @param first The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
Self& disable(flecs::id_t first, flecs::id_t second) {
|
||||
return this->disable(ecs_pair(first, second));
|
||||
}
|
||||
|
||||
/** Disable a pair.
|
||||
* @see disable(flecs::id_t id)
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
*/
|
||||
template<typename First>
|
||||
Self& disable(flecs::id_t second) {
|
||||
return this->disable(_::cpp_type<First>::id(), second);
|
||||
}
|
||||
|
||||
/** Disable a pair.
|
||||
* @see disable(flecs::id_t id)
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @tparam Second The second element of the pair.
|
||||
*/
|
||||
template<typename First, typename Second>
|
||||
Self& disable() {
|
||||
return this->disable<First>(_::cpp_type<Second>::id());
|
||||
}
|
||||
|
||||
Self& set_ptr(entity_t comp, size_t size, const void *ptr) {
|
||||
ecs_set_id(this->m_world, this->m_id, comp, size, ptr);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
Self& set_ptr(entity_t comp, const void *ptr) {
|
||||
const flecs::Component *cptr = ecs_get(
|
||||
this->m_world, comp, EcsComponent);
|
||||
|
||||
/* Can't set if it's not a component */
|
||||
ecs_assert(cptr != NULL, ECS_INVALID_PARAMETER, NULL);
|
||||
|
||||
return set_ptr(comp, cptr->size, ptr);
|
||||
}
|
||||
|
||||
template<typename T, if_t<
|
||||
!is_callable<T>::value && is_actual<T>::value> = 0 >
|
||||
Self& set(T&& value) {
|
||||
flecs::set<T>(this->m_world, this->m_id, FLECS_FWD(value));
|
||||
return to_base();
|
||||
}
|
||||
|
||||
template<typename T, if_t<
|
||||
!is_callable<T>::value && is_actual<T>::value > = 0>
|
||||
Self& set(const T& value) {
|
||||
flecs::set<T>(this->m_world, this->m_id, value);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
template<typename T, typename A = actual_type_t<T>, if_not_t<
|
||||
is_callable<T>::value || is_actual<T>::value > = 0>
|
||||
Self& set(A&& value) {
|
||||
flecs::set<T>(this->m_world, this->m_id, FLECS_FWD(value));
|
||||
return to_base();
|
||||
}
|
||||
|
||||
template<typename T, typename A = actual_type_t<T>, if_not_t<
|
||||
is_callable<T>::value || is_actual<T>::value > = 0>
|
||||
Self& set(const A& value) {
|
||||
flecs::set<T>(this->m_world, this->m_id, value);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Set a pair for an entity.
|
||||
* This operation sets the pair value, and uses First as type. If the
|
||||
* entity did not yet have the pair, it will be added.
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @tparam Second The second element of the pair
|
||||
* @param value The value to set.
|
||||
*/
|
||||
template <typename First, typename Second, typename P = pair<First, Second>,
|
||||
typename A = actual_type_t<P>, if_not_t< flecs::is_pair<First>::value> = 0>
|
||||
Self& set(A&& value) {
|
||||
flecs::set<P>(this->m_world, this->m_id, FLECS_FWD(value));
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Set a pair for an entity.
|
||||
* This operation sets the pair value, and uses First as type. If the
|
||||
* entity did not yet have the pair, it will be added.
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @tparam Second The second element of the pair
|
||||
* @param value The value to set.
|
||||
*/
|
||||
template <typename First, typename Second, typename P = pair<First, Second>,
|
||||
typename A = actual_type_t<P>, if_not_t< flecs::is_pair<First>::value> = 0>
|
||||
Self& set(const A& value) {
|
||||
flecs::set<P>(this->m_world, this->m_id, value);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Set a pair for an entity.
|
||||
* This operation sets the pair value, and uses First as type. If the
|
||||
* entity did not yet have the pair, it will be added.
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
* @param value The value to set.
|
||||
*/
|
||||
template <typename First, typename Second, if_not_t< is_enum<Second>::value > = 0>
|
||||
Self& set(Second second, const First& value) {
|
||||
auto first = _::cpp_type<First>::id(this->m_world);
|
||||
flecs::set(this->m_world, this->m_id, value,
|
||||
ecs_pair(first, second));
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Set a pair for an entity.
|
||||
* This operation sets the pair value, and uses First as type. If the
|
||||
* entity did not yet have the pair, it will be added.
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @param second The second element of the pair.
|
||||
* @param value The value to set.
|
||||
*/
|
||||
template <typename First, typename Second, if_not_t< is_enum<Second>::value > = 0>
|
||||
Self& set(Second second, First&& value) {
|
||||
auto first = _::cpp_type<First>::id(this->m_world);
|
||||
flecs::set(this->m_world, this->m_id, FLECS_FWD(value),
|
||||
ecs_pair(first, second));
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Set a pair for an entity.
|
||||
* This operation sets the pair value, and uses First as type. If the
|
||||
* entity did not yet have the pair, it will be added.
|
||||
*
|
||||
* @tparam First The first element of the pair.
|
||||
* @param constant The enum constant.
|
||||
* @param value The value to set.
|
||||
*/
|
||||
template <typename First, typename Second, if_t< is_enum<Second>::value > = 0>
|
||||
Self& set(Second constant, const First& value) {
|
||||
const auto& et = enum_type<Second>(this->m_world);
|
||||
flecs::entity_t second = et.entity(constant);
|
||||
return set<First>(second, value);
|
||||
}
|
||||
|
||||
/** Set a pair for an entity.
|
||||
* This operation sets the pair value, and uses Second as type. If the
|
||||
* entity did not yet have the pair, it will be added.
|
||||
*
|
||||
* @tparam Second The second element of the pair
|
||||
* @param first The first element of the pair.
|
||||
* @param value The value to set.
|
||||
*/
|
||||
template <typename Second>
|
||||
Self& set_second(entity_t first, const Second& value) {
|
||||
auto second = _::cpp_type<Second>::id(this->m_world);
|
||||
flecs::set(this->m_world, this->m_id, value,
|
||||
ecs_pair(first, second));
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Set a pair for an entity.
|
||||
* This operation sets the pair value, and uses Second as type. If the
|
||||
* entity did not yet have the pair, it will be added.
|
||||
*
|
||||
* @tparam Second The second element of the pair
|
||||
* @param first The first element of the pair.
|
||||
* @param value The value to set.
|
||||
*/
|
||||
template <typename Second>
|
||||
Self& set_second(entity_t first, Second&& value) {
|
||||
auto second = _::cpp_type<Second>::id(this->m_world);
|
||||
flecs::set(this->m_world, this->m_id, FLECS_FWD(value),
|
||||
ecs_pair(first, second));
|
||||
return to_base();
|
||||
}
|
||||
|
||||
template <typename First, typename Second>
|
||||
Self& set_second(const Second& value) {
|
||||
flecs::set<pair_object<First, Second>>(this->m_world, this->m_id, value);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Set 1..N components.
|
||||
* This operation accepts a callback with as arguments the components to
|
||||
* set. If the entity does not have all of the provided components, they
|
||||
* will be added.
|
||||
*
|
||||
* This operation is faster than individually calling get for each component
|
||||
* as it only obtains entity metadata once. When this operation is called
|
||||
* while deferred, its performance is equivalent to that of calling get_mut
|
||||
* for each component separately.
|
||||
*
|
||||
* The operation will invoke modified for each component after the callback
|
||||
* has been invoked.
|
||||
*
|
||||
* @param func The callback to invoke.
|
||||
*/
|
||||
template <typename Func, if_t< is_callable<Func>::value > = 0>
|
||||
Self& set(const Func& func);
|
||||
|
||||
/** Emplace component.
|
||||
* Emplace constructs a component in the storage, which prevents calling the
|
||||
* destructor on the value passed into the function.
|
||||
*
|
||||
* Emplace attempts the following signatures to construct the component:
|
||||
* T{Args...}
|
||||
* T{flecs::entity, Args...}
|
||||
*
|
||||
* If the second signature matches, emplace will pass in the current entity
|
||||
* as argument to the constructor, which is useful if the component needs
|
||||
* to be aware of the entity to which it has been added.
|
||||
*
|
||||
* Emplace may only be called for components that have not yet been added
|
||||
* to the entity.
|
||||
*
|
||||
* @tparam T the component to emplace
|
||||
* @param args The arguments to pass to the constructor of T
|
||||
*/
|
||||
template<typename T, typename ... Args, typename A = actual_type_t<T>>
|
||||
Self& emplace(Args&&... args) {
|
||||
flecs::emplace<A>(this->m_world, this->m_id,
|
||||
_::cpp_type<T>::id(this->m_world), FLECS_FWD(args)...);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
template <typename First, typename Second, typename ... Args, typename P = pair<First, Second>,
|
||||
typename A = actual_type_t<P>, if_not_t< flecs::is_pair<First>::value> = 0>
|
||||
Self& emplace(Args&&... args) {
|
||||
flecs::emplace<A>(this->m_world, this->m_id,
|
||||
ecs_pair(_::cpp_type<First>::id(this->m_world),
|
||||
_::cpp_type<Second>::id(this->m_world)),
|
||||
FLECS_FWD(args)...);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
template <typename First, typename ... Args>
|
||||
Self& emplace_first(flecs::entity_t second, Args&&... args) {
|
||||
flecs::emplace<First>(this->m_world, this->m_id,
|
||||
ecs_pair(_::cpp_type<First>::id(this->m_world), second),
|
||||
FLECS_FWD(args)...);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
template <typename Second, typename ... Args>
|
||||
Self& emplace_second(flecs::entity_t first, Args&&... args) {
|
||||
flecs::emplace<Second>(this->m_world, this->m_id,
|
||||
ecs_pair(first, _::cpp_type<Second>::id(this->m_world)),
|
||||
FLECS_FWD(args)...);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Entities created in function will have the current entity.
|
||||
* This operation is thread safe.
|
||||
*
|
||||
* @param func The function to call.
|
||||
*/
|
||||
template <typename Func>
|
||||
Self& with(const Func& func) {
|
||||
ecs_id_t prev = ecs_set_with(this->m_world, this->m_id);
|
||||
func();
|
||||
ecs_set_with(this->m_world, prev);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Entities created in function will have (First, this).
|
||||
* This operation is thread safe.
|
||||
*
|
||||
* @tparam First The first element of the pair
|
||||
* @param func The function to call.
|
||||
*/
|
||||
template <typename First, typename Func>
|
||||
Self& with(const Func& func) {
|
||||
with(_::cpp_type<First>::id(this->m_world), func);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Entities created in function will have (first, this).
|
||||
* This operation is thread safe.
|
||||
*
|
||||
* @param first The first element of the pair.
|
||||
* @param func The function to call.
|
||||
*/
|
||||
template <typename Func>
|
||||
Self& with(entity_t first, const Func& func) {
|
||||
ecs_id_t prev = ecs_set_with(this->m_world,
|
||||
ecs_pair(first, this->m_id));
|
||||
func();
|
||||
ecs_set_with(this->m_world, prev);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** The function will be ran with the scope set to the current entity. */
|
||||
template <typename Func>
|
||||
Self& scope(const Func& func) {
|
||||
ecs_entity_t prev = ecs_set_scope(this->m_world, this->m_id);
|
||||
func();
|
||||
ecs_set_scope(this->m_world, prev);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Return world scoped to entity */
|
||||
scoped_world scope() const {
|
||||
return scoped_world(m_world, m_id);
|
||||
}
|
||||
|
||||
/* Set the entity name.
|
||||
*/
|
||||
Self& set_name(const char *name) {
|
||||
ecs_set_name(this->m_world, this->m_id, name);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/* Set entity alias.
|
||||
*/
|
||||
Self& set_alias(const char *name) {
|
||||
ecs_set_alias(this->m_world, this->m_id, name);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
# ifdef FLECS_DOC
|
||||
# include "../doc/entity_builder.inl"
|
||||
# endif
|
||||
|
||||
# ifdef FLECS_META
|
||||
# include "../meta/entity_builder.inl"
|
||||
# endif
|
||||
|
||||
# ifdef FLECS_JSON
|
||||
# include "../json/entity_builder.inl"
|
||||
# endif
|
||||
|
||||
# include "../event/entity_builder.inl"
|
||||
|
||||
protected:
|
||||
Self& to_base() {
|
||||
return *static_cast<Self*>(this);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/entity/impl.hpp
|
||||
* @brief Entity implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
template <typename T>
|
||||
flecs::entity ref<T>::entity() const {
|
||||
return flecs::entity(m_world, m_ref.entity);
|
||||
}
|
||||
|
||||
template <typename Self>
|
||||
template <typename Func, if_t< is_callable<Func>::value > >
|
||||
inline Self& entity_builder<Self>::set(const Func& func) {
|
||||
_::entity_with_delegate<Func>::invoke_get_mut(
|
||||
this->m_world, this->m_id, func);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
template <typename T, if_t< is_enum<T>::value > >
|
||||
const T* entity_view::get() const {
|
||||
entity_t r = _::cpp_type<T>::id(m_world);
|
||||
entity_t c = ecs_get_target(m_world, m_id, r, 0);
|
||||
|
||||
if (c) {
|
||||
// Get constant value from constant entity
|
||||
const T* v = static_cast<const T*>(ecs_get_id(m_world, c, r));
|
||||
ecs_assert(v != NULL, ECS_INTERNAL_ERROR,
|
||||
"missing enum constant value");
|
||||
return v;
|
||||
} else {
|
||||
// If there is no matching pair for (r, *), try just r
|
||||
return static_cast<const T*>(ecs_get_id(m_world, m_id, r));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename First>
|
||||
inline flecs::entity entity_view::target(int32_t index) const
|
||||
{
|
||||
return flecs::entity(m_world,
|
||||
ecs_get_target(m_world, m_id, _::cpp_type<First>::id(m_world), index));
|
||||
}
|
||||
|
||||
inline flecs::entity entity_view::target(
|
||||
flecs::entity_t relationship,
|
||||
int32_t index) const
|
||||
{
|
||||
return flecs::entity(m_world,
|
||||
ecs_get_target(m_world, m_id, relationship, index));
|
||||
}
|
||||
|
||||
inline flecs::entity entity_view::target_for(
|
||||
flecs::entity_t relationship,
|
||||
flecs::id_t id) const
|
||||
{
|
||||
return flecs::entity(m_world,
|
||||
ecs_get_target_for_id(m_world, m_id, relationship, id));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline flecs::entity entity_view::target_for(flecs::entity_t relationship) const {
|
||||
return target_for(relationship, _::cpp_type<T>::id(m_world));
|
||||
}
|
||||
|
||||
template <typename First, typename Second>
|
||||
inline flecs::entity entity_view::target_for(flecs::entity_t relationship) const {
|
||||
return target_for(relationship, _::cpp_type<First, Second>::id(m_world));
|
||||
}
|
||||
|
||||
inline flecs::entity entity_view::parent() const {
|
||||
return target(flecs::ChildOf);
|
||||
}
|
||||
|
||||
inline flecs::entity entity_view::mut(const flecs::world& stage) const {
|
||||
ecs_assert(!stage.is_readonly(), ECS_INVALID_PARAMETER,
|
||||
"cannot use readonly world/stage to create mutable handle");
|
||||
return flecs::entity(m_id).set_stage(stage.c_ptr());
|
||||
}
|
||||
|
||||
inline flecs::entity entity_view::mut(const flecs::iter& it) const {
|
||||
ecs_assert(!it.world().is_readonly(), ECS_INVALID_PARAMETER,
|
||||
"cannot use iterator created for readonly world/stage to create mutable handle");
|
||||
return flecs::entity(m_id).set_stage(it.world().c_ptr());
|
||||
}
|
||||
|
||||
inline flecs::entity entity_view::mut(const flecs::entity_view& e) const {
|
||||
ecs_assert(!e.world().is_readonly(), ECS_INVALID_PARAMETER,
|
||||
"cannot use entity created for readonly world/stage to create mutable handle");
|
||||
return flecs::entity(m_id).set_stage(e.m_world);
|
||||
}
|
||||
|
||||
inline flecs::entity entity_view::set_stage(world_t *stage) {
|
||||
return flecs::entity(stage, m_id);
|
||||
}
|
||||
|
||||
inline flecs::type entity_view::type() const {
|
||||
return flecs::type(m_world, ecs_get_type(m_world, m_id));
|
||||
}
|
||||
|
||||
inline flecs::table entity_view::table() const {
|
||||
return flecs::table(m_world, ecs_get_table(m_world, m_id));
|
||||
}
|
||||
|
||||
inline flecs::table_range entity_view::range() const {
|
||||
ecs_record_t *r = ecs_record_find(m_world, m_id);
|
||||
if (r) {
|
||||
return flecs::table_range(m_world, r->table,
|
||||
ECS_RECORD_TO_ROW(r->row), 1);
|
||||
}
|
||||
return flecs::table_range();
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
inline void entity_view::each(const Func& func) const {
|
||||
const ecs_type_t *type = ecs_get_type(m_world, m_id);
|
||||
if (!type) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ecs_id_t *ids = type->array;
|
||||
int32_t count = type->count;
|
||||
|
||||
for (int i = 0; i < count; i ++) {
|
||||
ecs_id_t id = ids[i];
|
||||
flecs::id ent(m_world, id);
|
||||
func(ent);
|
||||
|
||||
// Union object is not stored in type, so handle separately
|
||||
if (ECS_PAIR_FIRST(id) == EcsUnion) {
|
||||
ent = flecs::id(m_world, ECS_PAIR_SECOND(id),
|
||||
ecs_get_target(m_world, m_id, ECS_PAIR_SECOND(id), 0));
|
||||
func(ent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
inline void entity_view::each(flecs::id_t pred, flecs::id_t obj, const Func& func) const {
|
||||
flecs::world_t *real_world = const_cast<flecs::world_t*>(
|
||||
ecs_get_world(m_world));
|
||||
|
||||
const ecs_table_t *table = ecs_get_table(m_world, m_id);
|
||||
if (!table) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ecs_type_t *type = ecs_table_get_type(table);
|
||||
if (!type) {
|
||||
return;
|
||||
}
|
||||
|
||||
flecs::id_t pattern = pred;
|
||||
if (obj) {
|
||||
pattern = ecs_pair(pred, obj);
|
||||
}
|
||||
|
||||
int32_t cur = 0;
|
||||
id_t *ids = type->array;
|
||||
|
||||
while (-1 != (cur = ecs_search_offset(real_world, table, cur, pattern, 0)))
|
||||
{
|
||||
flecs::id ent(m_world, ids[cur]);
|
||||
func(ent);
|
||||
cur ++;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
inline void entity_view::each(const flecs::entity_view& rel, const Func& func) const {
|
||||
return this->each(rel, flecs::Wildcard, [&](flecs::id id) {
|
||||
flecs::entity obj = id.second();
|
||||
func(obj);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Func, if_t< is_callable<Func>::value > >
|
||||
inline bool entity_view::get(const Func& func) const {
|
||||
return _::entity_with_delegate<Func>::invoke_get(m_world, m_id, func);
|
||||
}
|
||||
|
||||
inline flecs::entity entity_view::lookup(const char *path, bool search_path) const {
|
||||
ecs_assert(m_id != 0, ECS_INVALID_PARAMETER, "invalid lookup from null handle");
|
||||
auto id = ecs_lookup_path_w_sep(m_world, m_id, path, "::", "::", search_path);
|
||||
return flecs::entity(m_world, id);
|
||||
}
|
||||
|
||||
inline flecs::entity entity_view::clone(bool copy_value, flecs::entity_t dst_id) const {
|
||||
if (!dst_id) {
|
||||
dst_id = ecs_new_id(m_world);
|
||||
}
|
||||
|
||||
flecs::entity dst = flecs::entity(m_world, dst_id);
|
||||
ecs_clone(m_world, dst_id, m_id, copy_value);
|
||||
return dst;
|
||||
}
|
||||
|
||||
// Entity mixin implementation
|
||||
template <typename... Args>
|
||||
inline flecs::entity world::entity(Args &&... args) const {
|
||||
return flecs::entity(m_world, FLECS_FWD(args)...);
|
||||
}
|
||||
|
||||
template <typename E, if_t< is_enum<E>::value >>
|
||||
inline flecs::id world::id(E value) const {
|
||||
flecs::entity_t constant = enum_type<E>(m_world).entity(value);
|
||||
return flecs::id(m_world, constant);
|
||||
}
|
||||
|
||||
template <typename E, if_t< is_enum<E>::value >>
|
||||
inline flecs::entity world::entity(E value) const {
|
||||
flecs::entity_t constant = enum_type<E>(m_world).entity(value);
|
||||
return flecs::entity(m_world, constant);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline flecs::entity world::entity(const char *name) const {
|
||||
return flecs::entity(m_world,
|
||||
_::cpp_type<T>::id_explicit(m_world, name, true, 0, false) );
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline flecs::entity world::prefab(Args &&... args) const {
|
||||
flecs::entity result = flecs::entity(m_world, FLECS_FWD(args)...);
|
||||
result.add(flecs::Prefab);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline flecs::entity world::prefab(const char *name) const {
|
||||
flecs::entity result = flecs::component<T>(m_world, name, true);
|
||||
result.add(flecs::Prefab);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/entity/mixin.inl
|
||||
* @brief Entity world mixin.
|
||||
*/
|
||||
|
||||
/** Create an entity.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_entities
|
||||
*/
|
||||
template <typename... Args>
|
||||
flecs::entity entity(Args &&... args) const;
|
||||
|
||||
/** Convert enum constant to entity.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_entities
|
||||
*/
|
||||
template <typename E, if_t< is_enum<E>::value > = 0>
|
||||
flecs::id id(E value) const;
|
||||
|
||||
/** Convert enum constant to entity.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_entities
|
||||
*/
|
||||
template <typename E, if_t< is_enum<E>::value > = 0>
|
||||
flecs::entity entity(E value) const;
|
||||
|
||||
/** Create a prefab.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_entities
|
||||
*/
|
||||
template <typename... Args>
|
||||
flecs::entity prefab(Args &&... args) const;
|
||||
|
||||
/** Create an entity that's associated with a type.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_entities
|
||||
*/
|
||||
template <typename T>
|
||||
flecs::entity entity(const char *name = nullptr) const;
|
||||
|
||||
/** Create a prefab that's associated with a type.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_entities
|
||||
*/
|
||||
template <typename T>
|
||||
flecs::entity prefab(const char *name = nullptr) const;
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/enum/entity_view.inl
|
||||
* @brief Enum entity view mixin.
|
||||
*/
|
||||
|
||||
/** Convert entity to enum constant.
|
||||
*
|
||||
* \memberof flecs::entity_view
|
||||
* \ingroup cpp_entities
|
||||
*/
|
||||
template <typename E>
|
||||
E to_constant() const;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/enum/impl.hpp
|
||||
* @brief Enum implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
template <typename E>
|
||||
inline E entity_view::to_constant() const {
|
||||
const E* ptr = this->get<E>();
|
||||
ecs_assert(ptr != NULL, ECS_INVALID_PARAMETER, "entity is not a constant");
|
||||
return ptr[0];
|
||||
}
|
||||
|
||||
template <typename E, if_t< is_enum<E>::value >>
|
||||
inline flecs::entity world::to_entity(E constant) const {
|
||||
const auto& et = enum_type<E>(m_world);
|
||||
return flecs::entity(m_world, et.entity(constant));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/enum/mixin.inl
|
||||
* @brief Enum world mixin.
|
||||
*/
|
||||
|
||||
/** Convert enum constant to entity.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_entities
|
||||
*/
|
||||
template <typename E, if_t< is_enum<E>::value > = 0>
|
||||
flecs::entity to_entity(E constant) const;
|
||||
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/event/builder.hpp
|
||||
* @brief Event builder.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define ECS_EVENT_DESC_ID_COUNT_MAX (8)
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/**
|
||||
* \ingroup cpp_addons_event
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Event builder interface */
|
||||
template <typename Base, typename E>
|
||||
struct event_builder_base {
|
||||
event_builder_base(flecs::world_t *world, flecs::entity_t event)
|
||||
: m_world(world)
|
||||
, m_desc{}
|
||||
, m_ids{}
|
||||
, m_ids_array{}
|
||||
{
|
||||
m_desc.event = event;
|
||||
}
|
||||
|
||||
/** Add component to emit for */
|
||||
template <typename T>
|
||||
Base& id() {
|
||||
m_ids.array = m_ids_array;
|
||||
m_ids.array[m_ids.count] = _::cpp_type<T>().id(m_world);
|
||||
m_ids.count ++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add pair to emit for
|
||||
* @tparam First The first element of the pair.
|
||||
* @tparam Second the second element of a pair.
|
||||
*/
|
||||
template <typename First, typename Second>
|
||||
Base& id() {
|
||||
return id(
|
||||
ecs_pair(_::cpp_type<First>::id(this->m_world),
|
||||
_::cpp_type<Second>::id(this->m_world)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add pair to emit for
|
||||
* @tparam First The first element of the pair.
|
||||
* @param second The second element of the pair id.
|
||||
*/
|
||||
template <typename First>
|
||||
Base& id(entity_t second) {
|
||||
return id(ecs_pair(_::cpp_type<First>::id(this->m_world), second));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add pair to emit for
|
||||
* @param first The first element of the pair type.
|
||||
* @param second The second element of the pair id.
|
||||
*/
|
||||
Base& id(entity_t first, entity_t second) {
|
||||
return id(ecs_pair(first, second));
|
||||
}
|
||||
|
||||
/** Add (component) id to emit for */
|
||||
Base& id(flecs::id_t id) {
|
||||
m_ids.array = m_ids_array;
|
||||
m_ids.array[m_ids.count] = id;
|
||||
m_ids.count ++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set entity for which to emit event */
|
||||
Base& entity(flecs::entity_t e) {
|
||||
m_desc.entity = e;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* Set table for which to emit event */
|
||||
Base& table(flecs::table_t *t, int32_t offset = 0, int32_t count = 0) {
|
||||
m_desc.table = t;
|
||||
m_desc.offset = offset;
|
||||
m_desc.count = count;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* Set event data */
|
||||
Base& ctx(const E* ptr) {
|
||||
m_desc.param = ptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void emit() {
|
||||
m_ids.array = m_ids_array;
|
||||
m_desc.ids = &m_ids;
|
||||
m_desc.observable = const_cast<flecs::world_t*>(ecs_get_world(m_world));
|
||||
ecs_emit(m_world, &m_desc);
|
||||
}
|
||||
|
||||
protected:
|
||||
flecs::world_t *m_world;
|
||||
ecs_event_desc_t m_desc;
|
||||
flecs::type_t m_ids;
|
||||
flecs::id_t m_ids_array[ECS_EVENT_DESC_ID_COUNT_MAX];
|
||||
|
||||
private:
|
||||
operator Base&() {
|
||||
return *static_cast<Base*>(this);
|
||||
}
|
||||
};
|
||||
|
||||
struct event_builder : event_builder_base<event_builder, void> {
|
||||
using event_builder_base::event_builder_base;
|
||||
};
|
||||
|
||||
template <typename E>
|
||||
struct event_builder_typed : event_builder_base<event_builder_typed<E>, E> {
|
||||
private:
|
||||
using Class = event_builder_typed<E>;
|
||||
|
||||
public:
|
||||
using event_builder_base<Class, E>::event_builder_base;
|
||||
|
||||
/* Set event data */
|
||||
Class& ctx(const E& ptr) {
|
||||
this->m_desc.param = &ptr;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/event/decl.hpp
|
||||
* @brief Event declarations.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "builder.hpp"
|
||||
|
||||
namespace flecs {
|
||||
namespace _ {
|
||||
|
||||
// Utility to derive event type from function
|
||||
template <typename Func, typename U = int>
|
||||
struct event_from_func;
|
||||
|
||||
// Specialization for observer callbacks with a single argument
|
||||
template <typename Func>
|
||||
struct event_from_func<Func, if_t< arity<Func>::value == 1>> {
|
||||
using type = decay_t<first_arg_t<Func>>;
|
||||
};
|
||||
|
||||
// Specialization for observer callbacks with an initial entity src argument
|
||||
template <typename Func>
|
||||
struct event_from_func<Func, if_t< arity<Func>::value == 2>> {
|
||||
using type = decay_t<second_arg_t<Func>>;
|
||||
};
|
||||
|
||||
template <typename Func>
|
||||
using event_from_func_t = typename event_from_func<Func>::type;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/event/entity_builder.hpp
|
||||
* @brief Event entity mixin.
|
||||
*/
|
||||
|
||||
/** Observe event on entity
|
||||
*
|
||||
* \memberof flecs::entity_builder
|
||||
*
|
||||
* @param evt The event id.
|
||||
* @param callback The observer callback.
|
||||
* @return Event builder.
|
||||
*/
|
||||
template <typename Func>
|
||||
Self& observe(flecs::entity_t evt, Func&& callback);
|
||||
|
||||
/** Observe event on entity
|
||||
*
|
||||
* \memberof flecs::entity_builder
|
||||
*
|
||||
* @tparam Evt The event type.
|
||||
* @param callback The observer callback.
|
||||
* @return Event builder.
|
||||
*/
|
||||
template <typename Evt, typename Func>
|
||||
Self& observe(Func&& callback);
|
||||
|
||||
/** Observe event on entity
|
||||
*
|
||||
* \memberof flecs::entity_builder
|
||||
*
|
||||
* @param callback The observer callback.
|
||||
* @return Event builder.
|
||||
*/
|
||||
template <typename Func>
|
||||
Self& observe(Func&& callback);
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/event/entity_builder.hpp
|
||||
* @brief Event entity mixin.
|
||||
*/
|
||||
|
||||
/** Emit event for entity.
|
||||
*
|
||||
* \memberof flecs::entity_view
|
||||
*
|
||||
* @param evt The event to emit.
|
||||
*/
|
||||
void emit(flecs::entity_t evt) {
|
||||
flecs::world(m_world)
|
||||
.event(evt)
|
||||
.entity(m_id)
|
||||
.emit();
|
||||
}
|
||||
|
||||
/** Emit event for entity.
|
||||
*
|
||||
* \memberof flecs::entity_view
|
||||
*
|
||||
* @param evt The event to emit.
|
||||
*/
|
||||
void emit(flecs::entity evt);
|
||||
|
||||
/** Emit event for entity.
|
||||
*
|
||||
* \memberof flecs::entity_view
|
||||
*
|
||||
* @tparam Evt The event to emit.
|
||||
*/
|
||||
template <typename Evt, if_t<is_empty<Evt>::value> = 0>
|
||||
void emit() {
|
||||
this->emit(_::cpp_type<Evt>::id(m_world));
|
||||
}
|
||||
|
||||
/** Emit event with payload for entity.
|
||||
*
|
||||
* \memberof flecs::entity_view
|
||||
*
|
||||
* @tparam Evt The event to emit.
|
||||
*/
|
||||
template <typename Evt, if_not_t<is_empty<Evt>::value> = 0>
|
||||
void emit(const Evt& payload) {
|
||||
flecs::world(m_world)
|
||||
.event(_::cpp_type<Evt>::id(m_world))
|
||||
.entity(m_id)
|
||||
.ctx(&payload)
|
||||
.emit();
|
||||
}
|
||||
|
||||
103
engine/libs/flecs/include/flecs/addons/cpp/mixins/event/impl.hpp
Normal file
103
engine/libs/flecs/include/flecs/addons/cpp/mixins/event/impl.hpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/event/impl.hpp
|
||||
* @brief Event implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "builder.hpp"
|
||||
|
||||
namespace flecs
|
||||
{
|
||||
|
||||
// Mixin implementation
|
||||
|
||||
inline flecs::event_builder world::event(flecs::entity_t evt) const {
|
||||
return flecs::event_builder(m_world, evt);
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
inline flecs::event_builder_typed<E> world::event() const {
|
||||
return flecs::event_builder_typed<E>(m_world, _::cpp_type<E>().id(m_world));
|
||||
}
|
||||
|
||||
namespace _ {
|
||||
inline void entity_observer_create(
|
||||
flecs::world_t *world,
|
||||
flecs::entity_t event,
|
||||
flecs::entity_t entity,
|
||||
ecs_iter_action_t callback,
|
||||
void *binding_ctx,
|
||||
ecs_ctx_free_t binding_ctx_free)
|
||||
{
|
||||
ecs_observer_desc_t desc = {};
|
||||
desc.events[0] = event;
|
||||
desc.filter.terms[0].id = EcsAny;
|
||||
desc.filter.terms[0].src.id = entity;
|
||||
desc.callback = callback;
|
||||
desc.binding_ctx = binding_ctx;
|
||||
desc.binding_ctx_free = binding_ctx_free;
|
||||
|
||||
flecs::entity_t o = ecs_observer_init(world, &desc);
|
||||
ecs_add_pair(world, o, EcsChildOf, entity);
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
struct entity_observer_factory {
|
||||
template <typename Evt, if_t<is_empty<Evt>::value> = 0>
|
||||
static void create(
|
||||
flecs::world_t *world,
|
||||
flecs::entity_t entity,
|
||||
Func&& f)
|
||||
{
|
||||
using Delegate = _::entity_observer_delegate<Func>;
|
||||
auto ctx = FLECS_NEW(Delegate)(FLECS_FWD(f));
|
||||
entity_observer_create(world, _::cpp_type<Evt>::id(world), entity, Delegate::run, ctx,
|
||||
reinterpret_cast<ecs_ctx_free_t>(_::free_obj<Delegate>));
|
||||
}
|
||||
|
||||
template <typename Evt, if_not_t<is_empty<Evt>::value> = 0>
|
||||
static void create(
|
||||
flecs::world_t *world,
|
||||
flecs::entity_t entity,
|
||||
Func&& f)
|
||||
{
|
||||
using Delegate = _::entity_payload_observer_delegate<Func, Evt>;
|
||||
auto ctx = FLECS_NEW(Delegate)(FLECS_FWD(f));
|
||||
entity_observer_create(world, _::cpp_type<Evt>::id(world), entity, Delegate::run, ctx,
|
||||
reinterpret_cast<ecs_ctx_free_t>(_::free_obj<Delegate>));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename Self>
|
||||
template <typename Func>
|
||||
inline Self& entity_builder<Self>::observe(flecs::entity_t evt, Func&& f) {
|
||||
using Delegate = _::entity_observer_delegate<Func>;
|
||||
auto ctx = FLECS_NEW(Delegate)(FLECS_FWD(f));
|
||||
|
||||
_::entity_observer_create(m_world, evt, m_id, Delegate::run, ctx,
|
||||
reinterpret_cast<ecs_ctx_free_t>(_::free_obj<Delegate>));
|
||||
|
||||
return to_base();
|
||||
}
|
||||
|
||||
template <typename Self>
|
||||
template <typename Evt, typename Func>
|
||||
inline Self& entity_builder<Self>::observe(Func&& f) {
|
||||
_::entity_observer_factory<Func>::template create<Evt>(
|
||||
m_world, m_id, FLECS_FWD(f));
|
||||
return to_base();
|
||||
}
|
||||
|
||||
template <typename Self>
|
||||
template <typename Func>
|
||||
inline Self& entity_builder<Self>::observe(Func&& f) {
|
||||
return this->observe<_::event_from_func_t<Func>>(FLECS_FWD(f));
|
||||
}
|
||||
|
||||
inline void entity_view::emit(flecs::entity evt) {
|
||||
this->emit(evt.id());
|
||||
}
|
||||
|
||||
} // namespace flecs
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/event/mixin.inl
|
||||
* @brief Event world mixin.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup cpp_addons_event Events
|
||||
* @brief API for emitting events.
|
||||
*
|
||||
* \ingroup cpp_addons
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Create a new event.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
*
|
||||
* @param evt The event id.
|
||||
* @return Event builder.
|
||||
*/
|
||||
flecs::event_builder event(flecs::entity_t evt) const;
|
||||
|
||||
/** Create a new event.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
*
|
||||
* @tparam E The event type.
|
||||
* @return Event builder.
|
||||
*/
|
||||
template <typename E>
|
||||
flecs::event_builder_typed<E> event() const;
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/filter/builder.hpp
|
||||
* @brief Filter builder.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../utils/builder.hpp"
|
||||
#include "builder_i.hpp"
|
||||
|
||||
namespace flecs {
|
||||
namespace _ {
|
||||
template <typename ... Components>
|
||||
using filter_builder_base = builder<
|
||||
filter, ecs_filter_desc_t, filter_builder<Components...>,
|
||||
filter_builder_i, Components ...>;
|
||||
}
|
||||
|
||||
/** Filter builder.
|
||||
*
|
||||
* \ingroup cpp_filters
|
||||
*/
|
||||
template <typename ... Components>
|
||||
struct filter_builder final : _::filter_builder_base<Components...> {
|
||||
filter_builder(flecs::world_t* world, const char *name = nullptr)
|
||||
: _::filter_builder_base<Components...>(world)
|
||||
{
|
||||
_::sig<Components...>(world).populate(this);
|
||||
if (name != nullptr) {
|
||||
ecs_entity_desc_t entity_desc = {};
|
||||
entity_desc.name = name;
|
||||
entity_desc.sep = "::";
|
||||
entity_desc.root_sep = "::";
|
||||
this->m_desc.entity = ecs_entity_init(world, &entity_desc);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
void each(Func&& func) {
|
||||
this->build().each(FLECS_FWD(func));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/filter/builder_i.hpp
|
||||
* @brief Filter builder interface.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../term/builder_i.hpp"
|
||||
|
||||
namespace flecs
|
||||
{
|
||||
|
||||
/** Filter builder interface.
|
||||
*
|
||||
* \ingroup cpp_filters
|
||||
*/
|
||||
template<typename Base, typename ... Components>
|
||||
struct filter_builder_i : term_builder_i<Base> {
|
||||
filter_builder_i(ecs_filter_desc_t *desc, int32_t term_index = 0)
|
||||
: m_term_index(term_index)
|
||||
, m_expr_count(0)
|
||||
, m_desc(desc) { }
|
||||
|
||||
Base& instanced() {
|
||||
m_desc->instanced = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Base& filter_flags(ecs_flags32_t flags) {
|
||||
m_desc->flags |= flags;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Base& expr(const char *expr) {
|
||||
ecs_check(m_expr_count == 0, ECS_INVALID_OPERATION,
|
||||
"filter_builder::expr() called more than once");
|
||||
m_desc->expr = expr;
|
||||
m_expr_count ++;
|
||||
|
||||
error:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* With/without shorthand notation. */
|
||||
|
||||
template <typename ... Args>
|
||||
Base& with(Args&&... args) {
|
||||
return this->term(FLECS_FWD(args)...).inout_none();
|
||||
}
|
||||
|
||||
template <typename T, typename ... Args>
|
||||
Base& with(Args&&... args) {
|
||||
return this->term<T>(FLECS_FWD(args)...).inout_none();
|
||||
}
|
||||
|
||||
template <typename First, typename Second>
|
||||
Base& with() {
|
||||
return this->term<First, Second>().inout_none();
|
||||
}
|
||||
|
||||
template <typename ... Args>
|
||||
Base& without(Args&&... args) {
|
||||
return this->term(FLECS_FWD(args)...).not_();
|
||||
}
|
||||
|
||||
template <typename T, typename ... Args>
|
||||
Base& without(Args&&... args) {
|
||||
return this->term<T>(FLECS_FWD(args)...).not_();
|
||||
}
|
||||
|
||||
template <typename First, typename Second>
|
||||
Base& without() {
|
||||
return this->term<First, Second>().not_();
|
||||
}
|
||||
|
||||
/* Write/read shorthand notation */
|
||||
|
||||
Base& write() {
|
||||
term_builder_i<Base>::write();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename ... Args>
|
||||
Base& write(Args&&... args) {
|
||||
return this->term(FLECS_FWD(args)...).write();
|
||||
}
|
||||
|
||||
template <typename T, typename ... Args>
|
||||
Base& write(Args&&... args) {
|
||||
return this->term<T>(FLECS_FWD(args)...).write();
|
||||
}
|
||||
|
||||
template <typename First, typename Second>
|
||||
Base& write() {
|
||||
return this->term<First, Second>().write();
|
||||
}
|
||||
|
||||
Base& read() {
|
||||
term_builder_i<Base>::read();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename ... Args>
|
||||
Base& read(Args&&... args) {
|
||||
return this->term(FLECS_FWD(args)...).read();
|
||||
}
|
||||
|
||||
template <typename T, typename ... Args>
|
||||
Base& read(Args&&... args) {
|
||||
return this->term<T>(FLECS_FWD(args)...).read();
|
||||
}
|
||||
|
||||
template <typename First, typename Second>
|
||||
Base& read() {
|
||||
return this->term<First, Second>().read();
|
||||
}
|
||||
|
||||
/* Scope_open/scope_close shorthand notation. */
|
||||
Base& scope_open() {
|
||||
return this->with(flecs::ScopeOpen).entity(0);
|
||||
}
|
||||
|
||||
Base& scope_close() {
|
||||
return this->with(flecs::ScopeClose).entity(0);
|
||||
}
|
||||
|
||||
/* Term notation for more complex query features */
|
||||
|
||||
Base& term() {
|
||||
if (this->m_term) {
|
||||
ecs_check(ecs_term_is_initialized(this->m_term),
|
||||
ECS_INVALID_OPERATION,
|
||||
"filter_builder::term() called without initializing term");
|
||||
}
|
||||
|
||||
if (m_term_index >= FLECS_TERM_DESC_MAX) {
|
||||
if (m_term_index == FLECS_TERM_DESC_MAX) {
|
||||
m_desc->terms_buffer = ecs_os_calloc_n(
|
||||
ecs_term_t, m_term_index + 1);
|
||||
ecs_os_memcpy_n(m_desc->terms_buffer, m_desc->terms,
|
||||
ecs_term_t, m_term_index);
|
||||
ecs_os_memset_n(m_desc->terms, 0,
|
||||
ecs_term_t, FLECS_TERM_DESC_MAX);
|
||||
} else {
|
||||
m_desc->terms_buffer = ecs_os_realloc_n(m_desc->terms_buffer,
|
||||
ecs_term_t, m_term_index + 1);
|
||||
}
|
||||
|
||||
m_desc->terms_buffer_count = m_term_index + 1;
|
||||
|
||||
this->set_term(&m_desc->terms_buffer[m_term_index]);
|
||||
} else {
|
||||
this->set_term(&m_desc->terms[m_term_index]);
|
||||
}
|
||||
|
||||
m_term_index ++;
|
||||
|
||||
error:
|
||||
return *this;
|
||||
}
|
||||
|
||||
Base& term_at(int32_t term_index) {
|
||||
ecs_assert(term_index > 0, ECS_INVALID_PARAMETER, NULL);
|
||||
int32_t prev_index = m_term_index;
|
||||
m_term_index = term_index - 1;
|
||||
this->term();
|
||||
m_term_index = prev_index;
|
||||
ecs_assert(ecs_term_is_initialized(this->m_term),
|
||||
ECS_INVALID_PARAMETER, NULL);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Base& arg(int32_t term_index) {
|
||||
return this->term_at(term_index);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Base& term() {
|
||||
this->term();
|
||||
*this->m_term = flecs::term(_::cpp_type<T>::id(this->world_v())).move();
|
||||
this->m_term->inout = static_cast<ecs_inout_kind_t>(
|
||||
_::type_to_inout<T>());
|
||||
return *this;
|
||||
}
|
||||
|
||||
Base& term(id_t id) {
|
||||
this->term();
|
||||
*this->m_term = flecs::term(id).move();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Base& term(const char *name) {
|
||||
this->term();
|
||||
*this->m_term = flecs::term().first(name).move();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Base& term(const char *first, const char *second) {
|
||||
this->term();
|
||||
*this->m_term = flecs::term().first(first).second(second).move();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Base& term(entity_t r, entity_t o) {
|
||||
this->term();
|
||||
*this->m_term = flecs::term(r, o).move();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Base& term(entity_t r, const char *o) {
|
||||
this->term();
|
||||
*this->m_term = flecs::term(r).second(o).move();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename First>
|
||||
Base& term(id_t o) {
|
||||
return this->term(_::cpp_type<First>::id(this->world_v()), o);
|
||||
}
|
||||
|
||||
template<typename First>
|
||||
Base& term(const char *second) {
|
||||
return this->term(_::cpp_type<First>::id(this->world_v())).second(second);
|
||||
}
|
||||
|
||||
template<typename First, typename Second>
|
||||
Base& term() {
|
||||
return this->term<First>(_::cpp_type<Second>::id(this->world_v()));
|
||||
}
|
||||
|
||||
template <typename E, if_t< is_enum<E>::value > = 0>
|
||||
Base& term(E value) {
|
||||
flecs::entity_t r = _::cpp_type<E>::id(this->world_v());
|
||||
auto o = enum_type<E>(this->world_v()).entity(value);
|
||||
return this->term(r, o);
|
||||
}
|
||||
|
||||
Base& term(flecs::term& term) {
|
||||
this->term();
|
||||
*this->m_term = term.move();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Base& term(flecs::term&& term) {
|
||||
this->term();
|
||||
*this->m_term = term.move();
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual flecs::world_t* world_v() = 0;
|
||||
int32_t m_term_index;
|
||||
int32_t m_expr_count;
|
||||
|
||||
private:
|
||||
operator Base&() {
|
||||
return *static_cast<Base*>(this);
|
||||
}
|
||||
|
||||
ecs_filter_desc_t *m_desc;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/filter/decl.hpp
|
||||
* @brief Filter declarations.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/**
|
||||
* @defgroup cpp_core_filters Filters
|
||||
* @brief Filters are cheaper to create, but slower to iterate than flecs::query.
|
||||
*
|
||||
* \ingroup cpp_core
|
||||
* @{
|
||||
*/
|
||||
|
||||
struct filter_base;
|
||||
|
||||
template<typename ... Components>
|
||||
struct filter;
|
||||
|
||||
template<typename ... Components>
|
||||
struct filter_builder;
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/filter/impl.hpp
|
||||
* @brief Filter implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "builder.hpp"
|
||||
|
||||
namespace flecs
|
||||
{
|
||||
|
||||
struct filter_base {
|
||||
filter_base()
|
||||
: m_world(nullptr)
|
||||
, m_filter({})
|
||||
, m_filter_ptr(nullptr) { }
|
||||
|
||||
filter_base(world_t *world, const ecs_filter_t *filter)
|
||||
: m_world(world)
|
||||
, m_filter({})
|
||||
, m_filter_ptr(filter) { }
|
||||
|
||||
filter_base(world_t *world, ecs_filter_t *filter)
|
||||
: m_world(world)
|
||||
, m_filter_ptr(&m_filter) {
|
||||
ecs_filter_move(&m_filter, filter);
|
||||
}
|
||||
|
||||
filter_base(world_t *world, ecs_filter_desc_t *desc)
|
||||
: m_world(world)
|
||||
{
|
||||
desc->storage = &m_filter;
|
||||
|
||||
if (ecs_filter_init(world, desc) == NULL) {
|
||||
ecs_abort(ECS_INVALID_PARAMETER, NULL);
|
||||
}
|
||||
|
||||
if (desc->terms_buffer) {
|
||||
ecs_os_free(desc->terms_buffer);
|
||||
}
|
||||
|
||||
m_filter_ptr = &m_filter;
|
||||
}
|
||||
|
||||
filter_base(const filter_base& obj) {
|
||||
this->m_world = obj.m_world;
|
||||
if (obj.m_filter_ptr) {
|
||||
this->m_filter_ptr = &this->m_filter;
|
||||
} else {
|
||||
this->m_filter_ptr = nullptr;
|
||||
}
|
||||
ecs_filter_copy(&m_filter, &obj.m_filter);
|
||||
}
|
||||
|
||||
filter_base& operator=(const filter_base& obj) {
|
||||
this->m_world = obj.m_world;
|
||||
if (obj.m_filter_ptr) {
|
||||
this->m_filter_ptr = &this->m_filter;
|
||||
} else {
|
||||
this->m_filter_ptr = nullptr;
|
||||
}
|
||||
ecs_filter_copy(&m_filter, &obj.m_filter);
|
||||
return *this;
|
||||
}
|
||||
|
||||
filter_base(filter_base&& obj) {
|
||||
this->m_world = obj.m_world;
|
||||
if (obj.m_filter_ptr) {
|
||||
this->m_filter_ptr = &this->m_filter;
|
||||
} else {
|
||||
this->m_filter_ptr = nullptr;
|
||||
}
|
||||
ecs_filter_move(&m_filter, &obj.m_filter);
|
||||
}
|
||||
|
||||
filter_base& operator=(filter_base&& obj) {
|
||||
this->m_world = obj.m_world;
|
||||
if (obj.m_filter_ptr) {
|
||||
this->m_filter_ptr = &this->m_filter;
|
||||
} else {
|
||||
this->m_filter_ptr = nullptr;
|
||||
}
|
||||
ecs_filter_move(&m_filter, &obj.m_filter);
|
||||
return *this;
|
||||
}
|
||||
|
||||
flecs::entity entity() {
|
||||
return flecs::entity(m_world, ecs_get_entity(m_filter_ptr));
|
||||
}
|
||||
|
||||
operator const flecs::filter_t*() const {
|
||||
return m_filter_ptr;
|
||||
}
|
||||
|
||||
/** Free the filter.
|
||||
*/
|
||||
~filter_base() {
|
||||
if ((&m_filter == m_filter_ptr) && m_filter_ptr) {
|
||||
ecs_filter_fini(&m_filter);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
void each_term(const Func& func) {
|
||||
for (int i = 0; i < m_filter_ptr->term_count; i ++) {
|
||||
flecs::term t(m_world, m_filter_ptr->terms[i]);
|
||||
func(t);
|
||||
t.reset(); // prevent freeing resources
|
||||
}
|
||||
}
|
||||
|
||||
flecs::term term(int32_t index) {
|
||||
return flecs::term(m_world, m_filter_ptr->terms[index]);
|
||||
}
|
||||
|
||||
int32_t field_count() {
|
||||
return m_filter_ptr->term_count;
|
||||
}
|
||||
|
||||
flecs::string str() {
|
||||
char *result = ecs_filter_str(m_world, m_filter_ptr);
|
||||
return flecs::string(result);
|
||||
}
|
||||
|
||||
operator filter<>() const;
|
||||
|
||||
protected:
|
||||
world_t *m_world = nullptr;
|
||||
filter_t m_filter = ECS_FILTER_INIT;
|
||||
const filter_t *m_filter_ptr;
|
||||
};
|
||||
|
||||
template<typename ... Components>
|
||||
struct filter : filter_base, iterable<Components...> {
|
||||
private:
|
||||
using Terms = typename _::term_ptrs<Components...>::array;
|
||||
|
||||
public:
|
||||
using filter_base::filter_base;
|
||||
|
||||
filter() : filter_base() { } // necessary not to confuse msvc
|
||||
|
||||
filter(const filter& obj) : filter_base(obj) { }
|
||||
|
||||
filter& operator=(const filter& obj) {
|
||||
filter_base::operator=(obj);
|
||||
return *this;
|
||||
}
|
||||
|
||||
filter(filter&& obj) : filter_base(FLECS_MOV(obj)) { }
|
||||
|
||||
filter& operator=(filter&& obj) {
|
||||
filter_base::operator=(FLECS_FWD(obj));
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
ecs_iter_t get_iter(flecs::world_t *world) const override {
|
||||
if (!world) {
|
||||
world = m_world;
|
||||
}
|
||||
return ecs_filter_iter(world, m_filter_ptr);
|
||||
}
|
||||
|
||||
ecs_iter_next_action_t next_action() const override {
|
||||
return ecs_filter_next;
|
||||
}
|
||||
|
||||
ecs_iter_next_action_t next_each_action() const override {
|
||||
return ecs_filter_next_instanced;
|
||||
}
|
||||
};
|
||||
|
||||
// World mixin implementation
|
||||
template <typename... Comps, typename... Args>
|
||||
inline flecs::filter<Comps...> world::filter(Args &&... args) const {
|
||||
return flecs::filter_builder<Comps...>(m_world, FLECS_FWD(args)...)
|
||||
.build();
|
||||
}
|
||||
|
||||
template <typename... Comps, typename... Args>
|
||||
inline flecs::filter_builder<Comps...> world::filter_builder(Args &&... args) const {
|
||||
return flecs::filter_builder<Comps...>(m_world, FLECS_FWD(args)...);
|
||||
}
|
||||
|
||||
// world::each
|
||||
namespace _ {
|
||||
|
||||
// Each with entity parameter
|
||||
template<typename Func, typename ... Args>
|
||||
struct filter_delegate_w_ent;
|
||||
|
||||
template<typename Func, typename E, typename ... Args>
|
||||
struct filter_delegate_w_ent<Func, arg_list<E, Args ...> >
|
||||
{
|
||||
filter_delegate_w_ent(const flecs::world& world, Func&& func) {
|
||||
auto f = world.filter<Args ...>();
|
||||
f.each(FLECS_MOV(func));
|
||||
}
|
||||
};
|
||||
|
||||
// Each without entity parameter
|
||||
template<typename Func, typename ... Args>
|
||||
struct filter_delegate_no_ent;
|
||||
|
||||
template<typename Func, typename ... Args>
|
||||
struct filter_delegate_no_ent<Func, arg_list<Args ...> >
|
||||
{
|
||||
filter_delegate_no_ent(const flecs::world& world, Func&& func) {
|
||||
auto f = world.filter<Args ...>();
|
||||
f.each(FLECS_MOV(func));
|
||||
}
|
||||
};
|
||||
|
||||
// Switch between function with & without entity parameter
|
||||
template<typename Func, typename T = int>
|
||||
struct filter_delegate;
|
||||
|
||||
template <typename Func>
|
||||
struct filter_delegate<Func, if_t<is_same<first_arg_t<Func>, flecs::entity>::value> > {
|
||||
filter_delegate(const flecs::world& world, Func&& func) {
|
||||
filter_delegate_w_ent<Func, arg_list_t<Func>>(world, FLECS_MOV(func));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Func>
|
||||
struct filter_delegate<Func, if_not_t<is_same<first_arg_t<Func>, flecs::entity>::value> > {
|
||||
filter_delegate(const flecs::world& world, Func&& func) {
|
||||
filter_delegate_no_ent<Func, arg_list_t<Func>>(world, FLECS_MOV(func));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
inline void world::each(Func&& func) const {
|
||||
_::filter_delegate<Func> f_delegate(*this, FLECS_MOV(func));
|
||||
}
|
||||
|
||||
template <typename T, typename Func>
|
||||
inline void world::each(Func&& func) const {
|
||||
ecs_term_t t = {};
|
||||
t.id = _::cpp_type<T>::id();
|
||||
ecs_iter_t it = ecs_term_iter(m_world, &t);
|
||||
|
||||
while (ecs_term_next(&it)) {
|
||||
_::each_delegate<Func, T>(func).invoke(&it);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
inline void world::each(flecs::id_t term_id, Func&& func) const {
|
||||
ecs_term_t t = {};
|
||||
t.id = term_id;
|
||||
ecs_iter_t it = ecs_term_iter(m_world, &t);
|
||||
|
||||
while (ecs_term_next(&it)) {
|
||||
_::each_delegate<Func>(func).invoke(&it);
|
||||
}
|
||||
}
|
||||
|
||||
// filter_base implementation
|
||||
inline filter_base::operator flecs::filter<> () const {
|
||||
flecs::filter<> f;
|
||||
ecs_filter_copy(&f.m_filter, &this->m_filter);
|
||||
f.m_filter_ptr = &f.m_filter;
|
||||
f.m_world = this->m_world;
|
||||
return f;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/filter/mixin.inl
|
||||
* @brief Filter world mixin.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_core_filters
|
||||
*/
|
||||
|
||||
/** Create a filter.
|
||||
*
|
||||
* @see ecs_filter_init
|
||||
*/
|
||||
template <typename... Comps, typename... Args>
|
||||
flecs::filter<Comps...> filter(Args &&... args) const;
|
||||
|
||||
/** Create a filter builder.
|
||||
*
|
||||
* @see ecs_filter_init
|
||||
*/
|
||||
template <typename... Comps, typename... Args>
|
||||
flecs::filter_builder<Comps...> filter_builder(Args &&... args) const;
|
||||
|
||||
/** Iterate over all entities with components in argument list of function.
|
||||
* The function parameter must match the following signature:
|
||||
* void(*)(T&, U&, ...) or
|
||||
* void(*)(flecs::entity, T&, U&, ...)
|
||||
*
|
||||
*/
|
||||
template <typename Func>
|
||||
void each(Func&& func) const;
|
||||
|
||||
/** Iterate over all entities with provided component.
|
||||
* The function parameter must match the following signature:
|
||||
* void(*)(T&) or
|
||||
* void(*)(flecs::entity, T&)
|
||||
*
|
||||
*/
|
||||
template <typename T, typename Func>
|
||||
void each(Func&& func) const;
|
||||
|
||||
/** Iterate over all entities with provided (component) id. */
|
||||
template <typename Func>
|
||||
void each(flecs::id_t term_id, Func&& func) const;
|
||||
|
||||
/** @} */
|
||||
148
engine/libs/flecs/include/flecs/addons/cpp/mixins/id/decl.hpp
Normal file
148
engine/libs/flecs/include/flecs/addons/cpp/mixins/id/decl.hpp
Normal file
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/id/decl.hpp
|
||||
* @brief Id class.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
struct id;
|
||||
struct entity;
|
||||
|
||||
/**
|
||||
* @defgroup cpp_ids Ids
|
||||
* @brief Class for working with entity, component, tag and pair ids.
|
||||
*
|
||||
* \ingroup cpp_core
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Class that wraps around a flecs::id_t.
|
||||
* A flecs id is an identifier that can be added to entities. Ids can be:
|
||||
* - entities (including components, tags)
|
||||
* - pair ids
|
||||
* - entities with id flags set (like flecs::Override, flecs::Toggle)
|
||||
*/
|
||||
struct id {
|
||||
id()
|
||||
: m_world(nullptr)
|
||||
, m_id(0) { }
|
||||
|
||||
explicit id(flecs::id_t value)
|
||||
: m_world(nullptr)
|
||||
, m_id(value) { }
|
||||
|
||||
explicit id(flecs::world_t *world, flecs::id_t value = 0)
|
||||
: m_world(world)
|
||||
, m_id(value) { }
|
||||
|
||||
explicit id(flecs::world_t *world, flecs::id_t first, flecs::id_t second)
|
||||
: m_world(world)
|
||||
, m_id(ecs_pair(first, second)) { }
|
||||
|
||||
explicit id(flecs::id_t first, flecs::id_t second)
|
||||
: m_world(nullptr)
|
||||
, m_id(ecs_pair(first, second)) { }
|
||||
|
||||
explicit id(const flecs::id& first, const flecs::id& second)
|
||||
: m_world(first.m_world)
|
||||
, m_id(ecs_pair(first.m_id, second.m_id)) { }
|
||||
|
||||
/** Test if id is pair (has first, second) */
|
||||
bool is_pair() const {
|
||||
return (m_id & ECS_ID_FLAGS_MASK) == flecs::Pair;
|
||||
}
|
||||
|
||||
/** Test if id is a wildcard */
|
||||
bool is_wildcard() const {
|
||||
return ecs_id_is_wildcard(m_id);
|
||||
}
|
||||
|
||||
/** Test if id is entity */
|
||||
bool is_entity() const {
|
||||
return !(m_id & ECS_ID_FLAGS_MASK);
|
||||
}
|
||||
|
||||
/** Return id as entity (only allowed when id is valid entity) */
|
||||
flecs::entity entity() const;
|
||||
|
||||
/** Return id with role added */
|
||||
flecs::entity add_flags(flecs::id_t flags) const;
|
||||
|
||||
/** Return id with role removed */
|
||||
flecs::entity remove_flags(flecs::id_t flags) const;
|
||||
|
||||
/** Return id without role */
|
||||
flecs::entity remove_flags() const;
|
||||
|
||||
/** Return id without role */
|
||||
flecs::entity remove_generation() const;
|
||||
|
||||
/** Return component type of id */
|
||||
flecs::entity type_id() const;
|
||||
|
||||
/** Test if id has specified role */
|
||||
bool has_flags(flecs::id_t flags) const {
|
||||
return ((m_id & flags) == flags);
|
||||
}
|
||||
|
||||
/** Test if id has any role */
|
||||
bool has_flags() const {
|
||||
return (m_id & ECS_ID_FLAGS_MASK) != 0;
|
||||
}
|
||||
|
||||
/** Return id flags set on id */
|
||||
flecs::entity flags() const;
|
||||
|
||||
/** Test if id has specified first */
|
||||
bool has_relation(flecs::id_t first) const {
|
||||
if (!is_pair()) {
|
||||
return false;
|
||||
}
|
||||
return ECS_PAIR_FIRST(m_id) == first;
|
||||
}
|
||||
|
||||
/** Get first element from a pair.
|
||||
* If the id is not a pair, this operation will fail. When the id has a
|
||||
* world, the operation will ensure that the returned id has the correct
|
||||
* generation count. */
|
||||
flecs::entity first() const;
|
||||
|
||||
/** Get second element from a pair.
|
||||
* If the id is not a pair, this operation will fail. When the id has a
|
||||
* world, the operation will ensure that the returned id has the correct
|
||||
* generation count. */
|
||||
flecs::entity second() const;
|
||||
|
||||
/* Convert id to string */
|
||||
flecs::string str() const {
|
||||
return flecs::string(ecs_id_str(m_world, m_id));
|
||||
}
|
||||
|
||||
/** Convert role of id to string. */
|
||||
flecs::string flags_str() const {
|
||||
return flecs::string_view( ecs_id_flag_str(m_id & ECS_ID_FLAGS_MASK));
|
||||
}
|
||||
|
||||
/** Return flecs::id_t value */
|
||||
flecs::id_t raw_id() const {
|
||||
return m_id;
|
||||
}
|
||||
|
||||
operator flecs::id_t() const {
|
||||
return m_id;
|
||||
}
|
||||
|
||||
flecs::world world() const;
|
||||
|
||||
protected:
|
||||
/* World is optional, but guarantees that entity identifiers extracted from
|
||||
* the id are valid */
|
||||
flecs::world_t *m_world;
|
||||
flecs::id_t m_id;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
109
engine/libs/flecs/include/flecs/addons/cpp/mixins/id/impl.hpp
Normal file
109
engine/libs/flecs/include/flecs/addons/cpp/mixins/id/impl.hpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/id/impl.hpp
|
||||
* @brief Id class implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
inline flecs::entity id::entity() const {
|
||||
ecs_assert(!is_pair(), ECS_INVALID_OPERATION, NULL);
|
||||
ecs_assert(!flags(), ECS_INVALID_OPERATION, NULL);
|
||||
return flecs::entity(m_world, m_id);
|
||||
}
|
||||
|
||||
inline flecs::entity id::flags() const {
|
||||
return flecs::entity(m_world, m_id & ECS_ID_FLAGS_MASK);
|
||||
}
|
||||
|
||||
inline flecs::entity id::first() const {
|
||||
ecs_assert(is_pair(), ECS_INVALID_OPERATION, NULL);
|
||||
|
||||
flecs::entity_t e = ECS_PAIR_FIRST(m_id);
|
||||
if (m_world) {
|
||||
return flecs::entity(m_world, ecs_get_alive(m_world, e));
|
||||
} else {
|
||||
return flecs::entity(e);
|
||||
}
|
||||
}
|
||||
|
||||
inline flecs::entity id::second() const {
|
||||
flecs::entity_t e = ECS_PAIR_SECOND(m_id);
|
||||
if (m_world) {
|
||||
return flecs::entity(m_world, ecs_get_alive(m_world, e));
|
||||
} else {
|
||||
return flecs::entity(e);
|
||||
}
|
||||
}
|
||||
|
||||
inline flecs::entity id::add_flags(flecs::id_t flags) const {
|
||||
return flecs::entity(m_world, m_id | flags);
|
||||
}
|
||||
|
||||
inline flecs::entity id::remove_flags(flecs::id_t flags) const {
|
||||
(void)flags;
|
||||
ecs_assert((m_id & ECS_ID_FLAGS_MASK) == flags, ECS_INVALID_PARAMETER, NULL);
|
||||
return flecs::entity(m_world, m_id & ECS_COMPONENT_MASK);
|
||||
}
|
||||
|
||||
inline flecs::entity id::remove_flags() const {
|
||||
return flecs::entity(m_world, m_id & ECS_COMPONENT_MASK);
|
||||
}
|
||||
|
||||
inline flecs::entity id::remove_generation() const {
|
||||
return flecs::entity(m_world, static_cast<uint32_t>(m_id));
|
||||
}
|
||||
|
||||
inline flecs::world id::world() const {
|
||||
return flecs::world(m_world);
|
||||
}
|
||||
|
||||
inline flecs::entity id::type_id() const {
|
||||
return flecs::entity(m_world, ecs_get_typeid(m_world, m_id));
|
||||
}
|
||||
|
||||
|
||||
// Id mixin implementation
|
||||
|
||||
template <typename T>
|
||||
inline flecs::id world::id() const {
|
||||
return flecs::id(m_world, _::cpp_type<T>::id(m_world));
|
||||
}
|
||||
|
||||
template <typename ... Args>
|
||||
inline flecs::id world::id(Args&&... args) const {
|
||||
return flecs::id(m_world, FLECS_FWD(args)...);
|
||||
}
|
||||
|
||||
template <typename First, typename Second>
|
||||
inline flecs::id world::pair() const {
|
||||
return flecs::id(
|
||||
m_world,
|
||||
ecs_pair(
|
||||
_::cpp_type<First>::id(m_world),
|
||||
_::cpp_type<Second>::id(m_world)));
|
||||
}
|
||||
|
||||
template <typename First>
|
||||
inline flecs::id world::pair(entity_t o) const {
|
||||
ecs_assert(!ECS_IS_PAIR(o), ECS_INVALID_PARAMETER,
|
||||
"cannot create nested pairs");
|
||||
|
||||
return flecs::id(
|
||||
m_world,
|
||||
ecs_pair(
|
||||
_::cpp_type<First>::id(m_world),
|
||||
o));
|
||||
}
|
||||
|
||||
inline flecs::id world::pair(entity_t r, entity_t o) const {
|
||||
ecs_assert(!ECS_IS_PAIR(r) && !ECS_IS_PAIR(o), ECS_INVALID_PARAMETER,
|
||||
"cannot create nested pairs");
|
||||
|
||||
return flecs::id(
|
||||
m_world,
|
||||
ecs_pair(r, o));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/id/mixin.inl
|
||||
* @brief Id world mixin.
|
||||
*/
|
||||
|
||||
/** Get id from a type.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
*/
|
||||
template <typename T>
|
||||
flecs::id id() const;
|
||||
|
||||
/** Id factory.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
*/
|
||||
template <typename ... Args>
|
||||
flecs::id id(Args&&... args) const;
|
||||
|
||||
/** Get pair id from relationship, object.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
*/
|
||||
template <typename First, typename Second>
|
||||
flecs::id pair() const;
|
||||
|
||||
/** Get pair id from relationship, object.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
*/
|
||||
template <typename First>
|
||||
flecs::id pair(entity_t o) const;
|
||||
|
||||
/** Get pair id from relationship, object.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
*/
|
||||
flecs::id pair(entity_t r, entity_t o) const;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/json/decl.hpp
|
||||
* @brief JSON addon declarations.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/**
|
||||
* @defgroup cpp_addons_json Json
|
||||
* @brief Functions for serializing to/from JSON.
|
||||
*
|
||||
* \ingroup cpp_addons
|
||||
* @{
|
||||
*/
|
||||
|
||||
using from_json_desc_t = ecs_from_json_desc_t;
|
||||
using entity_to_json_desc_t = ecs_entity_to_json_desc_t;
|
||||
using iter_to_json_desc_t = ecs_iter_to_json_desc_t;
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
/** Deserialize entity to JSON.
|
||||
*
|
||||
* \memberof flecs::entity
|
||||
* \ingroup cpp_addons_json
|
||||
*/
|
||||
const char* from_json(const char *json) {
|
||||
return ecs_entity_from_json(m_world, m_id, json, nullptr);
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/json/entity_builder.inl
|
||||
* @brief JSON entity mixin.
|
||||
*/
|
||||
|
||||
/** Set component from JSON.
|
||||
*
|
||||
* \memberof flecs::entity_builder
|
||||
* \ingroup cpp_addons_json
|
||||
*/
|
||||
Self& set_json(
|
||||
flecs::id_t e,
|
||||
const char *json,
|
||||
flecs::from_json_desc_t *desc = nullptr)
|
||||
{
|
||||
flecs::entity_t type = ecs_get_typeid(m_world, e);
|
||||
if (!type) {
|
||||
ecs_err("id is not a type");
|
||||
return to_base();
|
||||
}
|
||||
|
||||
void *ptr = ecs_get_mut_id(m_world, m_id, e);
|
||||
ecs_assert(ptr != NULL, ECS_INTERNAL_ERROR, NULL);
|
||||
ecs_ptr_from_json(m_world, type, ptr, json, desc);
|
||||
ecs_modified_id(m_world, m_id, e);
|
||||
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Set pair from JSON.
|
||||
*
|
||||
* \memberof flecs::entity_builder
|
||||
* \ingroup cpp_addons_json
|
||||
*/
|
||||
Self& set_json(
|
||||
flecs::entity_t r,
|
||||
flecs::entity_t t,
|
||||
const char *json,
|
||||
flecs::from_json_desc_t *desc = nullptr)
|
||||
{
|
||||
return set_json(ecs_pair(r, t), json, desc);
|
||||
}
|
||||
|
||||
/** Set component from JSON.
|
||||
*
|
||||
* \memberof flecs::entity_builder
|
||||
* \ingroup cpp_addons_json
|
||||
*/
|
||||
template <typename T>
|
||||
Self& set_json(
|
||||
const char *json,
|
||||
flecs::from_json_desc_t *desc = nullptr)
|
||||
{
|
||||
return set_json(_::cpp_type<T>::id(m_world), json, desc);
|
||||
}
|
||||
|
||||
/** Set pair from JSON.
|
||||
*
|
||||
* \memberof flecs::entity_builder
|
||||
* \ingroup cpp_addons_json
|
||||
*/
|
||||
template <typename R, typename T>
|
||||
Self& set_json(
|
||||
const char *json,
|
||||
flecs::from_json_desc_t *desc = nullptr)
|
||||
{
|
||||
return set_json(
|
||||
_::cpp_type<R>::id(m_world),
|
||||
_::cpp_type<T>::id(m_world),
|
||||
json, desc);
|
||||
}
|
||||
|
||||
/** Set pair from JSON.
|
||||
*
|
||||
* \memberof flecs::entity_builder
|
||||
* \ingroup cpp_addons_json
|
||||
*/
|
||||
template <typename R>
|
||||
Self& set_json(
|
||||
flecs::entity_t t,
|
||||
const char *json,
|
||||
flecs::from_json_desc_t *desc = nullptr)
|
||||
{
|
||||
return set_json(
|
||||
_::cpp_type<R>::id(m_world), t,
|
||||
json, desc);
|
||||
}
|
||||
|
||||
/** Set pair from JSON.
|
||||
*
|
||||
* \memberof flecs::entity_builder
|
||||
* \ingroup cpp_addons_json
|
||||
*/
|
||||
template <typename T>
|
||||
Self& set_json_second(
|
||||
flecs::entity_t r,
|
||||
const char *json,
|
||||
flecs::from_json_desc_t *desc = nullptr)
|
||||
{
|
||||
return set_json(
|
||||
r, _::cpp_type<T>::id(m_world),
|
||||
json, desc);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/json/entity_view.inl
|
||||
* @brief JSON entity mixin.
|
||||
*/
|
||||
|
||||
/** Serialize entity to JSON.
|
||||
*
|
||||
* \memberof flecs::entity_view
|
||||
* \ingroup cpp_addons_json
|
||||
*/
|
||||
flecs::string to_json(const flecs::entity_to_json_desc_t *desc = nullptr) {
|
||||
char *json = ecs_entity_to_json(m_world, m_id, desc);
|
||||
return flecs::string(json);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/json/iterable.inl
|
||||
* @brief JSON iterable mixin.
|
||||
*/
|
||||
|
||||
/** Serialize iterator result to JSON.
|
||||
*
|
||||
* \memberof flecs::iter
|
||||
* \ingroup cpp_addons_json
|
||||
*/
|
||||
flecs::string to_json(flecs::iter_to_json_desc_t *desc = nullptr) {
|
||||
char *json = ecs_iter_to_json(m_it.real_world, &m_it, desc);
|
||||
return flecs::string(json);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/json/world.inl
|
||||
* @brief JSON world mixin.
|
||||
*/
|
||||
|
||||
/** Serialize untyped value to JSON.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_addons_json
|
||||
*/
|
||||
flecs::string to_json(flecs::entity_t tid, const void* value) {
|
||||
char *json = ecs_ptr_to_json(m_world, tid, value);
|
||||
return flecs::string(json);
|
||||
}
|
||||
|
||||
/** Serialize value to JSON.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_addons_json
|
||||
*/
|
||||
template <typename T>
|
||||
flecs::string to_json(const T* value) {
|
||||
flecs::entity_t tid = _::cpp_type<T>::id(m_world);
|
||||
return to_json(tid, value);
|
||||
}
|
||||
|
||||
/** Serialize world to JSON.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_addons_json
|
||||
*/
|
||||
flecs::string to_json() {
|
||||
return flecs::string( ecs_world_to_json(m_world, nullptr) );
|
||||
}
|
||||
|
||||
/** Deserialize value from JSON.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_addons_json
|
||||
*/
|
||||
const char* from_json(flecs::entity_t tid, void* value, const char *json, flecs::from_json_desc_t *desc = nullptr) {
|
||||
return ecs_ptr_from_json(m_world, tid, value, json, desc);
|
||||
}
|
||||
|
||||
/** Deserialize value from JSON.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_addons_json
|
||||
*/
|
||||
template <typename T>
|
||||
const char* from_json(T* value, const char *json, flecs::from_json_desc_t *desc = nullptr) {
|
||||
return ecs_ptr_from_json(m_world, _::cpp_type<T>::id(m_world),
|
||||
value, json, desc);
|
||||
}
|
||||
|
||||
/** Deserialize JSON into world.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_addons_json
|
||||
*/
|
||||
const char* from_json(const char *json, flecs::from_json_desc_t *desc = nullptr) {
|
||||
return ecs_world_from_json(m_world, json, desc);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
/** Register opaque type interface */
|
||||
template <typename Func>
|
||||
component& opaque(const Func& type_support) {
|
||||
flecs::world world(m_world);
|
||||
auto ts = type_support(world);
|
||||
ts.desc.entity = _::cpp_type<T>::id(m_world);
|
||||
ecs_opaque_init(m_world, &ts.desc);
|
||||
return *this;
|
||||
}
|
||||
|
||||
flecs::opaque<T> opaque(flecs::entity_t as_type) {
|
||||
return flecs::opaque<T>(m_world).as_type(as_type);
|
||||
}
|
||||
|
||||
flecs::opaque<T> opaque(flecs::entity as_type) {
|
||||
return this->opaque(as_type.id());
|
||||
}
|
||||
|
||||
flecs::opaque<T> opaque(flecs::untyped_component as_type) {
|
||||
return this->opaque(as_type.id());
|
||||
}
|
||||
|
||||
/** Return opaque type builder for collection type */
|
||||
template <typename ElemType>
|
||||
flecs::opaque<T, ElemType> opaque(flecs::id_t as_type) {
|
||||
return flecs::opaque<T, ElemType>(m_world).as_type(as_type);
|
||||
}
|
||||
|
||||
/** Add constant. */
|
||||
component<T>& constant(const char *name, T value) {
|
||||
int32_t v = static_cast<int32_t>(value);
|
||||
untyped_component::constant(name, v);
|
||||
return *this;
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/meta/opaque.hpp
|
||||
* @brief Helpers for opaque type registration.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/**
|
||||
* @defgroup cpp_addons_meta Meta
|
||||
* @brief Flecs reflection framework.
|
||||
*
|
||||
* \ingroup cpp_addons
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Class for reading/writing dynamic values.
|
||||
*
|
||||
* \ingroup cpp_addons_meta
|
||||
*/
|
||||
struct cursor {
|
||||
cursor(flecs::world_t *world, flecs::entity_t type_id, void *ptr) {
|
||||
m_cursor = ecs_meta_cursor(world, type_id, ptr);
|
||||
}
|
||||
|
||||
/** Push value scope (such as a nested struct) */
|
||||
int push() {
|
||||
return ecs_meta_push(&m_cursor);
|
||||
}
|
||||
|
||||
/** Pop value scope */
|
||||
int pop() {
|
||||
return ecs_meta_pop(&m_cursor);
|
||||
}
|
||||
|
||||
/** Move to next member/element */
|
||||
int next() {
|
||||
return ecs_meta_next(&m_cursor);
|
||||
}
|
||||
|
||||
/** Move to member by name */
|
||||
int member(const char *name) {
|
||||
return ecs_meta_member(&m_cursor, name);
|
||||
}
|
||||
|
||||
/** Move to element by index */
|
||||
int elem(int32_t elem) {
|
||||
return ecs_meta_elem(&m_cursor, elem);
|
||||
}
|
||||
|
||||
/** Test if current scope is a collection type */
|
||||
bool is_collection() {
|
||||
return ecs_meta_is_collection(&m_cursor);
|
||||
}
|
||||
|
||||
/** Get member name */
|
||||
flecs::string_view get_member() const {
|
||||
return flecs::string_view(ecs_meta_get_member(&m_cursor));
|
||||
}
|
||||
|
||||
/** Get type of value */
|
||||
flecs::entity get_type() const;
|
||||
|
||||
/** Get unit of value */
|
||||
flecs::entity get_unit() const;
|
||||
|
||||
/** Get untyped pointer to value */
|
||||
void* get_ptr() {
|
||||
return ecs_meta_get_ptr(&m_cursor);
|
||||
}
|
||||
|
||||
/** Set boolean value */
|
||||
int set_bool(bool value) {
|
||||
return ecs_meta_set_bool(&m_cursor, value);
|
||||
}
|
||||
|
||||
/** Set char value */
|
||||
int set_char(char value) {
|
||||
return ecs_meta_set_char(&m_cursor, value);
|
||||
}
|
||||
|
||||
/** Set signed int value */
|
||||
int set_int(int64_t value) {
|
||||
return ecs_meta_set_int(&m_cursor, value);
|
||||
}
|
||||
|
||||
/** Set unsigned int value */
|
||||
int set_uint(uint64_t value) {
|
||||
return ecs_meta_set_uint(&m_cursor, value);
|
||||
}
|
||||
|
||||
/** Set float value */
|
||||
int set_float(double value) {
|
||||
return ecs_meta_set_float(&m_cursor, value);
|
||||
}
|
||||
|
||||
/** Set string value */
|
||||
int set_string(const char *value) {
|
||||
return ecs_meta_set_string(&m_cursor, value);
|
||||
}
|
||||
|
||||
/** Set string literal value */
|
||||
int set_string_literal(const char *value) {
|
||||
return ecs_meta_set_string_literal(&m_cursor, value);
|
||||
}
|
||||
|
||||
/** Set entity value */
|
||||
int set_entity(flecs::entity_t value) {
|
||||
return ecs_meta_set_entity(&m_cursor, value);
|
||||
}
|
||||
|
||||
/** Set null value */
|
||||
int set_null() {
|
||||
return ecs_meta_set_null(&m_cursor);
|
||||
}
|
||||
|
||||
/** Get boolean value */
|
||||
bool get_bool() const {
|
||||
return ecs_meta_get_bool(&m_cursor);
|
||||
}
|
||||
|
||||
/** Get char value */
|
||||
char get_char() const {
|
||||
return ecs_meta_get_char(&m_cursor);
|
||||
}
|
||||
|
||||
/** Get signed int value */
|
||||
int64_t get_int() const {
|
||||
return ecs_meta_get_int(&m_cursor);
|
||||
}
|
||||
|
||||
/** Get unsigned int value */
|
||||
uint64_t get_uint() const {
|
||||
return ecs_meta_get_uint(&m_cursor);
|
||||
}
|
||||
|
||||
/** Get float value */
|
||||
double get_float() const {
|
||||
return ecs_meta_get_float(&m_cursor);
|
||||
}
|
||||
|
||||
/** Get string value */
|
||||
const char *get_string() const {
|
||||
return ecs_meta_get_string(&m_cursor);
|
||||
}
|
||||
|
||||
/** Get entity value */
|
||||
flecs::entity get_entity() const;
|
||||
|
||||
/** Cursor object */
|
||||
ecs_meta_cursor_t m_cursor;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
123
engine/libs/flecs/include/flecs/addons/cpp/mixins/meta/decl.hpp
Normal file
123
engine/libs/flecs/include/flecs/addons/cpp/mixins/meta/decl.hpp
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/meta/decl.hpp
|
||||
* @brief Meta declarations.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/**
|
||||
* @defgroup cpp_addons_meta Meta
|
||||
* @brief Flecs reflection framework.
|
||||
*
|
||||
* \ingroup cpp_addons
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Primitive type aliases */
|
||||
using bool_t = ecs_bool_t;
|
||||
using char_t = ecs_char_t;
|
||||
using u8_t = ecs_u8_t;
|
||||
using u16_t = ecs_u16_t;
|
||||
using u32_t = ecs_u32_t;
|
||||
using u64_t = ecs_u64_t;
|
||||
using uptr_t = ecs_uptr_t;
|
||||
using i8_t = ecs_i8_t;
|
||||
using i16_t = ecs_i16_t;
|
||||
using i32_t = ecs_i32_t;
|
||||
using i64_t = ecs_i64_t;
|
||||
using iptr_t = ecs_iptr_t;
|
||||
using f32_t = ecs_f32_t;
|
||||
using f64_t = ecs_f64_t;
|
||||
|
||||
/* Embedded type aliases */
|
||||
using member_t = ecs_member_t;
|
||||
using enum_constant_t = ecs_enum_constant_t;
|
||||
using bitmask_constant_t = ecs_bitmask_constant_t;
|
||||
|
||||
/* Components */
|
||||
using MetaType = EcsMetaType;
|
||||
using MetaTypeSerialized = EcsMetaTypeSerialized;
|
||||
using Primitive = EcsPrimitive;
|
||||
using Enum = EcsEnum;
|
||||
using Bitmask = EcsBitmask;
|
||||
using Member = EcsMember;
|
||||
using MemberRanges = EcsMemberRanges;
|
||||
using Struct = EcsStruct;
|
||||
using Array = EcsArray;
|
||||
using Vector = EcsVector;
|
||||
using Unit = EcsUnit;
|
||||
|
||||
/** Base type for bitmasks */
|
||||
struct bitmask {
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
/* Handles to builtin reflection types */
|
||||
static const flecs::entity_t Bool = ecs_id(ecs_bool_t);
|
||||
static const flecs::entity_t Char = ecs_id(ecs_char_t);
|
||||
static const flecs::entity_t Byte = ecs_id(ecs_byte_t);
|
||||
static const flecs::entity_t U8 = ecs_id(ecs_u8_t);
|
||||
static const flecs::entity_t U16 = ecs_id(ecs_u16_t);
|
||||
static const flecs::entity_t U32 = ecs_id(ecs_u32_t);
|
||||
static const flecs::entity_t U64 = ecs_id(ecs_u64_t);
|
||||
static const flecs::entity_t Uptr = ecs_id(ecs_uptr_t);
|
||||
static const flecs::entity_t I8 = ecs_id(ecs_i8_t);
|
||||
static const flecs::entity_t I16 = ecs_id(ecs_i16_t);
|
||||
static const flecs::entity_t I32 = ecs_id(ecs_i32_t);
|
||||
static const flecs::entity_t I64 = ecs_id(ecs_i64_t);
|
||||
static const flecs::entity_t Iptr = ecs_id(ecs_iptr_t);
|
||||
static const flecs::entity_t F32 = ecs_id(ecs_f32_t);
|
||||
static const flecs::entity_t F64 = ecs_id(ecs_f64_t);
|
||||
static const flecs::entity_t String = ecs_id(ecs_string_t);
|
||||
static const flecs::entity_t Entity = ecs_id(ecs_entity_t);
|
||||
static const flecs::entity_t Constant = EcsConstant;
|
||||
static const flecs::entity_t Quantity = EcsQuantity;
|
||||
|
||||
namespace meta {
|
||||
|
||||
/* Type kinds supported by reflection system */
|
||||
using type_kind_t = ecs_type_kind_t;
|
||||
static const type_kind_t PrimitiveType = EcsPrimitiveType;
|
||||
static const type_kind_t BitmaskType = EcsBitmaskType;
|
||||
static const type_kind_t EnumType = EcsEnumType;
|
||||
static const type_kind_t StructType = EcsStructType;
|
||||
static const type_kind_t ArrayType = EcsArrayType;
|
||||
static const type_kind_t VectorType = EcsVectorType;
|
||||
static const type_kind_t CustomType = EcsOpaqueType;
|
||||
static const type_kind_t TypeKindLast = EcsTypeKindLast;
|
||||
|
||||
/* Primitive type kinds supported by reflection system */
|
||||
using primitive_kind_t = ecs_primitive_kind_t;
|
||||
static const primitive_kind_t Bool = EcsBool;
|
||||
static const primitive_kind_t Char = EcsChar;
|
||||
static const primitive_kind_t Byte = EcsByte;
|
||||
static const primitive_kind_t U8 = EcsU8;
|
||||
static const primitive_kind_t U16 = EcsU16;
|
||||
static const primitive_kind_t U32 = EcsU32;
|
||||
static const primitive_kind_t U64 = EcsU64;
|
||||
static const primitive_kind_t I8 = EcsI8;
|
||||
static const primitive_kind_t I16 = EcsI16;
|
||||
static const primitive_kind_t I32 = EcsI32;
|
||||
static const primitive_kind_t I64 = EcsI64;
|
||||
static const primitive_kind_t F32 = EcsF32;
|
||||
static const primitive_kind_t F64 = EcsF64;
|
||||
static const primitive_kind_t UPtr = EcsUPtr;
|
||||
static const primitive_kind_t IPtr = EcsIPtr;
|
||||
static const primitive_kind_t String = EcsString;
|
||||
static const primitive_kind_t Entity = EcsEntity;
|
||||
static const primitive_kind_t PrimitiveKindLast = EcsPrimitiveKindLast;
|
||||
|
||||
/** @} */
|
||||
|
||||
namespace _ {
|
||||
|
||||
void init(flecs::world& world);
|
||||
|
||||
} // namespace _
|
||||
} // namespace meta
|
||||
} // namespace flecs
|
||||
|
||||
#include "cursor.hpp"
|
||||
#include "opaque.hpp"
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/meta/entity_builder.inl
|
||||
* @brief Meta entity builder mixin.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \memberof flecs::entity_view
|
||||
* \ingroup cpp_addons_meta
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Make entity a unit */
|
||||
Self& unit(
|
||||
const char *symbol,
|
||||
flecs::entity_t prefix = 0,
|
||||
flecs::entity_t base = 0,
|
||||
flecs::entity_t over = 0,
|
||||
int32_t factor = 0,
|
||||
int32_t power = 0)
|
||||
{
|
||||
ecs_unit_desc_t desc = {};
|
||||
desc.entity = this->m_id;
|
||||
desc.symbol = const_cast<char*>(symbol); /* safe, will be copied in */
|
||||
desc.base = base;
|
||||
desc.over = over;
|
||||
desc.prefix = prefix;
|
||||
desc.translation.factor = factor;
|
||||
desc.translation.power = power;
|
||||
ecs_unit_init(this->world(), &desc);
|
||||
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Make entity a derived unit */
|
||||
Self& unit(
|
||||
flecs::entity_t prefix = 0,
|
||||
flecs::entity_t base = 0,
|
||||
flecs::entity_t over = 0,
|
||||
int32_t factor = 0,
|
||||
int32_t power = 0)
|
||||
{
|
||||
ecs_unit_desc_t desc = {};
|
||||
desc.entity = this->m_id;
|
||||
desc.base = base;
|
||||
desc.over = over;
|
||||
desc.prefix = prefix;
|
||||
desc.translation.factor = factor;
|
||||
desc.translation.power = power;
|
||||
ecs_unit_init(this->world(), &desc);
|
||||
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Make entity a derived unit */
|
||||
Self& unit_prefix(
|
||||
const char *symbol,
|
||||
int32_t factor = 0,
|
||||
int32_t power = 0)
|
||||
{
|
||||
ecs_unit_prefix_desc_t desc = {};
|
||||
desc.entity = this->m_id;
|
||||
desc.symbol = const_cast<char*>(symbol); /* safe, will be copied in */
|
||||
desc.translation.factor = factor;
|
||||
desc.translation.power = power;
|
||||
ecs_unit_prefix_init(this->world(), &desc);
|
||||
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Add quantity to unit */
|
||||
Self& quantity(flecs::entity_t quantity) {
|
||||
ecs_add_pair(this->world(), this->id(), flecs::Quantity, quantity);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** Make entity a unity prefix */
|
||||
template <typename Quantity>
|
||||
Self& quantity() {
|
||||
return this->quantity(_::cpp_type<Quantity>::id(this->world()));
|
||||
}
|
||||
|
||||
/** Make entity a quantity */
|
||||
Self& quantity() {
|
||||
ecs_add_id(this->world(), this->id(), flecs::Quantity);
|
||||
return to_base();
|
||||
}
|
||||
|
||||
/** @} */
|
||||
161
engine/libs/flecs/include/flecs/addons/cpp/mixins/meta/impl.hpp
Normal file
161
engine/libs/flecs/include/flecs/addons/cpp/mixins/meta/impl.hpp
Normal file
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/meta/impl.hpp
|
||||
* @brief Meta implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
FLECS_ENUM_LAST(flecs::meta::type_kind_t, flecs::meta::TypeKindLast)
|
||||
FLECS_ENUM_LAST(flecs::meta::primitive_kind_t, flecs::meta::PrimitiveKindLast)
|
||||
|
||||
namespace flecs {
|
||||
namespace meta {
|
||||
namespace _ {
|
||||
|
||||
/* Type support for entity wrappers */
|
||||
template <typename EntityType>
|
||||
inline flecs::opaque<EntityType> flecs_entity_support(flecs::world&) {
|
||||
return flecs::opaque<EntityType>()
|
||||
.as_type(flecs::Entity)
|
||||
.serialize([](const flecs::serializer *ser, const EntityType *data) {
|
||||
flecs::entity_t id = data->id();
|
||||
return ser->value(flecs::Entity, &id);
|
||||
})
|
||||
.assign_entity(
|
||||
[](EntityType *dst, flecs::world_t *world, flecs::entity_t e) {
|
||||
*dst = EntityType(world, e);
|
||||
});
|
||||
}
|
||||
|
||||
inline void init(flecs::world& world) {
|
||||
world.component<bool_t>("flecs::meta::bool");
|
||||
world.component<char_t>("flecs::meta::char");
|
||||
world.component<u8_t>("flecs::meta::u8");
|
||||
world.component<u16_t>("flecs::meta::u16");
|
||||
world.component<u32_t>("flecs::meta::u32");
|
||||
world.component<u64_t>("flecs::meta::u64");
|
||||
world.component<i8_t>("flecs::meta::i8");
|
||||
world.component<i16_t>("flecs::meta::i16");
|
||||
world.component<i32_t>("flecs::meta::i32");
|
||||
world.component<i64_t>("flecs::meta::i64");
|
||||
world.component<f32_t>("flecs::meta::f32");
|
||||
world.component<f64_t>("flecs::meta::f64");
|
||||
|
||||
world.component<type_kind_t>("flecs::meta::type_kind");
|
||||
world.component<primitive_kind_t>("flecs::meta::primitive_kind");
|
||||
world.component<member_t>("flecs::meta::member");
|
||||
world.component<enum_constant_t>("flecs::meta::enum_constant");
|
||||
world.component<bitmask_constant_t>("flecs::meta::bitmask_constant");
|
||||
|
||||
world.component<MetaType>("flecs::meta::MetaType");
|
||||
world.component<MetaTypeSerialized>("flecs::meta::MetaTypeSerialized");
|
||||
world.component<Primitive>("flecs::meta::Primitive");
|
||||
world.component<Enum>("flecs::meta::Enum");
|
||||
world.component<Bitmask>("flecs::meta::Bitmask");
|
||||
world.component<Member>("flecs::meta::Member");
|
||||
world.component<Struct>("flecs::meta::Struct");
|
||||
world.component<Array>("flecs::meta::Array");
|
||||
world.component<Vector>("flecs::meta::Vector");
|
||||
|
||||
world.component<Unit>("flecs::meta::Unit");
|
||||
|
||||
// To support member<uintptr_t> and member<intptr_t> register components
|
||||
// (that do not have conflicting symbols with builtin ones) for platform
|
||||
// specific types.
|
||||
|
||||
if (!flecs::is_same<i32_t, iptr_t>() && !flecs::is_same<i64_t, iptr_t>()) {
|
||||
flecs::_::cpp_type<iptr_t>::init(flecs::Iptr, true);
|
||||
ecs_assert(flecs::type_id<iptr_t>() == flecs::Iptr,
|
||||
ECS_INTERNAL_ERROR, NULL);
|
||||
// Remove symbol to prevent validation errors, as it doesn't match with
|
||||
// the typename
|
||||
ecs_remove_pair(world, flecs::Iptr, ecs_id(EcsIdentifier), EcsSymbol);
|
||||
}
|
||||
|
||||
if (!flecs::is_same<u32_t, uptr_t>() && !flecs::is_same<u64_t, uptr_t>()) {
|
||||
flecs::_::cpp_type<uptr_t>::init(flecs::Uptr, true);
|
||||
ecs_assert(flecs::type_id<uptr_t>() == flecs::Uptr,
|
||||
ECS_INTERNAL_ERROR, NULL);
|
||||
// Remove symbol to prevent validation errors, as it doesn't match with
|
||||
// the typename
|
||||
ecs_remove_pair(world, flecs::Uptr, ecs_id(EcsIdentifier), EcsSymbol);
|
||||
}
|
||||
|
||||
// Register opaque type support for C++ entity wrappers
|
||||
world.component<flecs::entity_view>()
|
||||
.opaque(flecs_entity_support<flecs::entity_view>);
|
||||
|
||||
world.component<flecs::entity>()
|
||||
.opaque(flecs_entity_support<flecs::entity>);
|
||||
}
|
||||
|
||||
} // namespace _
|
||||
|
||||
} // namespace meta
|
||||
|
||||
|
||||
inline flecs::entity cursor::get_type() const {
|
||||
return flecs::entity(m_cursor.world, ecs_meta_get_type(&m_cursor));
|
||||
}
|
||||
|
||||
inline flecs::entity cursor::get_unit() const {
|
||||
return flecs::entity(m_cursor.world, ecs_meta_get_unit(&m_cursor));
|
||||
}
|
||||
|
||||
inline flecs::entity cursor::get_entity() const {
|
||||
return flecs::entity(m_cursor.world, ecs_meta_get_entity(&m_cursor));
|
||||
}
|
||||
|
||||
/** Create primitive type */
|
||||
inline flecs::entity world::primitive(flecs::meta::primitive_kind_t kind) {
|
||||
ecs_primitive_desc_t desc = {};
|
||||
desc.kind = kind;
|
||||
flecs::entity_t eid = ecs_primitive_init(m_world, &desc);
|
||||
ecs_assert(eid != 0, ECS_INVALID_OPERATION, NULL);
|
||||
return flecs::entity(m_world, eid);
|
||||
}
|
||||
|
||||
/** Create array type. */
|
||||
inline flecs::entity world::array(flecs::entity_t elem_id, int32_t array_count) {
|
||||
ecs_array_desc_t desc = {};
|
||||
desc.type = elem_id;
|
||||
desc.count = array_count;
|
||||
flecs::entity_t eid = ecs_array_init(m_world, &desc);
|
||||
ecs_assert(eid != 0, ECS_INVALID_OPERATION, NULL);
|
||||
return flecs::entity(m_world, eid);
|
||||
}
|
||||
|
||||
/** Create array type. */
|
||||
template <typename T>
|
||||
inline flecs::entity world::array(int32_t array_count) {
|
||||
return this->array(_::cpp_type<T>::id(m_world), array_count);
|
||||
}
|
||||
|
||||
inline flecs::entity world::vector(flecs::entity_t elem_id) {
|
||||
ecs_vector_desc_t desc = {};
|
||||
desc.type = elem_id;
|
||||
flecs::entity_t eid = ecs_vector_init(m_world, &desc);
|
||||
ecs_assert(eid != 0, ECS_INVALID_OPERATION, NULL);
|
||||
return flecs::entity(m_world, eid);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline flecs::entity world::vector() {
|
||||
return this->vector(_::cpp_type<T>::id(m_world));
|
||||
}
|
||||
|
||||
} // namespace flecs
|
||||
|
||||
inline int ecs_serializer_t::value(ecs_entity_t type, const void *v) const {
|
||||
return this->value_(this, type, v);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline int ecs_serializer_t::value(const T& v) const {
|
||||
return this->value(flecs::_::cpp_type<T>::id(
|
||||
const_cast<flecs::world_t*>(this->world)), &v);
|
||||
}
|
||||
|
||||
inline int ecs_serializer_t::member(const char *name) const {
|
||||
return this->member_(this, name);
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/meta/opaque.hpp
|
||||
* @brief Helpers for opaque type registration.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/**
|
||||
* @defgroup cpp_addons_meta Meta
|
||||
* @brief Flecs reflection framework.
|
||||
*
|
||||
* \ingroup cpp_addons
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Serializer object, used for serializing opaque types */
|
||||
using serializer = ecs_serializer_t;
|
||||
|
||||
/** Serializer function, used to serialize opaque types */
|
||||
using serialize_t = ecs_meta_serialize_t;
|
||||
|
||||
/** Type safe variant of serializer function */
|
||||
template <typename T>
|
||||
using serialize = int(*)(const serializer *, const T*);
|
||||
|
||||
/** Type safe interface for opaque types */
|
||||
template <typename T, typename ElemType = void>
|
||||
struct opaque {
|
||||
opaque(flecs::world_t *w = nullptr) : world(w) {
|
||||
if (world) {
|
||||
desc.entity = _::cpp_type<T>::id(world);
|
||||
}
|
||||
}
|
||||
|
||||
/** Type that describes the type kind/structure of the opaque type */
|
||||
opaque& as_type(flecs::id_t func) {
|
||||
this->desc.type.as_type = func;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Serialize function */
|
||||
opaque& serialize(flecs::serialize<T> func) {
|
||||
this->desc.type.serialize =
|
||||
reinterpret_cast<decltype(
|
||||
this->desc.type.serialize)>(func);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Assign bool value */
|
||||
opaque& assign_bool(void (*func)(T *dst, bool value)) {
|
||||
this->desc.type.assign_bool =
|
||||
reinterpret_cast<decltype(
|
||||
this->desc.type.assign_bool)>(func);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Assign char value */
|
||||
opaque& assign_char(void (*func)(T *dst, char value)) {
|
||||
this->desc.type.assign_char =
|
||||
reinterpret_cast<decltype(
|
||||
this->desc.type.assign_char)>(func);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Assign int value */
|
||||
opaque& assign_int(void (*func)(T *dst, int64_t value)) {
|
||||
this->desc.type.assign_int =
|
||||
reinterpret_cast<decltype(
|
||||
this->desc.type.assign_int)>(func);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Assign unsigned int value */
|
||||
opaque& assign_uint(void (*func)(T *dst, uint64_t value)) {
|
||||
this->desc.type.assign_uint =
|
||||
reinterpret_cast<decltype(
|
||||
this->desc.type.assign_uint)>(func);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Assign float value */
|
||||
opaque& assign_float(void (*func)(T *dst, double value)) {
|
||||
this->desc.type.assign_float =
|
||||
reinterpret_cast<decltype(
|
||||
this->desc.type.assign_float)>(func);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Assign string value */
|
||||
opaque& assign_string(void (*func)(T *dst, const char *value)) {
|
||||
this->desc.type.assign_string =
|
||||
reinterpret_cast<decltype(
|
||||
this->desc.type.assign_string)>(func);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Assign entity value */
|
||||
opaque& assign_entity(
|
||||
void (*func)(T *dst, ecs_world_t *world, ecs_entity_t entity))
|
||||
{
|
||||
this->desc.type.assign_entity =
|
||||
reinterpret_cast<decltype(
|
||||
this->desc.type.assign_entity)>(func);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Assign null value */
|
||||
opaque& assign_null(void (*func)(T *dst)) {
|
||||
this->desc.type.assign_null =
|
||||
reinterpret_cast<decltype(
|
||||
this->desc.type.assign_null)>(func);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Clear collection elements */
|
||||
opaque& clear(void (*func)(T *dst)) {
|
||||
this->desc.type.clear =
|
||||
reinterpret_cast<decltype(
|
||||
this->desc.type.clear)>(func);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Ensure & get collection element */
|
||||
opaque& ensure_element(ElemType* (*func)(T *dst, size_t elem)) {
|
||||
this->desc.type.ensure_element =
|
||||
reinterpret_cast<decltype(
|
||||
this->desc.type.ensure_element)>(func);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Ensure & get element */
|
||||
opaque& ensure_member(void* (*func)(T *dst, const char *member)) {
|
||||
this->desc.type.ensure_member =
|
||||
reinterpret_cast<decltype(
|
||||
this->desc.type.ensure_member)>(func);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Return number of elements */
|
||||
opaque& count(size_t (*func)(const T *dst)) {
|
||||
this->desc.type.count =
|
||||
reinterpret_cast<decltype(
|
||||
this->desc.type.count)>(func);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Resize to number of elements */
|
||||
opaque& resize(void (*func)(T *dst, size_t count)) {
|
||||
this->desc.type.resize =
|
||||
reinterpret_cast<decltype(
|
||||
this->desc.type.resize)>(func);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~opaque() {
|
||||
if (world) {
|
||||
ecs_opaque_init(world, &desc);
|
||||
}
|
||||
}
|
||||
|
||||
/** Opaque type descriptor */
|
||||
flecs::world_t *world = nullptr;
|
||||
ecs_opaque_desc_t desc = {};
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/meta/untyped_component.inl
|
||||
* @brief Meta component mixin.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \memberof flecs::component
|
||||
* \ingroup cpp_addons_meta
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Add member with unit. */
|
||||
untyped_component& member(flecs::entity_t type_id, flecs::entity_t unit, const char *name, int32_t count = 0, size_t offset = 0) {
|
||||
ecs_entity_desc_t desc = {};
|
||||
desc.name = name;
|
||||
desc.add[0] = ecs_pair(flecs::ChildOf, m_id);
|
||||
ecs_entity_t eid = ecs_entity_init(m_world, &desc);
|
||||
ecs_assert(eid != 0, ECS_INTERNAL_ERROR, NULL);
|
||||
|
||||
flecs::entity e(m_world, eid);
|
||||
|
||||
Member m = {};
|
||||
m.type = type_id;
|
||||
m.unit = unit;
|
||||
m.count = count;
|
||||
m.offset = static_cast<int32_t>(offset);
|
||||
e.set<Member>(m);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Add member. */
|
||||
untyped_component& member(flecs::entity_t type_id, const char* name, int32_t count = 0, size_t offset = 0) {
|
||||
return member(type_id, 0, name, count, offset);
|
||||
}
|
||||
|
||||
/** Add member. */
|
||||
template <typename MemberType>
|
||||
untyped_component& member(const char *name, int32_t count = 0, size_t offset = 0) {
|
||||
flecs::entity_t type_id = _::cpp_type<MemberType>::id(m_world);
|
||||
return member(type_id, name, count, offset);
|
||||
}
|
||||
|
||||
/** Add member with unit. */
|
||||
template <typename MemberType>
|
||||
untyped_component& member(flecs::entity_t unit, const char *name, int32_t count = 0, size_t offset = 0) {
|
||||
flecs::entity_t type_id = _::cpp_type<MemberType>::id(m_world);
|
||||
return member(type_id, unit, name, count, offset);
|
||||
}
|
||||
|
||||
/** Add member with unit. */
|
||||
template <typename MemberType, typename UnitType>
|
||||
untyped_component& member(const char *name, int32_t count = 0, size_t offset = 0) {
|
||||
flecs::entity_t type_id = _::cpp_type<MemberType>::id(m_world);
|
||||
flecs::entity_t unit_id = _::cpp_type<UnitType>::id(m_world);
|
||||
return member(type_id, unit_id, name, count, offset);
|
||||
}
|
||||
|
||||
/** Add member using pointer-to-member. */
|
||||
template <typename MemberType, typename ComponentType, typename RealType = typename std::remove_extent<MemberType>::type>
|
||||
untyped_component& member(const char* name, const MemberType ComponentType::* ptr) {
|
||||
flecs::entity_t type_id = _::cpp_type<RealType>::id(m_world);
|
||||
size_t offset = reinterpret_cast<size_t>(&(static_cast<ComponentType*>(nullptr)->*ptr));
|
||||
return member(type_id, name, std::extent<MemberType>::value, offset);
|
||||
}
|
||||
|
||||
/** Add member with unit using pointer-to-member. */
|
||||
template <typename MemberType, typename ComponentType, typename RealType = typename std::remove_extent<MemberType>::type>
|
||||
untyped_component& member(flecs::entity_t unit, const char* name, const MemberType ComponentType::* ptr) {
|
||||
flecs::entity_t type_id = _::cpp_type<RealType>::id(m_world);
|
||||
size_t offset = reinterpret_cast<size_t>(&(static_cast<ComponentType*>(nullptr)->*ptr));
|
||||
return member(type_id, unit, name, std::extent<MemberType>::value, offset);
|
||||
}
|
||||
|
||||
/** Add member with unit using pointer-to-member. */
|
||||
template <typename UnitType, typename MemberType, typename ComponentType, typename RealType = typename std::remove_extent<MemberType>::type>
|
||||
untyped_component& member(const char* name, const MemberType ComponentType::* ptr) {
|
||||
flecs::entity_t type_id = _::cpp_type<RealType>::id(m_world);
|
||||
flecs::entity_t unit_id = _::cpp_type<UnitType>::id(m_world);
|
||||
size_t offset = reinterpret_cast<size_t>(&(static_cast<ComponentType*>(nullptr)->*ptr));
|
||||
return member(type_id, unit_id, name, std::extent<MemberType>::value, offset);
|
||||
}
|
||||
|
||||
/** Add constant. */
|
||||
untyped_component& constant(const char *name, int32_t value) {
|
||||
ecs_add_id(m_world, m_id, _::cpp_type<flecs::Enum>::id(m_world));
|
||||
|
||||
ecs_entity_desc_t desc = {};
|
||||
desc.name = name;
|
||||
desc.add[0] = ecs_pair(flecs::ChildOf, m_id);
|
||||
ecs_entity_t eid = ecs_entity_init(m_world, &desc);
|
||||
ecs_assert(eid != 0, ECS_INTERNAL_ERROR, NULL);
|
||||
|
||||
ecs_set_id(m_world, eid,
|
||||
ecs_pair(flecs::Constant, flecs::I32), sizeof(int32_t),
|
||||
&value);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Add bitmask constant. */
|
||||
untyped_component& bit(const char *name, uint32_t value) {
|
||||
ecs_add_id(m_world, m_id, _::cpp_type<flecs::Bitmask>::id(m_world));
|
||||
|
||||
ecs_entity_desc_t desc = {};
|
||||
desc.name = name;
|
||||
desc.add[0] = ecs_pair(flecs::ChildOf, m_id);
|
||||
ecs_entity_t eid = ecs_entity_init(m_world, &desc);
|
||||
ecs_assert(eid != 0, ECS_INTERNAL_ERROR, NULL);
|
||||
|
||||
ecs_set_id(m_world, eid,
|
||||
ecs_pair(flecs::Constant, flecs::U32), sizeof(uint32_t),
|
||||
&value);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Register array metadata for component */
|
||||
template <typename Elem>
|
||||
untyped_component& array(int32_t elem_count) {
|
||||
ecs_array_desc_t desc = {};
|
||||
desc.entity = m_id;
|
||||
desc.type = _::cpp_type<Elem>::id(m_world);
|
||||
desc.count = elem_count;
|
||||
ecs_array_init(m_world, &desc);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Add member value range */
|
||||
untyped_component& range(double min, double max) {
|
||||
const flecs::member_t *m = ecs_cpp_last_member(m_world, m_id);
|
||||
if (!m) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
flecs::world w(m_world);
|
||||
flecs::entity me = w.entity(m->member);
|
||||
flecs::MemberRanges *mr = me.get_mut<flecs::MemberRanges>();
|
||||
mr->value.min = min;
|
||||
mr->value.max = max;
|
||||
me.modified<flecs::MemberRanges>();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Add member warning range */
|
||||
untyped_component& warning_range(double min, double max) {
|
||||
const flecs::member_t *m = ecs_cpp_last_member(m_world, m_id);
|
||||
if (!m) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
flecs::world w(m_world);
|
||||
flecs::entity me = w.entity(m->member);
|
||||
flecs::MemberRanges *mr = me.get_mut<flecs::MemberRanges>();
|
||||
mr->warning.min = min;
|
||||
mr->warning.max = max;
|
||||
me.modified<flecs::MemberRanges>();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Add member error range */
|
||||
untyped_component& error_range(double min, double max) {
|
||||
const flecs::member_t *m = ecs_cpp_last_member(m_world, m_id);
|
||||
if (!m) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
flecs::world w(m_world);
|
||||
flecs::entity me = w.entity(m->member);
|
||||
flecs::MemberRanges *mr = me.get_mut<flecs::MemberRanges>();
|
||||
mr->error.min = min;
|
||||
mr->error.max = max;
|
||||
me.modified<flecs::MemberRanges>();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/meta/world.inl
|
||||
* @brief Meta world mixin.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_addons_meta
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Convert value to string */
|
||||
flecs::string to_expr(flecs::entity_t tid, const void* value) {
|
||||
char *expr = ecs_ptr_to_expr(m_world, tid, value);
|
||||
return flecs::string(expr);
|
||||
}
|
||||
|
||||
/** Convert value to string */
|
||||
template <typename T>
|
||||
flecs::string to_expr(const T* value) {
|
||||
flecs::entity_t tid = _::cpp_type<T>::id(m_world);
|
||||
return to_expr(tid, value);
|
||||
}
|
||||
|
||||
/** Return meta cursor to value */
|
||||
flecs::cursor cursor(flecs::entity_t tid, void *ptr) {
|
||||
return flecs::cursor(m_world, tid, ptr);
|
||||
}
|
||||
|
||||
/** Return meta cursor to value */
|
||||
template <typename T>
|
||||
flecs::cursor cursor(void *ptr) {
|
||||
flecs::entity_t tid = _::cpp_type<T>::id(m_world);
|
||||
return cursor(tid, ptr);
|
||||
}
|
||||
|
||||
/** Create primitive type */
|
||||
flecs::entity primitive(flecs::meta::primitive_kind_t kind);
|
||||
|
||||
/** Create array type. */
|
||||
flecs::entity array(flecs::entity_t elem_id, int32_t array_count);
|
||||
|
||||
/** Create array type. */
|
||||
template <typename T>
|
||||
flecs::entity array(int32_t array_count);
|
||||
|
||||
/** Create vector type. */
|
||||
flecs::entity vector(flecs::entity_t elem_id);
|
||||
|
||||
/** Create vector type. */
|
||||
template <typename T>
|
||||
flecs::entity vector();
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/metrics/builder.hpp
|
||||
* @brief Metric builder.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define ECS_EVENT_DESC_ID_COUNT_MAX (8)
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/**
|
||||
* \ingroup cpp_addon_metrics
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Event builder interface */
|
||||
struct metric_builder {
|
||||
metric_builder(flecs::world_t *world, flecs::entity_t entity)
|
||||
: m_world(world)
|
||||
{
|
||||
m_desc.entity = entity;
|
||||
}
|
||||
|
||||
~metric_builder();
|
||||
|
||||
metric_builder& member(flecs::entity_t e) {
|
||||
m_desc.member = e;
|
||||
return *this;
|
||||
}
|
||||
|
||||
metric_builder& member(const char *name);
|
||||
|
||||
template <typename T>
|
||||
metric_builder& member(const char *name);
|
||||
|
||||
metric_builder& dotmember(const char *name);
|
||||
|
||||
template <typename T>
|
||||
metric_builder& dotmember(const char *name);
|
||||
|
||||
metric_builder& id(flecs::id_t the_id) {
|
||||
m_desc.id = the_id;
|
||||
return *this;
|
||||
}
|
||||
|
||||
metric_builder& id(flecs::entity_t first, flecs::entity_t second) {
|
||||
m_desc.id = ecs_pair(first, second);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
metric_builder& id() {
|
||||
return id(_::cpp_type<T>::id(m_world));
|
||||
}
|
||||
|
||||
template <typename First>
|
||||
metric_builder& id(flecs::entity_t second) {
|
||||
return id(_::cpp_type<First>::id(m_world), second);
|
||||
}
|
||||
|
||||
template <typename Second>
|
||||
metric_builder& id_second(flecs::entity_t first) {
|
||||
return id(first, _::cpp_type<Second>::id(m_world));
|
||||
}
|
||||
|
||||
template <typename First, typename Second>
|
||||
metric_builder& id() {
|
||||
return id<First>(_::cpp_type<Second>::id(m_world));
|
||||
}
|
||||
|
||||
metric_builder& targets(bool value = true) {
|
||||
m_desc.targets = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
metric_builder& kind(flecs::entity_t the_kind) {
|
||||
m_desc.kind = the_kind;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Kind>
|
||||
metric_builder& kind() {
|
||||
return kind(_::cpp_type<Kind>::id(m_world));
|
||||
}
|
||||
|
||||
metric_builder& brief(const char *b) {
|
||||
m_desc.brief = b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator flecs::entity();
|
||||
|
||||
protected:
|
||||
flecs::world_t *m_world;
|
||||
ecs_metric_desc_t m_desc = {};
|
||||
bool m_created = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/metrics/decl.hpp
|
||||
* @brief Metrics declarations.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "builder.hpp"
|
||||
|
||||
namespace flecs {
|
||||
|
||||
struct metrics {
|
||||
using Value = EcsMetricValue;
|
||||
using Source = EcsMetricSource;
|
||||
|
||||
struct Instance { };
|
||||
struct Metric { };
|
||||
struct Counter { };
|
||||
struct CounterIncrement { };
|
||||
struct CounterId { };
|
||||
struct Gauge { };
|
||||
|
||||
metrics(flecs::world& world);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/metrics/impl.hpp
|
||||
* @brief Metrics module implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
inline metrics::metrics(flecs::world& world) {
|
||||
world.import<flecs::units>();
|
||||
|
||||
/* Import C module */
|
||||
FlecsMetricsImport(world);
|
||||
|
||||
world.entity<metrics::Instance>("::flecs::metrics::Instance");
|
||||
world.entity<metrics::Metric>("::flecs::metrics::Metric");
|
||||
world.entity<metrics::Counter>("::flecs::metrics::Metric::Counter");
|
||||
world.entity<metrics::CounterId>("::flecs::metrics::Metric::CounterId");
|
||||
world.entity<metrics::CounterIncrement>("::flecs::metrics::Metric::CounterIncrement");
|
||||
world.entity<metrics::Gauge>("::flecs::metrics::Metric::Gauge");
|
||||
}
|
||||
|
||||
inline metric_builder::~metric_builder() {
|
||||
if (!m_created) {
|
||||
ecs_metric_init(m_world, &m_desc);
|
||||
}
|
||||
}
|
||||
|
||||
inline metric_builder& metric_builder::member(const char *name) {
|
||||
flecs::entity m;
|
||||
if (m_desc.id) {
|
||||
flecs::entity_t type = ecs_get_typeid(m_world, m_desc.id);
|
||||
m = flecs::entity(m_world, type).lookup(name);
|
||||
} else {
|
||||
m = flecs::world(m_world).lookup(name);
|
||||
}
|
||||
if (!m) {
|
||||
flecs::log::err("member '%s' not found", name);
|
||||
}
|
||||
return member(m);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline metric_builder& metric_builder::member(const char *name) {
|
||||
flecs::entity e (m_world, _::cpp_type<T>::id(m_world));
|
||||
flecs::entity_t m = e.lookup(name);
|
||||
if (!m) {
|
||||
flecs::log::err("member '%s' not found in type '%s'",
|
||||
name, e.path().c_str());
|
||||
return *this;
|
||||
}
|
||||
return member(m);
|
||||
}
|
||||
|
||||
inline metric_builder& metric_builder::dotmember(const char *expr) {
|
||||
m_desc.dotmember = expr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline metric_builder& metric_builder::dotmember(const char *expr) {
|
||||
m_desc.dotmember = expr;
|
||||
m_desc.id = _::cpp_type<T>::id(m_world);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline metric_builder::operator flecs::entity() {
|
||||
if (!m_created) {
|
||||
m_created = true;
|
||||
flecs::entity result(m_world, ecs_metric_init(m_world, &m_desc));
|
||||
m_desc.entity = result;
|
||||
return result;
|
||||
} else {
|
||||
return flecs::entity(m_world, m_desc.entity);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline flecs::metric_builder world::metric(Args &&... args) const {
|
||||
flecs::entity result(m_world, FLECS_FWD(args)...);
|
||||
return flecs::metric_builder(m_world, result);
|
||||
}
|
||||
|
||||
template <typename Kind>
|
||||
inline untyped_component& untyped_component::metric(
|
||||
flecs::entity_t parent,
|
||||
const char *brief,
|
||||
const char *metric_name)
|
||||
{
|
||||
flecs::world w(m_world);
|
||||
flecs::entity e(m_world, m_id);
|
||||
|
||||
const flecs::member_t *m = ecs_cpp_last_member(w, e);
|
||||
if (!m) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
flecs::entity me = w.entity(m->member);
|
||||
flecs::entity metric_entity = me;
|
||||
if (parent) {
|
||||
const char *component_name = e.name();
|
||||
if (!metric_name) {
|
||||
if (ecs_os_strcmp(m->name, "value") || !component_name) {
|
||||
metric_entity = w.scope(parent).entity(m->name);
|
||||
} else {
|
||||
// If name of member is "value", use name of type.
|
||||
char *snake_name = flecs_to_snake_case(component_name);
|
||||
metric_entity = w.scope(parent).entity(snake_name);
|
||||
ecs_os_free(snake_name);
|
||||
}
|
||||
} else {
|
||||
metric_entity = w.scope(parent).entity(metric_name);
|
||||
}
|
||||
}
|
||||
|
||||
w.metric(metric_entity).member(me).kind<Kind>().brief(brief);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
/** Create metric.
|
||||
*
|
||||
* \ingroup cpp_addons_metrics
|
||||
* \memberof flecs::world
|
||||
*/
|
||||
template <typename... Args>
|
||||
flecs::metric_builder metric(Args &&... args) const;
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/meta/untyped_component.inl
|
||||
* @brief Metrics component mixin.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \memberof flecs::component
|
||||
* \ingroup cpp_addons_metrics
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Register member as metric.
|
||||
* When no explicit name is provided, this operation will derive the metric name
|
||||
* from the member name. When the member name is "value", the operation will use
|
||||
* the name of the component.
|
||||
*
|
||||
* When the brief parameter is provided, it is set on the metric as if
|
||||
* set_doc_brief is used. The brief description can be obtained with
|
||||
* get_doc_brief.
|
||||
*
|
||||
* @tparam Kind Metric kind (Counter, CounterIncrement or Gauge).
|
||||
* @param parent Parent entity of the metric (optional).
|
||||
* @param brief Description for metric (optional).
|
||||
* @param name Name of metric (optional).
|
||||
*
|
||||
* \ingroup cpp_addons_metrics
|
||||
* \memberof flecs::world
|
||||
*/
|
||||
template <typename Kind>
|
||||
untyped_component& metric(
|
||||
flecs::entity_t parent = 0,
|
||||
const char *brief = nullptr,
|
||||
const char *name = nullptr);
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/module/impl.hpp
|
||||
* @brief Module implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
namespace _ {
|
||||
|
||||
template <typename T>
|
||||
ecs_entity_t do_import(world& world, const char *symbol) {
|
||||
ecs_trace("#[magenta]import#[reset] %s", _::type_name<T>());
|
||||
ecs_log_push();
|
||||
|
||||
ecs_entity_t scope = ecs_set_scope(world, 0);
|
||||
|
||||
// Initialize module component type & don't allow it to be registered as a
|
||||
// tag, as this would prevent calling emplace()
|
||||
auto m_c = component<T>(world, nullptr, false);
|
||||
ecs_add_id(world, m_c, EcsModule);
|
||||
|
||||
ecs_set_scope(world, m_c);
|
||||
world.emplace<T>(world);
|
||||
ecs_set_scope(world, scope);
|
||||
|
||||
// It should now be possible to lookup the module
|
||||
ecs_entity_t m = ecs_lookup_symbol(world, symbol, true, false);
|
||||
ecs_assert(m != 0, ECS_MODULE_UNDEFINED, symbol);
|
||||
ecs_assert(m == m_c, ECS_INTERNAL_ERROR, NULL);
|
||||
|
||||
ecs_log_pop();
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
flecs::entity import(world& world) {
|
||||
const char *symbol = _::symbol_name<T>();
|
||||
|
||||
ecs_entity_t m = ecs_lookup_symbol(world, symbol, true, false);
|
||||
|
||||
if (!_::cpp_type<T>::registered(world)) {
|
||||
|
||||
/* Module is registered with world, initialize static data */
|
||||
if (m) {
|
||||
_::cpp_type<T>::init(m, false);
|
||||
|
||||
/* Module is not yet registered, register it now */
|
||||
} else {
|
||||
m = _::do_import<T>(world, symbol);
|
||||
}
|
||||
|
||||
/* Module has been registered, but could have been for another world. Import
|
||||
* if module hasn't been registered for this world. */
|
||||
} else if (!m) {
|
||||
m = _::do_import<T>(world, symbol);
|
||||
}
|
||||
|
||||
return flecs::entity(world, m);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @defgroup cpp_addons_modules Modules
|
||||
* @brief Modules organize components, systems and more in reusable units of code.
|
||||
*
|
||||
* \ingroup cpp_addons
|
||||
* @{
|
||||
*/
|
||||
|
||||
template <typename Module>
|
||||
inline flecs::entity world::module(const char *name) const {
|
||||
flecs::id_t result = _::cpp_type<Module>::id(m_world, nullptr, false);
|
||||
if (name) {
|
||||
ecs_add_path_w_sep(m_world, result, 0, name, "::", "::");
|
||||
}
|
||||
ecs_set_scope(m_world, result);
|
||||
return flecs::entity(m_world, result);
|
||||
}
|
||||
|
||||
template <typename Module>
|
||||
inline flecs::entity world::import() {
|
||||
return flecs::_::import<Module>(*this);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/module/mixin.inl
|
||||
* @brief Module world mixin.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_addons_modules
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Define a module.
|
||||
* This operation is not mandatory, but can be called inside the module ctor to
|
||||
* obtain the entity associated with the module, or override the module name.
|
||||
*
|
||||
* @tparam Module module class.
|
||||
* @return Module entity.
|
||||
*/
|
||||
template <typename Module>
|
||||
flecs::entity module(const char *name = nullptr) const;
|
||||
|
||||
/** Import a module.
|
||||
*
|
||||
* @tparam Module module class.
|
||||
* @return Module entity.
|
||||
*/
|
||||
template <typename Module>
|
||||
flecs::entity import();
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/monitor/decl.hpp
|
||||
* @brief Monitor module declarations.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/**
|
||||
* @defgroup cpp_addons_monitor Monitor
|
||||
* @brief The monitor addon periodically tracks statistics for the world and systems.
|
||||
*
|
||||
* \ingroup cpp_addons
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Component that stores world statistics */
|
||||
using WorldStats = EcsWorldStats;
|
||||
|
||||
/** Component that stores system/pipeline statistics */
|
||||
using PipelineStats = EcsPipelineStats;
|
||||
|
||||
struct monitor {
|
||||
monitor(flecs::world& world);
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/monitor/impl.hpp
|
||||
* @brief Monitor module implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
inline monitor::monitor(flecs::world& world) {
|
||||
/* Import C module */
|
||||
FlecsMonitorImport(world);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/observer/builder.hpp
|
||||
* @brief Observer builder.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../utils/node_builder.hpp"
|
||||
#include "builder_i.hpp"
|
||||
|
||||
namespace flecs {
|
||||
namespace _ {
|
||||
template <typename ... Components>
|
||||
using observer_builder_base = node_builder<
|
||||
observer, ecs_observer_desc_t, observer_builder<Components...>,
|
||||
observer_builder_i, Components ...>;
|
||||
}
|
||||
|
||||
/** Observer builder.
|
||||
*
|
||||
* \ingroup cpp_observers
|
||||
*/
|
||||
template <typename ... Components>
|
||||
struct observer_builder final : _::observer_builder_base<Components...> {
|
||||
observer_builder(flecs::world_t* world, const char *name = nullptr)
|
||||
: _::observer_builder_base<Components...>(world, name)
|
||||
{
|
||||
_::sig<Components...>(world).populate(this);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/observer/builder_i.hpp
|
||||
* @brief Observer builder interface.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../filter/builder_i.hpp"
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/** Observer builder interface.
|
||||
*
|
||||
* \ingroup cpp_observers
|
||||
*/
|
||||
template<typename Base, typename ... Components>
|
||||
struct observer_builder_i : filter_builder_i<Base, Components ...> {
|
||||
using BaseClass = filter_builder_i<Base, Components ...>;
|
||||
observer_builder_i()
|
||||
: BaseClass(nullptr)
|
||||
, m_desc(nullptr)
|
||||
, m_event_count(0) { }
|
||||
|
||||
observer_builder_i(ecs_observer_desc_t *desc)
|
||||
: BaseClass(&desc->filter)
|
||||
, m_desc(desc)
|
||||
, m_event_count(0) { }
|
||||
|
||||
/** Specify the event(s) for when the observer should run.
|
||||
* @param evt The event.
|
||||
*/
|
||||
Base& event(entity_t evt) {
|
||||
m_desc->events[m_event_count ++] = evt;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Specify the event(s) for when the observer should run.
|
||||
* @tparam E The event.
|
||||
*/
|
||||
template <typename E>
|
||||
Base& event() {
|
||||
m_desc->events[m_event_count ++] = _::cpp_type<E>().id(world_v());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Invoke observer for anything that matches its filter on creation */
|
||||
Base& yield_existing(bool value = true) {
|
||||
m_desc->yield_existing = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set observer context */
|
||||
Base& ctx(void *ptr) {
|
||||
m_desc->ctx = ptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set observer run callback */
|
||||
Base& run(ecs_iter_action_t action) {
|
||||
m_desc->run = action;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual flecs::world_t* world_v() = 0;
|
||||
|
||||
private:
|
||||
operator Base&() {
|
||||
return *static_cast<Base*>(this);
|
||||
}
|
||||
|
||||
ecs_observer_desc_t *m_desc;
|
||||
int32_t m_event_count;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/observer/decl.hpp
|
||||
* @brief Observer declarations.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/**
|
||||
* @defgroup cpp_observers Observers
|
||||
* @brief Observers let applications register callbacks for ECS events.
|
||||
*
|
||||
* \ingroup cpp_core
|
||||
* @{
|
||||
*/
|
||||
|
||||
struct observer;
|
||||
|
||||
template<typename ... Components>
|
||||
struct observer_builder;
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/observer/impl.hpp
|
||||
* @brief Observer implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "builder.hpp"
|
||||
|
||||
namespace flecs
|
||||
{
|
||||
|
||||
struct observer final : entity
|
||||
{
|
||||
using entity::entity;
|
||||
|
||||
explicit observer() : entity() { }
|
||||
|
||||
observer(flecs::world_t *world, ecs_observer_desc_t *desc, bool instanced)
|
||||
{
|
||||
if (!desc->filter.instanced) {
|
||||
desc->filter.instanced = instanced;
|
||||
}
|
||||
|
||||
m_world = world;
|
||||
m_id = ecs_observer_init(world, desc);
|
||||
|
||||
if (desc->filter.terms_buffer) {
|
||||
ecs_os_free(desc->filter.terms_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void ctx(void *ctx) {
|
||||
ecs_observer_desc_t desc = {};
|
||||
desc.entity = m_id;
|
||||
desc.ctx = ctx;
|
||||
ecs_observer_init(m_world, &desc);
|
||||
}
|
||||
|
||||
void* ctx() const {
|
||||
return ecs_observer_get_ctx(m_world, m_id);
|
||||
}
|
||||
|
||||
flecs::filter<> query() const {
|
||||
const flecs::Poly *poly = this->get<flecs::Poly>(flecs::Observer);
|
||||
const ecs_observer_t *ob = static_cast<const flecs::observer_t*>(poly->poly);
|
||||
return flecs::filter<>(m_world, &ob->filter);
|
||||
}
|
||||
};
|
||||
|
||||
// Mixin implementation
|
||||
inline observer world::observer(flecs::entity e) const {
|
||||
return flecs::observer(m_world, e);
|
||||
}
|
||||
|
||||
template <typename... Comps, typename... Args>
|
||||
inline observer_builder<Comps...> world::observer(Args &&... args) const {
|
||||
return flecs::observer_builder<Comps...>(m_world, FLECS_FWD(args)...);
|
||||
}
|
||||
|
||||
} // namespace flecs
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/observer/mixin.inl
|
||||
* @brief Observer world mixin.
|
||||
*/
|
||||
|
||||
/** Observer builder.
|
||||
*
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_observers
|
||||
*/
|
||||
|
||||
/** Upcast entity to an observer.
|
||||
* The provided entity must be an observer.
|
||||
*
|
||||
* @param e The entity.
|
||||
* @return An observer object.
|
||||
*/
|
||||
flecs::observer observer(flecs::entity e) const;
|
||||
|
||||
/** Create a new observer.
|
||||
*
|
||||
* @tparam Components The components to match on.
|
||||
* @tparam Args Arguments passed to the constructor of flecs::observer_builder.
|
||||
* @return Observer builder.
|
||||
*/
|
||||
template <typename... Components, typename... Args>
|
||||
flecs::observer_builder<Components...> observer(Args &&... args) const;
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/pipeline/builder.hpp
|
||||
* @brief Pipeline builder.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../utils/builder.hpp"
|
||||
#include "builder_i.hpp"
|
||||
|
||||
namespace flecs {
|
||||
namespace _ {
|
||||
template <typename ... Components>
|
||||
using pipeline_builder_base = builder<
|
||||
pipeline, ecs_pipeline_desc_t, pipeline_builder<Components...>,
|
||||
pipeline_builder_i, Components ...>;
|
||||
}
|
||||
|
||||
/** Pipeline builder.
|
||||
*
|
||||
* \ingroup cpp_pipelines
|
||||
*/
|
||||
template <typename ... Components>
|
||||
struct pipeline_builder final : _::pipeline_builder_base<Components...> {
|
||||
pipeline_builder(flecs::world_t* world, flecs::entity_t id = 0)
|
||||
: _::pipeline_builder_base<Components...>(world)
|
||||
{
|
||||
_::sig<Components...>(world).populate(this);
|
||||
this->m_desc.entity = id;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/pipeline/builder_i.hpp
|
||||
* @brief Pipeline builder interface.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../query/builder_i.hpp"
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/** Pipeline builder interface.
|
||||
*
|
||||
* \ingroup cpp_pipelines
|
||||
*/
|
||||
template<typename Base>
|
||||
struct pipeline_builder_i : query_builder_i<Base> {
|
||||
pipeline_builder_i(ecs_pipeline_desc_t *desc, int32_t term_index = 0)
|
||||
: query_builder_i<Base>(&desc->query, term_index)
|
||||
, m_desc(desc) { }
|
||||
|
||||
private:
|
||||
ecs_pipeline_desc_t *m_desc;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/pipeline/decl.hpp
|
||||
* @brief Pipeline module declarations.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/**
|
||||
* @defgroup cpp_pipelines Pipelines
|
||||
* @brief Pipelines order and schedule systems for execution.
|
||||
*
|
||||
* \ingroup cpp_addons
|
||||
* @{
|
||||
*/
|
||||
|
||||
template <typename ... Components>
|
||||
struct pipeline;
|
||||
|
||||
template <typename ... Components>
|
||||
struct pipeline_builder;
|
||||
|
||||
/* Builtin pipeline tags */
|
||||
static const flecs::entity_t OnStart = EcsOnStart;
|
||||
static const flecs::entity_t PreFrame = EcsPreFrame;
|
||||
static const flecs::entity_t OnLoad = EcsOnLoad;
|
||||
static const flecs::entity_t PostLoad = EcsPostLoad;
|
||||
static const flecs::entity_t PreUpdate = EcsPreUpdate;
|
||||
static const flecs::entity_t OnUpdate = EcsOnUpdate;
|
||||
static const flecs::entity_t OnValidate = EcsOnValidate;
|
||||
static const flecs::entity_t PostUpdate = EcsPostUpdate;
|
||||
static const flecs::entity_t PreStore = EcsPreStore;
|
||||
static const flecs::entity_t OnStore = EcsOnStore;
|
||||
static const flecs::entity_t PostFrame = EcsPostFrame;
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/pipeline/impl.hpp
|
||||
* @brief Pipeline module implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "builder.hpp"
|
||||
|
||||
namespace flecs {
|
||||
|
||||
template <typename ... Components>
|
||||
struct pipeline : entity {
|
||||
pipeline(world_t *world, ecs_pipeline_desc_t *desc)
|
||||
: entity(world)
|
||||
{
|
||||
m_id = ecs_pipeline_init(world, desc);
|
||||
|
||||
if (!m_id) {
|
||||
ecs_abort(ECS_INVALID_PARAMETER, NULL);
|
||||
}
|
||||
|
||||
if (desc->query.filter.terms_buffer) {
|
||||
ecs_os_free(desc->query.filter.terms_buffer);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline flecs::pipeline_builder<> world::pipeline() const {
|
||||
return flecs::pipeline_builder<>(m_world);
|
||||
}
|
||||
|
||||
template <typename Pipeline, if_not_t< is_enum<Pipeline>::value >>
|
||||
inline flecs::pipeline_builder<> world::pipeline() const {
|
||||
return flecs::pipeline_builder<>(m_world, _::cpp_type<Pipeline>::id(m_world));
|
||||
}
|
||||
|
||||
inline void world::set_pipeline(const flecs::entity pip) const {
|
||||
return ecs_set_pipeline(m_world, pip);
|
||||
}
|
||||
|
||||
template <typename Pipeline>
|
||||
inline void world::set_pipeline() const {
|
||||
return ecs_set_pipeline(m_world, _::cpp_type<Pipeline>::id(m_world));
|
||||
}
|
||||
|
||||
inline flecs::entity world::get_pipeline() const {
|
||||
return flecs::entity(m_world, ecs_get_pipeline(m_world));
|
||||
}
|
||||
|
||||
inline bool world::progress(ecs_ftime_t delta_time) const {
|
||||
return ecs_progress(m_world, delta_time);
|
||||
}
|
||||
|
||||
inline void world::run_pipeline(const flecs::entity_t pip, ecs_ftime_t delta_time) const {
|
||||
return ecs_run_pipeline(m_world, pip, delta_time);
|
||||
}
|
||||
|
||||
template <typename Pipeline, if_not_t< is_enum<Pipeline>::value >>
|
||||
inline void world::run_pipeline(ecs_ftime_t delta_time) const {
|
||||
return ecs_run_pipeline(m_world, _::cpp_type<Pipeline>::id(m_world), delta_time);
|
||||
}
|
||||
|
||||
inline void world::set_time_scale(ecs_ftime_t mul) const {
|
||||
ecs_set_time_scale(m_world, mul);
|
||||
}
|
||||
|
||||
inline void world::set_target_fps(ecs_ftime_t target_fps) const {
|
||||
ecs_set_target_fps(m_world, target_fps);
|
||||
}
|
||||
|
||||
inline void world::reset_clock() const {
|
||||
ecs_reset_clock(m_world);
|
||||
}
|
||||
|
||||
inline void world::set_threads(int32_t threads) const {
|
||||
ecs_set_threads(m_world, threads);
|
||||
}
|
||||
|
||||
inline int32_t world::get_threads() const {
|
||||
return ecs_get_stage_count(m_world);
|
||||
}
|
||||
|
||||
inline void world::set_task_threads(int32_t task_threads) const {
|
||||
ecs_set_task_threads(m_world, task_threads);
|
||||
}
|
||||
|
||||
inline bool world::using_task_threads() const {
|
||||
return ecs_using_task_threads(m_world);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/pipeline/mixin.inl
|
||||
* @brief Pipeline world mixin.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_pipelines
|
||||
*/
|
||||
|
||||
/** Create a new pipeline.
|
||||
*
|
||||
* @return A pipeline builder.
|
||||
*/
|
||||
flecs::pipeline_builder<> pipeline() const;
|
||||
|
||||
/** Create a new pipeline.
|
||||
*
|
||||
* @tparam Pipeline Type associated with pipeline.
|
||||
* @return A pipeline builder.
|
||||
*/
|
||||
template <typename Pipeline, if_not_t< is_enum<Pipeline>::value > = 0>
|
||||
flecs::pipeline_builder<> pipeline() const;
|
||||
|
||||
/** Set pipeline.
|
||||
* @see ecs_set_pipeline
|
||||
*/
|
||||
void set_pipeline(const flecs::entity pip) const;
|
||||
|
||||
/** Set pipeline.
|
||||
* @see ecs_set_pipeline
|
||||
*/
|
||||
template <typename Pipeline>
|
||||
void set_pipeline() const;
|
||||
|
||||
/** Get pipeline.
|
||||
* @see ecs_get_pipeline
|
||||
*/
|
||||
flecs::entity get_pipeline() const;
|
||||
|
||||
/** Progress world one tick.
|
||||
* @see ecs_progress
|
||||
*/
|
||||
bool progress(ecs_ftime_t delta_time = 0.0) const;
|
||||
|
||||
/** Run pipeline.
|
||||
* @see ecs_run_pipeline
|
||||
*/
|
||||
void run_pipeline(const flecs::entity_t pip, ecs_ftime_t delta_time = 0.0) const;
|
||||
|
||||
/** Run pipeline.
|
||||
* @tparam Pipeline Type associated with pipeline.
|
||||
* @see ecs_run_pipeline
|
||||
*/
|
||||
template <typename Pipeline, if_not_t< is_enum<Pipeline>::value > = 0>
|
||||
void run_pipeline(ecs_ftime_t delta_time = 0.0) const;
|
||||
|
||||
/** Set timescale.
|
||||
* @see ecs_set_time_scale
|
||||
*/
|
||||
void set_time_scale(ecs_ftime_t mul) const;
|
||||
|
||||
/** Set target FPS.
|
||||
* @see ecs_set_target_fps
|
||||
*/
|
||||
void set_target_fps(ecs_ftime_t target_fps) const;
|
||||
|
||||
/** Reset simulation clock.
|
||||
* @see ecs_reset_clock
|
||||
*/
|
||||
void reset_clock() const;
|
||||
|
||||
/** Set number of threads.
|
||||
* @see ecs_set_threads
|
||||
*/
|
||||
void set_threads(int32_t threads) const;
|
||||
|
||||
/** Set number of threads.
|
||||
* @see ecs_get_stage_count
|
||||
*/
|
||||
int32_t get_threads() const;
|
||||
|
||||
/** Set number of task threads.
|
||||
* @see ecs_set_task_threads
|
||||
*/
|
||||
void set_task_threads(int32_t task_threads) const;
|
||||
|
||||
/** Returns true if task thread use has been requested.
|
||||
* @see ecs_using_task_threads
|
||||
*/
|
||||
bool using_task_threads() const;
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/plecs/mixin.inl
|
||||
* @brief Plecs world mixin.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup cpp_addons_plecs Plecs
|
||||
* @brief Data definition format for loading entity data.
|
||||
*
|
||||
* \ingroup cpp_addons
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Load plecs string.
|
||||
* @see ecs_plecs_from_str
|
||||
*/
|
||||
int plecs_from_str(const char *name, const char *str) const {
|
||||
return ecs_plecs_from_str(m_world, name, str);
|
||||
}
|
||||
|
||||
/** Load plecs from file.
|
||||
* @see ecs_plecs_from_file
|
||||
*/
|
||||
int plecs_from_file(const char *filename) const {
|
||||
return ecs_plecs_from_file(m_world, filename);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/query/builder.hpp
|
||||
* @brief Query builder.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../utils/builder.hpp"
|
||||
#include "builder_i.hpp"
|
||||
|
||||
namespace flecs {
|
||||
namespace _ {
|
||||
template <typename ... Components>
|
||||
using query_builder_base = builder<
|
||||
query, ecs_query_desc_t, query_builder<Components...>,
|
||||
query_builder_i, Components ...>;
|
||||
}
|
||||
|
||||
/** Query builder.
|
||||
*
|
||||
* \ingroup cpp_core_queries
|
||||
*/
|
||||
template <typename ... Components>
|
||||
struct query_builder final : _::query_builder_base<Components...> {
|
||||
query_builder(flecs::world_t* world, const char *name = nullptr)
|
||||
: _::query_builder_base<Components...>(world)
|
||||
{
|
||||
_::sig<Components...>(world).populate(this);
|
||||
if (name != nullptr) {
|
||||
ecs_entity_desc_t entity_desc = {};
|
||||
entity_desc.name = name;
|
||||
entity_desc.sep = "::";
|
||||
entity_desc.root_sep = "::";
|
||||
this->m_desc.filter.entity = ecs_entity_init(world, &entity_desc);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/query/builder_i.hpp
|
||||
* @brief Query builder interface.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../filter/builder_i.hpp"
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/** Query builder interface.
|
||||
*
|
||||
* \ingroup cpp_core_queries
|
||||
*/
|
||||
template<typename Base, typename ... Components>
|
||||
struct query_builder_i : filter_builder_i<Base, Components ...> {
|
||||
private:
|
||||
using BaseClass = filter_builder_i<Base, Components ...>;
|
||||
|
||||
public:
|
||||
query_builder_i()
|
||||
: BaseClass(nullptr)
|
||||
, m_desc(nullptr) { }
|
||||
|
||||
query_builder_i(ecs_query_desc_t *desc, int32_t term_index = 0)
|
||||
: BaseClass(&desc->filter, term_index)
|
||||
, m_desc(desc) { }
|
||||
|
||||
/** Sort the output of a query.
|
||||
* This enables sorting of entities across matched tables. As a result of this
|
||||
* operation, the order of entities in the matched tables may be changed.
|
||||
* Resorting happens when a query iterator is obtained, and only if the table
|
||||
* data has changed.
|
||||
*
|
||||
* If multiple queries that match the same (down)set of tables specify different
|
||||
* sorting functions, resorting is likely to happen every time an iterator is
|
||||
* obtained, which can significantly slow down iterations.
|
||||
*
|
||||
* The sorting function will be applied to the specified component. Resorting
|
||||
* only happens if that component has changed, or when the entity order in the
|
||||
* table has changed. If no component is provided, resorting only happens when
|
||||
* the entity order changes.
|
||||
*
|
||||
* @tparam T The component used to sort.
|
||||
* @param compare The compare function used to sort the components.
|
||||
*/
|
||||
template <typename T>
|
||||
Base& order_by(int(*compare)(flecs::entity_t, const T*, flecs::entity_t, const T*)) {
|
||||
ecs_order_by_action_t cmp = reinterpret_cast<ecs_order_by_action_t>(compare);
|
||||
return this->order_by(_::cpp_type<T>::id(this->world_v()), cmp);
|
||||
}
|
||||
|
||||
/** Sort the output of a query.
|
||||
* Same as order_by<T>, but with component identifier.
|
||||
*
|
||||
* @param component The component used to sort.
|
||||
* @param compare The compare function used to sort the components.
|
||||
*/
|
||||
Base& order_by(flecs::entity_t component, int(*compare)(flecs::entity_t, const void*, flecs::entity_t, const void*)) {
|
||||
m_desc->order_by = reinterpret_cast<ecs_order_by_action_t>(compare);
|
||||
m_desc->order_by_component = component;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Group and sort matched tables.
|
||||
* Similar yo ecs_query_order_by, but instead of sorting individual entities, this
|
||||
* operation only sorts matched tables. This can be useful of a query needs to
|
||||
* enforce a certain iteration order upon the tables it is iterating, for
|
||||
* example by giving a certain component or tag a higher priority.
|
||||
*
|
||||
* The sorting function assigns a "rank" to each type, which is then used to
|
||||
* sort the tables. Tables with higher ranks will appear later in the iteration.
|
||||
*
|
||||
* Resorting happens when a query iterator is obtained, and only if the set of
|
||||
* matched tables for a query has changed. If table sorting is enabled together
|
||||
* with entity sorting, table sorting takes precedence, and entities will be
|
||||
* sorted within each set of tables that are assigned the same rank.
|
||||
*
|
||||
* @tparam T The component used to determine the group rank.
|
||||
* @param group_by_action Callback that determines group id for table.
|
||||
*/
|
||||
template <typename T>
|
||||
Base& group_by(uint64_t(*group_by_action)(flecs::world_t*, flecs::table_t *table, flecs::id_t id, void* ctx)) {
|
||||
ecs_group_by_action_t action = reinterpret_cast<ecs_group_by_action_t>(group_by_action);
|
||||
return this->group_by(_::cpp_type<T>::id(this->world_v()), action);
|
||||
}
|
||||
|
||||
/** Group and sort matched tables.
|
||||
* Same as group_by<T>, but with component identifier.
|
||||
*
|
||||
* @param component The component used to determine the group rank.
|
||||
* @param group_by_action Callback that determines group id for table.
|
||||
*/
|
||||
Base& group_by(flecs::entity_t component, uint64_t(*group_by_action)(flecs::world_t*, flecs::table_t *table, flecs::id_t id, void* ctx)) {
|
||||
m_desc->group_by = reinterpret_cast<ecs_group_by_action_t>(group_by_action);
|
||||
m_desc->group_by_id = component;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Group and sort matched tables.
|
||||
* Same as group_by<T>, but with default group_by action.
|
||||
*
|
||||
* @tparam T The component used to determine the group rank.
|
||||
*/
|
||||
template <typename T>
|
||||
Base& group_by() {
|
||||
return this->group_by(_::cpp_type<T>::id(this->world_v()), nullptr);
|
||||
}
|
||||
|
||||
/** Group and sort matched tables.
|
||||
* Same as group_by, but with default group_by action.
|
||||
*
|
||||
* @param component The component used to determine the group rank.
|
||||
*/
|
||||
Base& group_by(flecs::entity_t component) {
|
||||
return this->group_by(component, nullptr);
|
||||
}
|
||||
|
||||
/** Specify context to be passed to group_by function.
|
||||
*
|
||||
* @param ctx Context to pass to group_by function.
|
||||
* @param ctx_free Function to cleanup context (called when query is deleted).
|
||||
*/
|
||||
Base& group_by_ctx(void *ctx, ecs_ctx_free_t ctx_free = nullptr) {
|
||||
m_desc->group_by_ctx = ctx;
|
||||
m_desc->group_by_ctx_free = ctx_free;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Specify on_group_create action.
|
||||
*/
|
||||
Base& on_group_create(ecs_group_create_action_t action) {
|
||||
m_desc->on_group_create = action;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Specify on_group_delete action.
|
||||
*/
|
||||
Base& on_group_delete(ecs_group_delete_action_t action) {
|
||||
m_desc->on_group_delete = action;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Specify parent query (creates subquery) */
|
||||
Base& observable(const query_base& parent);
|
||||
|
||||
protected:
|
||||
virtual flecs::world_t* world_v() = 0;
|
||||
|
||||
private:
|
||||
operator Base&() {
|
||||
return *static_cast<Base*>(this);
|
||||
}
|
||||
|
||||
ecs_query_desc_t *m_desc;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/query/decl.hpp
|
||||
* @brief Query declarations.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/**
|
||||
* @defgroup cpp_core_queries Queries
|
||||
* @brief Cached query implementation. Fast to iterate, but slower to create than flecs::filter.
|
||||
*
|
||||
* \ingroup cpp_core
|
||||
* @{
|
||||
*/
|
||||
|
||||
struct query_base;
|
||||
|
||||
template<typename ... Components>
|
||||
struct query;
|
||||
|
||||
template<typename ... Components>
|
||||
struct query_builder;
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
188
engine/libs/flecs/include/flecs/addons/cpp/mixins/query/impl.hpp
Normal file
188
engine/libs/flecs/include/flecs/addons/cpp/mixins/query/impl.hpp
Normal file
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/query/impl.hpp
|
||||
* @brief Query implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "builder.hpp"
|
||||
|
||||
namespace flecs {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Persistent queries
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct query_base {
|
||||
query_base()
|
||||
: m_world(nullptr)
|
||||
, m_query(nullptr) { }
|
||||
|
||||
query_base(world_t *world, query_t *query = nullptr)
|
||||
: m_world(world)
|
||||
, m_query(query) { }
|
||||
|
||||
query_base(world_t *world, ecs_query_desc_t *desc)
|
||||
: m_world(world)
|
||||
{
|
||||
m_query = ecs_query_init(world, desc);
|
||||
|
||||
if (!m_query) {
|
||||
ecs_abort(ECS_INVALID_PARAMETER, NULL);
|
||||
}
|
||||
|
||||
if (desc->filter.terms_buffer) {
|
||||
ecs_os_free(desc->filter.terms_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
operator query_t*() const {
|
||||
return m_query;
|
||||
}
|
||||
|
||||
/** Returns whether the query data changed since the last iteration.
|
||||
* This operation must be invoked before obtaining the iterator, as this will
|
||||
* reset the changed state. The operation will return true after:
|
||||
* - new entities have been matched with
|
||||
* - matched entities were deleted
|
||||
* - matched components were changed
|
||||
*
|
||||
* @return true if entities changed, otherwise false.
|
||||
*/
|
||||
bool changed() const {
|
||||
return ecs_query_changed(m_query, 0);
|
||||
}
|
||||
|
||||
/** Returns whether query is orphaned.
|
||||
* When the parent query of a subquery is deleted, it is left in an orphaned
|
||||
* state. The only valid operation on an orphaned query is deleting it. Only
|
||||
* subqueries can be orphaned.
|
||||
*
|
||||
* @return true if query is orphaned, otherwise false.
|
||||
*/
|
||||
bool orphaned() const {
|
||||
return ecs_query_orphaned(m_query);
|
||||
}
|
||||
|
||||
/** Get info for group.
|
||||
*
|
||||
* @param group_id The group id for which to retrieve the info.
|
||||
* @return The group info.
|
||||
*/
|
||||
const flecs::query_group_info_t* group_info(uint64_t group_id) const {
|
||||
return ecs_query_get_group_info(m_query, group_id);
|
||||
}
|
||||
|
||||
/** Get context for group.
|
||||
*
|
||||
* @param group_id The group id for which to retrieve the context.
|
||||
* @return The group context.
|
||||
*/
|
||||
void* group_ctx(uint64_t group_id) const {
|
||||
const flecs::query_group_info_t *gi = group_info(group_id);
|
||||
if (gi) {
|
||||
return gi->ctx;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/** Free the query.
|
||||
*/
|
||||
void destruct() {
|
||||
ecs_query_fini(m_query);
|
||||
m_world = nullptr;
|
||||
m_query = nullptr;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
void each_term(const Func& func) const {
|
||||
this->filter().each_term(func);
|
||||
}
|
||||
|
||||
filter_base filter() const {
|
||||
return filter_base(m_world, ecs_query_get_filter(m_query));
|
||||
}
|
||||
|
||||
flecs::term term(int32_t index) const {
|
||||
const ecs_filter_t *f = ecs_query_get_filter(m_query);
|
||||
ecs_assert(f != NULL, ECS_INVALID_PARAMETER, NULL);
|
||||
return flecs::term(m_world, f->terms[index]);
|
||||
}
|
||||
|
||||
int32_t field_count() const {
|
||||
const ecs_filter_t *f = ecs_query_get_filter(m_query);
|
||||
return f->term_count;
|
||||
}
|
||||
|
||||
flecs::string str() const {
|
||||
const ecs_filter_t *f = ecs_query_get_filter(m_query);
|
||||
char *result = ecs_filter_str(m_world, f);
|
||||
return flecs::string(result);
|
||||
}
|
||||
|
||||
flecs::entity entity() const {
|
||||
return flecs::entity(m_world, ecs_get_entity(m_query));
|
||||
}
|
||||
|
||||
operator query<>() const;
|
||||
|
||||
protected:
|
||||
world_t *m_world;
|
||||
query_t *m_query;
|
||||
};
|
||||
|
||||
template<typename ... Components>
|
||||
struct query final : query_base, iterable<Components...> {
|
||||
public:
|
||||
flecs::world world() const {
|
||||
return flecs::world(m_world);
|
||||
}
|
||||
|
||||
private:
|
||||
using Terms = typename _::term_ptrs<Components...>::array;
|
||||
|
||||
ecs_iter_t get_iter(flecs::world_t *world) const override {
|
||||
if (!world) {
|
||||
world = m_world;
|
||||
}
|
||||
return ecs_query_iter(world, m_query);
|
||||
}
|
||||
|
||||
ecs_iter_next_action_t next_action() const override {
|
||||
return ecs_query_next;
|
||||
}
|
||||
|
||||
ecs_iter_next_action_t next_each_action() const override {
|
||||
return ecs_query_next_instanced;
|
||||
}
|
||||
|
||||
public:
|
||||
using query_base::query_base;
|
||||
};
|
||||
|
||||
// Mixin implementation
|
||||
template <typename... Comps, typename... Args>
|
||||
inline flecs::query<Comps...> world::query(Args &&... args) const {
|
||||
return flecs::query_builder<Comps...>(m_world, FLECS_FWD(args)...)
|
||||
.build();
|
||||
}
|
||||
|
||||
template <typename... Comps, typename... Args>
|
||||
inline flecs::query_builder<Comps...> world::query_builder(Args &&... args) const {
|
||||
return flecs::query_builder<Comps...>(m_world, FLECS_FWD(args)...);
|
||||
}
|
||||
|
||||
// Builder implementation
|
||||
template <typename Base, typename ... Components>
|
||||
inline Base& query_builder_i<Base, Components ...>::observable(const query_base& parent) {
|
||||
m_desc->parent = parent;
|
||||
return *static_cast<Base*>(this);
|
||||
}
|
||||
|
||||
// query_base implementation
|
||||
inline query_base::operator query<>() const {
|
||||
return flecs::query<>(m_world, m_query);
|
||||
}
|
||||
|
||||
} // namespace flecs
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/query/mixin.inl
|
||||
* @brief Query world mixin.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_core_queries
|
||||
*/
|
||||
|
||||
/** Create a query.
|
||||
* @see ecs_query_init
|
||||
*/
|
||||
template <typename... Comps, typename... Args>
|
||||
flecs::query<Comps...> query(Args &&... args) const;
|
||||
|
||||
/** Create a subquery.
|
||||
* @see ecs_query_init
|
||||
*/
|
||||
template <typename... Comps, typename... Args>
|
||||
flecs::query<Comps...> query(flecs::query_base& parent, Args &&... args) const;
|
||||
|
||||
/** Create a query builder.
|
||||
* @see ecs_query_init
|
||||
*/
|
||||
template <typename... Comps, typename... Args>
|
||||
flecs::query_builder<Comps...> query_builder(Args &&... args) const;
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/rest/decl.hpp
|
||||
* @brief Rest module declarations.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/**
|
||||
* @defgroup cpp_addons_rest Rest
|
||||
* @brief REST API for querying and mutating entities.
|
||||
*
|
||||
* \ingroup cpp_addons
|
||||
* @{
|
||||
*/
|
||||
|
||||
using Rest = EcsRest;
|
||||
|
||||
namespace rest {
|
||||
|
||||
namespace _ {
|
||||
|
||||
void init(flecs::world& world);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/rest/impl.hpp
|
||||
* @brief Rest module implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
namespace rest {
|
||||
namespace _ {
|
||||
|
||||
inline void init(flecs::world& world) {
|
||||
world.component<Rest>("flecs::rest::Rest");
|
||||
}
|
||||
|
||||
} // namespace _
|
||||
} // namespace rest
|
||||
} // namespace flecs
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/rule/builder.hpp
|
||||
* @brief Rule builder.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../filter/builder_i.hpp"
|
||||
|
||||
namespace flecs {
|
||||
namespace _ {
|
||||
template <typename ... Components>
|
||||
using rule_builder_base = builder<
|
||||
rule, ecs_filter_desc_t, rule_builder<Components...>,
|
||||
filter_builder_i, Components ...>;
|
||||
}
|
||||
|
||||
/** Rule builder.
|
||||
*
|
||||
* \ingroup cpp_addons_rules
|
||||
*/
|
||||
template <typename ... Components>
|
||||
struct rule_builder final : _::rule_builder_base<Components...> {
|
||||
rule_builder(flecs::world_t* world, const char *name = nullptr)
|
||||
: _::rule_builder_base<Components...>(world)
|
||||
{
|
||||
_::sig<Components...>(world).populate(this);
|
||||
if (name != nullptr) {
|
||||
ecs_entity_desc_t entity_desc = {};
|
||||
entity_desc.name = name;
|
||||
entity_desc.sep = "::";
|
||||
entity_desc.root_sep = "::";
|
||||
this->m_desc.entity = ecs_entity_init(world, &entity_desc);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/rule/decl.hpp
|
||||
* @brief Rule declarations.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/**
|
||||
* @defgroup cpp_addons_rules Rules
|
||||
* @brief Rules are an advanced query engine for matching against entity graphs.
|
||||
*
|
||||
* \ingroup cpp_addons
|
||||
* @{
|
||||
*/
|
||||
|
||||
struct rule_base;
|
||||
|
||||
template<typename ... Components>
|
||||
struct rule;
|
||||
|
||||
template<typename ... Components>
|
||||
struct rule_builder;
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
144
engine/libs/flecs/include/flecs/addons/cpp/mixins/rule/impl.hpp
Normal file
144
engine/libs/flecs/include/flecs/addons/cpp/mixins/rule/impl.hpp
Normal file
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/rule/impl.hpp
|
||||
* @brief Rule implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "builder.hpp"
|
||||
|
||||
namespace flecs {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Persistent queries
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct rule_base {
|
||||
rule_base()
|
||||
: m_world(nullptr)
|
||||
, m_rule(nullptr) { }
|
||||
|
||||
rule_base(world_t *world, rule_t *rule = nullptr)
|
||||
: m_world(world)
|
||||
, m_rule(rule) { }
|
||||
|
||||
rule_base(world_t *world, ecs_filter_desc_t *desc)
|
||||
: m_world(world)
|
||||
{
|
||||
m_rule = ecs_rule_init(world, desc);
|
||||
if (desc->terms_buffer) {
|
||||
ecs_os_free(desc->terms_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_valid() const {
|
||||
return m_rule != nullptr;
|
||||
}
|
||||
|
||||
operator rule_t*() const {
|
||||
return m_rule;
|
||||
}
|
||||
|
||||
flecs::entity entity() {
|
||||
return flecs::entity(m_world, ecs_get_entity(m_rule));
|
||||
}
|
||||
|
||||
/** Free the rule. */
|
||||
void destruct() {
|
||||
if (m_rule) {
|
||||
ecs_rule_fini(m_rule);
|
||||
m_world = nullptr;
|
||||
m_rule = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
void each_term(const Func& func) const {
|
||||
this->filter().each_term(func);
|
||||
}
|
||||
|
||||
/** Move the rule. */
|
||||
void move(flecs::rule_base&& obj) {
|
||||
this->destruct();
|
||||
this->m_world = obj.m_world;
|
||||
this->m_rule = obj.m_rule;
|
||||
obj.m_world = nullptr;
|
||||
obj.m_rule = nullptr;
|
||||
}
|
||||
|
||||
flecs::filter_base filter() const {
|
||||
return filter_base(m_world, ecs_rule_get_filter(m_rule));
|
||||
}
|
||||
|
||||
/** Converts this rule to a string expression
|
||||
* @see ecs_filter_str
|
||||
*/
|
||||
flecs::string str() const {
|
||||
const ecs_filter_t *f = ecs_rule_get_filter(m_rule);
|
||||
char *result = ecs_filter_str(m_world, f);
|
||||
return flecs::string(result);
|
||||
}
|
||||
|
||||
|
||||
/** Converts this rule to a string that can be used to aid debugging
|
||||
* the behavior of the rule.
|
||||
* @see ecs_rule_str
|
||||
*/
|
||||
flecs::string rule_str() const {
|
||||
char *result = ecs_rule_str(m_rule);
|
||||
return flecs::string(result);
|
||||
}
|
||||
|
||||
operator rule<>() const;
|
||||
|
||||
protected:
|
||||
world_t *m_world;
|
||||
rule_t *m_rule;
|
||||
};
|
||||
|
||||
template<typename ... Components>
|
||||
struct rule final : rule_base, iterable<Components...> {
|
||||
private:
|
||||
using Terms = typename _::term_ptrs<Components...>::array;
|
||||
|
||||
ecs_iter_t get_iter(flecs::world_t *world) const override {
|
||||
if (!world) {
|
||||
world = m_world;
|
||||
}
|
||||
return ecs_rule_iter(world, m_rule);
|
||||
}
|
||||
|
||||
ecs_iter_next_action_t next_action() const override {
|
||||
return ecs_rule_next;
|
||||
}
|
||||
|
||||
ecs_iter_next_action_t next_each_action() const override {
|
||||
return ecs_rule_next_instanced;
|
||||
}
|
||||
|
||||
public:
|
||||
using rule_base::rule_base;
|
||||
|
||||
int32_t find_var(const char *name) {
|
||||
return ecs_rule_find_var(m_rule, name);
|
||||
}
|
||||
};
|
||||
|
||||
// Mixin implementation
|
||||
template <typename... Comps, typename... Args>
|
||||
inline flecs::rule<Comps...> world::rule(Args &&... args) const {
|
||||
return flecs::rule_builder<Comps...>(m_world, FLECS_FWD(args)...)
|
||||
.build();
|
||||
}
|
||||
|
||||
template <typename... Comps, typename... Args>
|
||||
inline flecs::rule_builder<Comps...> world::rule_builder(Args &&... args) const {
|
||||
return flecs::rule_builder<Comps...>(m_world, FLECS_FWD(args)...);
|
||||
}
|
||||
|
||||
// rule_base implementation
|
||||
inline rule_base::operator rule<>() const {
|
||||
return flecs::rule<>(m_world, m_rule);
|
||||
}
|
||||
|
||||
} // namespace flecs
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/rule/iterable.inl
|
||||
* @brief Rule iterable mixin.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \memberof flecs::iter
|
||||
* \ingroup cpp_addons_rules
|
||||
*/
|
||||
|
||||
iter_iterable<Components...>& set_var(const char *name, flecs::entity_t value) {
|
||||
ecs_rule_iter_t *rit = &m_it.priv.iter.rule;
|
||||
int var_id = ecs_rule_find_var(rit->rule, name);
|
||||
ecs_assert(var_id != -1, ECS_INVALID_PARAMETER, name);
|
||||
ecs_iter_set_var(&m_it, var_id, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/rule/mixin.inl
|
||||
* @brief Rule world mixin.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_addons_rules
|
||||
*/
|
||||
|
||||
/** Create a rule.
|
||||
* @see ecs_rule_init
|
||||
*/
|
||||
template <typename... Comps, typename... Args>
|
||||
flecs::rule<Comps...> rule(Args &&... args) const;
|
||||
|
||||
/** Create a subrule.
|
||||
* @see ecs_rule_init
|
||||
*/
|
||||
template <typename... Comps, typename... Args>
|
||||
flecs::rule<Comps...> rule(flecs::rule_base& parent, Args &&... args) const;
|
||||
|
||||
/** Create a rule builder.
|
||||
* @see ecs_rule_init
|
||||
*/
|
||||
template <typename... Comps, typename... Args>
|
||||
flecs::rule_builder<Comps...> rule_builder(Args &&... args) const;
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/snapshot/decl.hpp
|
||||
* @brief Snapshot module declarations.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
/**
|
||||
* @defgroup cpp_addons_snapshots Snapshots
|
||||
* @brief Save & restore world.
|
||||
*
|
||||
* \ingroup cpp_addons
|
||||
* @{
|
||||
*/
|
||||
|
||||
using snapshot_t = ecs_snapshot_t;
|
||||
|
||||
struct snapshot;
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/snapshot/impl.hpp
|
||||
* @brief Snapshot module implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace flecs {
|
||||
|
||||
struct snapshot final {
|
||||
explicit snapshot(const world& world)
|
||||
: m_world( world )
|
||||
, m_snapshot( nullptr ) { }
|
||||
|
||||
snapshot(const snapshot& obj)
|
||||
: m_world( obj.m_world )
|
||||
{
|
||||
ecs_iter_t it = ecs_snapshot_iter(obj.m_snapshot);
|
||||
m_snapshot = ecs_snapshot_take_w_iter(&it);
|
||||
}
|
||||
|
||||
snapshot(snapshot&& obj)
|
||||
: m_world(obj.m_world)
|
||||
, m_snapshot(obj.m_snapshot)
|
||||
{
|
||||
obj.m_snapshot = nullptr;
|
||||
}
|
||||
|
||||
snapshot& operator=(const snapshot& obj) {
|
||||
ecs_assert(m_world.c_ptr() == obj.m_world.c_ptr(), ECS_INVALID_PARAMETER, NULL);
|
||||
ecs_iter_t it = ecs_snapshot_iter(obj.m_snapshot);
|
||||
m_snapshot = ecs_snapshot_take_w_iter(&it);
|
||||
return *this;
|
||||
}
|
||||
|
||||
snapshot& operator=(snapshot&& obj) {
|
||||
ecs_assert(m_world.c_ptr() == obj.m_world.c_ptr(), ECS_INVALID_PARAMETER, NULL);
|
||||
m_snapshot = obj.m_snapshot;
|
||||
obj.m_snapshot = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void take() {
|
||||
if (m_snapshot) {
|
||||
ecs_snapshot_free(m_snapshot);
|
||||
}
|
||||
|
||||
m_snapshot = ecs_snapshot_take(m_world.c_ptr());
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void take(const F& f) {
|
||||
if (m_snapshot) {
|
||||
ecs_snapshot_free(m_snapshot);
|
||||
}
|
||||
|
||||
ecs_iter_t it = ecs_filter_iter(m_world, f.c_ptr());
|
||||
|
||||
m_snapshot = ecs_snapshot_take_w_iter(&it);
|
||||
}
|
||||
|
||||
void restore() {
|
||||
if (m_snapshot) {
|
||||
ecs_snapshot_restore(m_world.c_ptr(), m_snapshot);
|
||||
m_snapshot = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
~snapshot() {
|
||||
if (m_snapshot) {
|
||||
ecs_snapshot_free(m_snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
snapshot_t* c_ptr() const {
|
||||
return m_snapshot;
|
||||
}
|
||||
|
||||
private:
|
||||
const world& m_world;
|
||||
snapshot_t *m_snapshot;
|
||||
};
|
||||
|
||||
// Snapshot mixin implementation
|
||||
template <typename... Args>
|
||||
inline flecs::snapshot world::snapshot(Args &&... args) const {
|
||||
return flecs::snapshot(*this, FLECS_FWD(args)...);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/snapshot/mixin.inl
|
||||
* @brief Snapshot world mixin.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \memberof flecs::world
|
||||
* \ingroup cpp_addons_snapshot
|
||||
*/
|
||||
|
||||
/** Create a snapshot.
|
||||
*/
|
||||
template <typename... Args>
|
||||
flecs::snapshot snapshot(Args &&... args) const;
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/system/builder.hpp
|
||||
* @brief System builder.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../utils/node_builder.hpp"
|
||||
#include "builder_i.hpp"
|
||||
|
||||
namespace flecs {
|
||||
namespace _ {
|
||||
template <typename ... Components>
|
||||
using system_builder_base = node_builder<
|
||||
system, ecs_system_desc_t, system_builder<Components...>,
|
||||
system_builder_i, Components ...>;
|
||||
}
|
||||
|
||||
/** System builder.
|
||||
*
|
||||
* \ingroup cpp_addons_systems
|
||||
*/
|
||||
template <typename ... Components>
|
||||
struct system_builder final : _::system_builder_base<Components...> {
|
||||
system_builder(flecs::world_t* world, const char *name = nullptr)
|
||||
: _::system_builder_base<Components...>(world, name)
|
||||
{
|
||||
_::sig<Components...>(world).populate(this);
|
||||
|
||||
#ifdef FLECS_PIPELINE
|
||||
ecs_add_id(world, this->m_desc.entity, ecs_dependson(flecs::OnUpdate));
|
||||
ecs_add_id(world, this->m_desc.entity, flecs::OnUpdate);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* @file addons/cpp/mixins/system/builder_i.hpp
|
||||
* @brief System builder interface.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../query/builder_i.hpp"
|
||||
|
||||
namespace flecs
|
||||
{
|
||||
|
||||
/** System builder interface.
|
||||
*
|
||||
* \ingroup cpp_addons_systems
|
||||
*/
|
||||
template<typename Base, typename ... Components>
|
||||
struct system_builder_i : query_builder_i<Base, Components ...> {
|
||||
private:
|
||||
using BaseClass = query_builder_i<Base, Components ...>;
|
||||
|
||||
public:
|
||||
system_builder_i(ecs_system_desc_t *desc)
|
||||
: BaseClass(&desc->query)
|
||||
, m_desc(desc) { }
|
||||
|
||||
/** Specify in which phase the system should run.
|
||||
*
|
||||
* @param phase The phase.
|
||||
*/
|
||||
Base& kind(entity_t phase) {
|
||||
flecs::entity_t cur_phase = ecs_get_target(
|
||||
world_v(), m_desc->entity, EcsDependsOn, 0);
|
||||
if (cur_phase) {
|
||||
ecs_remove_id(world_v(), m_desc->entity, ecs_dependson(cur_phase));
|
||||
ecs_remove_id(world_v(), m_desc->entity, cur_phase);
|
||||
}
|
||||
if (phase) {
|
||||
ecs_add_id(world_v(), m_desc->entity, ecs_dependson(phase));
|
||||
ecs_add_id(world_v(), m_desc->entity, phase);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Specify in which phase the system should run.
|
||||
*
|
||||
* @tparam Phase The phase.
|
||||
*/
|
||||
template <typename Phase>
|
||||
Base& kind() {
|
||||
return this->kind(_::cpp_type<Phase>::id(world_v()));
|
||||
}
|
||||
|
||||
/** Specify whether system can run on multiple threads.
|
||||
*
|
||||
* @param value If false system will always run on a single thread.
|
||||
*/
|
||||
Base& multi_threaded(bool value = true) {
|
||||
m_desc->multi_threaded = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Specify whether system should be ran in staged context.
|
||||
*
|
||||
* @param value If false system will always run staged.
|
||||
*/
|
||||
Base& no_readonly(bool value = true) {
|
||||
m_desc->no_readonly = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set system interval.
|
||||
* This operation will cause the system to be ran at the specified interval.
|
||||
*
|
||||
* The timer is synchronous, and is incremented each frame by delta_time.
|
||||
*
|
||||
* @param interval The interval value.
|
||||
*/
|
||||
Base& interval(ecs_ftime_t interval) {
|
||||
m_desc->interval = interval;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set system rate.
|
||||
* This operation will cause the system to be ran at a multiple of the
|
||||
* provided tick source. The tick source may be any entity, including
|
||||
* another system.
|
||||
*
|
||||
* @param tick_source The tick source.
|
||||
* @param rate The multiple at which to run the system.
|
||||
*/
|
||||
Base& rate(const entity_t tick_source, int32_t rate) {
|
||||
m_desc->rate = rate;
|
||||
m_desc->tick_source = tick_source;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set system rate.
|
||||
* This operation will cause the system to be ran at a multiple of the
|
||||
* frame tick frequency. If a tick source was provided, this just updates
|
||||
* the rate of the system.
|
||||
*
|
||||
* @param rate The multiple at which to run the system.
|
||||
*/
|
||||
Base& rate(int32_t rate) {
|
||||
m_desc->rate = rate;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set tick source.
|
||||
* This operation sets a shared tick source for the system.
|
||||
*
|
||||
* @param tick_source The tick source to use for the system.
|
||||
*/
|
||||
Base& tick_source(flecs::entity_t tick_source) {
|
||||
m_desc->tick_source = tick_source;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set system context */
|
||||
Base& ctx(void *ptr) {
|
||||
m_desc->ctx = ptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set system run callback */
|
||||
Base& run(ecs_iter_action_t action) {
|
||||
m_desc->run = action;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual flecs::world_t* world_v() = 0;
|
||||
|
||||
private:
|
||||
operator Base&() {
|
||||
return *static_cast<Base*>(this);
|
||||
}
|
||||
|
||||
ecs_system_desc_t *m_desc;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user