// Comment out this line when using as DLL #define flecs_STATIC /** * @file flecs.h * @brief Flecs public API. * * This file contains the public API for Flecs. */ #ifndef FLECS_H #define FLECS_H /** * @defgroup c C API * * @{ * @} */ /** * @defgroup core Core * @ingroup c * Core ECS functionality (entities, storage, queries). * * @{ */ /** * @defgroup options API defines * Defines for customizing compile time features. * * @{ */ /* Flecs version macro */ #define FLECS_VERSION_MAJOR 3 #define FLECS_VERSION_MINOR 2 #define FLECS_VERSION_PATCH 12 #define FLECS_VERSION FLECS_VERSION_IMPL(\ FLECS_VERSION_MAJOR, FLECS_VERSION_MINOR, FLECS_VERSION_PATCH) /** @def FLECS_CONFIG_HEADER * Allows for including a user-customizable header that specifies compile-time * features. */ #ifdef FLECS_CONFIG_HEADER #include "flecs_config.h" #endif /** @def ecs_float_t * Customizable precision for floating point operations */ #ifndef ecs_float_t #define ecs_float_t float #endif /** @def ecs_ftime_t * Customizable precision for scalar time values. Change to double precision for * processes that can run for a long time (e.g. longer than a day). */ #ifndef ecs_ftime_t #define ecs_ftime_t ecs_float_t #endif /** @def FLECS_LEGACY * Define when building for C89 */ // #define FLECS_LEGACY /** @def FLECS_NO_DEPRECATED_WARNINGS * disables deprecated warnings */ #define FLECS_NO_DEPRECATED_WARNINGS /** @def FLECS_ACCURATE_COUNTERS * Define to ensure that global counters used for statistics (such as the * allocation counters in the OS API) are accurate in multithreaded * applications, at the cost of increased overhead. */ // #define FLECS_ACCURATE_COUNTERS /* Make sure provided configuration is valid */ #if defined(FLECS_DEBUG) && defined(FLECS_NDEBUG) #error "invalid configuration: cannot both define FLECS_DEBUG and FLECS_NDEBUG" #endif #if defined(FLECS_DEBUG) && defined(NDEBUG) #error "invalid configuration: cannot both define FLECS_DEBUG and NDEBUG" #endif /** @def FLECS_DEBUG * Used for input parameter checking and cheap sanity checks. There are lots of * asserts in every part of the code, so this will slow down applications. */ #if !defined(FLECS_DEBUG) && !defined(FLECS_NDEBUG) #if defined(NDEBUG) #define FLECS_NDEBUG #else #define FLECS_DEBUG #endif #endif /** @def FLECS_SANITIZE * Enables expensive checks that can detect issues early. Recommended for * running tests or when debugging issues. This will severely slow down code. */ #ifdef FLECS_SANITIZE #ifndef FLECS_DEBUG #define FLECS_DEBUG /* If sanitized mode is enabled, so is debug mode */ #endif #endif /* Tip: if you see weird behavior that you think might be a bug, make sure to * test with the FLECS_DEBUG or FLECS_SANITIZE flags enabled. There's a good * chance that this gives you more information about the issue! */ /** @def FLECS_SOFT_ASSERT * Define to not abort for recoverable errors, like invalid parameters. An error * is still thrown to the console. This is recommended for when running inside a * third party runtime, such as the Unreal editor. * * Note that internal sanity checks (ECS_INTERNAL_ERROR) will still abort a * process, as this gives more information than a (likely) subsequent crash. * * When a soft assert occurs, the code will attempt to minimize the number of * side effects of the failed operation, but this may not always be possible. * Even though an application may still be able to continue running after a soft * assert, it should be treated as if in an undefined state. */ // #define FLECS_SOFT_ASSERT /** @def FLECS_KEEP_ASSERT * By default asserts are disabled in release mode, when either FLECS_NDEBUG or * NDEBUG is defined. Defining FLECS_KEEP_ASSERT ensures that asserts are not * disabled. This define can be combined with FLECS_SOFT_ASSERT. */ // #define FLECS_KEEP_ASSERT /** @def FLECS_CUSTOM_BUILD * This macro lets you customize which addons to build flecs with. * Without any addons Flecs is just a minimal ECS storage, but addons add * features such as systems, scheduling and reflection. If an addon is disabled, * it is excluded from the build, so that it consumes no resources. By default * all addons are enabled. * * You can customize a build by either whitelisting or blacklisting addons. To * whitelist addons, first define the FLECS_CUSTOM_BUILD macro, which disables * all addons. You can then manually select the addons you need by defining * their macro, like "FLECS_SYSTEM". * * To blacklist an addon, make sure to *not* define FLECS_CUSTOM_BUILD, and * instead define the addons you don't need by defining FLECS_NO_, for * example "FLECS_NO_SYSTEM". If there are any addons that depend on the * blacklisted addon, an error will be thrown during the build. * * Note that addons can have dependencies on each other. Addons will * automatically enable their dependencies. To see the list of addons that was * compiled in a build, enable tracing before creating the world by doing: * * @code * ecs_log_set_level(0); * @endcode * * which outputs the full list of addons Flecs was compiled with. */ // #define FLECS_CUSTOM_BUILD /** @def FLECS_CPP_NO_AUTO_REGISTRATION * When set, the C++ API will require that components are registered before they * are used. This is useful in multithreaded applications, where components need * to be registered beforehand, and to catch issues in projects where component * registration is mandatory. Disabling automatic component registration also * slightly improves performance. * The C API is not affected by this feature. */ // #define FLECS_CPP_NO_AUTO_REGISTRATION #ifndef FLECS_CUSTOM_BUILD // #define FLECS_C /**< C API convenience macros, always enabled */ #define FLECS_CPP /**< C++ API */ #define FLECS_MODULE /**< Module support */ #define FLECS_PARSER /**< String parser for queries */ #define FLECS_PLECS /**< ECS data definition format */ #define FLECS_RULES /**< Constraint solver for advanced queries */ #define FLECS_SNAPSHOT /**< Snapshot & restore ECS data */ #define FLECS_STATS /**< Access runtime statistics */ #define FLECS_MONITOR /**< Track runtime statistics periodically */ #define FLECS_METRICS /**< Expose component data as statistics */ #define FLECS_ALERTS /**< Monitor conditions for errors */ #define FLECS_SYSTEM /**< System support */ #define FLECS_PIPELINE /**< Pipeline support */ #define FLECS_TIMER /**< Timer support */ #define FLECS_META /**< Reflection support */ #define FLECS_META_C /**< Utilities for populating reflection data */ #define FLECS_UNITS /**< Builtin standard units */ #define FLECS_EXPR /**< Parsing strings to/from component values */ #define FLECS_JSON /**< Parsing JSON to/from component values */ #define FLECS_DOC /**< Document entities & components */ #define FLECS_LOG /**< When enabled ECS provides more detailed logs */ #define FLECS_APP /**< Application addon */ #define FLECS_OS_API_IMPL /**< Default implementation for OS API */ #define FLECS_HTTP /**< Tiny HTTP server for connecting to remote UI */ #define FLECS_REST /**< REST API for querying application data */ // #define FLECS_JOURNAL /**< Journaling addon (disabled by default) */ #endif // ifndef FLECS_CUSTOM_BUILD /** @def FLECS_LOW_FOOTPRINT * Set a number of constants to values that decrease memory footprint, at the * cost of decreased performance. */ // #define FLECS_LOW_FOOTPRINT #ifdef FLECS_LOW_FOOTPRINT #define FLECS_HI_COMPONENT_ID (16) #define FLECS_HI_ID_RECORD_ID (16) #define FLECS_SPARSE_PAGE_BITS (6) #define FLECS_ENTITY_PAGE_BITS (6) #define FLECS_USE_OS_ALLOC #endif /** @def FLECS_HI_COMPONENT_ID * This constant can be used to balance between performance and memory * utilization. The constant is used in two ways: * - Entity ids 0..FLECS_HI_COMPONENT_ID are reserved for component ids. * - Used as lookup array size in table edges. * * Increasing this value increases the size of the lookup array, which allows * fast table traversal, which improves performance of ECS add/remove * operations. Component ids that fall outside of this range use a regular map * lookup, which is slower but more memory efficient. */ #ifndef FLECS_HI_COMPONENT_ID #define FLECS_HI_COMPONENT_ID (256) #endif /** @def FLECS_HI_ID_RECORD_ID * This constant can be used to balance between performance and memory * utilization. The constant is used to determine the size of the id record * lookup array. Id values that fall outside of this range use a regular map * lookup, which is slower but more memory efficient. */ #ifndef FLECS_HI_ID_RECORD_ID #define FLECS_HI_ID_RECORD_ID (1024) #endif /** @def FLECS_SPARSE_PAGE_BITS * This constant is used to determine the number of bits of an id that is used * to determine the page index when used with a sparse set. The number of bits * determines the page size, which is (1 << bits). * Lower values decrease memory utilization, at the cost of more allocations. */ #ifndef FLECS_SPARSE_PAGE_BITS #define FLECS_SPARSE_PAGE_BITS (12) #endif /** @def FLECS_ENTITY_PAGE_BITS * Same as FLECS_SPARSE_PAGE_BITS, but for the entity index. */ #ifndef FLECS_ENTITY_PAGE_BITS #define FLECS_ENTITY_PAGE_BITS (12) #endif /** @def FLECS_USE_OS_ALLOC * When enabled, Flecs will use the OS allocator provided in the OS API directly * instead of the builtin block allocator. This can decrease memory utilization * as memory will be freed more often, at the cost of decreased performance. */ // #define FLECS_USE_OS_ALLOC /** @def FLECS_ID_DESC_MAX * Maximum number of ids to add ecs_entity_desc_t / ecs_bulk_desc_t */ #ifndef FLECS_ID_DESC_MAX #define FLECS_ID_DESC_MAX (32) #endif /** @def FLECS_TERM_DESC_MAX * Maximum number of terms in ecs_filter_desc_t */ #define FLECS_TERM_DESC_MAX (16) /** @def FLECS_EVENT_DESC_MAX * Maximum number of events in ecs_observer_desc_t */ #define FLECS_EVENT_DESC_MAX (8) /** @def FLECS_VARIABLE_COUNT_MAX * Maximum number of query variables per query */ #define FLECS_VARIABLE_COUNT_MAX (64) /** @def FLECS_QUERY_SCOPE_NESTING_MAX * Maximum nesting depth of query scopes */ #define FLECS_QUERY_SCOPE_NESTING_MAX (8) /** @} */ /** * @file api_defines.h * @brief Supporting defines for the public API. * * This file contains constants / macros that are typically not used by an * application but support the public API, and therefore must be exposed. This * header should not be included by itself. */ #ifndef FLECS_API_DEFINES_H #define FLECS_API_DEFINES_H /** * @file api_flags.h * @brief Bitset flags used by internals. */ #ifndef FLECS_API_FLAGS_H #define FLECS_API_FLAGS_H #ifdef __cplusplus extern "C" { #endif //////////////////////////////////////////////////////////////////////////////// //// World flags //////////////////////////////////////////////////////////////////////////////// #define EcsWorldQuitWorkers (1u << 0) #define EcsWorldReadonly (1u << 1) #define EcsWorldInit (1u << 2) #define EcsWorldQuit (1u << 3) #define EcsWorldFini (1u << 4) #define EcsWorldMeasureFrameTime (1u << 5) #define EcsWorldMeasureSystemTime (1u << 6) #define EcsWorldMultiThreaded (1u << 7) //////////////////////////////////////////////////////////////////////////////// //// OS API flags //////////////////////////////////////////////////////////////////////////////// #define EcsOsApiHighResolutionTimer (1u << 0) #define EcsOsApiLogWithColors (1u << 1) #define EcsOsApiLogWithTimeStamp (1u << 2) #define EcsOsApiLogWithTimeDelta (1u << 3) //////////////////////////////////////////////////////////////////////////////// //// Entity flags (set in upper bits of ecs_record_t::row) //////////////////////////////////////////////////////////////////////////////// #define EcsEntityIsId (1u << 31) #define EcsEntityIsTarget (1u << 30) #define EcsEntityIsTraversable (1u << 29) //////////////////////////////////////////////////////////////////////////////// //// Id flags (used by ecs_id_record_t::flags) //////////////////////////////////////////////////////////////////////////////// #define EcsIdOnDeleteRemove (1u << 0) #define EcsIdOnDeleteDelete (1u << 1) #define EcsIdOnDeletePanic (1u << 2) #define EcsIdOnDeleteMask\ (EcsIdOnDeletePanic|EcsIdOnDeleteRemove|EcsIdOnDeleteDelete) #define EcsIdOnDeleteObjectRemove (1u << 3) #define EcsIdOnDeleteObjectDelete (1u << 4) #define EcsIdOnDeleteObjectPanic (1u << 5) #define EcsIdOnDeleteObjectMask\ (EcsIdOnDeleteObjectPanic|EcsIdOnDeleteObjectRemove|\ EcsIdOnDeleteObjectDelete) #define EcsIdExclusive (1u << 6) #define EcsIdDontInherit (1u << 7) #define EcsIdTraversable (1u << 8) #define EcsIdTag (1u << 9) #define EcsIdWith (1u << 10) #define EcsIdUnion (1u << 11) #define EcsIdAlwaysOverride (1u << 12) #define EcsIdHasOnAdd (1u << 16) /* Same values as table flags */ #define EcsIdHasOnRemove (1u << 17) #define EcsIdHasOnSet (1u << 18) #define EcsIdHasUnSet (1u << 19) #define EcsIdHasOnTableFill (1u << 20) #define EcsIdHasOnTableEmpty (1u << 21) #define EcsIdHasOnTableCreate (1u << 22) #define EcsIdHasOnTableDelete (1u << 23) #define EcsIdEventMask\ (EcsIdHasOnAdd|EcsIdHasOnRemove|EcsIdHasOnSet|EcsIdHasUnSet|\ EcsIdHasOnTableFill|EcsIdHasOnTableEmpty|EcsIdHasOnTableCreate|\ EcsIdHasOnTableDelete) #define EcsIdMarkedForDelete (1u << 30) /* Utilities for converting from flags to delete policies and vice versa */ #define ECS_ID_ON_DELETE(flags) \ ((ecs_entity_t[]){0, EcsRemove, EcsDelete, 0, EcsPanic}\ [((flags) & EcsIdOnDeleteMask)]) #define ECS_ID_ON_DELETE_TARGET(flags) ECS_ID_ON_DELETE(flags >> 3) #define ECS_ID_ON_DELETE_FLAG(id) (1u << ((id) - EcsRemove)) #define ECS_ID_ON_DELETE_TARGET_FLAG(id) (1u << (3 + ((id) - EcsRemove))) //////////////////////////////////////////////////////////////////////////////// //// Iterator flags (used by ecs_iter_t::flags) //////////////////////////////////////////////////////////////////////////////// #define EcsIterIsValid (1u << 0u) /* Does iterator contain valid result */ #define EcsIterNoData (1u << 1u) /* Does iterator provide (component) data */ #define EcsIterIsInstanced (1u << 2u) /* Is iterator instanced */ #define EcsIterHasShared (1u << 3u) /* Does result have shared terms */ #define EcsIterTableOnly (1u << 4u) /* Result only populates table */ #define EcsIterEntityOptional (1u << 5u) /* Treat terms with entity subject as optional */ #define EcsIterNoResults (1u << 6u) /* Iterator has no results */ #define EcsIterIgnoreThis (1u << 7u) /* Only evaluate non-this terms */ #define EcsIterMatchVar (1u << 8u) #define EcsIterHasCondSet (1u << 10u) /* Does iterator have conditionally set fields */ #define EcsIterProfile (1u << 11u) /* Profile iterator performance */ #define EcsIterTrivialSearch (1u << 12u) /* Trivial iterator mode */ #define EcsIterTrivialSearchNoData (1u << 13u) /* Trivial iterator w/no data */ #define EcsIterTrivialTest (1u << 14u) /* Trivial test mode (constrained $this) */ #define EcsIterTrivialSearchWildcard (1u << 15u) /* Trivial search with wildcard ids */ #define EcsIterCppEach (1u << 16u) /* Uses C++ 'each' iterator */ //////////////////////////////////////////////////////////////////////////////// //// Event flags (used by ecs_event_decs_t::flags) //////////////////////////////////////////////////////////////////////////////// #define EcsEventTableOnly (1u << 4u) /* Table event (no data, same as iter flags) */ #define EcsEventNoOnSet (1u << 16u) /* Don't emit OnSet/UnSet for inherited ids */ //////////////////////////////////////////////////////////////////////////////// //// Filter flags (used by ecs_filter_t::flags) //////////////////////////////////////////////////////////////////////////////// #define EcsFilterMatchThis (1u << 1u) /* Has terms that match This */ #define EcsFilterMatchOnlyThis (1u << 2u) /* Has only terms that match This */ #define EcsFilterMatchPrefab (1u << 3u) /* Does filter match prefabs */ #define EcsFilterMatchDisabled (1u << 4u) /* Does filter match disabled entities */ #define EcsFilterMatchEmptyTables (1u << 5u) /* Does filter return empty tables */ #define EcsFilterMatchAnything (1u << 6u) /* False if filter has no/only Not terms */ #define EcsFilterNoData (1u << 7u) /* When true, data fields won't be populated */ #define EcsFilterIsInstanced (1u << 8u) /* Is filter instanced (see ecs_filter_desc_t) */ #define EcsFilterPopulate (1u << 9u) /* Populate data, ignore non-matching fields */ #define EcsFilterHasCondSet (1u << 10u) /* Does filter have conditionally set fields */ #define EcsFilterUnresolvedByName (1u << 11u) /* Use by-name matching for unresolved entity identifiers */ #define EcsFilterHasPred (1u << 12u) /* Filter has equality predicates */ #define EcsFilterHasScopes (1u << 13u) /* Filter has query scopes */ #define EcsFilterIsTrivial (1u << 14u) /* Trivial filter */ #define EcsFilterMatchOnlySelf (1u << 15u) /* Filter has no up traversal */ #define EcsFilterHasWildcards (1u << 16u) /* Filter has no up traversal */ #define EcsFilterOwnsStorage (1u << 17u) /* Is ecs_filter_t object owned by filter */ #define EcsFilterOwnsTermsStorage (1u << 18u) /* Is terms array owned by filter */ //////////////////////////////////////////////////////////////////////////////// //// Observer flags (used by ecs_observer_t::flags) //////////////////////////////////////////////////////////////////////////////// #define EcsObserverIsMulti (1u << 1u) /* Does observer have multiple terms */ #define EcsObserverIsMonitor (1u << 2u) /* Is observer a monitor */ #define EcsObserverIsDisabled (1u << 3u) /* Is observer entity disabled */ #define EcsObserverIsParentDisabled (1u << 4u) /* Is module parent of observer disabled */ //////////////////////////////////////////////////////////////////////////////// //// Table flags (used by ecs_table_t::flags) //////////////////////////////////////////////////////////////////////////////// #define EcsTableHasBuiltins (1u << 1u) /* Does table have builtin components */ #define EcsTableIsPrefab (1u << 2u) /* Does the table store prefabs */ #define EcsTableHasIsA (1u << 3u) /* Does the table have IsA relationship */ #define EcsTableHasChildOf (1u << 4u) /* Does the table type ChildOf relationship */ #define EcsTableHasName (1u << 5u) /* Does the table type have (Identifier, Name) */ #define EcsTableHasPairs (1u << 6u) /* Does the table type have pairs */ #define EcsTableHasModule (1u << 7u) /* Does the table have module data */ #define EcsTableIsDisabled (1u << 8u) /* Does the table type has EcsDisabled */ #define EcsTableHasCtors (1u << 9u) #define EcsTableHasDtors (1u << 10u) #define EcsTableHasCopy (1u << 11u) #define EcsTableHasMove (1u << 12u) #define EcsTableHasUnion (1u << 13u) #define EcsTableHasToggle (1u << 14u) #define EcsTableHasOverrides (1u << 15u) #define EcsTableHasOnAdd (1u << 16u) /* Same values as id flags */ #define EcsTableHasOnRemove (1u << 17u) #define EcsTableHasOnSet (1u << 18u) #define EcsTableHasUnSet (1u << 19u) #define EcsTableHasOnTableFill (1u << 20u) #define EcsTableHasOnTableEmpty (1u << 21u) #define EcsTableHasOnTableCreate (1u << 22u) #define EcsTableHasOnTableDelete (1u << 23u) #define EcsTableHasTraversable (1u << 25u) #define EcsTableHasTarget (1u << 26u) #define EcsTableMarkedForDelete (1u << 30u) /* Composite table flags */ #define EcsTableHasLifecycle (EcsTableHasCtors | EcsTableHasDtors) #define EcsTableIsComplex (EcsTableHasLifecycle | EcsTableHasUnion | EcsTableHasToggle) #define EcsTableHasAddActions (EcsTableHasIsA | EcsTableHasUnion | EcsTableHasCtors | EcsTableHasOnAdd | EcsTableHasOnSet) #define EcsTableHasRemoveActions (EcsTableHasIsA | EcsTableHasDtors | EcsTableHasOnRemove | EcsTableHasUnSet) //////////////////////////////////////////////////////////////////////////////// //// Query flags (used by ecs_query_t::flags) //////////////////////////////////////////////////////////////////////////////// #define EcsQueryHasRefs (1u << 1u) /* Does query have references */ #define EcsQueryIsSubquery (1u << 2u) /* Is query a subquery */ #define EcsQueryIsOrphaned (1u << 3u) /* Is subquery orphaned */ #define EcsQueryHasOutTerms (1u << 4u) /* Does query have out terms */ #define EcsQueryHasNonThisOutTerms (1u << 5u) /* Does query have non-this out terms */ #define EcsQueryHasMonitor (1u << 6u) /* Does query track changes */ #define EcsQueryTrivialIter (1u << 7u) /* Does the query require special features to iterate */ //////////////////////////////////////////////////////////////////////////////// //// Aperiodic action flags (used by ecs_run_aperiodic) //////////////////////////////////////////////////////////////////////////////// #define EcsAperiodicEmptyTables (1u << 1u) /* Process pending empty table events */ #define EcsAperiodicComponentMonitors (1u << 2u) /* Process component monitors */ #define EcsAperiodicEmptyQueries (1u << 4u) /* Process empty queries */ #ifdef __cplusplus } #endif #endif #if defined(_WIN32) || defined(_MSC_VER) #define ECS_TARGET_WINDOWS #elif defined(__ANDROID__) #define ECS_TARGET_ANDROID #define ECS_TARGET_POSIX #elif defined(__linux__) #define ECS_TARGET_LINUX #define ECS_TARGET_POSIX #elif defined(__FreeBSD__) #define ECS_TARGET_FREEBSD #define ECS_TARGET_POSIX #elif defined(__APPLE__) && defined(__MACH__) #define ECS_TARGET_DARWIN #define ECS_TARGET_POSIX #elif defined(__EMSCRIPTEN__) #define ECS_TARGET_EM #define ECS_TARGET_POSIX #endif #if defined(__MINGW32__) || defined(__MINGW64__) #define ECS_TARGET_MINGW #endif #if defined(_MSC_VER) #ifndef __clang__ #define ECS_TARGET_MSVC #endif #endif #if defined(__clang__) #define ECS_TARGET_CLANG #endif #if defined(__GNUC__) #define ECS_TARGET_GNU #endif /* Map between clang and apple clang versions, as version 13 has a difference in * the format of __PRETTY_FUNCTION__ which enum reflection depends on. */ #if defined(__clang__) #if defined(__APPLE__) #if __clang_major__ == 13 #if __clang_minor__ < 1 #define ECS_CLANG_VERSION 12 #else #define ECS_CLANG_VERSION 13 #endif #else #define ECS_CLANG_VERSION __clang_major__ #endif #else #define ECS_CLANG_VERSION __clang_major__ #endif #endif /* Ignored warnings */ #if defined(ECS_TARGET_CLANG) /* Ignore unknown options so we don't have to care about the compiler version */ #pragma clang diagnostic ignored "-Wunknown-warning-option" /* Warns for double or redundant semicolons. There are legitimate cases where a * semicolon after an empty statement is useful, for example after a macro that * is replaced with a code block. With this warning enabled, semicolons would * only have to be added after macro's that are not code blocks, which in some * cases isn't possible as the implementation of a macro can be different in * debug/release mode. */ #pragma clang diagnostic ignored "-Wextra-semi-stmt" /* This is valid in C99, and Flecs must be compiled as C99. */ #pragma clang diagnostic ignored "-Wdeclaration-after-statement" /* Clang attribute to detect fallthrough isn't supported on older versions. * Implicit fallthrough is still detected by gcc and ignored with "fall through" * comments */ #pragma clang diagnostic ignored "-Wimplicit-fallthrough" /* This warning prevents adding a default case when all enum constants are part * of the switch. In C however an enum type can assume any value in the range of * the type, and this warning makes it harder to catch invalid enum values. */ #pragma clang diagnostic ignored "-Wcovered-switch-default" /* This warning prevents some casts of function results to a different kind of * type, e.g. casting an int result to double. Not very useful in practice, as * it just forces the code to assign to a variable first, then cast. */ #pragma clang diagnostic ignored "-Wbad-function-cast" /* Format strings can be passed down from other functions. */ #pragma clang diagnostic ignored "-Wformat-nonliteral" /* Useful, but not reliable enough. It can incorrectly flag macro's as unused * in standalone builds. */ #pragma clang diagnostic ignored "-Wunused-macros" #if __clang_major__ == 13 /* clang 13 can throw this warning for a define in ctype.h */ #pragma clang diagnostic ignored "-Wreserved-identifier" #endif /* Filenames aren't consistent across targets as they can use different casing * (e.g. WinSock2 vs winsock2). */ #pragma clang diagnostic ignored "-Wnonportable-system-include-path" /* Enum reflection relies on testing constant values that may not be valid for * the enumeration. */ #pragma clang diagnostic ignored "-Wenum-constexpr-conversion" /* Very difficult to workaround this warning in C, especially for an ECS. */ #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" /* This warning gets thrown when trying to cast pointer returned from dlproc */ #pragma clang diagnostic ignored "-Wcast-function-type-strict" /* This warning can get thrown for expressions that evaluate to constants * in debug/release mode. */ #pragma clang diagnostic ignored "-Wconstant-logical-operand" /* With soft asserts enabled the code won't abort, which in some cases means * code paths are reached where values are uninitialized. */ #ifdef FLECS_SOFT_ASSERT #pragma clang diagnostic ignored "-Wsometimes-uninitialized" #endif #elif defined(ECS_TARGET_GNU) #ifndef __cplusplus #pragma GCC diagnostic ignored "-Wdeclaration-after-statement" #pragma GCC diagnostic ignored "-Wbad-function-cast" #endif #pragma GCC diagnostic ignored "-Wformat-nonliteral" #pragma GCC diagnostic ignored "-Wunused-macros" /* This warning gets thrown *sometimes* when not all members for a struct are * provided in an initializer. Flecs heavily relies on descriptor structs that * only require partly initialization, so this warning isn't useful. * It doesn't introduce any safety issues (fields are guaranteed to be 0 * initialized), and later versions of gcc (>=11) seem to no longer throw this * warning. */ #pragma GCC diagnostic ignored "-Wmissing-field-initializers" #endif /* Standard library dependencies */ #include #include #include /* Non-standard but required. If not provided by platform, add manually. */ #include /* Contains macros for importing / exporting symbols */ /* ) (.) .|. | | _.--| |--._ .-'; ;`-'& ; `&. \ & ; & &_/ |"""---...---"""| \ | | | | | | | / `---.|.|.|.---' * This file is generated by bake.lang.c for your convenience. Headers of * dependencies will automatically show up in this file. Include bake_config.h * in your main project file. Do not edit! */ #ifndef FLECS_BAKE_CONFIG_H #define FLECS_BAKE_CONFIG_H /* Headers of public dependencies */ /* No dependencies */ /* Convenience macro for exporting symbols */ #ifndef flecs_STATIC #if defined(flecs_EXPORTS) && (defined(_MSC_VER) || defined(__MINGW32__)) #define FLECS_API __declspec(dllexport) #elif defined(flecs_EXPORTS) #define FLECS_API __attribute__((__visibility__("default"))) #elif defined(_MSC_VER) #define FLECS_API __declspec(dllimport) #else #define FLECS_API #endif #else #define FLECS_API #endif #endif #ifdef __cplusplus extern "C" { #endif #ifdef __BAKE_LEGACY__ #define FLECS_LEGACY #endif /* Some symbols are only exported when building in debug build, to enable * white-box testing of internal data structures */ #ifndef FLECS_NDEBUG #define FLECS_DBG_API FLECS_API #else #define FLECS_DBG_API #endif //////////////////////////////////////////////////////////////////////////////// //// Language support defines //////////////////////////////////////////////////////////////////////////////// #ifndef FLECS_LEGACY #include #endif #ifndef NULL #define NULL ((void*)0) #endif /* The API uses the native bool type in C++, or a custom one in C */ #if !defined(__cplusplus) && !defined(__bool_true_false_are_defined) #undef bool #undef true #undef false typedef char bool; #define false 0 #define true !false #endif /* Utility types to indicate usage as bitmask */ typedef uint8_t ecs_flags8_t; typedef uint16_t ecs_flags16_t; typedef uint32_t ecs_flags32_t; typedef uint64_t ecs_flags64_t; /* Keep unsigned integers out of the codebase as they do more harm than good */ typedef int32_t ecs_size_t; /* Allocator type */ typedef struct ecs_allocator_t ecs_allocator_t; #define ECS_SIZEOF(T) ECS_CAST(ecs_size_t, sizeof(T)) /* Use alignof in C++, or a trick in C. */ #ifdef __cplusplus #define ECS_ALIGNOF(T) static_cast(alignof(T)) #elif defined(ECS_TARGET_MSVC) #define ECS_ALIGNOF(T) (int64_t)__alignof(T) #elif defined(ECS_TARGET_GNU) #define ECS_ALIGNOF(T) (int64_t)__alignof__(T) #else #define ECS_ALIGNOF(T) ((int64_t)&((struct { char c; T d; } *)0)->d) #endif #ifndef FLECS_NO_DEPRECATED_WARNINGS #if defined(ECS_TARGET_GNU) #define ECS_DEPRECATED(msg) __attribute__((deprecated(msg))) #elif defined(ECS_TARGET_MSVC) #define ECS_DEPRECATED(msg) __declspec(deprecated(msg)) #else #define ECS_DEPRECATED(msg) #endif #else #define ECS_DEPRECATED(msg) #endif #define ECS_ALIGN(size, alignment) (ecs_size_t)((((((size_t)size) - 1) / ((size_t)alignment)) + 1) * ((size_t)alignment)) /* Simple utility for determining the max of two values */ #define ECS_MAX(a, b) (((a) > (b)) ? a : b) #define ECS_MIN(a, b) (((a) < (b)) ? a : b) /* Abstraction on top of C-style casts so that C functions can be used in C++ * code without producing warnings */ #ifndef __cplusplus #define ECS_CAST(T, V) ((T)(V)) #else #define ECS_CAST(T, V) (static_cast(V)) #endif /* Utility macro for doing const casts without warnings */ #ifndef __cplusplus #define ECS_CONST_CAST(type, value) ((type)(uintptr_t)(value)) #else #define ECS_CONST_CAST(type, value) (const_cast(value)) #endif /* Utility macro for doing pointer casts without warnings */ #ifndef __cplusplus #define ECS_PTR_CAST(type, value) ((type)(uintptr_t)(value)) #else #define ECS_PTR_CAST(type, value) (reinterpret_cast(value)) #endif /* Utility macro's to do bitwise comparisons between floats without warnings */ #define ECS_EQ(a, b) (ecs_os_memcmp(&(a), &(b), sizeof(a)) == 0) #define ECS_NEQ(a, b) (!ECS_EQ(a, b)) #define ECS_EQZERO(a) ECS_EQ(a, (uint64_t){0}) #define ECS_NEQZERO(a) ECS_NEQ(a, (uint64_t){0}) /* Utilities to convert flecs version to string */ #define FLECS_VERSION_IMPLSTR(major, minor, patch) #major "." #minor "." #patch #define FLECS_VERSION_IMPL(major, minor, patch) \ FLECS_VERSION_IMPLSTR(major, minor, patch) #define ECS_CONCAT(a, b) a ## b //////////////////////////////////////////////////////////////////////////////// //// Magic numbers for sanity checking //////////////////////////////////////////////////////////////////////////////// /* Magic number to identify the type of the object */ #define ecs_world_t_magic (0x65637377) #define ecs_stage_t_magic (0x65637373) #define ecs_query_t_magic (0x65637371) #define ecs_rule_t_magic (0x65637375) #define ecs_table_t_magic (0x65637374) #define ecs_filter_t_magic (0x65637366) #define ecs_trigger_t_magic (0x65637372) #define ecs_observer_t_magic (0x65637362) //////////////////////////////////////////////////////////////////////////////// //// Entity id macros //////////////////////////////////////////////////////////////////////////////// #define ECS_ROW_MASK (0x0FFFFFFFu) #define ECS_ROW_FLAGS_MASK (~ECS_ROW_MASK) #define ECS_RECORD_TO_ROW(v) (ECS_CAST(int32_t, (ECS_CAST(uint32_t, v) & ECS_ROW_MASK))) #define ECS_RECORD_TO_ROW_FLAGS(v) (ECS_CAST(uint32_t, v) & ECS_ROW_FLAGS_MASK) #define ECS_ROW_TO_RECORD(row, flags) (ECS_CAST(uint32_t, (ECS_CAST(uint32_t, row) | (flags)))) #define ECS_ID_FLAGS_MASK (0xFFull << 60) #define ECS_ENTITY_MASK (0xFFFFFFFFull) #define ECS_GENERATION_MASK (0xFFFFull << 32) #define ECS_GENERATION(e) ((e & ECS_GENERATION_MASK) >> 32) #define ECS_GENERATION_INC(e) ((e & ~ECS_GENERATION_MASK) | ((0xFFFF & (ECS_GENERATION(e) + 1)) << 32)) #define ECS_COMPONENT_MASK (~ECS_ID_FLAGS_MASK) #define ECS_HAS_ID_FLAG(e, flag) ((e) & ECS_##flag) #define ECS_IS_PAIR(id) (((id) & ECS_ID_FLAGS_MASK) == ECS_PAIR) #define ECS_PAIR_FIRST(e) (ecs_entity_t_hi(e & ECS_COMPONENT_MASK)) #define ECS_PAIR_SECOND(e) (ecs_entity_t_lo(e)) #define ECS_HAS_RELATION(e, rel) (ECS_HAS_ID_FLAG(e, PAIR) && (ECS_PAIR_FIRST(e) == rel)) //////////////////////////////////////////////////////////////////////////////// //// Convert between C typenames and variables //////////////////////////////////////////////////////////////////////////////// /** Translate C type to id. */ #define ecs_id(T) FLECS_ID##T##ID_ //////////////////////////////////////////////////////////////////////////////// //// Utilities for working with pair identifiers //////////////////////////////////////////////////////////////////////////////// #define ecs_entity_t_lo(value) ECS_CAST(uint32_t, value) #define ecs_entity_t_hi(value) ECS_CAST(uint32_t, (value) >> 32) #define ecs_entity_t_comb(lo, hi) ((ECS_CAST(uint64_t, hi) << 32) + ECS_CAST(uint32_t, lo)) #define ecs_pair(pred, obj) (ECS_PAIR | ecs_entity_t_comb(obj, pred)) #define ecs_pair_t(pred, obj) (ECS_PAIR | ecs_entity_t_comb(obj, ecs_id(pred))) #define ecs_pair_first(world, pair) ecs_get_alive(world, ECS_PAIR_FIRST(pair)) #define ecs_pair_second(world, pair) ecs_get_alive(world, ECS_PAIR_SECOND(pair)) #define ecs_pair_relation ecs_pair_first #define ecs_pair_object ecs_pair_second #define ecs_poly_id(tag) ecs_pair(ecs_id(EcsPoly), tag) //////////////////////////////////////////////////////////////////////////////// //// Debug macros //////////////////////////////////////////////////////////////////////////////// #ifndef FLECS_NDEBUG #define ECS_TABLE_LOCK(world, table) ecs_table_lock(world, table) #define ECS_TABLE_UNLOCK(world, table) ecs_table_unlock(world, table) #else #define ECS_TABLE_LOCK(world, table) #define ECS_TABLE_UNLOCK(world, table) #endif //////////////////////////////////////////////////////////////////////////////// //// Actions that drive iteration //////////////////////////////////////////////////////////////////////////////// #define EcsIterNextYield (0) /* Move to next table, yield current */ #define EcsIterYield (-1) /* Stay on current table, yield */ #define EcsIterNext (1) /* Move to next table, don't yield */ //////////////////////////////////////////////////////////////////////////////// //// Convenience macros for ctor, dtor, move and copy //////////////////////////////////////////////////////////////////////////////// #ifndef FLECS_LEGACY /* Constructor/Destructor convenience macro */ #define ECS_XTOR_IMPL(type, postfix, var, ...)\ void type##_##postfix(\ void *_ptr,\ int32_t _count,\ const ecs_type_info_t *type_info)\ {\ (void)_ptr;\ (void)_count;\ (void)type_info;\ for (int32_t i = 0; i < _count; i ++) {\ type *var = &((type*)_ptr)[i];\ (void)var;\ __VA_ARGS__\ }\ } /* Copy convenience macro */ #define ECS_COPY_IMPL(type, dst_var, src_var, ...)\ void type##_##copy(\ void *_dst_ptr,\ const void *_src_ptr,\ int32_t _count,\ const ecs_type_info_t *type_info)\ {\ (void)_dst_ptr;\ (void)_src_ptr;\ (void)_count;\ (void)type_info;\ for (int32_t i = 0; i < _count; i ++) {\ type *dst_var = &((type*)_dst_ptr)[i];\ const type *src_var = &((const type*)_src_ptr)[i];\ (void)dst_var;\ (void)src_var;\ __VA_ARGS__\ }\ } /* Move convenience macro */ #define ECS_MOVE_IMPL(type, dst_var, src_var, ...)\ void type##_##move(\ void *_dst_ptr,\ void *_src_ptr,\ int32_t _count,\ const ecs_type_info_t *type_info)\ {\ (void)_dst_ptr;\ (void)_src_ptr;\ (void)_count;\ (void)type_info;\ for (int32_t i = 0; i < _count; i ++) {\ type *dst_var = &((type*)_dst_ptr)[i];\ type *src_var = &((type*)_src_ptr)[i];\ (void)dst_var;\ (void)src_var;\ __VA_ARGS__\ }\ } #define ECS_HOOK_IMPL(type, func, var, ...)\ void func(ecs_iter_t *_it)\ {\ for (int32_t i = 0; i < _it->count; i ++) {\ ecs_entity_t entity = _it->entities[i];\ type *var = &((type*)_it->ptrs[0])[i];\ (void)entity;\ (void)var;\ __VA_ARGS__\ }\ } #endif #ifdef __cplusplus } #endif #endif /** * @file vec.h * @brief Vector with allocator support. */ #ifndef FLECS_VEC_H #define FLECS_VEC_H #ifdef __cplusplus extern "C" { #endif /** A component column. */ typedef struct ecs_vec_t { void *array; int32_t count; int32_t size; #ifdef FLECS_SANITIZE ecs_size_t elem_size; #endif } ecs_vec_t; FLECS_API ecs_vec_t* ecs_vec_init( struct ecs_allocator_t *allocator, ecs_vec_t *vec, ecs_size_t size, int32_t elem_count); #define ecs_vec_init_t(allocator, vec, T, elem_count) \ ecs_vec_init(allocator, vec, ECS_SIZEOF(T), elem_count) FLECS_API void ecs_vec_init_if( ecs_vec_t *vec, ecs_size_t size); #define ecs_vec_init_if_t(vec, T) \ ecs_vec_init_if(vec, ECS_SIZEOF(T)) FLECS_API void ecs_vec_fini( struct ecs_allocator_t *allocator, ecs_vec_t *vec, ecs_size_t size); #define ecs_vec_fini_t(allocator, vec, T) \ ecs_vec_fini(allocator, vec, ECS_SIZEOF(T)) FLECS_API ecs_vec_t* ecs_vec_reset( struct ecs_allocator_t *allocator, ecs_vec_t *vec, ecs_size_t size); #define ecs_vec_reset_t(allocator, vec, T) \ ecs_vec_reset(allocator, vec, ECS_SIZEOF(T)) FLECS_API void ecs_vec_clear( ecs_vec_t *vec); FLECS_API void* ecs_vec_append( struct ecs_allocator_t *allocator, ecs_vec_t *vec, ecs_size_t size); #define ecs_vec_append_t(allocator, vec, T) \ ECS_CAST(T*, ecs_vec_append(allocator, vec, ECS_SIZEOF(T))) FLECS_API void ecs_vec_remove( ecs_vec_t *vec, ecs_size_t size, int32_t elem); #define ecs_vec_remove_t(vec, T, elem) \ ecs_vec_remove(vec, ECS_SIZEOF(T), elem) FLECS_API void ecs_vec_remove_last( ecs_vec_t *vec); FLECS_API ecs_vec_t ecs_vec_copy( struct ecs_allocator_t *allocator, const ecs_vec_t *vec, ecs_size_t size); #define ecs_vec_copy_t(allocator, vec, T) \ ecs_vec_copy(allocator, vec, ECS_SIZEOF(T)) FLECS_API ecs_vec_t ecs_vec_copy_shrink( struct ecs_allocator_t *allocator, const ecs_vec_t *vec, ecs_size_t size); #define ecs_vec_copy_shrink_t(allocator, vec, T) \ ecs_vec_copy_shrink(allocator, vec, ECS_SIZEOF(T)) FLECS_API void ecs_vec_reclaim( struct ecs_allocator_t *allocator, ecs_vec_t *vec, ecs_size_t size); #define ecs_vec_reclaim_t(allocator, vec, T) \ ecs_vec_reclaim(allocator, vec, ECS_SIZEOF(T)) FLECS_API void ecs_vec_set_size( struct ecs_allocator_t *allocator, ecs_vec_t *vec, ecs_size_t size, int32_t elem_count); #define ecs_vec_set_size_t(allocator, vec, T, elem_count) \ ecs_vec_set_size(allocator, vec, ECS_SIZEOF(T), elem_count) FLECS_API void ecs_vec_set_min_size( struct ecs_allocator_t *allocator, ecs_vec_t *vec, ecs_size_t size, int32_t elem_count); #define ecs_vec_set_min_size_t(allocator, vec, T, elem_count) \ ecs_vec_set_min_size(allocator, vec, ECS_SIZEOF(T), elem_count) FLECS_API void ecs_vec_set_min_count( struct ecs_allocator_t *allocator, ecs_vec_t *vec, ecs_size_t size, int32_t elem_count); #define ecs_vec_set_min_count_t(allocator, vec, T, elem_count) \ ecs_vec_set_min_count(allocator, vec, ECS_SIZEOF(T), elem_count) FLECS_API void ecs_vec_set_min_count_zeromem( struct ecs_allocator_t *allocator, ecs_vec_t *vec, ecs_size_t size, int32_t elem_count); #define ecs_vec_set_min_count_zeromem_t(allocator, vec, T, elem_count) \ ecs_vec_set_min_count_zeromem(allocator, vec, ECS_SIZEOF(T), elem_count) FLECS_API void ecs_vec_set_count( struct ecs_allocator_t *allocator, ecs_vec_t *vec, ecs_size_t size, int32_t elem_count); #define ecs_vec_set_count_t(allocator, vec, T, elem_count) \ ecs_vec_set_count(allocator, vec, ECS_SIZEOF(T), elem_count) FLECS_API void* ecs_vec_grow( struct ecs_allocator_t *allocator, ecs_vec_t *vec, ecs_size_t size, int32_t elem_count); #define ecs_vec_grow_t(allocator, vec, T, elem_count) \ ecs_vec_grow(allocator, vec, ECS_SIZEOF(T), elem_count) FLECS_API int32_t ecs_vec_count( const ecs_vec_t *vec); FLECS_API int32_t ecs_vec_size( const ecs_vec_t *vec); FLECS_API void* ecs_vec_get( const ecs_vec_t *vec, ecs_size_t size, int32_t index); #define ecs_vec_get_t(vec, T, index) \ ECS_CAST(T*, ecs_vec_get(vec, ECS_SIZEOF(T), index)) FLECS_API void* ecs_vec_first( const ecs_vec_t *vec); #define ecs_vec_first_t(vec, T) \ ECS_CAST(T*, ecs_vec_first(vec)) FLECS_API void* ecs_vec_last( const ecs_vec_t *vec, ecs_size_t size); #define ecs_vec_last_t(vec, T) \ ECS_CAST(T*, ecs_vec_last(vec, ECS_SIZEOF(T))) #ifdef __cplusplus } #endif #endif /** * @file sparse.h * @brief Sparse set data structure. */ #ifndef FLECS_SPARSE_H #define FLECS_SPARSE_H #ifdef __cplusplus extern "C" { #endif /** The number of elements in a single page */ #define FLECS_SPARSE_PAGE_SIZE (1 << FLECS_SPARSE_PAGE_BITS) typedef struct ecs_sparse_t { ecs_vec_t dense; /* Dense array with indices to sparse array. The * dense array stores both alive and not alive * sparse indices. The 'count' member keeps * track of which indices are alive. */ ecs_vec_t pages; /* Chunks with sparse arrays & data */ ecs_size_t size; /* Element size */ int32_t count; /* Number of alive entries */ uint64_t max_id; /* Local max index (if no global is set) */ struct ecs_allocator_t *allocator; struct ecs_block_allocator_t *page_allocator; } ecs_sparse_t; /** Initialize sparse set */ FLECS_DBG_API void flecs_sparse_init( ecs_sparse_t *result, struct ecs_allocator_t *allocator, struct ecs_block_allocator_t *page_allocator, ecs_size_t size); #define flecs_sparse_init_t(result, allocator, page_allocator, T)\ flecs_sparse_init(result, allocator, page_allocator, ECS_SIZEOF(T)) FLECS_DBG_API void flecs_sparse_fini( ecs_sparse_t *sparse); /** Remove all elements from sparse set */ FLECS_DBG_API void flecs_sparse_clear( ecs_sparse_t *sparse); /** Add element to sparse set, this generates or recycles an id */ FLECS_DBG_API void* flecs_sparse_add( ecs_sparse_t *sparse, ecs_size_t elem_size); #define flecs_sparse_add_t(sparse, T)\ ECS_CAST(T*, flecs_sparse_add(sparse, ECS_SIZEOF(T))) /** Get last issued id. */ FLECS_DBG_API uint64_t flecs_sparse_last_id( const ecs_sparse_t *sparse); /** Generate or recycle a new id. */ FLECS_DBG_API uint64_t flecs_sparse_new_id( ecs_sparse_t *sparse); /** Remove an element */ FLECS_DBG_API void flecs_sparse_remove( ecs_sparse_t *sparse, ecs_size_t elem_size, uint64_t id); #define flecs_sparse_remove_t(sparse, T, id)\ flecs_sparse_remove(sparse, ECS_SIZEOF(T), id) /** Test if id is alive, which requires the generation count to match. */ FLECS_DBG_API bool flecs_sparse_is_alive( const ecs_sparse_t *sparse, uint64_t id); /** Get value from sparse set by dense id. This function is useful in * combination with flecs_sparse_count for iterating all values in the set. */ FLECS_DBG_API void* flecs_sparse_get_dense( const ecs_sparse_t *sparse, ecs_size_t elem_size, int32_t index); #define flecs_sparse_get_dense_t(sparse, T, index)\ ECS_CAST(T*, flecs_sparse_get_dense(sparse, ECS_SIZEOF(T), index)) /** Get the number of alive elements in the sparse set. */ FLECS_DBG_API int32_t flecs_sparse_count( const ecs_sparse_t *sparse); /** Get element by (sparse) id. The returned pointer is stable for the duration * of the sparse set, as it is stored in the sparse array. */ FLECS_DBG_API void* flecs_sparse_get( const ecs_sparse_t *sparse, ecs_size_t elem_size, uint64_t id); #define flecs_sparse_get_t(sparse, T, index)\ ECS_CAST(T*, flecs_sparse_get(sparse, ECS_SIZEOF(T), index)) /** Same as flecs_sparse_get, but doesn't assert if id is not alive. */ FLECS_DBG_API void* flecs_sparse_try( const ecs_sparse_t *sparse, ecs_size_t elem_size, uint64_t id); #define flecs_sparse_try_t(sparse, T, index)\ ECS_CAST(T*, flecs_sparse_try(sparse, ECS_SIZEOF(T), index)) /** Like get_sparse, but don't care whether element is alive or not. */ FLECS_DBG_API void* flecs_sparse_get_any( const ecs_sparse_t *sparse, ecs_size_t elem_size, uint64_t id); #define flecs_sparse_get_any_t(sparse, T, index)\ ECS_CAST(T*, flecs_sparse_get_any(sparse, ECS_SIZEOF(T), index)) /** Get or create element by (sparse) id. */ FLECS_DBG_API void* flecs_sparse_ensure( ecs_sparse_t *sparse, ecs_size_t elem_size, uint64_t id); #define flecs_sparse_ensure_t(sparse, T, index)\ ECS_CAST(T*, flecs_sparse_ensure(sparse, ECS_SIZEOF(T), index)) /** Fast version of ensure, no liveliness checking */ FLECS_DBG_API void* flecs_sparse_ensure_fast( ecs_sparse_t *sparse, ecs_size_t elem_size, uint64_t id); #define flecs_sparse_ensure_fast_t(sparse, T, index)\ ECS_CAST(T*, flecs_sparse_ensure_fast(sparse, ECS_SIZEOF(T), index)) /** Get pointer to ids (alive and not alive). Use with count() or size(). */ FLECS_DBG_API const uint64_t* flecs_sparse_ids( const ecs_sparse_t *sparse); /* Publicly exposed APIs * The flecs_ functions aren't exposed directly as this can cause some * optimizers to not consider them for link time optimization. */ FLECS_API void ecs_sparse_init( ecs_sparse_t *sparse, ecs_size_t elem_size); #define ecs_sparse_init_t(sparse, T)\ ecs_sparse_init(sparse, ECS_SIZEOF(T)) FLECS_API void* ecs_sparse_add( ecs_sparse_t *sparse, ecs_size_t elem_size); #define ecs_sparse_add_t(sparse, T)\ ECS_CAST(T*, ecs_sparse_add(sparse, ECS_SIZEOF(T))) FLECS_API uint64_t ecs_sparse_last_id( const ecs_sparse_t *sparse); FLECS_API int32_t ecs_sparse_count( const ecs_sparse_t *sparse); FLECS_API void* ecs_sparse_get_dense( const ecs_sparse_t *sparse, ecs_size_t elem_size, int32_t index); #define ecs_sparse_get_dense_t(sparse, T, index)\ ECS_CAST(T*, ecs_sparse_get_dense(sparse, ECS_SIZEOF(T), index)) FLECS_API void* ecs_sparse_get( const ecs_sparse_t *sparse, ecs_size_t elem_size, uint64_t id); #define ecs_sparse_get_t(sparse, T, index)\ ECS_CAST(T*, ecs_sparse_get(sparse, ECS_SIZEOF(T), index)) #ifdef __cplusplus } #endif #endif /** * @file block_allocator.h * @brief Block allocator. */ #ifndef FLECS_BLOCK_ALLOCATOR_H #define FLECS_BLOCK_ALLOCATOR_H typedef struct ecs_block_allocator_block_t { void *memory; struct ecs_block_allocator_block_t *next; } ecs_block_allocator_block_t; typedef struct ecs_block_allocator_chunk_header_t { struct ecs_block_allocator_chunk_header_t *next; } ecs_block_allocator_chunk_header_t; typedef struct ecs_block_allocator_t { ecs_block_allocator_chunk_header_t *head; ecs_block_allocator_block_t *block_head; ecs_block_allocator_block_t *block_tail; int32_t chunk_size; int32_t data_size; int32_t chunks_per_block; int32_t block_size; int32_t alloc_count; } ecs_block_allocator_t; FLECS_API void flecs_ballocator_init( ecs_block_allocator_t *ba, ecs_size_t size); #define flecs_ballocator_init_t(ba, T)\ flecs_ballocator_init(ba, ECS_SIZEOF(T)) #define flecs_ballocator_init_n(ba, T, count)\ flecs_ballocator_init(ba, ECS_SIZEOF(T) * count) FLECS_API ecs_block_allocator_t* flecs_ballocator_new( ecs_size_t size); #define flecs_ballocator_new_t(T)\ flecs_ballocator_new(ECS_SIZEOF(T)) #define flecs_ballocator_new_n(T, count)\ flecs_ballocator_new(ECS_SIZEOF(T) * count) FLECS_API void flecs_ballocator_fini( ecs_block_allocator_t *ba); FLECS_API void flecs_ballocator_free( ecs_block_allocator_t *ba); FLECS_API void* flecs_balloc( ecs_block_allocator_t *allocator); FLECS_API void* flecs_bcalloc( ecs_block_allocator_t *allocator); FLECS_API void flecs_bfree( ecs_block_allocator_t *allocator, void *memory); FLECS_API void* flecs_brealloc( ecs_block_allocator_t *dst, ecs_block_allocator_t *src, void *memory); FLECS_API void* flecs_bdup( ecs_block_allocator_t *ba, void *memory); #endif /** * @file map.h * @brief Map data structure. */ #ifndef FLECS_MAP_H #define FLECS_MAP_H #ifdef __cplusplus extern "C" { #endif typedef uint64_t ecs_map_data_t; typedef ecs_map_data_t ecs_map_key_t; typedef ecs_map_data_t ecs_map_val_t; /* Map type */ typedef struct ecs_bucket_entry_t { ecs_map_key_t key; ecs_map_val_t value; struct ecs_bucket_entry_t *next; } ecs_bucket_entry_t; typedef struct ecs_bucket_t { ecs_bucket_entry_t *first; } ecs_bucket_t; typedef struct ecs_map_t { uint8_t bucket_shift; bool shared_allocator; ecs_bucket_t *buckets; int32_t bucket_count; int32_t count; struct ecs_block_allocator_t *entry_allocator; struct ecs_allocator_t *allocator; } ecs_map_t; typedef struct ecs_map_iter_t { const ecs_map_t *map; ecs_bucket_t *bucket; ecs_bucket_entry_t *entry; ecs_map_data_t *res; } ecs_map_iter_t; typedef struct ecs_map_params_t { struct ecs_allocator_t *allocator; struct ecs_block_allocator_t entry_allocator; } ecs_map_params_t; /* Function/macro postfixes meaning: * _ptr: access ecs_map_val_t as void* * _ref: access ecs_map_val_t* as T** * _deref: dereferences a _ref * _alloc: if _ptr is NULL, alloc * _free: if _ptr is not NULL, free */ FLECS_API void ecs_map_params_init( ecs_map_params_t *params, struct ecs_allocator_t *allocator); FLECS_API void ecs_map_params_fini( ecs_map_params_t *params); /** Initialize new map. */ FLECS_API void ecs_map_init( ecs_map_t *map, struct ecs_allocator_t *allocator); /** Initialize new map. */ FLECS_API void ecs_map_init_w_params( ecs_map_t *map, ecs_map_params_t *params); /** Initialize new map if uninitialized, leave as is otherwise */ FLECS_API void ecs_map_init_if( ecs_map_t *map, struct ecs_allocator_t *allocator); FLECS_API void ecs_map_init_w_params_if( ecs_map_t *result, ecs_map_params_t *params); /** Deinitialize map. */ FLECS_API void ecs_map_fini( ecs_map_t *map); /** Get element for key, returns NULL if they key doesn't exist. */ FLECS_API ecs_map_val_t* ecs_map_get( const ecs_map_t *map, ecs_map_key_t key); /* Get element as pointer (auto-dereferences _ptr) */ FLECS_API void* ecs_map_get_deref_( const ecs_map_t *map, ecs_map_key_t key); /** Get or insert element for key. */ FLECS_API ecs_map_val_t* ecs_map_ensure( ecs_map_t *map, ecs_map_key_t key); /** Get or insert pointer element for key, allocate if the pointer is NULL */ FLECS_API void* ecs_map_ensure_alloc( ecs_map_t *map, ecs_size_t elem_size, ecs_map_key_t key); /** Insert element for key. */ FLECS_API void ecs_map_insert( ecs_map_t *map, ecs_map_key_t key, ecs_map_val_t value); /** Insert pointer element for key, populate with new allocation. */ FLECS_API void* ecs_map_insert_alloc( ecs_map_t *map, ecs_size_t elem_size, ecs_map_key_t key); /** Remove key from map. */ FLECS_API ecs_map_val_t ecs_map_remove( ecs_map_t *map, ecs_map_key_t key); /* Remove pointer element, free if not NULL */ FLECS_API void ecs_map_remove_free( ecs_map_t *map, ecs_map_key_t key); /** Remove all elements from map. */ FLECS_API void ecs_map_clear( ecs_map_t *map); /** Return number of elements in map. */ #define ecs_map_count(map) ((map) ? (map)->count : 0) /** Is map initialized */ #define ecs_map_is_init(map) ((map) ? (map)->bucket_shift != 0 : false) /** Return iterator to map contents. */ FLECS_API ecs_map_iter_t ecs_map_iter( const ecs_map_t *map); /** Obtain next element in map from iterator. */ FLECS_API bool ecs_map_next( ecs_map_iter_t *iter); /** Copy map. */ FLECS_API void ecs_map_copy( ecs_map_t *dst, const ecs_map_t *src); #define ecs_map_get_ref(m, T, k) ECS_CAST(T**, ecs_map_get(m, k)) #define ecs_map_get_deref(m, T, k) ECS_CAST(T*, ecs_map_get_deref_(m, k)) #define ecs_map_ensure_ref(m, T, k) ECS_CAST(T**, ecs_map_ensure(m, k)) #define ecs_map_insert_ptr(m, k, v) ecs_map_insert(m, k, ECS_CAST(ecs_map_val_t, ECS_PTR_CAST(uintptr_t, v))) #define ecs_map_insert_alloc_t(m, T, k) ECS_CAST(T*, ecs_map_insert_alloc(m, ECS_SIZEOF(T), k)) #define ecs_map_ensure_alloc_t(m, T, k) ECS_PTR_CAST(T*, (uintptr_t)ecs_map_ensure_alloc(m, ECS_SIZEOF(T), k)) #define ecs_map_remove_ptr(m, k) (ECS_PTR_CAST(void*, ECS_CAST(uintptr_t, (ecs_map_remove(m, k))))) #define ecs_map_key(it) ((it)->res[0]) #define ecs_map_value(it) ((it)->res[1]) #define ecs_map_ptr(it) ECS_PTR_CAST(void*, ECS_CAST(uintptr_t, ecs_map_value(it))) #define ecs_map_ref(it, T) (ECS_CAST(T**, &((it)->res[1]))) #ifdef __cplusplus } #endif #endif /** * @file allocator.h * @brief Allocator that returns memory objects of any size. */ #ifndef FLECS_ALLOCATOR_H #define FLECS_ALLOCATOR_H FLECS_DBG_API extern int64_t ecs_block_allocator_alloc_count; FLECS_DBG_API extern int64_t ecs_block_allocator_free_count; FLECS_DBG_API extern int64_t ecs_stack_allocator_alloc_count; FLECS_DBG_API extern int64_t ecs_stack_allocator_free_count; struct ecs_allocator_t { ecs_block_allocator_t chunks; struct ecs_sparse_t sizes; /* */ }; FLECS_API void flecs_allocator_init( ecs_allocator_t *a); FLECS_API void flecs_allocator_fini( ecs_allocator_t *a); FLECS_API ecs_block_allocator_t* flecs_allocator_get( ecs_allocator_t *a, ecs_size_t size); FLECS_API char* flecs_strdup( ecs_allocator_t *a, const char* str); FLECS_API void flecs_strfree( ecs_allocator_t *a, char* str); FLECS_API void* flecs_dup( ecs_allocator_t *a, ecs_size_t size, const void *src); #define flecs_allocator(obj) (&obj->allocators.dyn) #define flecs_alloc(a, size) flecs_balloc(flecs_allocator_get(a, size)) #define flecs_alloc_t(a, T) flecs_alloc(a, ECS_SIZEOF(T)) #define flecs_alloc_n(a, T, count) flecs_alloc(a, ECS_SIZEOF(T) * (count)) #define flecs_calloc(a, size) flecs_bcalloc(flecs_allocator_get(a, size)) #define flecs_calloc_t(a, T) flecs_calloc(a, ECS_SIZEOF(T)) #define flecs_calloc_n(a, T, count) flecs_calloc(a, ECS_SIZEOF(T) * (count)) #define flecs_free(a, size, ptr) flecs_bfree(flecs_allocator_get(a, size), ptr) #define flecs_free_t(a, T, ptr) flecs_free(a, ECS_SIZEOF(T), ptr) #define flecs_free_n(a, T, count, ptr) flecs_free(a, ECS_SIZEOF(T) * (count), ptr) #define flecs_realloc(a, size_dst, size_src, ptr)\ flecs_brealloc(flecs_allocator_get(a, size_dst),\ flecs_allocator_get(a, size_src),\ ptr) #define flecs_realloc_n(a, T, count_dst, count_src, ptr)\ flecs_realloc(a, ECS_SIZEOF(T) * (count_dst), ECS_SIZEOF(T) * (count_src), ptr) #define flecs_dup_n(a, T, count, ptr) flecs_dup(a, ECS_SIZEOF(T) * (count), ptr) #endif /** * @file strbuf.h * @brief Utility for constructing strings. */ #ifndef FLECS_STRBUF_H_ #define FLECS_STRBUF_H_ #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus /* Fixes missing field initializer warning on g++ */ #define ECS_STRBUF_INIT (ecs_strbuf_t){} #else #define ECS_STRBUF_INIT (ecs_strbuf_t){0} #endif #define ECS_STRBUF_SMALL_STRING_SIZE (512) #define ECS_STRBUF_MAX_LIST_DEPTH (32) typedef struct ecs_strbuf_list_elem { int32_t count; const char *separator; } ecs_strbuf_list_elem; typedef struct ecs_strbuf_t { char *content; ecs_size_t length; ecs_size_t size; ecs_strbuf_list_elem list_stack[ECS_STRBUF_MAX_LIST_DEPTH]; int32_t list_sp; char small_string[ECS_STRBUF_SMALL_STRING_SIZE]; } ecs_strbuf_t; /* Append format string to a buffer. * Returns false when max is reached, true when there is still space */ FLECS_API void ecs_strbuf_append( ecs_strbuf_t *buffer, const char *fmt, ...); /* Append format string with argument list to a buffer. * Returns false when max is reached, true when there is still space */ FLECS_API void ecs_strbuf_vappend( ecs_strbuf_t *buffer, const char *fmt, va_list args); /* Append string to buffer. * Returns false when max is reached, true when there is still space */ FLECS_API void ecs_strbuf_appendstr( ecs_strbuf_t *buffer, const char *str); /* Append character to buffer. * Returns false when max is reached, true when there is still space */ FLECS_API void ecs_strbuf_appendch( ecs_strbuf_t *buffer, char ch); /* Append int to buffer. * Returns false when max is reached, true when there is still space */ FLECS_API void ecs_strbuf_appendint( ecs_strbuf_t *buffer, int64_t v); /* Append float to buffer. * Returns false when max is reached, true when there is still space */ FLECS_API void ecs_strbuf_appendflt( ecs_strbuf_t *buffer, double v, char nan_delim); /* Append boolean to buffer. * Returns false when max is reached, true when there is still space */ FLECS_API void ecs_strbuf_appendbool( ecs_strbuf_t *buffer, bool v); /* Append source buffer to destination buffer. * Returns false when max is reached, true when there is still space */ FLECS_API void ecs_strbuf_mergebuff( ecs_strbuf_t *dst_buffer, ecs_strbuf_t *src_buffer); /* Append n characters to buffer. * Returns false when max is reached, true when there is still space */ FLECS_API void ecs_strbuf_appendstrn( ecs_strbuf_t *buffer, const char *str, int32_t n); /* Return result string */ FLECS_API char* ecs_strbuf_get( ecs_strbuf_t *buffer); /* Return small string from first element (appends \0) */ FLECS_API char* ecs_strbuf_get_small( ecs_strbuf_t *buffer); /* Reset buffer without returning a string */ FLECS_API void ecs_strbuf_reset( ecs_strbuf_t *buffer); /* Push a list */ FLECS_API void ecs_strbuf_list_push( ecs_strbuf_t *buffer, const char *list_open, const char *separator); /* Pop a new list */ FLECS_API void ecs_strbuf_list_pop( ecs_strbuf_t *buffer, const char *list_close); /* Insert a new element in list */ FLECS_API void ecs_strbuf_list_next( ecs_strbuf_t *buffer); /* Append character to as new element in list. */ FLECS_API void ecs_strbuf_list_appendch( ecs_strbuf_t *buffer, char ch); /* Append formatted string as a new element in list */ FLECS_API void ecs_strbuf_list_append( ecs_strbuf_t *buffer, const char *fmt, ...); /* Append string as a new element in list */ FLECS_API void ecs_strbuf_list_appendstr( ecs_strbuf_t *buffer, const char *str); /* Append string as a new element in list */ FLECS_API void ecs_strbuf_list_appendstrn( ecs_strbuf_t *buffer, const char *str, int32_t n); FLECS_API int32_t ecs_strbuf_written( const ecs_strbuf_t *buffer); #define ecs_strbuf_appendlit(buf, str)\ ecs_strbuf_appendstrn(buf, str, (int32_t)(sizeof(str) - 1)) #define ecs_strbuf_list_appendlit(buf, str)\ ecs_strbuf_list_appendstrn(buf, str, (int32_t)(sizeof(str) - 1)) #ifdef __cplusplus } #endif #endif /** * @file os_api.h * @brief Operating system abstraction API. * * This file contains the operating system abstraction API. The flecs core * library avoids OS/runtime specific API calls as much as possible. Instead it * provides an interface that can be implemented by applications. * * Examples for how to implement this interface can be found in the * examples/os_api folder. */ #ifndef FLECS_OS_API_H #define FLECS_OS_API_H /** * @defgroup c_os_api OS API * @ingroup c * Interface for providing OS specific functionality. * * @{ */ #include #include #include #if defined(ECS_TARGET_WINDOWS) #include #elif defined(ECS_TARGET_FREEBSD) #include #else #include #endif #ifdef __cplusplus extern "C" { #endif typedef struct ecs_time_t { uint32_t sec; uint32_t nanosec; } ecs_time_t; /* Allocation counters */ extern int64_t ecs_os_api_malloc_count; extern int64_t ecs_os_api_realloc_count; extern int64_t ecs_os_api_calloc_count; extern int64_t ecs_os_api_free_count; /* Use handle types that _at least_ can store pointers */ typedef uintptr_t ecs_os_thread_t; typedef uintptr_t ecs_os_cond_t; typedef uintptr_t ecs_os_mutex_t; typedef uintptr_t ecs_os_dl_t; typedef uintptr_t ecs_os_sock_t; /* 64 bit thread id */ typedef uint64_t ecs_os_thread_id_t; /* Generic function pointer type */ typedef void (*ecs_os_proc_t)(void); /* OS API init */ typedef void (*ecs_os_api_init_t)(void); /* OS API deinit */ typedef void (*ecs_os_api_fini_t)(void); /* Memory management */ typedef void* (*ecs_os_api_malloc_t)( ecs_size_t size); typedef void (*ecs_os_api_free_t)( void *ptr); typedef void* (*ecs_os_api_realloc_t)( void *ptr, ecs_size_t size); typedef void* (*ecs_os_api_calloc_t)( ecs_size_t size); typedef char* (*ecs_os_api_strdup_t)( const char *str); /* Threads */ typedef void* (*ecs_os_thread_callback_t)( void*); typedef ecs_os_thread_t (*ecs_os_api_thread_new_t)( ecs_os_thread_callback_t callback, void *param); typedef void* (*ecs_os_api_thread_join_t)( ecs_os_thread_t thread); typedef ecs_os_thread_id_t (*ecs_os_api_thread_self_t)(void); /* Tasks */ typedef ecs_os_thread_t (*ecs_os_api_task_new_t)( ecs_os_thread_callback_t callback, void *param); typedef void* (*ecs_os_api_task_join_t)( ecs_os_thread_t thread); /* Atomic increment / decrement */ typedef int32_t (*ecs_os_api_ainc_t)( int32_t *value); typedef int64_t (*ecs_os_api_lainc_t)( int64_t *value); /* Mutex */ typedef ecs_os_mutex_t (*ecs_os_api_mutex_new_t)( void); typedef void (*ecs_os_api_mutex_lock_t)( ecs_os_mutex_t mutex); typedef void (*ecs_os_api_mutex_unlock_t)( ecs_os_mutex_t mutex); typedef void (*ecs_os_api_mutex_free_t)( ecs_os_mutex_t mutex); /* Condition variable */ typedef ecs_os_cond_t (*ecs_os_api_cond_new_t)( void); typedef void (*ecs_os_api_cond_free_t)( ecs_os_cond_t cond); typedef void (*ecs_os_api_cond_signal_t)( ecs_os_cond_t cond); typedef void (*ecs_os_api_cond_broadcast_t)( ecs_os_cond_t cond); typedef void (*ecs_os_api_cond_wait_t)( ecs_os_cond_t cond, ecs_os_mutex_t mutex); typedef void (*ecs_os_api_sleep_t)( int32_t sec, int32_t nanosec); typedef void (*ecs_os_api_enable_high_timer_resolution_t)( bool enable); typedef void (*ecs_os_api_get_time_t)( ecs_time_t *time_out); typedef uint64_t (*ecs_os_api_now_t)(void); /* Logging */ typedef void (*ecs_os_api_log_t)( int32_t level, /* Logging level */ const char *file, /* File where message was logged */ int32_t line, /* Line it was logged */ const char *msg); /* Application termination */ typedef void (*ecs_os_api_abort_t)( void); /* Dynamic libraries */ typedef ecs_os_dl_t (*ecs_os_api_dlopen_t)( const char *libname); typedef ecs_os_proc_t (*ecs_os_api_dlproc_t)( ecs_os_dl_t lib, const char *procname); typedef void (*ecs_os_api_dlclose_t)( ecs_os_dl_t lib); typedef char* (*ecs_os_api_module_to_path_t)( const char *module_id); /* Prefix members of struct with 'ecs_' as some system headers may define * macros for functions like "strdup", "log" or "_free" */ typedef struct ecs_os_api_t { /* API init / deinit */ ecs_os_api_init_t init_; ecs_os_api_fini_t fini_; /* Memory management */ ecs_os_api_malloc_t malloc_; ecs_os_api_realloc_t realloc_; ecs_os_api_calloc_t calloc_; ecs_os_api_free_t free_; /* Strings */ ecs_os_api_strdup_t strdup_; /* Threads */ ecs_os_api_thread_new_t thread_new_; ecs_os_api_thread_join_t thread_join_; ecs_os_api_thread_self_t thread_self_; /* Tasks */ ecs_os_api_thread_new_t task_new_; ecs_os_api_thread_join_t task_join_; /* Atomic increment / decrement */ ecs_os_api_ainc_t ainc_; ecs_os_api_ainc_t adec_; ecs_os_api_lainc_t lainc_; ecs_os_api_lainc_t ladec_; /* Mutex */ ecs_os_api_mutex_new_t mutex_new_; ecs_os_api_mutex_free_t mutex_free_; ecs_os_api_mutex_lock_t mutex_lock_; ecs_os_api_mutex_lock_t mutex_unlock_; /* Condition variable */ ecs_os_api_cond_new_t cond_new_; ecs_os_api_cond_free_t cond_free_; ecs_os_api_cond_signal_t cond_signal_; ecs_os_api_cond_broadcast_t cond_broadcast_; ecs_os_api_cond_wait_t cond_wait_; /* Time */ ecs_os_api_sleep_t sleep_; ecs_os_api_now_t now_; ecs_os_api_get_time_t get_time_; /* Logging */ ecs_os_api_log_t log_; /* Logging function. The level should be interpreted as: */ /* >0: Debug tracing. Only enabled in debug builds. */ /* 0: Tracing. Enabled in debug/release builds. */ /* -2: Warning. An issue occurred, but operation was successful. */ /* -3: Error. An issue occurred, and operation was unsuccessful. */ /* -4: Fatal. An issue occurred, and application must quit. */ /* Application termination */ ecs_os_api_abort_t abort_; /* Dynamic library loading */ ecs_os_api_dlopen_t dlopen_; ecs_os_api_dlproc_t dlproc_; ecs_os_api_dlclose_t dlclose_; /* Overridable function that translates from a logical module id to a * shared library filename */ ecs_os_api_module_to_path_t module_to_dl_; /* Overridable function that translates from a logical module id to a * path that contains module-specif resources or assets */ ecs_os_api_module_to_path_t module_to_etc_; /* Trace level */ int32_t log_level_; /* Trace indentation */ int32_t log_indent_; /* Last error code */ int32_t log_last_error_; /* Last recorded timestamp */ int64_t log_last_timestamp_; /* OS API flags */ ecs_flags32_t flags_; /* File used for logging output (hint, log_ decides where to write) */ FILE *log_out_; } ecs_os_api_t; FLECS_API extern ecs_os_api_t ecs_os_api; FLECS_API void ecs_os_init(void); FLECS_API void ecs_os_fini(void); FLECS_API void ecs_os_set_api( ecs_os_api_t *os_api); FLECS_API ecs_os_api_t ecs_os_get_api(void); FLECS_API void ecs_os_set_api_defaults(void); /* Memory management */ #ifndef ecs_os_malloc #define ecs_os_malloc(size) ecs_os_api.malloc_(size) #endif #ifndef ecs_os_free #define ecs_os_free(ptr) ecs_os_api.free_(ptr) #endif #ifndef ecs_os_realloc #define ecs_os_realloc(ptr, size) ecs_os_api.realloc_(ptr, size) #endif #ifndef ecs_os_calloc #define ecs_os_calloc(size) ecs_os_api.calloc_(size) #endif #if defined(ECS_TARGET_WINDOWS) #define ecs_os_alloca(size) _alloca((size_t)(size)) #else #define ecs_os_alloca(size) alloca((size_t)(size)) #endif #define ecs_os_malloc_t(T) ECS_CAST(T*, ecs_os_malloc(ECS_SIZEOF(T))) #define ecs_os_malloc_n(T, count) ECS_CAST(T*, ecs_os_malloc(ECS_SIZEOF(T) * (count))) #define ecs_os_calloc_t(T) ECS_CAST(T*, ecs_os_calloc(ECS_SIZEOF(T))) #define ecs_os_calloc_n(T, count) ECS_CAST(T*, ecs_os_calloc(ECS_SIZEOF(T) * (count))) #define ecs_os_realloc_t(ptr, T) ECS_CAST(T*, ecs_os_realloc(ptr, ECS_SIZEOF(T))) #define ecs_os_realloc_n(ptr, T, count) ECS_CAST(T*, ecs_os_realloc(ptr, ECS_SIZEOF(T) * (count))) #define ecs_os_alloca_t(T) ECS_CAST(T*, ecs_os_alloca(ECS_SIZEOF(T))) #define ecs_os_alloca_n(T, count) ECS_CAST(T*, ecs_os_alloca(ECS_SIZEOF(T) * (count))) /* Strings */ #ifndef ecs_os_strdup #define ecs_os_strdup(str) ecs_os_api.strdup_(str) #endif #ifdef __cplusplus #define ecs_os_strlen(str) static_cast(strlen(str)) #define ecs_os_strncmp(str1, str2, num) strncmp(str1, str2, static_cast(num)) #define ecs_os_memcmp(ptr1, ptr2, num) memcmp(ptr1, ptr2, static_cast(num)) #define ecs_os_memcpy(ptr1, ptr2, num) memcpy(ptr1, ptr2, static_cast(num)) #define ecs_os_memset(ptr, value, num) memset(ptr, value, static_cast(num)) #define ecs_os_memmove(dst, src, size) memmove(dst, src, static_cast(size)) #else #define ecs_os_strlen(str) (ecs_size_t)strlen(str) #define ecs_os_strncmp(str1, str2, num) strncmp(str1, str2, (size_t)(num)) #define ecs_os_memcmp(ptr1, ptr2, num) memcmp(ptr1, ptr2, (size_t)(num)) #define ecs_os_memcpy(ptr1, ptr2, num) memcpy(ptr1, ptr2, (size_t)(num)) #define ecs_os_memset(ptr, value, num) memset(ptr, value, (size_t)(num)) #define ecs_os_memmove(dst, src, size) memmove(dst, src, (size_t)(size)) #endif #define ecs_os_memcpy_t(ptr1, ptr2, T) ecs_os_memcpy(ptr1, ptr2, ECS_SIZEOF(T)) #define ecs_os_memcpy_n(ptr1, ptr2, T, count) ecs_os_memcpy(ptr1, ptr2, ECS_SIZEOF(T) * count) #define ecs_os_memcmp_t(ptr1, ptr2, T) ecs_os_memcmp(ptr1, ptr2, ECS_SIZEOF(T)) #define ecs_os_memmove_t(ptr1, ptr2, T) ecs_os_memmove(ptr1, ptr2, ECS_SIZEOF(T)) #define ecs_os_memmove_n(ptr1, ptr2, T, count) ecs_os_memmove(ptr1, ptr2, ECS_SIZEOF(T) * count) #define ecs_os_memmove_t(ptr1, ptr2, T) ecs_os_memmove(ptr1, ptr2, ECS_SIZEOF(T)) #define ecs_os_strcmp(str1, str2) strcmp(str1, str2) #define ecs_os_memset_t(ptr, value, T) ecs_os_memset(ptr, value, ECS_SIZEOF(T)) #define ecs_os_memset_n(ptr, value, T, count) ecs_os_memset(ptr, value, ECS_SIZEOF(T) * count) #define ecs_os_zeromem(ptr) ecs_os_memset(ptr, 0, ECS_SIZEOF(*ptr)) #define ecs_os_memdup_t(ptr, T) ecs_os_memdup(ptr, ECS_SIZEOF(T)) #define ecs_os_memdup_n(ptr, T, count) ecs_os_memdup(ptr, ECS_SIZEOF(T) * count) #define ecs_offset(ptr, T, index)\ ECS_CAST(T*, ECS_OFFSET(ptr, ECS_SIZEOF(T) * index)) #if !defined(ECS_TARGET_POSIX) && !defined(ECS_TARGET_MINGW) #define ecs_os_strcat(str1, str2) strcat_s(str1, INT_MAX, str2) #define ecs_os_sprintf(ptr, ...) sprintf_s(ptr, INT_MAX, __VA_ARGS__) #define ecs_os_snprintf(ptr, len, ...) sprintf_s(ptr, len, __VA_ARGS__) #define ecs_os_vsprintf(ptr, fmt, args) vsprintf_s(ptr, INT_MAX, fmt, args) #define ecs_os_strcpy(str1, str2) strcpy_s(str1, INT_MAX, str2) #ifdef __cplusplus #define ecs_os_strncpy(str1, str2, num) strncpy_s(str1, INT_MAX, str2, static_cast(num)) #else #define ecs_os_strncpy(str1, str2, num) strncpy_s(str1, INT_MAX, str2, (size_t)(num)) #endif #else #define ecs_os_strcat(str1, str2) strcat(str1, str2) #define ecs_os_sprintf(ptr, ...) sprintf(ptr, __VA_ARGS__) #define ecs_os_snprintf(ptr, len, ...) snprintf(ptr, len, __VA_ARGS__) #define ecs_os_vsprintf(ptr, fmt, args) vsprintf(ptr, fmt, args) #define ecs_os_strcpy(str1, str2) strcpy(str1, str2) #ifdef __cplusplus #define ecs_os_strncpy(str1, str2, num) strncpy(str1, str2, static_cast(num)) #else #define ecs_os_strncpy(str1, str2, num) strncpy(str1, str2, (size_t)(num)) #endif #endif /* Files */ #ifndef ECS_TARGET_POSIX #define ecs_os_fopen(result, file, mode) fopen_s(result, file, mode) #else #define ecs_os_fopen(result, file, mode) (*(result)) = fopen(file, mode) #endif /* Threads */ #define ecs_os_thread_new(callback, param) ecs_os_api.thread_new_(callback, param) #define ecs_os_thread_join(thread) ecs_os_api.thread_join_(thread) #define ecs_os_thread_self() ecs_os_api.thread_self_() /* Tasks */ #define ecs_os_task_new(callback, param) ecs_os_api.task_new_(callback, param) #define ecs_os_task_join(thread) ecs_os_api.task_join_(thread) /* Atomic increment / decrement */ #define ecs_os_ainc(value) ecs_os_api.ainc_(value) #define ecs_os_adec(value) ecs_os_api.adec_(value) #define ecs_os_lainc(value) ecs_os_api.lainc_(value) #define ecs_os_ladec(value) ecs_os_api.ladec_(value) /* Mutex */ #define ecs_os_mutex_new() ecs_os_api.mutex_new_() #define ecs_os_mutex_free(mutex) ecs_os_api.mutex_free_(mutex) #define ecs_os_mutex_lock(mutex) ecs_os_api.mutex_lock_(mutex) #define ecs_os_mutex_unlock(mutex) ecs_os_api.mutex_unlock_(mutex) /* Condition variable */ #define ecs_os_cond_new() ecs_os_api.cond_new_() #define ecs_os_cond_free(cond) ecs_os_api.cond_free_(cond) #define ecs_os_cond_signal(cond) ecs_os_api.cond_signal_(cond) #define ecs_os_cond_broadcast(cond) ecs_os_api.cond_broadcast_(cond) #define ecs_os_cond_wait(cond, mutex) ecs_os_api.cond_wait_(cond, mutex) /* Time */ #define ecs_os_sleep(sec, nanosec) ecs_os_api.sleep_(sec, nanosec) #define ecs_os_now() ecs_os_api.now_() #define ecs_os_get_time(time_out) ecs_os_api.get_time_(time_out) /* Logging */ FLECS_API void ecs_os_dbg(const char *file, int32_t line, const char *msg); FLECS_API void ecs_os_trace(const char *file, int32_t line, const char *msg); FLECS_API void ecs_os_warn(const char *file, int32_t line, const char *msg); FLECS_API void ecs_os_err(const char *file, int32_t line, const char *msg); FLECS_API void ecs_os_fatal(const char *file, int32_t line, const char *msg); FLECS_API const char* ecs_os_strerror(int err); FLECS_API void ecs_os_strset(char **str, const char *value); #ifdef FLECS_ACCURATE_COUNTERS #define ecs_os_inc(v) (ecs_os_ainc(v)) #define ecs_os_linc(v) (ecs_os_lainc(v)) #define ecs_os_dec(v) (ecs_os_adec(v)) #define ecs_os_ldec(v) (ecs_os_ladec(v)) #else #define ecs_os_inc(v) (++(*v)) #define ecs_os_linc(v) (++(*v)) #define ecs_os_dec(v) (--(*v)) #define ecs_os_ldec(v) (--(*v)) #endif #ifdef ECS_TARGET_MINGW /* mingw bug: without this a conversion error is thrown, but isnan/isinf should * accept float, double and long double. */ #define ecs_os_isnan(val) (isnan((float)val)) #define ecs_os_isinf(val) (isinf((float)val)) #else #define ecs_os_isnan(val) (isnan(val)) #define ecs_os_isinf(val) (isinf(val)) #endif /* Application termination */ #define ecs_os_abort() ecs_os_api.abort_() /* Dynamic libraries */ #define ecs_os_dlopen(libname) ecs_os_api.dlopen_(libname) #define ecs_os_dlproc(lib, procname) ecs_os_api.dlproc_(lib, procname) #define ecs_os_dlclose(lib) ecs_os_api.dlclose_(lib) /* Module id translation */ #define ecs_os_module_to_dl(lib) ecs_os_api.module_to_dl_(lib) #define ecs_os_module_to_etc(lib) ecs_os_api.module_to_etc_(lib) /* Sleep with floating point time */ FLECS_API void ecs_sleepf( double t); /* Measure time since provided timestamp */ FLECS_API double ecs_time_measure( ecs_time_t *start); /* Calculate difference between two timestamps */ FLECS_API ecs_time_t ecs_time_sub( ecs_time_t t1, ecs_time_t t2); /* Convert time value to a double */ FLECS_API double ecs_time_to_double( ecs_time_t t); FLECS_API void* ecs_os_memdup( const void *src, ecs_size_t size); /** Are heap functions available? */ FLECS_API bool ecs_os_has_heap(void); /** Are threading functions available? */ FLECS_API bool ecs_os_has_threading(void); /** Are task functions available? */ FLECS_API bool ecs_os_has_task_support(void); /** Are time functions available? */ FLECS_API bool ecs_os_has_time(void); /** Are logging functions available? */ FLECS_API bool ecs_os_has_logging(void); /** Are dynamic library functions available? */ FLECS_API bool ecs_os_has_dl(void); /** Are module path functions available? */ FLECS_API bool ecs_os_has_modules(void); #ifdef __cplusplus } #endif /** @} */ #endif #ifdef __cplusplus extern "C" { #endif /** * @defgroup api_types API types * Public API types. * * @{ */ /** * @defgroup core_types Core API Types * Types for core API objects. * * @{ */ /** Ids are the things that can be added to an entity. * An id can be an entity or pair, and can have optional id flags. */ typedef uint64_t ecs_id_t; /** An entity identifier. * Entity ids consist out of a number unique to the entity in the lower 32 bits, * and a counter used to track entity liveliness in the upper 32 bits. When an * id is recycled, its generation count is increased. This causes recycled ids * to be very large (>4 billion), which is normal. */ typedef ecs_id_t ecs_entity_t; /** A type is a list of (component) ids. * Types are used to communicate the "type" of an entity. In most type systems a * typeof operation returns a single type. In ECS however, an entity can have * multiple components, which is why an ECS type consists of a vector of ids. * * The component ids of a type are sorted, which ensures that it doesn't matter * in which order components are added to an entity. For example, if adding * Position then Velocity would result in type [Position, Velocity], first * adding Velocity then Position would also result in type [Position, Velocity]. * * Entities are grouped together by type in the ECS storage in tables. The * storage has exactly one table per unique type that is created by the * application that stores all entities and components for that type. This is * also referred to as an archetype. */ typedef struct { ecs_id_t *array; int32_t count; } ecs_type_t; /** A world is the container for all ECS data and supporting features. * Applications can have multiple worlds, though in most cases will only need * one. Worlds are isolated from each other, and can have separate sets of * systems, components, modules etc. * * If an application has multiple worlds with overlapping components, it is * common (though not strictly required) to use the same component ids across * worlds, which can be achieved by declaring a global component id variable. * To do this in the C API, see the entities/fwd_component_decl example. The * C++ API automatically synchronizes component ids between worlds. * * Component id conflicts between worlds can occur when a world has already used * an id for something else. There are a few ways to avoid this: * * - Ensure to register the same components in each world, in the same order. * - Create a dummy world in which all components are preregistered which * initializes the global id variables. * * In some use cases, typically when writing tests, multiple worlds are created * and deleted with different components, registered in different order. To * ensure isolation between tests, the C++ API has a `flecs::reset` function * that forces the API to ignore the old component ids. */ typedef struct ecs_world_t ecs_world_t; /** A table stores entities and components for a specific type. */ typedef struct ecs_table_t ecs_table_t; /** A term is a single element in a query. */ typedef struct ecs_term_t ecs_term_t; /** A filter is an iterable data structure that describes a query. * Filters are used by the various query implementations in Flecs, like queries, * observers and rules, to describe a query. Filters themselves can also be * iterated. */ typedef struct ecs_filter_t ecs_filter_t; /** A query that caches its results. * Queries are the fastest mechanism for finding and iterating over entities. * Queries cache results as a list of matching tables (vs. individual entities). * * This has several advantages: * - Matching is only performed when new tables are created, which is infrequent * - Iterating a query just walks over the cache, no actual searching is needed * - Iteration is table-based, which allows for direct iteration of underlying * component arrays, providing good cache locality. * * While queries are the fastest mechanism to iterate entities, they are slower * to create than other mechanisms, as a result of having to build the cache * first. For this reason queries are best suited for use cases where a single * query can be reused many times (like is the case for systems). * * For ad-hoc queries it is recommended to use filters or rules instead, which * are slower to iterate, but much faster to create. Applications should at all * times avoid frequent creation/deletion of queries. */ typedef struct ecs_query_t ecs_query_t; /** A rule is a query with advanced graph traversal features. * Rules are fast uncached queries with support for advanced graph features such * as the usage of query variables. A simple example of a rule that matches all * spaceship entities docked to a planet: * * SpaceShip, (DockedTo, $planet), Planet($planet) * * Here, the rule traverses the DockedTo relationship, and matches Planet on the * target of this relationship. Through the usage of variables rules can match * arbitrary patterns against entity graphs. Other features supported * exclusively by rules are: * - Component inheritance * - Transitivity * * Rules have similar iteration performance to filters, but are slower than * queries. Rules and filters will eventually be merged into a single query * implementation. Features still lacking for rules are: * - Up traversal * - AndFrom, OrFrom, NotFrom operators */ typedef struct ecs_rule_t ecs_rule_t; /** An observer is a system that is invoked when an event matches its query. * Observers allow applications to respond to specific events, such as adding or * removing a component. Observers are created by both specifying a query and * a list of event kinds that should be listened for. An example of an observer * that triggers when a Position component is added to an entity (in C++): * * @code * world.observer() * .event(flecs::OnAdd) * .each([](Position& p) { * // called when Position is added to an entity * }); * @endcode * * Observer queries can be as complex as filters. Observers only trigger when * the source of the event matches the full observer query. For example, an * OnAdd observer for Position, Velocity will only trigger after both components * have been added to the entity. */ typedef struct ecs_observer_t ecs_observer_t; /** An observable produces events that can be listened for by an observer. * Currently only the world is observable. In the future, queries will become * observable objects as well. */ typedef struct ecs_observable_t ecs_observable_t; /* Type used for iterating iterable objects. * Iterators are a common interface across iterable objects (world, filters, * rules, queries, systems, observers) to provide applications with information * about the currently iterated result, and to store any state required for the * iteration. */ typedef struct ecs_iter_t ecs_iter_t; /** A ref is a fast way to fetch a component for a specific entity. * Refs are a faster alternative to repeatedly calling ecs_get() for the same * entity/component combination. When comparing the performance of getting a ref * to calling ecs_get(), a ref is typically 3-5x faster. * * Refs achieve this performance by caching internal data structures associated * with the entity and component on the ecs_ref_t object that otherwise would * have to be looked up. */ typedef struct ecs_ref_t ecs_ref_t; /** Type hooks are callbacks associated with component lifecycle events. * Typical examples of lifecycle events are construction, destruction, copying * and moving of components. */ typedef struct ecs_type_hooks_t ecs_type_hooks_t; /** Type information. * Contains information about a (component) type, such as its size and * alignment and type hooks. */ typedef struct ecs_type_info_t ecs_type_info_t; /** Information about an entity, like its table and row. */ typedef struct ecs_record_t ecs_record_t; /** Information about a (component) id, such as type info and tables with the id */ typedef struct ecs_id_record_t ecs_id_record_t; /** Information about where in a table a specific (component) id is stored. */ typedef struct ecs_table_record_t ecs_table_record_t; /** A poly object. * A poly (short for polymorph) object is an object that has a variable list of * capabilities, determined by a mixin table. This is the current list of types * in the flecs API that can be used as an ecs_poly_t: * * - ecs_world_t * - ecs_stage_t * - ecs_query_t * - ecs_filter_t * - ecs_rule_t * - (more to come) * * Functions that accept an ecs_poly_t argument can accept objects of these * types. If the object does not have the requested mixin the API will throw an * assert. * * The poly/mixin framework enables partially overlapping features to be * implemented once, and enables objects of different types to interact with * each other depending on what mixins they have, rather than their type * (in some ways it's like a mini-ECS). Additionally, each poly object has a * header that enables the API to do sanity checking on the input arguments. */ typedef void ecs_poly_t; /** Type that stores poly mixins */ typedef struct ecs_mixins_t ecs_mixins_t; /** Header for ecs_poly_t objects. */ typedef struct ecs_header_t { int32_t magic; /* Magic number verifying it's a flecs object */ int32_t type; /* Magic number indicating which type of flecs object */ ecs_mixins_t *mixins; /* Table with offsets to (optional) mixins */ } ecs_header_t; /** @} */ /** * @defgroup function_types Function types. * Function callback types. * * @{ */ /** Function prototype for runnables (systems, observers). * The run callback overrides the default behavior for iterating through the * results of a runnable object. * * The default runnable iterates the iterator, and calls an iter_action (see * below) for each returned result. * * @param it The iterator to be iterated by the runnable. */ typedef void (*ecs_run_action_t)( ecs_iter_t *it); /** Function prototype for iterables. * A system may invoke a callback multiple times, typically once for each * matched table. * * @param it The iterator containing the data for the current match. */ typedef void (*ecs_iter_action_t)( ecs_iter_t *it); /** Function prototype for creating an iterator from a poly. * Used to create iterators from poly objects with the iterable mixin. When a * filter is provided, an array of two iterators must be passed to the function. * This allows the mixin implementation to create a chained iterator when * necessary, which requires two iterator objects. * * @param world The world or stage for which to create the iterator. * @param iterable An iterable poly object. * @param it The iterator to create (out parameter) * @param filter Optional term to filter results. */ typedef void (*ecs_iter_init_action_t)( const ecs_world_t *world, const ecs_poly_t *iterable, ecs_iter_t *it, ecs_term_t *filter); /** Function prototype for iterating an iterator. * Stored inside initialized iterators. This allows an application to iterate * an iterator without needing to know what created it. * * @param it The iterator to iterate. * @return True if iterator has no more results, false if it does. */ typedef bool (*ecs_iter_next_action_t)( ecs_iter_t *it); /** Function prototype for freeing an iterator. * Free iterator resources. * * @param it The iterator to free. */ typedef void (*ecs_iter_fini_action_t)( ecs_iter_t *it); /** Callback used for comparing components */ typedef int (*ecs_order_by_action_t)( ecs_entity_t e1, const void *ptr1, ecs_entity_t e2, const void *ptr2); /** Callback used for sorting the entire table of components */ typedef void (*ecs_sort_table_action_t)( ecs_world_t* world, ecs_table_t* table, ecs_entity_t* entities, void* ptr, int32_t size, int32_t lo, int32_t hi, ecs_order_by_action_t order_by); /** Callback used for grouping tables in a query */ typedef uint64_t (*ecs_group_by_action_t)( ecs_world_t *world, ecs_table_t *table, ecs_id_t group_id, void *ctx); /* Callback invoked when a query creates a new group. */ typedef void* (*ecs_group_create_action_t)( ecs_world_t *world, uint64_t group_id, void *group_by_ctx); /* from ecs_query_desc_t */ /* Callback invoked when a query deletes an existing group. */ typedef void (*ecs_group_delete_action_t)( ecs_world_t *world, uint64_t group_id, void *group_ctx, /* return value from ecs_group_create_action_t */ void *group_by_ctx); /* from ecs_query_desc_t */ /** Initialization action for modules */ typedef void (*ecs_module_action_t)( ecs_world_t *world); /** Action callback on world exit */ typedef void (*ecs_fini_action_t)( ecs_world_t *world, void *ctx); /** Function to cleanup context data */ typedef void (*ecs_ctx_free_t)( void *ctx); /** Callback used for sorting values */ typedef int (*ecs_compare_action_t)( const void *ptr1, const void *ptr2); /** Callback used for hashing values */ typedef uint64_t (*ecs_hash_value_action_t)( const void *ptr); /** Constructor/destructor callback */ typedef void (*ecs_xtor_t)( void *ptr, int32_t count, const ecs_type_info_t *type_info); /** Copy is invoked when a component is copied into another component. */ typedef void (*ecs_copy_t)( void *dst_ptr, const void *src_ptr, int32_t count, const ecs_type_info_t *type_info); /** Move is invoked when a component is moved to another component. */ typedef void (*ecs_move_t)( void *dst_ptr, void *src_ptr, int32_t count, const ecs_type_info_t *type_info); /* Destructor function for poly objects */ typedef void (*ecs_poly_dtor_t)( ecs_poly_t *poly); /** @} */ /** * @defgroup mixins Poly mixin types. * Mixin types for poly mechanism. * * @{ */ /** Iterable mixin. * Allows its container to be iterated. */ typedef struct ecs_iterable_t { ecs_iter_init_action_t init; /**< Callback that creates iterator. */ } ecs_iterable_t; /** @} */ /** * @defgroup query_types Query descriptor types. * Types used to describe queries. * * @{ */ /** Specify read/write access for term */ typedef enum ecs_inout_kind_t { EcsInOutDefault, /**< InOut for regular terms, In for shared terms */ EcsInOutNone, /**< Term is neither read nor written */ EcsInOut, /**< Term is both read and written */ EcsIn, /**< Term is only read */ EcsOut, /**< Term is only written */ } ecs_inout_kind_t; /** Specify operator for term */ typedef enum ecs_oper_kind_t { EcsAnd, /**< The term must match */ EcsOr, /**< One of the terms in an or chain must match */ EcsNot, /**< The term must not match */ EcsOptional, /**< The term may match */ EcsAndFrom, /**< Term must match all components from term id */ EcsOrFrom, /**< Term must match at least one component from term id */ EcsNotFrom, /**< Term must match none of the components from term id */ } ecs_oper_kind_t; /* Term id flags */ #define EcsSelf (1u << 1) /**< Match on self */ #define EcsUp (1u << 2) /**< Match by traversing upwards */ #define EcsDown (1u << 3) /**< Match by traversing downwards (derived, cannot be set) */ #define EcsTraverseAll (1u << 4) /**< Match all entities encountered through traversal */ #define EcsCascade (1u << 5) /**< Sort results breadth first */ #define EcsDesc (1u << 6) /**< Iterate groups in descending order */ #define EcsParent (1u << 7) /**< Short for up(ChildOf) */ #define EcsIsVariable (1u << 8) /**< Term id is a variable */ #define EcsIsEntity (1u << 9) /**< Term id is an entity */ #define EcsIsName (1u << 10) /**< Term id is a name (don't attempt to lookup as entity) */ #define EcsFilter (1u << 11) /**< Prevent observer from triggering on term */ #define EcsTraverseFlags (EcsUp|EcsDown|EcsTraverseAll|EcsSelf|EcsCascade|EcsDesc|EcsParent) /* Term flags discovered & set during filter creation. Mostly used internally to * store information relevant to queries. */ #define EcsTermMatchAny (1u << 0) #define EcsTermMatchAnySrc (1u << 1) #define EcsTermSrcFirstEq (1u << 2) #define EcsTermSrcSecondEq (1u << 3) #define EcsTermTransitive (1u << 4) #define EcsTermReflexive (1u << 5) #define EcsTermIdInherited (1u << 6) #define EcsTermIsTrivial (1u << 7) #define EcsTermNoData (1u << 8) /* Term flags used for term iteration */ #define EcsTermMatchDisabled (1u << 7) #define EcsTermMatchPrefab (1u << 8) /** Type that describes a single identifier in a term */ typedef struct ecs_term_id_t { ecs_entity_t id; /**< Entity id. If left to 0 and flags does not * specify whether id is an entity or a variable * the id will be initialized to EcsThis. * To explicitly set the id to 0, leave the id * member to 0 and set EcsIsEntity in flags. */ const char *name; /**< Name. This can be either the variable name * (when the EcsIsVariable flag is set) or an * entity name. When ecs_term_t::move is true, * the API assumes ownership over the string and * will free it when the term is destroyed. */ ecs_entity_t trav; /**< Relationship to traverse when looking for the * component. The relationship must have * the Traversable property. Default is IsA. */ ecs_flags32_t flags; /**< Term flags */ } ecs_term_id_t; /** Type that describes a term (single element in a query) */ struct ecs_term_t { ecs_id_t id; /**< Component id to be matched by term. Can be * set directly, or will be populated from the * first/second members, which provide more * flexibility. */ ecs_term_id_t src; /**< Source of term */ ecs_term_id_t first; /**< Component or first element of pair */ ecs_term_id_t second; /**< Second element of pair */ ecs_inout_kind_t inout; /**< Access to contents matched by term */ ecs_oper_kind_t oper; /**< Operator of term */ ecs_id_t id_flags; /**< Id flags of term id */ char *name; /**< Name of term */ int32_t field_index; /**< Index of field for term in iterator */ ecs_id_record_t *idr; /**< Cached pointer to internal index */ ecs_flags16_t flags; /**< Flags that help eval, set by ecs_filter_init */ bool move; /**< Used by internals */ }; /** Use $this variable to initialize user-allocated filter object */ FLECS_API extern ecs_filter_t ECS_FILTER_INIT; /** Filters allow for ad-hoc quick filtering of entity tables. */ struct ecs_filter_t { ecs_header_t hdr; int8_t term_count; /**< Number of elements in terms array */ int8_t field_count; /**< Number of fields in iterator for filter */ ecs_flags32_t flags; /**< Filter flags */ ecs_flags64_t data_fields; /**< Bitset with fields that have data */ ecs_term_t *terms; /**< Array containing terms for filter */ char *variable_names[1]; /**< Placeholder variable names array */ int32_t *sizes; /**< Field size (same for each result) */ ecs_id_t *ids; /**< Array with field ids */ int32_t eval_count; /**< Number of times query is evaluated */ /* Mixins */ ecs_entity_t entity; /**< Entity associated with filter (optional) */ ecs_iterable_t iterable; /**< Iterable mixin */ ecs_poly_dtor_t dtor; /**< Dtor mixin */ ecs_world_t *world; /**< World mixin */ }; /* An observer reacts to events matching a filter */ struct ecs_observer_t { ecs_header_t hdr; ecs_filter_t filter; /**< Query for observer */ /* Observer events */ ecs_entity_t events[FLECS_EVENT_DESC_MAX]; int32_t event_count; ecs_iter_action_t callback; /**< See ecs_observer_desc_t::callback */ ecs_run_action_t run; /**< See ecs_observer_desc_t::run */ void *ctx; /**< Callback context */ void *binding_ctx; /**< Binding context (for language bindings) */ ecs_ctx_free_t ctx_free; /**< Callback to free ctx */ ecs_ctx_free_t binding_ctx_free; /**< Callback to free binding_ctx */ ecs_observable_t *observable; /**< Observable for observer */ int32_t *last_event_id; /**< Last handled event id */ int32_t last_event_id_storage; ecs_id_t register_id; /**< Id observer is registered with (single term observers only) */ int32_t term_index; /**< Index of the term in parent observer (single term observers only) */ ecs_flags32_t flags; /**< Observer flags */ /* Mixins */ ecs_poly_dtor_t dtor; }; /** @} */ /** Type that contains component lifecycle callbacks. * * @ingroup components */ struct ecs_type_hooks_t { ecs_xtor_t ctor; /**< ctor */ ecs_xtor_t dtor; /**< dtor */ ecs_copy_t copy; /**< copy assignment */ ecs_move_t move; /**< move assignment */ /** Ctor + copy */ ecs_copy_t copy_ctor; /** Ctor + move */ ecs_move_t move_ctor; /** Ctor + move + dtor (or move_ctor + dtor). * This combination is typically used when a component is moved from one * location to a new location, like when it is moved to a new table. If * not set explicitly it will be derived from other callbacks. */ ecs_move_t ctor_move_dtor; /** Move + dtor. * This combination is typically used when a component is moved from one * location to an existing location, like what happens during a remove. If * not set explicitly it will be derived from other callbacks. */ ecs_move_t move_dtor; /** Callback that is invoked when an instance of a component is added. This * callback is invoked before triggers are invoked. */ ecs_iter_action_t on_add; /** Callback that is invoked when an instance of the component is set. This * callback is invoked before triggers are invoked, and enable the component * to respond to changes on itself before others can. */ ecs_iter_action_t on_set; /** Callback that is invoked when an instance of the component is removed. * This callback is invoked after the triggers are invoked, and before the * destructor is invoked. */ ecs_iter_action_t on_remove; void *ctx; /**< User defined context */ void *binding_ctx; /**< Language binding context */ ecs_ctx_free_t ctx_free; /**< Callback to free ctx */ ecs_ctx_free_t binding_ctx_free; /**< Callback to free binding_ctx */ }; /** Type that contains component information (passed to ctors/dtors/...) * * @ingroup components */ struct ecs_type_info_t { ecs_size_t size; /**< Size of type */ ecs_size_t alignment; /**< Alignment of type */ ecs_type_hooks_t hooks; /**< Type hooks */ ecs_entity_t component; /**< Handle to component (do not set) */ const char *name; /**< Type name. */ }; /** * @file api_types.h * @brief Supporting types for the public API. * * This file contains types that are typically not used by an application but * support the public API, and therefore must be exposed. This header should not * be included by itself. */ #ifndef FLECS_API_TYPES_H #define FLECS_API_TYPES_H #ifdef __cplusplus extern "C" { #endif //////////////////////////////////////////////////////////////////////////////// //// Opaque types //////////////////////////////////////////////////////////////////////////////// /** A stage enables modification while iterating and from multiple threads */ typedef struct ecs_stage_t ecs_stage_t; /** Table data */ typedef struct ecs_data_t ecs_data_t; /* Switch list */ typedef struct ecs_switch_t ecs_switch_t; /* Cached query table data */ typedef struct ecs_query_table_match_t ecs_query_table_match_t; //////////////////////////////////////////////////////////////////////////////// //// Non-opaque types //////////////////////////////////////////////////////////////////////////////// /** Mixin for emitting events to triggers/observers */ /** All observers for a specific event */ typedef struct ecs_event_record_t { struct ecs_event_id_record_t *any; struct ecs_event_id_record_t *wildcard; struct ecs_event_id_record_t *wildcard_pair; ecs_map_t event_ids; /* map */ ecs_entity_t event; } ecs_event_record_t; struct ecs_observable_t { ecs_event_record_t on_add; ecs_event_record_t on_remove; ecs_event_record_t on_set; ecs_event_record_t un_set; ecs_event_record_t on_wildcard; ecs_sparse_t events; /* sparse */ }; /** Record for entity index */ struct ecs_record_t { ecs_id_record_t *idr; /* Id record to (*, entity) for target entities */ ecs_table_t *table; /* Identifies a type (and table) in world */ uint32_t row; /* Table row of the entity */ int32_t dense; /* Index in dense array */ }; /** Range in table */ typedef struct ecs_table_range_t { ecs_table_t *table; int32_t offset; /* Leave both members to 0 to cover entire table */ int32_t count; } ecs_table_range_t; /** Value of query variable */ typedef struct ecs_var_t { ecs_table_range_t range; /* Set when variable stores a range of entities */ ecs_entity_t entity; /* Set when variable stores single entity */ /* Most entities can be stored as a range by setting range.count to 1, * however in order to also be able to store empty entities in variables, * a separate entity member is needed. Both range and entity may be set at * the same time, as long as they are consistent. */ } ecs_var_t; /** Cached reference. */ struct ecs_ref_t { ecs_entity_t entity; /* Entity */ ecs_entity_t id; /* Component id */ uint64_t table_id; /* Table id for detecting ABA issues */ struct ecs_table_record_t *tr; /* Table record for component */ ecs_record_t *record; /* Entity index record */ }; /* Cursor to stack allocator. Type is public to allow for white box testing. */ struct ecs_stack_page_t; typedef struct ecs_stack_cursor_t { struct ecs_stack_cursor_t *prev; struct ecs_stack_page_t *page; int16_t sp; bool is_free; #ifdef FLECS_DEBUG struct ecs_stack_t *owner; #endif } ecs_stack_cursor_t; /* Page-iterator specific data */ typedef struct ecs_page_iter_t { int32_t offset; int32_t limit; int32_t remaining; } ecs_page_iter_t; /* Worker-iterator specific data */ typedef struct ecs_worker_iter_t { int32_t index; int32_t count; } ecs_worker_iter_t; /* Convenience struct to iterate table array for id */ typedef struct ecs_table_cache_iter_t { struct ecs_table_cache_hdr_t *cur, *next; struct ecs_table_cache_hdr_t *next_list; } ecs_table_cache_iter_t; /** Term-iterator specific data */ typedef struct ecs_term_iter_t { ecs_term_t term; ecs_id_record_t *self_index; ecs_id_record_t *set_index; ecs_id_record_t *cur; ecs_table_cache_iter_t it; int32_t index; int32_t observed_table_count; ecs_table_t *table; int32_t cur_match; int32_t match_count; int32_t last_column; bool empty_tables; /* Storage */ ecs_id_t id; int32_t column; ecs_entity_t subject; ecs_size_t size; void *ptr; } ecs_term_iter_t; typedef enum ecs_iter_kind_t { EcsIterEvalCondition, EcsIterEvalTables, EcsIterEvalChain, EcsIterEvalNone } ecs_iter_kind_t; /** Filter-iterator specific data */ typedef struct ecs_filter_iter_t { const ecs_filter_t *filter; ecs_iter_kind_t kind; ecs_term_iter_t term_iter; int32_t matches_left; int32_t pivot_term; } ecs_filter_iter_t; /** Query-iterator specific data */ typedef struct ecs_query_iter_t { ecs_query_t *query; ecs_query_table_match_t *node, *prev, *last; int32_t sparse_smallest; int32_t sparse_first; int32_t bitset_first; int32_t skip_count; } ecs_query_iter_t; /** Snapshot-iterator specific data */ typedef struct ecs_snapshot_iter_t { ecs_filter_t filter; ecs_vec_t tables; /* ecs_table_leaf_t */ int32_t index; } ecs_snapshot_iter_t; typedef struct ecs_rule_op_profile_t { int32_t count[2]; /* 0 = enter, 1 = redo */ } ecs_rule_op_profile_t; /** Rule-iterator specific data */ typedef struct ecs_rule_iter_t { const ecs_rule_t *rule; struct ecs_var_t *vars; /* Variable storage */ const struct ecs_rule_var_t *rule_vars; const struct ecs_rule_op_t *ops; struct ecs_rule_op_ctx_t *op_ctx; /* Operation-specific state */ uint64_t *written; ecs_flags32_t source_set; #ifdef FLECS_DEBUG ecs_rule_op_profile_t *profile; #endif int16_t op; int16_t sp; } ecs_rule_iter_t; /* Bits for tracking whether a cache was used/whether the array was allocated. * Used by flecs_iter_init, flecs_iter_validate and ecs_iter_fini. * Constants are named to enable easy macro substitution. */ #define flecs_iter_cache_ids (1u << 0u) #define flecs_iter_cache_columns (1u << 1u) #define flecs_iter_cache_sources (1u << 2u) #define flecs_iter_cache_ptrs (1u << 3u) #define flecs_iter_cache_match_indices (1u << 4u) #define flecs_iter_cache_variables (1u << 5u) #define flecs_iter_cache_all (255) /* Inline iterator arrays to prevent allocations for small array sizes */ typedef struct ecs_iter_cache_t { ecs_stack_cursor_t *stack_cursor; /* Stack cursor to restore to */ ecs_flags8_t used; /* For which fields is the cache used */ ecs_flags8_t allocated; /* Which fields are allocated */ } ecs_iter_cache_t; /* Private iterator data. Used by iterator implementations to keep track of * progress & to provide builtin storage. */ typedef struct ecs_iter_private_t { union { ecs_term_iter_t term; ecs_filter_iter_t filter; ecs_query_iter_t query; ecs_rule_iter_t rule; ecs_snapshot_iter_t snapshot; ecs_page_iter_t page; ecs_worker_iter_t worker; } iter; /* Iterator specific data */ void *entity_iter; /* Filter applied after matching a table */ ecs_iter_cache_t cache; /* Inline arrays to reduce allocations */ } ecs_iter_private_t; /** Iterator */ struct ecs_iter_t { /* World */ ecs_world_t *world; /* The world */ ecs_world_t *real_world; /* Actual world. This differs from world when in readonly mode */ /* Matched data */ ecs_entity_t *entities; /* Entity identifiers */ void **ptrs; /* Pointers to components. Array if from this, pointer if not. */ ecs_size_t *sizes; /* Component sizes */ ecs_table_t *table; /* Current table */ ecs_table_t *other_table; /* Prev or next table when adding/removing */ ecs_id_t *ids; /* (Component) ids */ ecs_var_t *variables; /* Values of variables (if any) */ int32_t *columns; /* Query term to table column mapping */ ecs_entity_t *sources; /* Entity on which the id was matched (0 if same as entities) */ int32_t *match_indices; /* Indices of current match for term. Allows an iterator to iterate * all permutations of wildcards in query. */ ecs_ref_t *references; /* Cached refs to components (if iterating a cache) */ ecs_flags64_t constrained_vars; /* Bitset that marks constrained variables */ uint64_t group_id; /* Group id for table, if group_by is used */ int32_t field_count; /* Number of fields in iterator */ /* Input information */ ecs_entity_t system; /* The system (if applicable) */ ecs_entity_t event; /* The event (if applicable) */ ecs_id_t event_id; /* The (component) id for the event */ int32_t event_cur; /* Unique event id. Used to dedup observer calls */ /* Query information */ const ecs_filter_t *query; /* Query being evaluated */ ecs_term_t *terms; /* Term array of query being evaluated */ int32_t table_count; /* Active table count for query */ int32_t term_index; /* Index of term that emitted an event. * This field will be set to the 'index' field * of an observer term. */ int32_t variable_count; /* Number of variables for query */ char **variable_names; /* Names of variables (if any) */ /* Context */ void *param; /* Param passed to ecs_run */ void *ctx; /* System context */ void *binding_ctx; /* Binding context */ /* Time */ ecs_ftime_t delta_time; /* Time elapsed since last frame */ ecs_ftime_t delta_system_time;/* Time elapsed since last system invocation */ /* Iterator counters */ int32_t frame_offset; /* Offset relative to start of iteration */ int32_t offset; /* Offset relative to current table */ int32_t count; /* Number of entities to iterate */ int32_t instance_count; /* Number of entities to iterate before next table */ /* Iterator flags */ ecs_flags32_t flags; ecs_entity_t interrupted_by; /* When set, system execution is interrupted */ ecs_iter_private_t priv; /* Private data */ /* Chained iterators */ ecs_iter_next_action_t next; /* Function to progress iterator */ ecs_iter_action_t callback; /* Callback of system or observer */ ecs_iter_action_t set_var; /* Invoked after setting variable (optionally set) */ ecs_iter_fini_action_t fini; /* Function to cleanup iterator resources */ ecs_iter_t *chain_it; /* Optional, allows for creating iterator chains */ }; #ifdef __cplusplus } #endif #endif /** * @file api_support.h * @brief Support functions and constants. * * Supporting types and functions that need to be exposed either in support of * the public API or for unit tests, but that may change between minor / patch * releases. */ #ifndef FLECS_API_SUPPORT_H #define FLECS_API_SUPPORT_H #ifdef __cplusplus extern "C" { #endif /** This is the largest possible component id. Components for the most part * occupy the same id range as entities, however they are not allowed to overlap * with (8) bits reserved for id flags. */ #define ECS_MAX_COMPONENT_ID (~((uint32_t)(ECS_ID_FLAGS_MASK >> 32))) /** The maximum number of nested function calls before the core will throw a * cycle detected error */ #define ECS_MAX_RECURSION (512) /** Maximum length of a parser token (used by parser-related addons) */ #define ECS_MAX_TOKEN_SIZE (256) //////////////////////////////////////////////////////////////////////////////// //// Global type handles //////////////////////////////////////////////////////////////////////////////// /** This allows passing 0 as type to functions that accept ids */ #define FLECS_ID0ID_ 0 FLECS_API char* ecs_module_path_from_c( const char *c_name); bool ecs_identifier_is_0( const char *id); /* Constructor that zeromem's a component value */ FLECS_API void ecs_default_ctor( void *ptr, int32_t count, const ecs_type_info_t *ctx); /* Create allocated string from format */ FLECS_DBG_API char* ecs_vasprintf( const char *fmt, va_list args); /* Create allocated string from format */ FLECS_API char* ecs_asprintf( const char *fmt, ...); /* Convert identifier to snake case */ FLECS_API char* flecs_to_snake_case( const char *str); FLECS_DBG_API int32_t flecs_table_observed_count( const ecs_table_t *table); FLECS_DBG_API void flecs_dump_backtrace( void *stream); FLECS_API ecs_iter_t flecs_children( const ecs_world_t *stage, ecs_entity_t rel, ecs_entity_t parent); /** Calculate offset from address */ #ifdef __cplusplus #define ECS_OFFSET(o, offset) reinterpret_cast((reinterpret_cast(o)) + (static_cast(offset))) #else #define ECS_OFFSET(o, offset) (void*)(((uintptr_t)(o)) + ((uintptr_t)(offset))) #endif #define ECS_OFFSET_T(o, T) ECS_OFFSET(o, ECS_SIZEOF(T)) #define ECS_ELEM(ptr, size, index) ECS_OFFSET(ptr, (size) * (index)) #define ECS_ELEM_T(o, T, index) ECS_ELEM(o, ECS_SIZEOF(T), index) /** Enable/disable bitsets */ #define ECS_BIT_SET(flags, bit) (flags) |= (bit) #define ECS_BIT_CLEAR(flags, bit) (flags) &= ~(bit) #define ECS_BIT_COND(flags, bit, cond) ((cond) \ ? (ECS_BIT_SET(flags, bit)) \ : (ECS_BIT_CLEAR(flags, bit))) #define ECS_BIT_IS_SET(flags, bit) ((flags) & (bit)) #ifdef __cplusplus } #endif #endif /** * @file hashmap.h * @brief Hashmap data structure. */ #ifndef FLECS_HASHMAP_H #define FLECS_HASHMAP_H #ifdef __cplusplus extern "C" { #endif typedef struct { ecs_vec_t keys; ecs_vec_t values; } ecs_hm_bucket_t; typedef struct { ecs_hash_value_action_t hash; ecs_compare_action_t compare; ecs_size_t key_size; ecs_size_t value_size; ecs_block_allocator_t *hashmap_allocator; ecs_block_allocator_t bucket_allocator; ecs_map_t impl; } ecs_hashmap_t; typedef struct { ecs_map_iter_t it; ecs_hm_bucket_t *bucket; int32_t index; } flecs_hashmap_iter_t; typedef struct { void *key; void *value; uint64_t hash; } flecs_hashmap_result_t; FLECS_DBG_API void flecs_hashmap_init_( ecs_hashmap_t *hm, ecs_size_t key_size, ecs_size_t value_size, ecs_hash_value_action_t hash, ecs_compare_action_t compare, ecs_allocator_t *allocator); #define flecs_hashmap_init(hm, K, V, hash, compare, allocator)\ flecs_hashmap_init_(hm, ECS_SIZEOF(K), ECS_SIZEOF(V), hash, compare, allocator) FLECS_DBG_API void flecs_hashmap_fini( ecs_hashmap_t *map); FLECS_DBG_API void* flecs_hashmap_get_( const ecs_hashmap_t *map, ecs_size_t key_size, const void *key, ecs_size_t value_size); #define flecs_hashmap_get(map, key, V)\ (V*)flecs_hashmap_get_(map, ECS_SIZEOF(*key), key, ECS_SIZEOF(V)) FLECS_DBG_API flecs_hashmap_result_t flecs_hashmap_ensure_( ecs_hashmap_t *map, ecs_size_t key_size, const void *key, ecs_size_t value_size); #define flecs_hashmap_ensure(map, key, V)\ flecs_hashmap_ensure_(map, ECS_SIZEOF(*key), key, ECS_SIZEOF(V)) FLECS_DBG_API void flecs_hashmap_set_( ecs_hashmap_t *map, ecs_size_t key_size, void *key, ecs_size_t value_size, const void *value); #define flecs_hashmap_set(map, key, value)\ flecs_hashmap_set_(map, ECS_SIZEOF(*key), key, ECS_SIZEOF(*value), value) FLECS_DBG_API void flecs_hashmap_remove_( ecs_hashmap_t *map, ecs_size_t key_size, const void *key, ecs_size_t value_size); #define flecs_hashmap_remove(map, key, V)\ flecs_hashmap_remove_(map, ECS_SIZEOF(*key), key, ECS_SIZEOF(V)) FLECS_DBG_API void flecs_hashmap_remove_w_hash_( ecs_hashmap_t *map, ecs_size_t key_size, const void *key, ecs_size_t value_size, uint64_t hash); #define flecs_hashmap_remove_w_hash(map, key, V, hash)\ flecs_hashmap_remove_w_hash_(map, ECS_SIZEOF(*key), key, ECS_SIZEOF(V), hash) FLECS_DBG_API ecs_hm_bucket_t* flecs_hashmap_get_bucket( const ecs_hashmap_t *map, uint64_t hash); FLECS_DBG_API void flecs_hm_bucket_remove( ecs_hashmap_t *map, ecs_hm_bucket_t *bucket, uint64_t hash, int32_t index); FLECS_DBG_API void flecs_hashmap_copy( ecs_hashmap_t *dst, const ecs_hashmap_t *src); FLECS_DBG_API flecs_hashmap_iter_t flecs_hashmap_iter( ecs_hashmap_t *map); FLECS_DBG_API void* flecs_hashmap_next_( flecs_hashmap_iter_t *it, ecs_size_t key_size, void *key_out, ecs_size_t value_size); #define flecs_hashmap_next(map, V)\ (V*)flecs_hashmap_next_(map, 0, NULL, ECS_SIZEOF(V)) #define flecs_hashmap_next_w_key(map, K, key, V)\ (V*)flecs_hashmap_next_(map, ECS_SIZEOF(K), key, ECS_SIZEOF(V)) #ifdef __cplusplus } #endif #endif /** Used with ecs_entity_init(). * * @ingroup entities */ typedef struct ecs_entity_desc_t { int32_t _canary; ecs_entity_t id; /**< Set to modify existing entity (optional) */ const char *name; /**< Name of the entity. If no entity is provided, an * entity with this name will be looked up first. When * an entity is provided, the name will be verified * with the existing entity. */ const char *sep; /**< Optional custom separator for hierarchical names. * Leave to NULL for default ('.') separator. Set to * an empty string to prevent tokenization of name. */ const char *root_sep; /**< Optional, used for identifiers relative to root */ const char *symbol; /**< Optional entity symbol. A symbol is an unscoped * identifier that can be used to lookup an entity. The * primary use case for this is to associate the entity * with a language identifier, such as a type or * function name, where these identifiers differ from * the name they are registered with in flecs. For * example, C type "EcsPosition" might be registered * as "flecs.components.transform.Position", with the * symbol set to "EcsPosition". */ bool use_low_id; /**< When set to true, a low id (typically reserved for * components) will be used to create the entity, if * no id is specified. */ /** Array of ids to add to the new or existing entity. */ ecs_id_t add[FLECS_ID_DESC_MAX]; /** String expression with components to add */ const char *add_expr; } ecs_entity_desc_t; /** Used with ecs_bulk_init(). * * @ingroup entities */ typedef struct ecs_bulk_desc_t { int32_t _canary; ecs_entity_t *entities; /**< Entities to bulk insert. Entity ids provided by * the application must be empty (cannot * have components). If no entity ids are provided, the * operation will create 'count' new entities. */ int32_t count; /**< Number of entities to create/populate */ ecs_id_t ids[FLECS_ID_DESC_MAX]; /**< Ids to create the entities with */ void **data; /**< Array with component data to insert. Each element in * the array must correspond with an element in the ids * array. If an element in the ids array is a tag, the * data array must contain a NULL. An element may be * set to NULL for a component, in which case the * component will not be set by the operation. */ ecs_table_t *table; /**< Table to insert the entities into. Should not be set * at the same time as ids. When 'table' is set at the * same time as 'data', the elements in the data array * must correspond with the ids in the table's type. */ } ecs_bulk_desc_t; /** Used with ecs_component_init(). * * @ingroup components */ typedef struct ecs_component_desc_t { int32_t _canary; /** Existing entity to associate with observer (optional) */ ecs_entity_t entity; /** Parameters for type (size, hooks, ...) */ ecs_type_info_t type; } ecs_component_desc_t; /** Used with ecs_filter_init(). * * @ingroup filters */ typedef struct ecs_filter_desc_t { int32_t _canary; /** Terms of the filter. If a filter has more terms than * FLECS_TERM_DESC_MAX use terms_buffer */ ecs_term_t terms[FLECS_TERM_DESC_MAX]; /** For filters with lots of terms an outside array can be provided. */ ecs_term_t *terms_buffer; /** Number of terms in array provided in terms_buffer. */ int32_t terms_buffer_count; /** External storage to prevent allocation of the filter object */ ecs_filter_t *storage; /** When true, terms returned by an iterator may either contain 1 or N * elements, where terms with N elements are owned, and terms with 1 element * are shared, for example from a parent or base entity. When false, the * iterator will at most return 1 element when the result contains both * owned and shared terms. */ bool instanced; /** Flags for advanced usage */ ecs_flags32_t flags; /** Filter expression. Should not be set at the same time as terms array */ const char *expr; /** Entity associated with query (optional) */ ecs_entity_t entity; } ecs_filter_desc_t; /** Used with ecs_query_init(). * * @ingroup queries */ typedef struct ecs_query_desc_t { int32_t _canary; /** Filter for the query */ ecs_filter_desc_t filter; /** Component to be used by order_by */ ecs_entity_t order_by_component; /** Callback used for ordering query results. If order_by_id is 0, the * pointer provided to the callback will be NULL. If the callback is not * set, results will not be ordered. */ ecs_order_by_action_t order_by; /** Callback used for ordering query results. Same as order_by, * but more efficient. */ ecs_sort_table_action_t sort_table; /** Id to be used by group_by. This id is passed to the group_by function and * can be used identify the part of an entity type that should be used for * grouping. */ ecs_id_t group_by_id; /** Callback used for grouping results. If the callback is not set, results * will not be grouped. When set, this callback will be used to calculate a * "rank" for each entity (table) based on its components. This rank is then * used to sort entities (tables), so that entities (tables) of the same * rank are "grouped" together when iterated. */ ecs_group_by_action_t group_by; /** Callback that is invoked when a new group is created. The return value of * the callback is stored as context for a group. */ ecs_group_create_action_t on_group_create; /** Callback that is invoked when an existing group is deleted. The return * value of the on_group_create callback is passed as context parameter. */ ecs_group_delete_action_t on_group_delete; /** Context to pass to group_by */ void *group_by_ctx; /** Function to free group_by_ctx */ ecs_ctx_free_t group_by_ctx_free; /** If set, the query will be created as a subquery. A subquery matches at * most a subset of its parent query. Subqueries do not directly receive * (table) notifications from the world. Instead parent queries forward * results to subqueries. This can improve matching performance, as fewer * queries need to be matched with new tables. * Subqueries can be nested. */ ecs_query_t *parent; /** User context to pass to callback */ void *ctx; /** Context to be used for language bindings */ void *binding_ctx; /** Callback to free ctx */ ecs_ctx_free_t ctx_free; /** Callback to free binding_ctx */ ecs_ctx_free_t binding_ctx_free; } ecs_query_desc_t; /** Used with ecs_observer_init(). * * @ingroup observers */ typedef struct ecs_observer_desc_t { int32_t _canary; /** Existing entity to associate with observer (optional) */ ecs_entity_t entity; /** Filter for observer */ ecs_filter_desc_t filter; /** Events to observe (OnAdd, OnRemove, OnSet, UnSet) */ ecs_entity_t events[FLECS_EVENT_DESC_MAX]; /** When observer is created, generate events from existing data. For example, * EcsOnAdd Position would match all existing instances of Position. * This is only supported for events that are iterable (see EcsIterable) */ bool yield_existing; /** Callback to invoke on an event, invoked when the observer matches. */ ecs_iter_action_t callback; /** Callback invoked on an event. When left to NULL the default runner * is used which matches the event with the observer's filter, and calls * 'callback' when it matches. * A reason to override the run function is to improve performance, if there * are more efficient way to test whether an event matches the observer than * the general purpose query matcher. */ ecs_run_action_t run; /** User context to pass to callback */ void *ctx; /** Context to be used for language bindings */ void *binding_ctx; /** Callback to free ctx */ ecs_ctx_free_t ctx_free; /** Callback to free binding_ctx */ ecs_ctx_free_t binding_ctx_free; /** Observable with which to register the observer */ ecs_poly_t *observable; /** Optional shared last event id for multiple observers. Ensures only one * of the observers with the shared id gets triggered for an event */ int32_t *last_event_id; /** Used for internal purposes */ int32_t term_index; } ecs_observer_desc_t; /** Used with ecs_emit(). * * @ingroup observers */ typedef struct ecs_event_desc_t { /** The event id. Only observers for the specified event will be notified */ ecs_entity_t event; /** Component ids. Only observers with a matching component id will be * notified. Observers are guaranteed to get notified once, even if they * match more than one id. */ const ecs_type_t *ids; /** The table for which to notify. */ ecs_table_t *table; /** Optional 2nd table to notify. This can be used to communicate the * previous or next table, in case an entity is moved between tables. */ ecs_table_t *other_table; /** Limit notified entities to ones starting from offset (row) in table */ int32_t offset; /** Limit number of notified entities to count. offset+count must be less * than the total number of entities in the table. If left to 0, it will be * automatically determined by doing ecs_table_count(table) - offset. */ int32_t count; /** Single-entity alternative to setting table / offset / count */ ecs_entity_t entity; /** Optional context. * The type of the param must be the event, where the event is a component. * When an event is enqueued, the value of param is coped to a temporary * storage of the event type. */ void *param; /* Same as param, but with the guarantee that the value won't be modified. * When an event with a const parameter is enqueued, the value of the param * is copied to a temporary storage of the event type. */ const void *const_param; /** Observable (usually the world) */ ecs_poly_t *observable; /** Event flags */ ecs_flags32_t flags; } ecs_event_desc_t; /** * @defgroup misc_types Miscellaneous types * Types used to create entities, observers, queries and more. * * @{ */ /* Utility to hold a value of a dynamic type */ typedef struct ecs_value_t { ecs_entity_t type; void *ptr; } ecs_value_t; /** Type with information about the current Flecs build */ typedef struct ecs_build_info_t { const char *compiler; /**< Compiler used to compile flecs */ const char **addons; /**< Addons included in build */ const char *version; /**< Stringified version */ int16_t version_major; /**< Major flecs version */ int16_t version_minor; /**< Minor flecs version */ int16_t version_patch; /**< Patch flecs version */ bool debug; /**< Is this a debug build */ bool sanitize; /**< Is this a sanitize build */ bool perf_trace; /**< Is this a perf tracing build */ } ecs_build_info_t; /** Type that contains information about the world. */ typedef struct ecs_world_info_t { ecs_entity_t last_component_id; /**< Last issued component entity id */ ecs_entity_t min_id; /**< First allowed entity id */ ecs_entity_t max_id; /**< Last allowed entity id */ ecs_ftime_t delta_time_raw; /**< Raw delta time (no time scaling) */ ecs_ftime_t delta_time; /**< Time passed to or computed by ecs_progress */ ecs_ftime_t time_scale; /**< Time scale applied to delta_time */ ecs_ftime_t target_fps; /**< Target fps */ ecs_ftime_t frame_time_total; /**< Total time spent processing a frame */ ecs_ftime_t system_time_total; /**< Total time spent in systems */ ecs_ftime_t emit_time_total; /**< Total time spent notifying observers */ ecs_ftime_t merge_time_total; /**< Total time spent in merges */ ecs_ftime_t world_time_total; /**< Time elapsed in simulation */ ecs_ftime_t world_time_total_raw; /**< Time elapsed in simulation (no scaling) */ ecs_ftime_t rematch_time_total; /**< Time spent on query rematching */ int64_t frame_count_total; /**< Total number of frames */ int64_t merge_count_total; /**< Total number of merges */ int64_t rematch_count_total; /**< Total number of rematches */ int64_t id_create_total; /**< Total number of times a new id was created */ int64_t id_delete_total; /**< Total number of times an id was deleted */ int64_t table_create_total; /**< Total number of times a table was created */ int64_t table_delete_total; /**< Total number of times a table was deleted */ int64_t pipeline_build_count_total; /**< Total number of pipeline builds */ int64_t systems_ran_frame; /**< Total number of systems ran in last frame */ int64_t observers_ran_frame; /**< Total number of times observer was invoked */ int32_t tag_id_count; /**< Number of tag (no data) ids in the world */ int32_t component_id_count; /**< Number of component (data) ids in the world */ int32_t pair_id_count; /**< Number of pair ids in the world */ int32_t table_count; /**< Number of tables */ int32_t empty_table_count; /**< Number of tables without entities */ /* -- Command counts -- */ struct { int64_t add_count; /**< Add commands processed */ int64_t remove_count; /**< Remove commands processed */ int64_t delete_count; /**< Selete commands processed */ int64_t clear_count; /**< Clear commands processed */ int64_t set_count; /**< Set commands processed */ int64_t ensure_count; /**< Ensure/emplace commands processed */ int64_t modified_count; /**< Modified commands processed */ int64_t discard_count; /**< Commands discarded, happens when entity is no longer alive when running the command */ int64_t event_count; /**< Enqueued custom events */ int64_t other_count; /**< Other commands processed */ int64_t batched_entity_count; /**< Entities for which commands were batched */ int64_t batched_command_count; /**< Commands batched */ } cmd; const char *name_prefix; /**< Value set by ecs_set_name_prefix(). Used * to remove library prefixes of symbol * names (such as `Ecs`, `ecs_`) when * registering them as names. */ } ecs_world_info_t; /** Type that contains information about a query group. */ typedef struct ecs_query_group_info_t { int32_t match_count; /**< How often tables have been matched/unmatched */ int32_t table_count; /**< Number of tables in group */ void *ctx; /**< Group context, returned by on_group_create */ } ecs_query_group_info_t; /** @} */ /** * @defgroup builtin_components Builtin component types. * Types that represent builtin components. * * @{ */ /** A (string) identifier. Used as pair with EcsName and EcsSymbol tags */ typedef struct EcsIdentifier { char *value; /**< Identifier string */ ecs_size_t length; /**< Length of identifier */ uint64_t hash; /**< Hash of current value */ uint64_t index_hash; /**< Hash of existing record in current index */ ecs_hashmap_t *index; /**< Current index */ } EcsIdentifier; /** Component information. */ typedef struct EcsComponent { ecs_size_t size; /**< Component size */ ecs_size_t alignment; /**< Component alignment */ } EcsComponent; /** Component for storing a poly object */ typedef struct EcsPoly { ecs_poly_t *poly; /**< Pointer to poly object */ } EcsPoly; /** Target data for flattened relationships. */ typedef struct EcsFlattenTarget { int32_t count; ecs_record_t *target; } EcsFlattenTarget; /** Component for iterable entities */ typedef ecs_iterable_t EcsIterable; /** @} */ /** @} */ /* Only include deprecated definitions if deprecated addon is required */ #ifdef FLECS_DEPRECATED /** * @file addons/deprecated.h * @brief The deprecated addon contains deprecated operations. */ #ifdef FLECS_DEPRECATED #ifndef FLECS_DEPRECATED_H #define FLECS_DEPRECATED_H #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus } #endif #endif #endif #endif /** * @defgroup api_constants API Constants * Public API constants. * * @{ */ /** * @defgroup id_flags Component id flags. * Id flags are bits that can be set on an id (ecs_id_t). * * @{ */ /** Indicates that the id is a pair. */ FLECS_API extern const ecs_id_t ECS_PAIR; /** Automatically override component when it is inherited */ FLECS_API extern const ecs_id_t ECS_OVERRIDE; /** Adds bitset to storage which allows component to be enabled/disabled */ FLECS_API extern const ecs_id_t ECS_TOGGLE; /** Include all components from entity to which AND is applied */ FLECS_API extern const ecs_id_t ECS_AND; /** @} */ /** * @defgroup builtin_tags Builtin component ids. * @{ */ /* Builtin component ids */ FLECS_API extern const ecs_entity_t ecs_id(EcsComponent); FLECS_API extern const ecs_entity_t ecs_id(EcsIdentifier); FLECS_API extern const ecs_entity_t ecs_id(EcsIterable); FLECS_API extern const ecs_entity_t ecs_id(EcsPoly); FLECS_API extern const ecs_entity_t EcsQuery; FLECS_API extern const ecs_entity_t EcsObserver; /* System module component ids */ FLECS_API extern const ecs_entity_t EcsSystem; FLECS_API extern const ecs_entity_t ecs_id(EcsTickSource); /* Pipeline module component ids */ FLECS_API extern const ecs_entity_t ecs_id(EcsPipelineQuery); /* Timer module component ids */ FLECS_API extern const ecs_entity_t ecs_id(EcsTimer); FLECS_API extern const ecs_entity_t ecs_id(EcsRateFilter); /** Root scope for builtin flecs entities */ FLECS_API extern const ecs_entity_t EcsFlecs; /** Core module scope */ FLECS_API extern const ecs_entity_t EcsFlecsCore; /** Entity associated with world (used for "attaching" components to world) */ FLECS_API extern const ecs_entity_t EcsWorld; /** Wildcard entity ("*"). Matches any id, returns all matches. */ FLECS_API extern const ecs_entity_t EcsWildcard; /** Any entity ("_"). Matches any id, returns only the first. */ FLECS_API extern const ecs_entity_t EcsAny; /** This entity. Default source for queries. */ FLECS_API extern const ecs_entity_t EcsThis; /** Variable entity ("$"). Used in expressions to prefix variable names */ FLECS_API extern const ecs_entity_t EcsVariable; /** Marks a relationship as transitive. * Behavior: * if R(X, Y) and R(Y, Z) then R(X, Z) */ FLECS_API extern const ecs_entity_t EcsTransitive; /** Marks a relationship as reflexive. * Behavior: * R(X, X) == true */ FLECS_API extern const ecs_entity_t EcsReflexive; /** Ensures that entity/component cannot be used as target in IsA relationship. * Final can improve the performance of rule-based queries, as they will not * attempt to substitute a final component with its subsets. * * Behavior: * if IsA(X, Y) and Final(Y) throw error */ FLECS_API extern const ecs_entity_t EcsFinal; /** Ensures that component is never inherited from an IsA target. * * Behavior: * if DontInherit(X) and X(B) and IsA(A, B) then X(A) is false. */ FLECS_API extern const ecs_entity_t EcsDontInherit; /** Ensures a component is always overridden. * * Behavior: * As if the component is added together with OVERRIDE | T */ FLECS_API extern const ecs_entity_t EcsAlwaysOverride; /** Marks relationship as commutative. * Behavior: * if R(X, Y) then R(Y, X) */ FLECS_API extern const ecs_entity_t EcsSymmetric; /** Can be added to relationship to indicate that the relationship can only occur * once on an entity. Adding a 2nd instance will replace the 1st. * * Behavior: * R(X, Y) + R(X, Z) = R(X, Z) */ FLECS_API extern const ecs_entity_t EcsExclusive; /** Marks a relationship as acyclic. Acyclic relationships may not form cycles. */ FLECS_API extern const ecs_entity_t EcsAcyclic; /** Marks a relationship as traversable. Traversable relationships may be * traversed with "up" queries. Traversable relationships are acyclic. */ FLECS_API extern const ecs_entity_t EcsTraversable; /** Ensure that a component always is added together with another component. * * Behavior: * If With(R, O) and R(X) then O(X) * If With(R, O) and R(X, Y) then O(X, Y) */ FLECS_API extern const ecs_entity_t EcsWith; /** Ensure that relationship target is child of specified entity. * * Behavior: * If OneOf(R, O) and R(X, Y), Y must be a child of O * If OneOf(R) and R(X, Y), Y must be a child of R */ FLECS_API extern const ecs_entity_t EcsOneOf; /** Can be added to relationship to indicate that it should never hold data, * even when it or the relationship target is a component. */ FLECS_API extern const ecs_entity_t EcsTag; /** Can be added to components to indicate it is a trait. Traits are components * and/or tags that are added to other components to modify their behavior. */ FLECS_API extern const ecs_entity_t EcsTrait; /** Ensure that an entity is always used in pair as relationship. * * Behavior: * e.add(R) panics * e.add(X, R) panics, unless X has the "Trait" trait */ FLECS_API extern const ecs_entity_t EcsRelationship; /** Ensure that an entity is always used in pair as target. * * Behavior: * e.add(T) panics * e.add(T, X) panics */ FLECS_API extern const ecs_entity_t EcsTarget; /** Tag to indicate that relationship is stored as union. Union relationships * enable changing the target of a union without switching tables. Union * relationships are also marked as exclusive. */ FLECS_API extern const ecs_entity_t EcsUnion; /** Tag to indicate name identifier */ FLECS_API extern const ecs_entity_t EcsName; /** Tag to indicate symbol identifier */ FLECS_API extern const ecs_entity_t EcsSymbol; /** Tag to indicate alias identifier */ FLECS_API extern const ecs_entity_t EcsAlias; /** Used to express parent-child relationships. */ FLECS_API extern const ecs_entity_t EcsChildOf; /** Used to express inheritance relationships. */ FLECS_API extern const ecs_entity_t EcsIsA; /** Used to express dependency relationships */ FLECS_API extern const ecs_entity_t EcsDependsOn; /** Used to express a slot (used with prefab inheritance) */ FLECS_API extern const ecs_entity_t EcsSlotOf; /** Tag added to module entities */ FLECS_API extern const ecs_entity_t EcsModule; /** Tag to indicate an entity/component/system is private to a module */ FLECS_API extern const ecs_entity_t EcsPrivate; /** Tag added to prefab entities. Any entity with this tag is automatically * ignored by queries, unless EcsPrefab is explicitly queried for. */ FLECS_API extern const ecs_entity_t EcsPrefab; /** When this tag is added to an entity it is skipped by queries, unless * EcsDisabled is explicitly queried for. */ FLECS_API extern const ecs_entity_t EcsDisabled; /** Event that triggers when an id is added to an entity */ FLECS_API extern const ecs_entity_t EcsOnAdd; /** Event that triggers when an id is removed from an entity */ FLECS_API extern const ecs_entity_t EcsOnRemove; /** Event that triggers when a component is set for an entity */ FLECS_API extern const ecs_entity_t EcsOnSet; /** Event that triggers when a component is unset for an entity */ FLECS_API extern const ecs_entity_t EcsUnSet; /** Event that triggers observer when an entity starts/stops matching a query */ FLECS_API extern const ecs_entity_t EcsMonitor; /** Event that triggers when a table is created. */ FLECS_API extern const ecs_entity_t EcsOnTableCreate; /** Event that triggers when a table is deleted. */ FLECS_API extern const ecs_entity_t EcsOnTableDelete; /** Event that triggers when a table becomes empty (doesn't emit on creation). */ FLECS_API extern const ecs_entity_t EcsOnTableEmpty; /** Event that triggers when a table becomes non-empty. */ FLECS_API extern const ecs_entity_t EcsOnTableFill; /** Relationship used for specifying cleanup behavior. */ FLECS_API extern const ecs_entity_t EcsOnDelete; /** Relationship used to define what should happen when a target entity (second * element of a pair) is deleted. */ FLECS_API extern const ecs_entity_t EcsOnDeleteTarget; /** Remove cleanup policy. Must be used as target in pair with EcsOnDelete or * EcsOnDeleteTarget. */ FLECS_API extern const ecs_entity_t EcsRemove; /** Delete cleanup policy. Must be used as target in pair with EcsOnDelete or * EcsOnDeleteTarget. */ FLECS_API extern const ecs_entity_t EcsDelete; /** Panic cleanup policy. Must be used as target in pair with EcsOnDelete or * EcsOnDeleteTarget. */ FLECS_API extern const ecs_entity_t EcsPanic; /** Component that stores data for flattened relationships */ FLECS_API extern const ecs_entity_t ecs_id(EcsFlattenTarget); /** Tag added to root entity to indicate its subtree should be flattened. Used * together with assemblies. */ FLECS_API extern const ecs_entity_t EcsFlatten; /** Used like (EcsDefaultChildComponent, Component). When added to an entity, * this informs serialization formats which component to use when a value is * assigned to an entity without specifying the component. This is intended as * a hint, serialization formats are not required to use it. Adding this * component does not change the behavior of core ECS operations. */ FLECS_API extern const ecs_entity_t EcsDefaultChildComponent; /* Builtin predicates for comparing entity ids in queries. Only supported by rules */ FLECS_API extern const ecs_entity_t EcsPredEq; FLECS_API extern const ecs_entity_t EcsPredMatch; FLECS_API extern const ecs_entity_t EcsPredLookup; /* Builtin marker entities for opening/closing query scopes */ FLECS_API extern const ecs_entity_t EcsScopeOpen; FLECS_API extern const ecs_entity_t EcsScopeClose; /** Tag used to indicate query is empty */ FLECS_API extern const ecs_entity_t EcsEmpty; /* Pipeline module tags */ FLECS_API extern const ecs_entity_t ecs_id(EcsPipeline); FLECS_API extern const ecs_entity_t EcsOnStart; FLECS_API extern const ecs_entity_t EcsPreFrame; FLECS_API extern const ecs_entity_t EcsOnLoad; FLECS_API extern const ecs_entity_t EcsPostLoad; FLECS_API extern const ecs_entity_t EcsPreUpdate; FLECS_API extern const ecs_entity_t EcsOnUpdate; FLECS_API extern const ecs_entity_t EcsOnValidate; FLECS_API extern const ecs_entity_t EcsPostUpdate; FLECS_API extern const ecs_entity_t EcsPreStore; FLECS_API extern const ecs_entity_t EcsOnStore; FLECS_API extern const ecs_entity_t EcsPostFrame; FLECS_API extern const ecs_entity_t EcsPhase; /** Value used to quickly check if component is builtin. This is used to quickly * filter out tables with builtin components (for example for ecs_delete()) */ #define EcsLastInternalComponentId (ecs_id(EcsPoly)) /** The first user-defined component starts from this id. Ids up to this number * are reserved for builtin components */ #define EcsFirstUserComponentId (8) /** The first user-defined entity starts from this id. Ids up to this number * are reserved for builtin entities */ #define EcsFirstUserEntityId (FLECS_HI_COMPONENT_ID + 128) /* When visualized the reserved id ranges look like this: * [1..8]: Builtin components * [9..FLECS_HI_COMPONENT_ID]: Low ids reserved for application components * [FLECS_HI_COMPONENT_ID + 1..EcsFirstUserEntityId]: Builtin entities */ /** @} */ /** @} */ /** * @defgroup world_api World * Functions for working with `ecs_world_t`. * * @{ */ /** * @defgroup world_creation_deletion Creation & Deletion * @{ */ /** Create a new world. * This operation automatically imports modules from addons Flecs has been built * with, except when the module specifies otherwise. * * @return A new world */ FLECS_API ecs_world_t* ecs_init(void); /** Create a new world with just the core module. * Same as ecs_init(), but doesn't import modules from addons. This operation is * faster than ecs_init() and results in less memory utilization. * * @return A new tiny world */ FLECS_API ecs_world_t* ecs_mini(void); /** Create a new world with arguments. * Same as ecs_init(), but allows passing in command line arguments. Command line * arguments are used to: * - automatically derive the name of the application from argv[0] * * @return A new world */ FLECS_API ecs_world_t* ecs_init_w_args( int argc, char *argv[]); /** Delete a world. * This operation deletes the world, and everything it contains. * * @param world The world to delete. * @return Zero if successful, non-zero if failed. */ FLECS_API int ecs_fini( ecs_world_t *world); /** Returns whether the world is being deleted. * This operation can be used in callbacks like type hooks or observers to * detect if they are invoked while the world is being deleted. * * @param world The world. * @return True if being deleted, false if not. */ FLECS_API bool ecs_is_fini( const ecs_world_t *world); /** Register action to be executed when world is destroyed. * Fini actions are typically used when a module needs to clean up before a * world shuts down. * * @param world The world. * @param action The function to execute. * @param ctx Userdata to pass to the function */ FLECS_API void ecs_atfini( ecs_world_t *world, ecs_fini_action_t action, void *ctx); /** @} */ /** * @defgroup world_frame Frame functions * @{ */ /** Begin frame. * When an application does not use ecs_progress() to control the main loop, it * can still use Flecs features such as FPS limiting and time measurements. This * operation needs to be invoked whenever a new frame is about to get processed. * * Calls to ecs_frame_begin() must always be followed by ecs_frame_end(). * * The function accepts a delta_time parameter, which will get passed to * systems. This value is also used to compute the amount of time the function * needs to sleep to ensure it does not exceed the target_fps, when it is set. * When 0 is provided for delta_time, the time will be measured. * * This function should only be ran from the main thread. * * @param world The world. * @param delta_time Time elapsed since the last frame. * @return The provided delta_time, or measured time if 0 was provided. */ FLECS_API ecs_ftime_t ecs_frame_begin( ecs_world_t *world, ecs_ftime_t delta_time); /** End frame. * This operation must be called at the end of the frame, and always after * ecs_frame_begin(). * * @param world The world. */ FLECS_API void ecs_frame_end( ecs_world_t *world); /** Register action to be executed once after frame. * Post frame actions are typically used for calling operations that cannot be * invoked during iteration, such as changing the number of threads. * * @param world The world. * @param action The function to execute. * @param ctx Userdata to pass to the function */ FLECS_API void ecs_run_post_frame( ecs_world_t *world, ecs_fini_action_t action, void *ctx); /** Signal exit * This operation signals that the application should quit. It will cause * ecs_progress() to return false. * * @param world The world to quit. */ FLECS_API void ecs_quit( ecs_world_t *world); /** Return whether a quit has been signaled. * * @param world The world. */ FLECS_API bool ecs_should_quit( const ecs_world_t *world); /** Measure frame time. * Frame time measurements measure the total time passed in a single frame, and * how much of that time was spent on systems and on merging. * * Frame time measurements add a small constant-time overhead to an application. * When an application sets a target FPS, frame time measurements are enabled by * default. * * @param world The world. * @param enable Whether to enable or disable frame time measuring. */ FLECS_API void ecs_measure_frame_time( ecs_world_t *world, bool enable); /** Measure system time. * System time measurements measure the time spent in each system. * * System time measurements add overhead to every system invocation and * therefore have a small but measurable impact on application performance. * System time measurements must be enabled before obtaining system statistics. * * @param world The world. * @param enable Whether to enable or disable system time measuring. */ FLECS_API void ecs_measure_system_time( ecs_world_t *world, bool enable); /** Set target frames per second (FPS) for application. * Setting the target FPS ensures that ecs_progress() is not invoked faster than * the specified FPS. When enabled, ecs_progress() tracks the time passed since * the last invocation, and sleeps the remaining time of the frame (if any). * * This feature ensures systems are ran at a consistent interval, as well as * conserving CPU time by not running systems more often than required. * * Note that ecs_progress() only sleeps if there is time left in the frame. Both * time spent in flecs as time spent outside of flecs are taken into * account. * * @param world The world. * @param fps The target FPS. */ FLECS_API void ecs_set_target_fps( ecs_world_t *world, ecs_ftime_t fps); /** @} */ /** * @defgroup commands Commands * @{ */ /** Begin readonly mode. * This operation puts the world in readonly mode, which disallows mutations on * the world. Readonly mode exists so that internal mechanisms can implement * optimizations that certain aspects of the world to not change, while also * providing a mechanism for applications to prevent accidental mutations in, * for example, multithreaded applications. * * Readonly mode is a stronger version of deferred mode. In deferred mode * ECS operations such as add/remove/set/delete etc. are added to a command * queue to be executed later. In readonly mode, operations that could break * scheduler logic (such as creating systems, queries) are also disallowed. * * Readonly mode itself has a single threaded and a multi threaded mode. In * single threaded mode certain mutations on the world are still allowed, for * example: * - Entity liveliness operations (such as new, make_alive), so that systems are * able to create new entities. * - Implicit component registration, so that this works from systems * - Mutations to supporting data structures for the evaluation of uncached * queries (filters), so that these can be created on the fly. * * These mutations are safe in a single threaded applications, but for * multithreaded applications the world needs to be entirely immutable. For this * purpose multi threaded readonly mode exists, which disallows all mutations on * the world. This means that in multi threaded applications, entity liveliness * operations, implicit component registration, and on-the-fly filter creation * are not guaranteed to work. * * While in readonly mode, applications can still enqueue ECS operations on a * stage. Stages are managed automatically when using the pipeline addon and * ecs_progress(), but they can also be configured manually as shown here: * * @code * // Number of stages typically corresponds with number of threads * ecs_set_stage_count(world, 2); * ecs_stage_t *stage = ecs_get_stage(world, 1); * * ecs_readonly_begin(world); * ecs_add(world, e, Tag); // readonly assert * ecs_add(stage, e, Tag); // OK * @endcode * * When an attempt is made to perform an operation on a world in readonly mode, * the code will throw an assert saying that the world is in readonly mode. * * A call to ecs_readonly_begin() must be followed up with ecs_readonly_end(). * When ecs_readonly_end() is called, all enqueued commands from configured * stages are merged back into the world. Calls to ecs_readonly_begin() and * ecs_readonly_end() should always happen from a context where the code has * exclusive access to the world. The functions themselves are not thread safe. * * In a typical application, a (non-exhaustive) call stack that uses * ecs_readonly_begin() and ecs_readonly_end() will look like this: * * @code * ecs_progress() * ecs_readonly_begin() * ecs_defer_begin() * * // user code * * ecs_readonly_end() * ecs_defer_end() *@endcode * * @param world The world * @param multi_threaded Whether to enable readonly/multi threaded mode. * @return Whether world is in readonly mode. */ FLECS_API bool ecs_readonly_begin( ecs_world_t *world, bool multi_threaded); /** End readonly mode. * This operation ends readonly mode, and must be called after * ecs_readonly_begin(). Operations that were deferred while the world was in * readonly mode will be flushed. * * @param world The world */ FLECS_API void ecs_readonly_end( ecs_world_t *world); /** Merge world or stage. * When automatic merging is disabled, an application can call this * operation on either an individual stage, or on the world which will merge * all stages. This operation may only be called when staging is not enabled * (either after ecs_progress() or after ecs_readonly_end()). * * This operation may be called on an already merged stage or world. * * @param world The world. */ FLECS_API void ecs_merge( ecs_world_t *world); /** Defer operations until end of frame. * When this operation is invoked while iterating, operations inbetween the * ecs_defer_begin() and ecs_defer_end() operations are executed at the end * of the frame. * * This operation is thread safe. * * @param world The world. * @return true if world changed from non-deferred mode to deferred mode. */ FLECS_API bool ecs_defer_begin( ecs_world_t *world); /** Test if deferring is enabled for current stage. * * @param world The world. * @return True if deferred, false if not. */ FLECS_API bool ecs_is_deferred( const ecs_world_t *world); /** End block of operations to defer. * See ecs_defer_begin(). * * This operation is thread safe. * * @param world The world. * @return true if world changed from deferred mode to non-deferred mode. */ FLECS_API bool ecs_defer_end( ecs_world_t *world); /** Suspend deferring but do not flush queue. * This operation can be used to do an undeferred operation while not flushing * the operations in the queue. * * An application should invoke ecs_defer_resume() before ecs_defer_end() is called. * The operation may only be called when deferring is enabled. * * @param world The world. */ FLECS_API void ecs_defer_suspend( ecs_world_t *world); /** Resume deferring. * See ecs_defer_suspend(). * * @param world The world. */ FLECS_API void ecs_defer_resume( ecs_world_t *world); /** Enable/disable auto-merging for world or stage. * When auto-merging is enabled, staged data will automatically be merged with * the world when staging ends. This happens at the end of ecs_progress(), at a * sync point or when ecs_readonly_end() is called. * * Applications can exercise more control over when data from a stage is merged * by disabling auto-merging. This requires an application to explicitly call * ecs_merge() on the stage. * * When this function is invoked on the world, it sets all current stages to * the provided value and sets the default for new stages. When this function is * invoked on a stage, auto-merging is only set for that specific stage. * * @param world The world. * @param automerge Whether to enable or disable auto-merging. */ FLECS_API void ecs_set_automerge( ecs_world_t *world, bool automerge); /** Configure world to have N stages. * This initializes N stages, which allows applications to defer operations to * multiple isolated defer queues. This is typically used for applications with * multiple threads, where each thread gets its own queue, and commands are * merged when threads are synchronized. * * Note that the ecs_set_threads() function already creates the appropriate * number of stages. The ecs_set_stage_count() operation is useful for applications * that want to manage their own stages and/or threads. * * @param world The world. * @param stages The number of stages. */ FLECS_API void ecs_set_stage_count( ecs_world_t *world, int32_t stages); /** Get number of configured stages. * Return number of stages set by ecs_set_stage_count(). * * @param world The world. * @return The number of stages used for threading. */ FLECS_API int32_t ecs_get_stage_count( const ecs_world_t *world); /** Get current stage id. * The stage id can be used by an application to learn about which stage it is * using, which typically corresponds with the worker thread id. * * @param world The world. * @return The stage id. */ FLECS_API int32_t ecs_get_stage_id( const ecs_world_t *world); /** Get stage-specific world pointer. * Flecs threads can safely invoke the API as long as they have a private * context to write to, also referred to as the stage. This function returns a * pointer to a stage, disguised as a world pointer. * * Note that this function does not(!) create a new world. It simply wraps the * existing world in a thread-specific context, which the API knows how to * unwrap. The reason the stage is returned as an ecs_world_t is so that it * can be passed transparently to the existing API functions, vs. having to * create a dedicated API for threading. * * @param world The world. * @param stage_id The index of the stage to retrieve. * @return A thread-specific pointer to the world. */ FLECS_API ecs_world_t* ecs_get_stage( const ecs_world_t *world, int32_t stage_id); /** Test whether the current world is readonly. * This function allows the code to test whether the currently used world * is readonly or whether it allows for writing. * * @param world A pointer to a stage or the world. * @return True if the world or stage is readonly. */ FLECS_API bool ecs_stage_is_readonly( const ecs_world_t *world); /** Create asynchronous stage. * An asynchronous stage can be used to asynchronously queue operations for * later merging with the world. An asynchronous stage is similar to a regular * stage, except that it does not allow reading from the world. * * Asynchronous stages are never merged automatically, and must therefore be * manually merged with the ecs_merge() function. It is not necessary to call * ecs_defer_begin() or ecs_defer_end() before and after enqueuing commands, as an * asynchronous stage unconditionally defers operations. * * The application must ensure that no commands are added to the stage while the * stage is being merged. * * An asynchronous stage must be cleaned up by ecs_async_stage_free(). * * @param world The world. * @return The stage. */ FLECS_API ecs_world_t* ecs_async_stage_new( ecs_world_t *world); /** Free asynchronous stage. * The provided stage must be an asynchronous stage. If a non-asynchronous stage * is provided, the operation will fail. * * @param stage The stage to free. */ FLECS_API void ecs_async_stage_free( ecs_world_t *stage); /** Test whether provided stage is asynchronous. * * @param stage The stage. * @return True when the stage is asynchronous, false for a regular stage or * world. */ FLECS_API bool ecs_stage_is_async( ecs_world_t *stage); /** @} */ /** * @defgroup world_misc Misc * @{ */ /** Set a world context. * This operation allows an application to register custom data with a world * that can be accessed anywhere where the application has the world. * * @param world The world. * @param ctx A pointer to a user defined structure. * @param ctx_free A function that is invoked with ctx when the world is freed. */ FLECS_API void ecs_set_ctx( ecs_world_t *world, void *ctx, ecs_ctx_free_t ctx_free); /** Set a world binding context. * Same as ecs_set_ctx() but for binding context. A binding context is intended * specifically for language bindings to store binding specific data. * * @param world The world. * @param ctx A pointer to a user defined structure. * @param ctx_free A function that is invoked with ctx when the world is freed. */ FLECS_API void ecs_set_binding_ctx( ecs_world_t *world, void *ctx, ecs_ctx_free_t ctx_free); /** Get the world context. * This operation retrieves a previously set world context. * * @param world The world. * @return The context set with ecs_set_ctx(). If no context was set, the * function returns NULL. */ FLECS_API void* ecs_get_ctx( const ecs_world_t *world); /** Get the world binding context. * This operation retrieves a previously set world binding context. * * @param world The world. * @return The context set with ecs_set_binding_ctx(). If no context was set, the * function returns NULL. */ FLECS_API void* ecs_get_binding_ctx( const ecs_world_t *world); /** Get build info. * Returns information about the current Flecs build. */ const ecs_build_info_t* ecs_get_build_info(void); /** Get world info. * * @param world The world. * @return Pointer to the world info. Valid for as long as the world exists. */ FLECS_API const ecs_world_info_t* ecs_get_world_info( const ecs_world_t *world); /** Dimension the world for a specified number of entities. * This operation will preallocate memory in the world for the specified number * of entities. Specifying a number lower than the current number of entities in * the world will have no effect. * * @param world The world. * @param entity_count The number of entities to preallocate. */ FLECS_API void ecs_dim( ecs_world_t *world, int32_t entity_count); /** Set a range for issuing new entity ids. * This function constrains the entity identifiers returned by ecs_new() to the * specified range. This operation can be used to ensure that multiple processes * can run in the same simulation without requiring a central service that * coordinates issuing identifiers. * * If id_end is set to 0, the range is infinite. If id_end is set to a non-zero * value, it has to be larger than id_start. If id_end is set and ecs_new is * invoked after an id is issued that is equal to id_end, the application will * abort. * * @param world The world. * @param id_start The start of the range. * @param id_end The end of the range. */ FLECS_API void ecs_set_entity_range( ecs_world_t *world, ecs_entity_t id_start, ecs_entity_t id_end); /** Enable/disable range limits. * When an application is both a receiver of range-limited entities and a * producer of range-limited entities, range checking needs to be temporarily * disabled when inserting received entities. Range checking is disabled on a * stage, so setting this value is thread safe. * * @param world The world. * @param enable True if range checking should be enabled, false to disable. * @return The previous value. */ FLECS_API bool ecs_enable_range_check( ecs_world_t *world, bool enable); /** Get the largest issued entity id (not counting generation). * * @param world The world. */ FLECS_API ecs_entity_t ecs_get_max_id( const ecs_world_t *world); /** Force aperiodic actions. * The world may delay certain operations until they are necessary for the * application to function correctly. This may cause observable side effects * such as delayed triggering of events, which can be inconvenient when for * example running a test suite. * * The flags parameter specifies which aperiodic actions to run. Specify 0 to * run all actions. Supported flags start with 'EcsAperiodic'. Flags identify * internal mechanisms and may change unannounced. * * @param world The world. * @param flags The flags specifying which actions to run. */ FLECS_API void ecs_run_aperiodic( ecs_world_t *world, ecs_flags32_t flags); /** Cleanup empty tables. * This operation cleans up empty tables that meet certain conditions. Having * large amounts of empty tables does not negatively impact performance of the * ECS, but can take up considerable amounts of memory, especially in * applications with many components, and many components per entity. * * The generation specifies the minimum number of times this operation has * to be called before an empty table is cleaned up. If a table becomes non * empty, the generation is reset. * * The operation allows for both a "clear" generation and a "delete" * generation. When the clear generation is reached, the table's * resources are freed (like component arrays) but the table itself is not * deleted. When the delete generation is reached, the empty table is deleted. * * By specifying a non-zero id the cleanup logic can be limited to tables with * a specific (component) id. The operation will only increase the generation * count of matching tables. * * The min_id_count specifies a lower bound for the number of components a table * should have. Often the more components a table has, the more specific it is * and therefore less likely to be reused. * * The time budget specifies how long the operation should take at most. * * @param world The world. * @param id Optional component filter for the tables to evaluate. * @param clear_generation Free table data when generation > clear_generation. * @param delete_generation Delete table when generation > delete_generation. * @param min_id_count Minimum number of component ids the table should have. * @param time_budget_seconds Amount of time operation is allowed to spend. * @return Number of deleted tables. */ FLECS_API int32_t ecs_delete_empty_tables( ecs_world_t *world, ecs_id_t id, uint16_t clear_generation, uint16_t delete_generation, int32_t min_id_count, double time_budget_seconds); /** Get world from poly. * * @param poly A pointer to a poly object. * @return The world. */ FLECS_API const ecs_world_t* ecs_get_world( const ecs_poly_t *poly); /** Get entity from poly. * * @param poly A pointer to a poly object. * @return Entity associated with the poly object. */ FLECS_API ecs_entity_t ecs_get_entity( const ecs_poly_t *poly); /** Test if pointer is of specified type. * Usage: * * @code * ecs_poly_is(ptr, ecs_world_t) * @endcode * * This operation only works for poly types. * * @param object The object to test. * @param type The id of the type. * @return True if the pointer is of the specified type. */ FLECS_API bool ecs_poly_is_( const ecs_poly_t *object, int32_t type); #define ecs_poly_is(object, type)\ ecs_poly_is_(object, type##_magic) /** Make a pair id. * This function is equivalent to using the ecs_pair() macro, and is added for * convenience to make it easier for non C/C++ bindings to work with pairs. * * @param first The first element of the pair of the pair. * @param second The target of the pair. */ FLECS_API ecs_id_t ecs_make_pair( ecs_entity_t first, ecs_entity_t second); /** @} */ /** @} */ /** * @defgroup entities Entities * Functions for working with `ecs_entity_t`. * * @{ */ /** * @defgroup creating_entities Creating & Deleting * Functions for creating and deleting entities. * * @{ */ /** Create new entity id. * This operation returns an unused entity id. This operation is guaranteed to * return an empty entity as it does not use values set by ecs_set_scope() or * ecs_set_with(). * * @param world The world. * @return The new entity id. */ FLECS_API ecs_entity_t ecs_new_id( ecs_world_t *world); /** Create new low id. * This operation returns a new low id. Entity ids start after the * FLECS_HI_COMPONENT_ID constant. This reserves a range of low ids for things * like components, and allows parts of the code to optimize operations. * * Note that FLECS_HI_COMPONENT_ID does not represent the maximum number of * components that can be created, only the maximum number of components that * can take advantage of these optimizations. * * This operation is guaranteed to return an empty entity as it does not use * values set by ecs_set_scope() or ecs_set_with(). * * This operation does not recycle ids. * * @param world The world. * @return The new component id. */ FLECS_API ecs_entity_t ecs_new_low_id( ecs_world_t *world); /** Create new entity with (component) id. * This operation creates a new entity with an optional (component) id. When 0 * is passed to the id parameter, no component is added to the new entity. * * @param world The world. * @param id The component id to initialize the new entity with. * @return The new entity. */ FLECS_API ecs_entity_t ecs_new_w_id( ecs_world_t *world, ecs_id_t id); /** Create new entity in table. * This operation creates a new entity in the specified table. * * @param world The world. * @param table The table to which to add the new entity. * @return The new entity. */ FLECS_API ecs_entity_t ecs_new_w_table( ecs_world_t *world, ecs_table_t *table); /** Find or create an entity. * This operation creates a new entity, or modifies an existing one. When a name * is set in the ecs_entity_desc_t::name field and ecs_entity_desc_t::entity is * not set, the operation will first attempt to find an existing entity by that * name. If no entity with that name can be found, it will be created. * * If both a name and entity handle are provided, the operation will check if * the entity name matches with the provided name. If the names do not match, * the function will fail and return 0. * * If an id to a non-existing entity is provided, that entity id become alive. * * See the documentation of ecs_entity_desc_t for more details. * * @param world The world. * @param desc Entity init parameters. * @return A handle to the new or existing entity, or 0 if failed. */ FLECS_API ecs_entity_t ecs_entity_init( ecs_world_t *world, const ecs_entity_desc_t *desc); /** Bulk create/populate new entities. * This operation bulk inserts a list of new or predefined entities into a * single table. * * The operation does not take ownership of component arrays provided by the * application. Components that are non-trivially copyable will be moved into * the storage. * * The operation will emit OnAdd events for each added id, and OnSet events for * each component that has been set. * * If no entity ids are provided by the application, the returned array of ids * points to an internal data structure which changes when new entities are * created/deleted. * * If as a result of the operation triggers are invoked that deletes * entities and no entity ids were provided by the application, the returned * array of identifiers may be incorrect. To avoid this problem, an application * can first call ecs_bulk_init() to create empty entities, copy the array to one * that is owned by the application, and then use this array to populate the * entities. * * @param world The world. * @param desc Bulk creation parameters. * @return Array with the list of entity ids created/populated. */ FLECS_API const ecs_entity_t* ecs_bulk_init( ecs_world_t *world, const ecs_bulk_desc_t *desc); /** Create N new entities. * This operation is the same as ecs_new_w_id(), but creates N entities * instead of one. * * @param world The world. * @param id The component id to create the entities with. * @param count The number of entities to create. * @return The first entity id of the newly created entities. */ FLECS_API const ecs_entity_t* ecs_bulk_new_w_id( ecs_world_t *world, ecs_id_t id, int32_t count); /** Clone an entity * This operation clones the components of one entity into another entity. If * no destination entity is provided, a new entity will be created. Component * values are not copied unless copy_value is true. * * If the source entity has a name, it will not be copied to the destination * entity. This is to prevent having two entities with the same name under the * same parent, which is not allowed. * * @param world The world. * @param dst The entity to copy the components to. * @param src The entity to copy the components from. * @param copy_value If true, the value of components will be copied to dst. * @return The destination entity. */ FLECS_API ecs_entity_t ecs_clone( ecs_world_t *world, ecs_entity_t dst, ecs_entity_t src, bool copy_value); /** Delete an entity. * This operation will delete an entity and all of its components. The entity id * will be made available for recycling. If the entity passed to ecs_delete() is * not alive, the operation will have no side effects. * * @param world The world. * @param entity The entity. */ FLECS_API void ecs_delete( ecs_world_t *world, ecs_entity_t entity); /** Delete all entities with the specified id. * This will delete all entities (tables) that have the specified id. The id * may be a wildcard and/or a pair. * * @param world The world. * @param id The id. */ FLECS_API void ecs_delete_with( ecs_world_t *world, ecs_id_t id); /** @} */ /** * @defgroup adding_removing Adding & Removing * Functions for adding and removing components. * * @{ */ /** Add a (component) id to an entity. * This operation adds a single (component) id to an entity. If the entity * already has the id, this operation will have no side effects. * * @param world The world. * @param entity The entity. * @param id The id to add. */ FLECS_API void ecs_add_id( ecs_world_t *world, ecs_entity_t entity, ecs_id_t id); /** Remove a (component) id from an entity. * This operation removes a single (component) id to an entity. If the entity * does not have the id, this operation will have no side effects. * * @param world The world. * @param entity The entity. * @param id The id to remove. */ FLECS_API void ecs_remove_id( ecs_world_t *world, ecs_entity_t entity, ecs_id_t id); /** Add override for (component) id. * Adding an override to an entity ensures that when the entity is instantiated * (by adding an IsA relationship to it) the component with the override is * copied to a component that is private to the instance. By default components * reachable through an IsA relationship are shared. * * Adding an override does not add the component. If an override is added to an * entity that does not have the component, it will still be added to the * instance, but with an uninitialized value (unless the component has a ctor). * When the entity does have the entity, the component of the instance will be * initialized with the value of the component on the entity. * * This is the same as what happens when calling ecs_add_id() for an id that is * inherited (reachable through an IsA relationship). * * This operation is equivalent to doing: * * @code * ecs_add_id(world, entity, ECS_OVERRIDE | id); * @endcode * * @param world The world. * @param entity The entity. * @param id The id to override. */ FLECS_API void ecs_override_id( ecs_world_t *world, ecs_entity_t entity, ecs_id_t id); /** Clear all components. * This operation will remove all components from an entity. * * @param world The world. * @param entity The entity. */ FLECS_API void ecs_clear( ecs_world_t *world, ecs_entity_t entity); /** Remove all instances of the specified (component) id. * This will remove the specified id from all entities (tables). The id may be * a wildcard and/or a pair. * * @param world The world. * @param id The id. */ FLECS_API void ecs_remove_all( ecs_world_t *world, ecs_id_t id); /** Set current with id. * New entities are automatically created with the specified id. * * @param world The world. * @param id The id. * @return The previous id. */ FLECS_API ecs_entity_t ecs_set_with( ecs_world_t *world, ecs_id_t id); /** Get current with id. * Get the id set with ecs_set_with(). * * @param world The world. * @return The last id provided to ecs_set_with(). */ FLECS_API ecs_id_t ecs_get_with( const ecs_world_t *world); /** @} */ /** * @defgroup enabling_disabling Enabling & Disabling * Functions for enabling/disabling entities and components. * * @{ */ /** Enable or disable entity. * This operation enables or disables an entity by adding or removing the * EcsDisabled tag. A disabled entity will not be matched with any systems, * unless the system explicitly specifies the EcsDisabled tag. * * @param world The world. * @param entity The entity to enable or disable. * @param enabled true to enable the entity, false to disable. */ FLECS_API void ecs_enable( ecs_world_t *world, ecs_entity_t entity, bool enabled); /** Enable or disable component. * Enabling or disabling a component does not add or remove a component from an * entity, but prevents it from being matched with queries. This operation can * be useful when a component must be temporarily disabled without destroying * its value. It is also a more performant operation for when an application * needs to add/remove components at high frequency, as enabling/disabling is * cheaper than a regular add or remove. * * @param world The world. * @param entity The entity. * @param id The component. * @param enable True to enable the component, false to disable. */ FLECS_API void ecs_enable_id( ecs_world_t *world, ecs_entity_t entity, ecs_id_t id, bool enable); /** Test if component is enabled. * Test whether a component is currently enabled or disabled. This operation * will return true when the entity has the component and if it has not been * disabled by ecs_enable_component(). * * @param world The world. * @param entity The entity. * @param id The component. * @return True if the component is enabled, otherwise false. */ FLECS_API bool ecs_is_enabled_id( const ecs_world_t *world, ecs_entity_t entity, ecs_id_t id); /** @} */ /** * @defgroup getting Getting & Setting * Functions for getting/setting components. * * @{ */ /** Get an immutable pointer to a component. * This operation obtains a const pointer to the requested component. The * operation accepts the component entity id. * * This operation can return inherited components reachable through an IsA * relationship. * * @param world The world. * @param entity The entity. * @param id The id of the component to get. * @return The component pointer, NULL if the entity does not have the component. */ FLECS_API const void* ecs_get_id( const ecs_world_t *world, ecs_entity_t entity, ecs_id_t id); /** Get a mutable pointer to a component. * This operation obtains a mutable pointer to the requested component. The * operation accepts the component entity id. * * Unlike ecs_get_id, this operation does not return inherited components. * * @param world The world. * @param entity The entity. * @param id The id of the component to get. * @return The component pointer, NULL if the entity does not have the component. */ FLECS_API void* ecs_get_mut_id( const ecs_world_t *world, ecs_entity_t entity, ecs_id_t id); /** Get a mutable pointer to a component. * This operation returns a mutable pointer to a component. If the component did * not yet exist, it will be added. * * If ensure is called when the world is in deferred/readonly mode, the * function will: * - return a pointer to a temp storage if the component does not yet exist, or * - return a pointer to the existing component if it exists * * @param world The world. * @param entity The entity. * @param id The entity id of the component to obtain. * @return The component pointer. */ FLECS_API void* ecs_ensure_id( ecs_world_t *world, ecs_entity_t entity, ecs_id_t id); /** Combines ensure + modified in single operation. * This operation is a more efficient alternative to calling ecs_ensure_id() and * ecs_modified_id() separately. This operation is only valid when the world is in * deferred mode, which ensures that the Modified event is not emitted before * the modification takes place. * * @param world The world. * @param entity The entity. * @param id The id of the component to obtain. * @return The component pointer. */ FLECS_API void* ecs_ensure_modified_id( ecs_world_t *world, ecs_entity_t entity, ecs_id_t id); /** Create a component ref. * A ref is a handle to an entity + component which caches a small amount of * data to reduce overhead of repeatedly accessing the component. Use * ecs_ref_get() to get the component data. * * @param world The world. * @param entity The entity. * @param id The id of the component. * @return The reference. */ FLECS_API ecs_ref_t ecs_ref_init_id( const ecs_world_t *world, ecs_entity_t entity, ecs_id_t id); /** Get component from ref. * Get component pointer from ref. The ref must be created with ecs_ref_init(). * * @param world The world. * @param ref The ref. * @param id The component id. * @return The component pointer, NULL if the entity does not have the component. */ FLECS_API void* ecs_ref_get_id( const ecs_world_t *world, ecs_ref_t *ref, ecs_id_t id); /** Update ref. * Ensures contents of ref are up to date. Same as ecs_ref_get_id(), but does not * return pointer to component id. * * @param world The world. * @param ref The ref. */ FLECS_API void ecs_ref_update( const ecs_world_t *world, ecs_ref_t *ref); /** Begin exclusive write access to entity. * This operation provides safe exclusive access to the components of an entity * without the overhead of deferring operations. * * When this operation is called simultaneously for the same entity more than * once it will throw an assert. Note that for this to happen, asserts must be * enabled. It is up to the application to ensure that access is exclusive, for * example by using a read-write mutex. * * Exclusive access is enforced at the table level, so only one entity can be * exclusively accessed per table. The exclusive access check is thread safe. * * This operation must be followed up with ecs_write_end(). * * @param world The world. * @param entity The entity. * @return A record to the entity. */ FLECS_API ecs_record_t* ecs_write_begin( ecs_world_t *world, ecs_entity_t entity); /** End exclusive write access to entity. * This operation ends exclusive access, and must be called after * ecs_write_begin(). * * @param record Record to the entity. */ FLECS_API void ecs_write_end( ecs_record_t *record); /** Begin read access to entity. * This operation provides safe read access to the components of an entity. * Multiple simultaneous reads are allowed per entity. * * This operation ensures that code attempting to mutate the entity's table will * throw an assert. Note that for this to happen, asserts must be enabled. It is * up to the application to ensure that this does not happen, for example by * using a read-write mutex. * * This operation does *not* provide the same guarantees as a read-write mutex, * as it is possible to call ecs_read_begin() after calling ecs_write_begin(). It is * up to application has to ensure that this does not happen. * * This operation must be followed up with ecs_read_end(). * * @param world The world. * @param entity The entity. * @return A record to the entity. */ FLECS_API const ecs_record_t* ecs_read_begin( ecs_world_t *world, ecs_entity_t entity); /** End read access to entity. * This operation ends read access, and must be called after ecs_read_begin(). * * @param record Record to the entity. */ FLECS_API void ecs_read_end( const ecs_record_t *record); /** Get entity corresponding with record. * This operation only works for entities that are not empty. * * @param record The record for which to obtain the entity id. */ FLECS_API ecs_entity_t ecs_record_get_entity( const ecs_record_t *record); /** Get component from entity record. * This operation returns a pointer to a component for the entity * associated with the provided record. For safe access to the component, obtain * the record with ecs_read_begin() or ecs_write_begin(). * * Obtaining a component from a record is faster than obtaining it from the * entity handle, as it reduces the number of lookups required. * * @param world The world. * @param record Record to the entity. * @param id The (component) id. * @return Pointer to component, or NULL if entity does not have the component. */ FLECS_API const void* ecs_record_get_id( const ecs_world_t *world, const ecs_record_t *record, ecs_id_t id); /** Same as ecs_record_get_id(), but returns a mutable pointer. * For safe access to the component, obtain the record with ecs_write_begin(). * * @param world The world. * @param record Record to the entity. * @param id The (component) id. * @return Pointer to component, or NULL if entity does not have the component. */ FLECS_API void* ecs_record_ensure_id( ecs_world_t *world, ecs_record_t *record, ecs_id_t id); /** Test if entity for record has component. * * @param world The world. * @param record Record to the entity. * @param id The (component) id. */ FLECS_API bool ecs_record_has_id( ecs_world_t *world, const ecs_record_t *record, ecs_id_t id); /** Emplace a component. * Emplace is similar to ecs_ensure_id() except that the component constructor is not * invoked for the returned pointer, allowing the component to be "constructed" * directly in the storage. * * Emplace can only be used if the entity does not yet have the component. If * the entity has the component, the operation will fail. * * @param world The world. * @param entity The entity. * @param id The component to obtain. * @return The (uninitialized) component pointer. */ FLECS_API void* ecs_emplace_id( ecs_world_t *world, ecs_entity_t entity, ecs_id_t id); /** Signal that a component has been modified. * This operation is usually used after modifying a component value obtained by * ecs_ensure_id(). The operation will mark the component as dirty, and invoke * OnSet observers and hooks. * * @param world The world. * @param entity The entity. * @param id The id of the component that was modified. */ FLECS_API void ecs_modified_id( ecs_world_t *world, ecs_entity_t entity, ecs_id_t id); /** Set the value of a component. * This operation allows an application to set the value of a component. The * operation is equivalent to calling ecs_ensure_id() followed by * ecs_modified_id(). The operation will not modify the value of the passed in * component. If the component has a copy hook registered, it will be used to * copy in the component. * * If the provided entity is 0, a new entity will be created. * * @param world The world. * @param entity The entity. * @param id The id of the component to set. * @param size The size of the pointed-to value. * @param ptr The pointer to the value. * @return The entity. A new entity if no entity was provided. */ FLECS_API ecs_entity_t ecs_set_id( ecs_world_t *world, ecs_entity_t entity, ecs_id_t id, size_t size, const void *ptr); /** @} */ /** * @defgroup liveliness Entity Liveliness * Functions for testing and modifying entity liveliness. * * @{ */ /** Test whether an entity is valid. * Entities that are valid can be used with API functions. Using invalid * entities with API operations will cause the function to panic. * * An entity is valid if it is not 0 and if it is alive. * * ecs_is_valid() will return true for ids that don't exist (alive or not alive). This * allows for using ids that have never been created by ecs_new() or similar. In * this the function differs from ecs_is_alive(), which will return false for * entities that do not yet exist. * * The operation will return false for an id that exists and is not alive, as * using this id with an API operation would cause it to assert. * * @param world The world. * @param e The entity. * @return True if the entity is valid, false if the entity is not valid. */ FLECS_API bool ecs_is_valid( const ecs_world_t *world, ecs_entity_t e); /** Test whether an entity is alive. * Entities are alive after they are created, and become not alive when they are * deleted. Operations that return alive ids are (amongst others) ecs_new_id(), * ecs_new_low_id() and ecs_entity_init(). Ids can be made alive with the ecs_make_alive() * function. * * After an id is deleted it can be recycled. Recycled ids are different from * the original id in that they have a different generation count. This makes it * possible for the API to distinguish between the two. An example: * * @code * ecs_entity_t e1 = ecs_new_id(world); * ecs_is_alive(world, e1); // true * ecs_delete(world, e1); * ecs_is_alive(world, e1); // false * * ecs_entity_t e2 = ecs_new_id(world); // recycles e1 * ecs_is_alive(world, e2); // true * ecs_is_alive(world, e1); // false * @endcode * * @param world The world. * @param e The entity. * @return True if the entity is alive, false if the entity is not alive. */ FLECS_API bool ecs_is_alive( const ecs_world_t *world, ecs_entity_t e); /** Remove generation from entity id. * * @param e The entity id. * @return The entity id without the generation count. */ FLECS_API ecs_id_t ecs_strip_generation( ecs_entity_t e); /** Override the generation of an entity. * The generation count of an entity is increased each time an entity is deleted * and is used to test whether an entity id is alive. * * This operation overrides the current generation of an entity with the * specified generation, which can be useful if an entity is externally managed, * like for external pools, savefiles or netcode. * * @param world The world. * @param entity Entity for which to set the generation with the new generation. */ FLECS_API void ecs_set_entity_generation( ecs_world_t *world, ecs_entity_t entity); /** Get alive identifier. * In some cases an application may need to work with identifiers from which * the generation has been stripped. A typical scenario in which this happens is * when iterating relationships in an entity type. * * For example, when obtaining the parent id from a ChildOf relationship, the parent * (second element of the pair) will have been stored in a 32 bit value, which * cannot store the entity generation. This function can retrieve the identifier * with the current generation for that id. * * If the provided identifier is not alive, the function will return 0. * * @param world The world. * @param e The for which to obtain the current alive entity id. * @return The alive entity id if there is one, or 0 if the id is not alive. */ FLECS_API ecs_entity_t ecs_get_alive( const ecs_world_t *world, ecs_entity_t e); /** Ensure id is alive. * This operation ensures that the provided id is alive. This is useful in * scenarios where an application has an existing id that has not been created * with ecs_new() (such as a global constant or an id from a remote application). * * When this operation is successful it guarantees that the provided id exists, * is valid and is alive. * * Before this operation the id must either not be alive or have a generation * that is equal to the passed in entity. * * If the provided id has a non-zero generation count and the id does not exist * in the world, the id will be created with the specified generation. * * If the provided id is alive and has a generation count that does not match * the provided id, the operation will fail. * * @param world The world. * @param entity The entity id to make alive. */ FLECS_API void ecs_make_alive( ecs_world_t *world, ecs_entity_t entity); /** Same as ecs_make_alive(), but for (component) ids. * An id can be an entity or pair, and can contain id flags. This operation * ensures that the entity (or entities, for a pair) are alive. * * When this operation is successful it guarantees that the provided id can be * used in operations that accept an id. * * Since entities in a pair do not encode their generation ids, this operation * will not fail when an entity with non-zero generation count already exists in * the world. * * This is different from ecs_make_alive(), which will fail if attempted with an id * that has generation 0 and an entity with a non-zero generation is currently * alive. * * @param world The world. * @param id The id to make alive. */ FLECS_API void ecs_make_alive_id( ecs_world_t *world, ecs_id_t id); /** Test whether an entity exists. * Similar as ecs_is_alive(), but ignores entity generation count. * * @param world The world. * @param entity The entity. * @return True if the entity exists, false if the entity does not exist. */ FLECS_API bool ecs_exists( const ecs_world_t *world, ecs_entity_t entity); /** @} */ /** * @defgroup entity_info Entity Information. * Get information from entity. * * @{ */ /** Get the type of an entity. * * @param world The world. * @param entity The entity. * @return The type of the entity, NULL if the entity has no components. */ FLECS_API const ecs_type_t* ecs_get_type( const ecs_world_t *world, ecs_entity_t entity); /** Get the table of an entity. * * @param world The world. * @param entity The entity. * @return The table of the entity, NULL if the entity has no components/tags. */ FLECS_API ecs_table_t* ecs_get_table( const ecs_world_t *world, ecs_entity_t entity); /** Convert type to string. * The result of this operation must be freed with ecs_os_free(). * * @param world The world. * @param type The type. * @return The stringified type. */ FLECS_API char* ecs_type_str( const ecs_world_t *world, const ecs_type_t* type); /** Convert table to string. * Same as ecs_type_str(world, ecs_table_get_type(table)). The result of this * operation must be freed with ecs_os_free(). * * @param world The world. * @param table The table. * @return The stringified table type. */ FLECS_API char* ecs_table_str( const ecs_world_t *world, const ecs_table_t *table); /** Convert entity to string. * Same as combining: * - ecs_get_fullpath(world, entity) * - ecs_type_str(world, ecs_get_type(world, entity)) * * The result of this operation must be freed with ecs_os_free(). * * @param world The world. * @param entity The entity. * @return The entity path with stringified type. */ FLECS_API char* ecs_entity_str( const ecs_world_t *world, ecs_entity_t entity); /** Test if an entity has an id. * This operation returns true if the entity has or inherits the specified id. * * @param world The world. * @param entity The entity. * @param id The id to test for. * @return True if the entity has the id, false if not. */ FLECS_API bool ecs_has_id( const ecs_world_t *world, ecs_entity_t entity, ecs_id_t id); /** Test if an entity owns an id. * This operation returns true if the entity has the specified id. The operation * behaves the same as ecs_has_id(), except that it will return false for * components that are inherited through an IsA relationship. * * @param world The world. * @param entity The entity. * @param id The id to test for. * @return True if the entity has the id, false if not. */ FLECS_API bool ecs_owns_id( const ecs_world_t *world, ecs_entity_t entity, ecs_id_t id); /** Get the target of a relationship. * This will return a target (second element of a pair) of the entity for the * specified relationship. The index allows for iterating through the targets, * if a single entity has multiple targets for the same relationship. * * If the index is larger than the total number of instances the entity has for * the relationship, the operation will return 0. * * @param world The world. * @param entity The entity. * @param rel The relationship between the entity and the target. * @param index The index of the relationship instance. * @return The target for the relationship at the specified index. */ FLECS_API ecs_entity_t ecs_get_target( const ecs_world_t *world, ecs_entity_t entity, ecs_entity_t rel, int32_t index); /** Get parent (target of ChildOf relationship) for entity. * This operation is the same as calling: * * @code * ecs_get_target(world, entity, EcsChildOf, 0); * @endcode * * @param world The world. * @param entity The entity. * @return The parent of the entity, 0 if the entity has no parent. */ FLECS_API ecs_entity_t ecs_get_parent( const ecs_world_t *world, ecs_entity_t entity); /** Get the target of a relationship for a given 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 relationship: * * @code * // Is Position provided by the entity or one of its base entities? * ecs_get_target_for_id(world, entity, EcsIsA, ecs_id(Position)) * @endcode * * @param world The world. * @param entity The entity. * @param rel The relationship to follow. * @param id The id to lookup. * @return The entity for which the target has been found. */ FLECS_API ecs_entity_t ecs_get_target_for_id( const ecs_world_t *world, ecs_entity_t entity, ecs_entity_t rel, ecs_id_t id); /** Return depth for entity in tree for the specified relationship. * Depth is determined by counting the number of targets encountered while * traversing up the relationship tree for rel. Only acyclic relationships are * supported. * * @param world The world. * @param entity The entity. * @param rel The relationship. * @return The depth of the entity in the tree. */ FLECS_API int32_t ecs_get_depth( const ecs_world_t *world, ecs_entity_t entity, ecs_entity_t rel); typedef struct ecs_flatten_desc_t { /* When true, the flatten operation will not remove names from entities in * the flattened tree. This may fail if entities from different subtrees * have the same name. */ bool keep_names; /* When true, the flattened tree won't contain information about the * original depth of the entities. This can reduce fragmentation, but may * cause existing code, such as cascade queries, to no longer work. */ bool lose_depth; } ecs_flatten_desc_t; /** Recursively flatten relationship for target entity (experimental). * This operation combines entities in the subtree of the specified pair from * different parents in the same table. This can reduce memory fragmentation * and reduces the number of tables in the storage, which improves RAM * utilization and various other operations, such as entity cleanup. * * The lifecycle of entities in a fixed subtree are bound to the specified * parent. Entities in a fixed subtree cannot be deleted individually. Entities * can also not change the target of the fixed relationship, which includes * removing the relationship. * * Entities in a fixed subtree are still fragmented on subtree depth. This * ensures that entities can still be iterated in breadth-first order with the * cascade query modifier. * * The current implementation is limited to exclusive acyclic relationships, and * does not allow for adding/removing to entities in flattened tables. An entity * may only be flattened for a single relationship. Future iterations of the * feature may remove these limitations. * * @param world The world. * @param pair The relationship pair from which to start flattening. * @param desc Options for flattening the tree. */ FLECS_API void ecs_flatten( ecs_world_t *world, ecs_id_t pair, const ecs_flatten_desc_t *desc); /** Count entities that have the specified id. * Returns the number of entities that have the specified id. * * @param world The world. * @param entity The id to search for. * @return The number of entities that have the id. */ FLECS_API int32_t ecs_count_id( const ecs_world_t *world, ecs_id_t entity); /** @} */ /** * @defgroup paths Entity Names * Functions for working with entity names and paths. * * @{ */ /** Get the name of an entity. * This will return the name stored in (EcsIdentifier, EcsName). * * @param world The world. * @param entity The entity. * @return The type of the entity, NULL if the entity has no name. */ FLECS_API const char* ecs_get_name( const ecs_world_t *world, ecs_entity_t entity); /** Get the symbol of an entity. * This will return the symbol stored in (EcsIdentifier, EcsSymbol). * * @param world The world. * @param entity The entity. * @return The type of the entity, NULL if the entity has no name. */ FLECS_API const char* ecs_get_symbol( const ecs_world_t *world, ecs_entity_t entity); /** Set the name of an entity. * This will set or overwrite the name of an entity. If no entity is provided, * a new entity will be created. * * The name is stored in (EcsIdentifier, EcsName). * * @param world The world. * @param entity The entity. * @param name The name. * @return The provided entity, or a new entity if 0 was provided. */ FLECS_API ecs_entity_t ecs_set_name( ecs_world_t *world, ecs_entity_t entity, const char *name); /** Set the symbol of an entity. * This will set or overwrite the symbol of an entity. If no entity is provided, * a new entity will be created. * * The symbol is stored in (EcsIdentifier, EcsSymbol). * * @param world The world. * @param entity The entity. * @param symbol The symbol. * @return The provided entity, or a new entity if 0 was provided. */ FLECS_API ecs_entity_t ecs_set_symbol( ecs_world_t *world, ecs_entity_t entity, const char *symbol); /** Set alias for entity. * An entity can be looked up using its alias from the root scope without * providing the fully qualified name if its parent. An entity can only have * a single alias. * * The symbol is stored in (EcsIdentifier, EcsAlias). * * @param world The world. * @param entity The entity. * @param alias The alias. */ FLECS_API void ecs_set_alias( ecs_world_t *world, ecs_entity_t entity, const char *alias); /** Lookup an entity by it's path. * This operation is equivalent to calling: * * @code * ecs_lookup_path_w_sep(world, 0, path, ".", NULL, true); * @endcode * * @param world The world. * @param path The entity path. * @return The entity with the specified path, or 0 if no entity was found. */ FLECS_API ecs_entity_t ecs_lookup( const ecs_world_t *world, const char *path); /** Lookup a child entity by name. * Returns an entity that matches the specified name. Only looks for entities in * the provided parent. If no parent is provided, look in the current scope ( * root if no scope is provided). * * @param world The world. * @param name The entity name. * @return The entity with the specified name, or 0 if no entity was found. */ FLECS_API ecs_entity_t ecs_lookup_child( const ecs_world_t *world, ecs_entity_t parent, const char *name); /** Lookup an entity from a path. * Lookup an entity from a provided path, relative to the provided parent. The * operation will use the provided separator to tokenize the path expression. If * the provided path contains the prefix, the search will start from the root. * * If the entity is not found in the provided parent, the operation will * continue to search in the parent of the parent, until the root is reached. If * the entity is still not found, the lookup will search in the flecs.core * scope. If the entity is not found there either, the function returns 0. * * @param world The world. * @param parent The entity from which to resolve the path. * @param path The path to resolve. * @param sep The path separator. * @param prefix The path prefix. * @param recursive Recursively traverse up the tree until entity is found. * @return The entity if found, else 0. */ FLECS_API ecs_entity_t ecs_lookup_path_w_sep( const ecs_world_t *world, ecs_entity_t parent, const char *path, const char *sep, const char *prefix, bool recursive); /** Lookup an entity by its symbol name. * This looks up an entity by symbol stored in (EcsIdentifier, EcsSymbol). The * operation does not take into account hierarchies. * * This operation can be useful to resolve, for example, a type by its C * identifier, which does not include the Flecs namespacing. * * @param world The world. * @param symbol The symbol. * @param lookup_as_path If not found as a symbol, lookup as path. * @param recursive If looking up as path, recursively traverse up the tree. * @return The entity if found, else 0. */ FLECS_API ecs_entity_t ecs_lookup_symbol( const ecs_world_t *world, const char *symbol, bool lookup_as_path, bool recursive); /** Get a path identifier for an entity. * This operation creates a path that contains the names of the entities from * the specified parent to the provided entity, separated by the provided * separator. If no parent is provided the path will be relative to the root. If * a prefix is provided, the path will be prefixed by the prefix. * * If the parent is equal to the provided child, the operation will return an * empty string. If a nonzero component is provided, the path will be created by * looking for parents with that component. * * The returned path should be freed by the application. * * @param world The world. * @param parent The entity from which to create the path. * @param child The entity to which to create the path. * @param sep The separator to use between path elements. * @param prefix The initial character to use for root elements. * @return The relative entity path. */ FLECS_API char* ecs_get_path_w_sep( const ecs_world_t *world, ecs_entity_t parent, ecs_entity_t child, const char *sep, const char *prefix); /** Write path identifier to buffer. * Same as ecs_get_path_w_sep(), but writes result to an ecs_strbuf_t. * * @param world The world. * @param parent The entity from which to create the path. * @param child The entity to which to create the path. * @param sep The separator to use between path elements. * @param prefix The initial character to use for root elements. * @param buf The buffer to write to. */ void ecs_get_path_w_sep_buf( const ecs_world_t *world, ecs_entity_t parent, ecs_entity_t child, const char *sep, const char *prefix, ecs_strbuf_t *buf); /** Find or create entity from path. * This operation will find or create an entity from a path, and will create any * intermediate entities if required. If the entity already exists, no entities * will be created. * * If the path starts with the prefix, then the entity will be created from the * root scope. * * @param world The world. * @param parent The entity relative to which the entity should be created. * @param path The path to create the entity for. * @param sep The separator used in the path. * @param prefix The prefix used in the path. * @return The entity. */ FLECS_API ecs_entity_t ecs_new_from_path_w_sep( ecs_world_t *world, ecs_entity_t parent, const char *path, const char *sep, const char *prefix); /** Add specified path to entity. * This operation is similar to ecs_new_from_path(), but will instead add the path * to an existing entity. * * If an entity already exists for the path, it will be returned instead. * * @param world The world. * @param entity The entity to which to add the path. * @param parent The entity relative to which the entity should be created. * @param path The path to create the entity for. * @param sep The separator used in the path. * @param prefix The prefix used in the path. * @return The entity. */ FLECS_API ecs_entity_t ecs_add_path_w_sep( ecs_world_t *world, ecs_entity_t entity, ecs_entity_t parent, const char *path, const char *sep, const char *prefix); /** Set the current scope. * This operation sets the scope of the current stage to the provided entity. * As a result new entities will be created in this scope, and lookups will be * relative to the provided scope. * * It is considered good practice to restore the scope to the old value. * * @param world The world. * @param scope The entity to use as scope. * @return The previous scope. */ FLECS_API ecs_entity_t ecs_set_scope( ecs_world_t *world, ecs_entity_t scope); /** Get the current scope. * Get the scope set by ecs_set_scope(). If no scope is set, this operation will * return 0. * * @param world The world. * @return The current scope. */ FLECS_API ecs_entity_t ecs_get_scope( const ecs_world_t *world); /** Set a name prefix for newly created entities. * This is a utility that lets C modules use prefixed names for C types and * C functions, while using names for the entity names that do not have the * prefix. The name prefix is currently only used by ECS_COMPONENT. * * @param world The world. * @param prefix The name prefix to use. * @return The previous prefix. */ FLECS_API const char* ecs_set_name_prefix( ecs_world_t *world, const char *prefix); /** Set search path for lookup operations. * This operation accepts an array of entity ids that will be used as search * scopes by lookup operations. The operation returns the current search path. * It is good practice to restore the old search path. * * The search path will be evaluated starting from the last element. * * The default search path includes flecs.core. When a custom search path is * provided it overwrites the existing search path. Operations that rely on * looking up names from flecs.core without providing the namespace may fail if * the custom search path does not include flecs.core (EcsFlecsCore). * * The search path array is not copied into managed memory. The application must * ensure that the provided array is valid for as long as it is used as the * search path. * * The provided array must be terminated with a 0 element. This enables an * application to push/pop elements to an existing array without invoking the * ecs_set_lookup_path() operation again. * * @param world The world. * @param lookup_path 0-terminated array with entity ids for the lookup path. * @return Current lookup path array. */ FLECS_API ecs_entity_t* ecs_set_lookup_path( ecs_world_t *world, const ecs_entity_t *lookup_path); /** Get current lookup path. * Returns value set by ecs_set_lookup_path(). * * @param world The world. * @return The current lookup path. */ FLECS_API ecs_entity_t* ecs_get_lookup_path( const ecs_world_t *world); /** @} */ /** @} */ /** * @defgroup components Components * Functions for registering and working with components. * * @{ */ /** Find or create a component. * This operation creates a new component, or finds an existing one. The find or * create behavior is the same as ecs_entity_init(). * * When an existing component is found, the size and alignment are verified with * the provided values. If the values do not match, the operation will fail. * * See the documentation of ecs_component_desc_t for more details. * * @param world The world. * @param desc Component init parameters. * @return A handle to the new or existing component, or 0 if failed. */ FLECS_API ecs_entity_t ecs_component_init( ecs_world_t *world, const ecs_component_desc_t *desc); /** Get the type for an id. * This function returns the type information for an id. The specified id can be * any valid id. For the rules on how type information is determined based on * id, see ecs_get_typeid(). * * @param world The world. * @param id The id. * @return The type information of the id. */ FLECS_API const ecs_type_info_t* ecs_get_type_info( const ecs_world_t *world, ecs_id_t id); /** Register hooks for component. * Hooks allow for the execution of user code when components are constructed, * copied, moved, destructed, added, removed or set. Hooks can be assigned as * as long as a component has not yet been used (added to an entity). * * The hooks that are currently set can be accessed with ecs_get_type_info(). * * @param world The world. * @param id The component id for which to register the actions * @param hooks Type that contains the component actions. */ FLECS_API void ecs_set_hooks_id( ecs_world_t *world, ecs_entity_t id, const ecs_type_hooks_t *hooks); /** Get hooks for component. * * @param world The world. * @param id The component id for which to retrieve the hooks. * @return The hooks for the component, or NULL if not registered. */ FLECS_API const ecs_type_hooks_t* ecs_get_hooks_id( ecs_world_t *world, ecs_entity_t id); /** @} */ /** * @defgroup ids Ids * Functions for working with `ecs_id_t`. * * @{ */ /** Returns whether specified id a tag. * This operation returns whether the specified type is a tag (a component * without data/size). * * An id is a tag when: * - it is an entity without the EcsComponent component * - it has an EcsComponent with size member set to 0 * - it is a pair where both elements are a tag * - it is a pair where the first element has the EcsTag tag * * @param world The world. * @param id The id. * @return Whether the provided id is a tag. */ FLECS_API bool ecs_id_is_tag( const ecs_world_t *world, ecs_id_t id); /** Return whether represents a union. * This operation returns whether the specified type represents a union. Only * pair ids can be unions. * * An id represents a union when: * - The first element of the pair is EcsUnion/flecs::Union * - The first element of the pair has EcsUnion/flecs::Union * * @param world The world. * @param id The id. * @return Whether the provided id represents a union. */ FLECS_API bool ecs_id_is_union( const ecs_world_t *world, ecs_id_t id); /** Returns whether specified id is in use. * This operation returns whether an id is in use in the world. An id is in use * if it has been added to one or more tables. * * @param world The world. * @param id The id. * @return Whether the id is in use. */ FLECS_API bool ecs_id_in_use( const ecs_world_t *world, ecs_id_t id); /** Get the type for an id. * This operation returns the component id for an id, if the id is associated * with a type. For a regular component with a non-zero size (an entity with the * EcsComponent component) the operation will return the entity itself. * * For an entity that does not have the EcsComponent component, or with an * EcsComponent value with size 0, the operation will return 0. * * For a pair id the operation will return the type associated with the pair, by * applying the following rules in order: * - The first pair element is returned if it is a component * - 0 is returned if the relationship entity has the Tag property * - The second pair element is returned if it is a component * - 0 is returned. * * @param world The world. * @param id The id. * @return The type id of the id. */ FLECS_API ecs_entity_t ecs_get_typeid( const ecs_world_t *world, ecs_id_t id); /** Utility to match an id with a pattern. * This operation returns true if the provided pattern matches the provided * id. The pattern may contain a wildcard (or wildcards, when a pair). * * @param id The id. * @param pattern The pattern to compare with. */ FLECS_API bool ecs_id_match( ecs_id_t id, ecs_id_t pattern); /** Utility to check if id is a pair. * * @param id The id. * @return True if id is a pair. */ FLECS_API bool ecs_id_is_pair( ecs_id_t id); /** Utility to check if id is a wildcard. * * @param id The id. * @return True if id is a wildcard or a pair containing a wildcard. */ FLECS_API bool ecs_id_is_wildcard( ecs_id_t id); /** Utility to check if id is valid. * A valid id is an id that can be added to an entity. Invalid ids are: * - ids that contain wildcards * - ids that contain invalid entities * - ids that are 0 or contain 0 entities * * Note that the same rules apply to removing from an entity, with the exception * of wildcards. * * @param world The world. * @param id The id. * @return True if the id is valid. */ FLECS_API bool ecs_id_is_valid( const ecs_world_t *world, ecs_id_t id); /** Get flags associated with id. * This operation returns the internal flags (see api_flags.h) that are * associated with the provided id. * * @param world The world. * @param id The id. * @return Flags associated with the id, or 0 if the id is not in use. */ FLECS_API ecs_flags32_t ecs_id_get_flags( const ecs_world_t *world, ecs_id_t id); /** Convert id flag to string. * This operation converts a id flag to a string. * * @param id_flags The id flag. * @return The id flag string, or NULL if no valid id is provided. */ FLECS_API const char* ecs_id_flag_str( ecs_id_t id_flags); /** Convert id to string. * This operation interprets the structure of an id and converts it to a string. * * @param world The world. * @param id The id to convert to a string. * @return The id converted to a string. */ FLECS_API char* ecs_id_str( const ecs_world_t *world, ecs_id_t id); /** Write id string to buffer. * Same as ecs_id_str() but writes result to ecs_strbuf_t. * * @param world The world. * @param id The id to convert to a string. * @param buf The buffer to write to. */ FLECS_API void ecs_id_str_buf( const ecs_world_t *world, ecs_id_t id, ecs_strbuf_t *buf); /** @} */ /** * @defgroup filters Filters * Functions for working with `ecs_term_t` and `ecs_filter_t`. * * @{ */ /** Iterator for a single (component) id. * A term iterator returns all entities (tables) that match a single (component) * id. The search for the matching set of entities (tables) is performed in * constant time. * * @param world The world. * @param term The term. * @return The iterator. */ FLECS_API ecs_iter_t ecs_term_iter( const ecs_world_t *world, ecs_term_t *term); /** Return a chained term iterator. * A chained iterator applies a filter to the results of the input iterator. The * resulting iterator must be iterated with ecs_term_next(). * * @param it The input iterator * @param term The term filter to apply to the iterator. * @return The chained iterator. */ FLECS_API ecs_iter_t ecs_term_chain_iter( const ecs_iter_t *it, ecs_term_t *term); /** Progress a term iterator. * This operation progresses the term iterator to the next table. The * iterator must have been initialized with ecs_term_iter(). This operation * must be invoked at least once before interpreting the contents of the * iterator. * * @param it The iterator. * @returns True if more data is available, false if not. */ FLECS_API bool ecs_term_next( ecs_iter_t *it); /** Iterator for a parent's children. * This operation is equivalent to a term iterator for (ChildOf, parent). * Iterate the result with ecs_children_next(). * * @param world The world. * @param parent The parent for which to iterate the children. * @return The iterator. */ FLECS_API ecs_iter_t ecs_children( const ecs_world_t *world, ecs_entity_t parent); /** Progress a children iterator. * Equivalent to ecs_term_next(). * * @param it The iterator. * @returns True if more data is available, false if not. */ FLECS_API bool ecs_children_next( ecs_iter_t *it); /** Test whether term id is set. * * @param id The term id. * @return True when set, false when not set. */ FLECS_API bool ecs_term_id_is_set( const ecs_term_id_t *id); /** Test whether a term is set. * This operation can be used to test whether a term has been initialized with * values or whether it is empty. * * An application generally does not need to invoke this operation. It is useful * when initializing a 0-initialized array of terms (like in ecs_term_desc_t) as * this operation can be used to find the last initialized element. * * @param term The term. * @return True when set, false when not set. */ FLECS_API bool ecs_term_is_initialized( const ecs_term_t *term); /** Is term matched on $this variable. * This operation checks whether a term is matched on the $this variable, which * is the default source for queries. * * A term has a $this source when: * - ecs_term_t::src::id is EcsThis * - ecs_term_t::src::flags is EcsIsVariable * * If ecs_term_t::src is not populated, it will be automatically initialized to * the $this source for the created query. * * @param term The term. * @return True if term matches $this, false if not. */ FLECS_API bool ecs_term_match_this( const ecs_term_t *term); /** Is term matched on 0 source. * This operation checks whether a term is matched on a 0 source. A 0 source is * a term that isn't matched against anything, and can be used just to pass * (component) ids to a query iterator. * * A term has a 0 source when: * - ecs_term_t::src::id is 0 * - ecs_term_t::src::flags has EcsIsEntity set * * @param term The term. * @return True if term has 0 source, false if not. */ FLECS_API bool ecs_term_match_0( const ecs_term_t *term); /** Finalize term. * Ensure that all fields of a term are consistent and filled out. This * operation should be invoked before using and after assigning members to, or * parsing a term. When a term contains unresolved identifiers, this operation * will resolve and assign the identifiers. If the term contains any identifiers * that cannot be resolved, the operation will fail. * * An application generally does not need to invoke this operation as the APIs * that use terms (such as filters, queries and triggers) will finalize terms * when they are created. * * The name and expr parameters are optional, and only used for giving more * descriptive error messages. * * @param world The world. * @param term The term to finalize. * @return Zero if success, nonzero if an error occurred. */ FLECS_API int ecs_term_finalize( const ecs_world_t *world, ecs_term_t *term); /** Copy resources of a term to another term. * This operation copies one term to another term. If the source term contains * allocated resources (such as identifiers), they will be duplicated so that * no memory is shared between the terms. * * @param src The term to copy from. * @return The destination term. */ FLECS_API ecs_term_t ecs_term_copy( const ecs_term_t *src); /** Move resources of a term to another term. * Same as copy, but moves resources from src, if src->move is set to true. If * src->move is not set to true, this operation will do a copy. * * The conditional move reduces redundant allocations in scenarios where a list * of terms is partially created with allocated resources. * * @param src The term to move from. * @return The destination term. */ FLECS_API ecs_term_t ecs_term_move( ecs_term_t *src); /** Free resources of term. * This operation frees all resources (such as identifiers) of a term. The term * itself is not freed. * * @param term The term to free. */ FLECS_API void ecs_term_fini( ecs_term_t *term); /** Initialize filter * A filter is a lightweight object that can be used to query for entities in * a world. Filters, as opposed to queries, do not cache results. They are * therefore slower to iterate, but are faster to create. * * When a filter is copied by value, make sure to use ecs_filter_move() to * ensure that the terms pointer still points to the inline array: * * @code * ecs_filter_move(&dst_filter, &src_filter) * @endcode * * Alternatively, the ecs_filter_move() function can be called with both arguments * set to the same filter, to ensure the pointer is valid: * * @code * ecs_filter_move(&f, &f) * @endcode * * It is possible to create a filter without allocating any memory, by setting * the .storage member in ecs_filter_desc_t. See the documentation for the * member for more details. * * @param world The world. * @param desc Properties for the filter to create. * @return The filter if successful, NULL if not successful. */ FLECS_API ecs_filter_t * ecs_filter_init( ecs_world_t *world, const ecs_filter_desc_t *desc); /** Deinitialize filter. * Free resources associated with filter. * * @param filter The filter to deinitialize. */ FLECS_API void ecs_filter_fini( ecs_filter_t *filter); /** Finalize filter. * When manually assigning an array of terms to the filter struct (so not when * using ecs_filter_init()), this operation should be used to ensure that all * terms are assigned properly and all (derived) fields have been set. * * When ecs_filter_init() is used to create the filter, this function should not * be called. The purpose of this operation is to support creation of filters * without allocating memory. * * @param filter The filter to finalize. * @return Zero if filter is valid, non-zero if it contains errors. * @ */ FLECS_API int ecs_filter_finalize( const ecs_world_t *world, ecs_filter_t *filter); /** Find index for $this variable. * This operation looks up the index of the $this variable. This index can * be used in operations like ecs_iter_set_var() and ecs_iter_get_var(). * * The operation will return -1 if the variable was not found. This happens when * a filter only has terms that are not matched on the $this variable, like a * filter that exclusively matches singleton components. * * @param filter The rule. * @return The index of the $this variable. */ FLECS_API int32_t ecs_filter_find_this_var( const ecs_filter_t *filter); /** Convert term to string expression. * Convert term to a string expression. The resulting expression is equivalent * to the same term, with the exception of And & Or operators. * * @param world The world. * @param term The term. * @return The term converted to a string. */ FLECS_API char* ecs_term_str( const ecs_world_t *world, const ecs_term_t *term); /** Convert filter to string expression. * Convert filter terms to a string expression. The resulting expression can be * parsed to create the same filter. * * @param world The world. * @param filter The filter. * @return The filter converted to a string. */ FLECS_API char* ecs_filter_str( const ecs_world_t *world, const ecs_filter_t *filter); /** Return a filter iterator. * A filter iterator lets an application iterate over entities that match the * specified filter. * * @param world The world. * @param filter The filter. * @return An iterator that can be used with ecs_filter_next(). */ FLECS_API ecs_iter_t ecs_filter_iter( const ecs_world_t *world, const ecs_filter_t *filter); /** Return a chained filter iterator. * A chained iterator applies a filter to the results of the input iterator. The * resulting iterator must be iterated with ecs_filter_next(). * * @param it The input iterator * @param filter The filter to apply to the iterator. * @return The chained iterator. */ FLECS_API ecs_iter_t ecs_filter_chain_iter( const ecs_iter_t *it, const ecs_filter_t *filter); /** Get pivot term for filter. * The pivot term is the term that matches the smallest set of tables, and is * a good default starting point for a search. * * The following conditions must be met for a term to be considered as pivot: * - It must have a This subject * - It must have the And operator * * When a filter does not have any terms that match those conditions, it will * return -1. * * If one or more terms in the filter have no matching tables the filter won't * yield any results. In this case the operation will return -2 which gives a * search function the option to early out. * * @param world The world. * @param filter The filter. * @return Index of the pivot term (use with filter->terms) */ FLECS_API int32_t ecs_filter_pivot_term( const ecs_world_t *world, const ecs_filter_t *filter); /** Iterate tables matched by filter. * This operation progresses the filter iterator to the next table. The * iterator must have been initialized with ecs_filter_iter(). This operation * must be invoked at least once before interpreting the contents of the * iterator. * * @param it The iterator * @return True if more data is available, false if not. */ FLECS_API bool ecs_filter_next( ecs_iter_t *it); /** Same as ecs_filter_next, but always instanced. * See instanced property of ecs_filter_desc_t. * * @param it The iterator * @return True if more data is available, false if not. */ FLECS_API bool ecs_filter_next_instanced( ecs_iter_t *it); /** Move resources of one filter to another. * * @param dst The destination filter. * @param src The source filter. */ FLECS_API void ecs_filter_move( ecs_filter_t *dst, ecs_filter_t *src); /** Copy resources of one filter to another. * * @param dst The destination filter. * @param src The source filter. */ FLECS_API void ecs_filter_copy( ecs_filter_t *dst, const ecs_filter_t *src); /** @} */ /** * @defgroup queries Queries * Functions for working with `ecs_query_t`. * * @{ */ /** Create a query. * This operation creates a query. Queries are used to iterate over entities * that match a filter and are the fastest way to find and iterate over entities * and their components. * * Queries should be created once, and reused multiple times. While iterating a * query is a cheap operation, creating and deleting a query is expensive. The * reason for this is that queries are "pre-matched", which means that a query * stores state about which entities (or rather, tables) match with the query. * Building up this state happens during query creation. * * Once a query is created, matching only happens when new tables are created. * In most applications this is an infrequent process, since it only occurs when * a new combination of components is introduced. While matching is expensive, * it is important to note that matching does not happen on a per-entity basis, * but on a per-table basis. This means that the average time spent on matching * per frame should rapidly approach zero over the lifetime of an application. * * A query provides direct access to the component arrays. When an application * creates/deletes entities or adds/removes components, these arrays can shift * component values around, or may grow in size. This can cause unexpected or * undefined behavior to occur if these operations are performed while * iterating. To prevent this from happening an application should either not * perform these operations while iterating, or use deferred operations (see * ecs_defer_begin() and ecs_defer_end()). * * Queries can be created and deleted dynamically. If a query was not deleted * (using ecs_query_fini()) before the world is deleted, it will be deleted * automatically. * * @param world The world. * @param desc A structure describing the query properties. * @return The new query. */ FLECS_API ecs_query_t* ecs_query_init( ecs_world_t *world, const ecs_query_desc_t *desc); /** Destroy a query. * This operation destroys a query and its resources. If the query is used as * the parent of subqueries, those subqueries will be orphaned and must be * deinitialized as well. * * @param query The query. */ FLECS_API void ecs_query_fini( ecs_query_t *query); /** Get filter from a query. * This operation obtains a pointer to the internally constructed filter * of the query and can be used to introspect the query terms. * * @param query The query. * @return The filter. */ FLECS_API const ecs_filter_t* ecs_query_get_filter( const ecs_query_t *query); /** Return a query iterator. * A query iterator lets an application iterate over entities that match the * specified query. If a sorting function is specified, the query will check * whether a resort is required upon creating the iterator. * * Creating a query iterator is a cheap operation that does not allocate any * resources. An application does not need to deinitialize or free a query * iterator before it goes out of scope. * * To iterate the iterator, an application should use ecs_query_next() to progress * the iterator and test if it has data. * * Query iteration requires an outer and an inner loop. The outer loop uses * ecs_query_next() to test if new tables are available. The inner loop iterates * the entities in the table, and is usually a for loop that uses iter.count to * loop through the entities and component arrays. * * The two loops are necessary because of how data is stored internally. * Entities are grouped by the components they have, in tables. A single query * can (and often does) match with multiple tables. Because each table has its * own set of arrays, an application has to reobtain pointers to those arrays * for each matching table. * * @param world The world or stage, when iterating in readonly mode. * @param query The query to iterate. * @return The query iterator. */ FLECS_API ecs_iter_t ecs_query_iter( const ecs_world_t *world, ecs_query_t *query); /** Progress the query iterator. * This operation progresses the query iterator to the next table. The * iterator must have been initialized with ecs_query_iter(). This operation * must be invoked at least once before interpreting the contents of the * iterator. * * @param iter The iterator. * @returns True if more data is available, false if not. */ FLECS_API bool ecs_query_next( ecs_iter_t *iter); /** Same as ecs_query_next, but always instanced. * See "instanced" property of ecs_filter_desc_t. * * @param iter The iterator. * @returns True if more data is available, false if not. */ FLECS_API bool ecs_query_next_instanced( ecs_iter_t *iter); /** Fast alternative to ecs_query_next() that only returns matched tables. * This operation only populates the ecs_iter_t::table field. To access the * matched components, call ecs_query_populate(). * * If this operation is used with a query that has inout/out terms, those terms * will not be marked dirty unless ecs_query_populate() is called. * * @param iter The iterator. * @returns True if more data is available, false if not. */ FLECS_API bool ecs_query_next_table( ecs_iter_t *iter); /** Populate iterator fields. * This operation can be combined with ecs_query_next_table() to populate the * iterator fields for the current table. * * Populating fields conditionally can save time when a query uses change * detection, and only needs iterator data when the table has changed. When this * operation is called, inout/out terms will be marked dirty. * * In cases where inout/out terms are conditionally written and no changes * were made after calling ecs_query_populate(), the ecs_query_skip() function can * be called to prevent the matched table components from being marked dirty. * * This operation does should not be used with queries that match disabled * components, union relationships, or with queries that use order_by. * * When the when_changed argument is set to true, the iterator data will only * populate when the data has changed, using query change detection. * * @param iter The iterator. * @param when_changed Only populate data when result has changed. */ FLECS_API int ecs_query_populate( ecs_iter_t *iter, bool when_changed); /** Returns whether the query data changed since the last iteration. * The operation will return true after: * - new entities have been matched with * - new tables have been matched/unmatched with * - matched entities were deleted * - matched components were changed * * The operation will not return true after a write-only (EcsOut) or filter * (EcsInOutNone) term has changed, when a term is not matched with the * current table (This subject) or for tag terms. * * The changed state of a table is reset after it is iterated. If a iterator was * not iterated until completion, tables may still be marked as changed. * * If no iterator is provided the operation will return the changed state of the * all matched tables of the query. * * If an iterator is provided, the operation will return the changed state of * the currently returned iterator result. The following preconditions must be * met before using an iterator with change detection: * * - The iterator is a query iterator (created with ecs_query_iter()) * - The iterator must be valid (ecs_query_next() must have returned true) * - The iterator must be instanced * * @param query The query (optional if 'it' is provided). * @param it The iterator result to test (optional if 'query' is provided). * @return true if entities changed, otherwise false. */ FLECS_API bool ecs_query_changed( ecs_query_t *query, const ecs_iter_t *it); /** Skip a table while iterating. * This operation lets the query iterator know that a table was skipped while * iterating. A skipped table will not reset its changed state, and the query * will not update the dirty flags of the table for its out columns. * * Only valid iterators must be provided (next has to be called at least once & * return true) and the iterator must be a query iterator. * * @param it The iterator result to skip. */ FLECS_API void ecs_query_skip( ecs_iter_t *it); /** Set group to iterate for query iterator. * This operation limits the results returned by the query to only the selected * group id. The query must have a group_by function, and the iterator must * be a query iterator. * * Groups are sets of tables that are stored together in the query cache based * on a group id, which is calculated per table by the group_by function. To * iterate a group, an iterator only needs to know the first and last cache node * for that group, which can both be found in a fast O(1) operation. * * As a result, group iteration is one of the most efficient mechanisms to * filter out large numbers of entities, even if those entities are distributed * across many tables. This makes it a good fit for things like dividing up * a world into cells, and only iterating cells close to a player. * * The group to iterate must be set before the first call to ecs_query_next(). No * operations that can add/remove components should be invoked between calling * ecs_query_set_group() and ecs_query_next(). * * @param it The query iterator. * @param group_id The group to iterate. */ FLECS_API void ecs_query_set_group( ecs_iter_t *it, uint64_t group_id); /** Get context of query group. * This operation returns the context of a query group as returned by the * on_group_create callback. * * @param query The query. * @param group_id The group for which to obtain the context. * @return The group context, NULL if the group doesn't exist. */ FLECS_API void* ecs_query_get_group_ctx( const ecs_query_t *query, uint64_t group_id); /** Get information about query group. * This operation returns information about a query group, including the group * context returned by the on_group_create callback. * * @param query The query. * @param group_id The group for which to obtain the group info. * @return The group info, NULL if the group doesn't exist. */ FLECS_API const ecs_query_group_info_t* ecs_query_get_group_info( const ecs_query_t *query, uint64_t group_id); /** 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. * * @param query The query. * @return true if query is orphaned, otherwise false. */ FLECS_API bool ecs_query_orphaned( const ecs_query_t *query); /** Convert query to string. * * @param query The query. * @return The query string. */ FLECS_API char* ecs_query_str( const ecs_query_t *query); /** Returns number of tables query matched with. * * @param query The query. * @return The number of matched tables. */ FLECS_API int32_t ecs_query_table_count( const ecs_query_t *query); /** Returns number of empty tables query matched with. * * @param query The query. * @return The number of matched empty tables. */ FLECS_API int32_t ecs_query_empty_table_count( const ecs_query_t *query); /** Returns number of entities query matched with. * This operation iterates all non-empty tables in the query cache to find the * total number of entities. * * @param query The query. * @return The number of matched entities. */ FLECS_API int32_t ecs_query_entity_count( const ecs_query_t *query); /** Get query ctx. * Return the value set in ecs_query_desc_t::ctx. * * @param query The query. * @return The context. */ FLECS_API void* ecs_query_get_ctx( const ecs_query_t *query); /** Get query binding ctx. * Return the value set in ecs_query_desc_t::binding_ctx. * * @param query The query. * @return The context. */ FLECS_API void* ecs_query_get_binding_ctx( const ecs_query_t *query); /** @} */ /** * @defgroup observers Observers * Functions for working with events and observers. * * @{ */ /** Send event. * This sends an event to matching triggers & is the mechanism used by flecs * itself to send OnAdd, OnRemove, etc events. * * Applications can use this function to send custom events, where a custom * event can be any regular entity. * * Applications should not send builtin flecs events, as this may violate * assumptions the code makes about the conditions under which those events are * sent. * * Triggers are invoked synchronously. It is therefore safe to use stack-based * data as event context, which can be set in the "param" member. * * @param world The world. * @param desc Event parameters. */ FLECS_API void ecs_emit( ecs_world_t *world, ecs_event_desc_t *desc); FLECS_API void ecs_enqueue( ecs_world_t *world, ecs_event_desc_t *desc); /** Create observer. * Observers are like triggers, but can subscribe for multiple terms. An * observer only triggers when the source of the event meets all terms. * * See the documentation for ecs_observer_desc_t for more details. * * @param world The world. * @param desc The observer creation parameters. */ FLECS_API ecs_entity_t ecs_observer_init( ecs_world_t *world, const ecs_observer_desc_t *desc); /** Default run action for observer. * This function can be called from a custom observer run action (see * ecs_observer_desc_t::run for more details). This function ensures that the * observer's filter is applied to the iterator's table, filters out duplicate * events and implements EcsMonitor logic. * * @param it The iterator. * @return True if the observer was invoked. */ FLECS_API bool ecs_observer_default_run_action( ecs_iter_t *it); /** Get observer ctx. * Return the value set in ecs_observer_desc_t::ctx. * * @param world The world. * @param observer The observer. * @return The context. */ FLECS_API void* ecs_observer_get_ctx( const ecs_world_t *world, ecs_entity_t observer); /** Get observer binding ctx. * Return the value set in ecs_observer_desc_t::binding_ctx. * * @param world The world. * @param observer The observer. * @return The context. */ FLECS_API void* ecs_observer_get_binding_ctx( const ecs_world_t *world, ecs_entity_t observer); /** Get observer query. * Return the observer query. * * @param world The world. * @param observer The observer. * @return The observer query. */ FLECS_API const ecs_filter_t* ecs_observer_get_filter( const ecs_world_t *world, ecs_entity_t observer); /** @} */ /** * @defgroup iterator Iterators * Functions for working with `ecs_iter_t`. * * @{ */ /** Create iterator from poly object. * The provided poly object must have the iterable mixin. If an object is * provided that does not have the mixin, the function will assert. * * When a filter is provided, an array of two iterators must be passed to the * function. This allows the mixin implementation to create a chained iterator * when necessary, which requires two iterator objects. * * If a filter is provided, the first element in the array of two iterators is * the one that should be iterated. The mixin implementation may or may not set * the second element, depending on whether an iterator chain is required. * * Additionally, when a filter is provided the returned iterator will be for a * single term with the provided filter id. If the iterator is chained, the * previous iterator in the chain can be accessed through it->chain_it. * * @param world The world or stage for which to create the iterator. * @param poly The poly object from which to create the iterator. * @param iter The iterator (out, ecs_iter_t[2] when filter is set). * @param filter Optional term used for filtering the results. */ FLECS_API void ecs_iter_poly( const ecs_world_t *world, const ecs_poly_t *poly, ecs_iter_t *iter, ecs_term_t *filter); /** Progress any iterator. * This operation is useful in combination with iterators for which it is not * known what created them. Example use cases are functions that should accept * any kind of iterator (such as serializers) or iterators created from poly * objects. * * This operation is slightly slower than using a type-specific iterator (e.g. * ecs_filter_next(), ecs_query_next()) as it has to call a function pointer which * introduces a level of indirection. * * @param it The iterator. * @return True if iterator has more results, false if not. */ FLECS_API bool ecs_iter_next( ecs_iter_t *it); /** Cleanup iterator resources. * This operation cleans up any resources associated with the iterator. * * This operation should only be used when an iterator is not iterated until * completion (next has not yet returned false). When an iterator is iterated * until completion, resources are automatically freed. * * @param it The iterator. */ FLECS_API void ecs_iter_fini( ecs_iter_t *it); /** Count number of matched entities in query. * This operation returns the number of matched entities. If a query contains no * matched entities but still yields results (e.g. it has no terms with This * sources) the operation will return 0. * * To determine the number of matched entities, the operation iterates the * iterator until it yields no more results. * * @param it The iterator. * @return True if iterator has more results, false if not. */ FLECS_API int32_t ecs_iter_count( ecs_iter_t *it); /** Test if iterator is true. * This operation will return true if the iterator returns at least one result. * This is especially useful in combination with fact-checking rules (see the * rules addon). * * The operation requires a valid iterator. After the operation is invoked, the * application should no longer invoke next on the iterator and should treat it * as if the iterator is iterated until completion. * * @param it The iterator. * @return true if the iterator returns at least one result. */ FLECS_API bool ecs_iter_is_true( ecs_iter_t *it); /** Get first matching entity from iterator. * After this operation the application should treat the iterator as if it has * been iterated until completion. * * @param it The iterator. * @return The first matching entity, or 0 if no entities were matched. */ FLECS_API ecs_entity_t ecs_iter_first( ecs_iter_t *it); /** Set value for iterator variable. * This constrains the iterator to return only results for which the variable * equals the specified value. The default value for all variables is * EcsWildcard, which means the variable can assume any value. * * Example: * * @code * // Rule that matches (Eats, *) * ecs_rule_t *r = ecs_rule_init(world, &(ecs_filter_desc_t){ * .terms = { * { .first.id = Eats, .second.name = "$food" } * } * }); * * int food_var = ecs_rule_find_var(r, "food"); * * // Set Food to Apples, so we're only matching (Eats, Apples) * ecs_iter_t it = ecs_rule_iter(world, r); * ecs_iter_set_var(&it, food_var, Apples); * * while (ecs_rule_next(&it)) { * for (int i = 0; i < it.count; i ++) { * // iterate as usual * } * } * @endcode * * The variable must be initialized after creating the iterator and before the * first call to next. * * @param it The iterator. * @param var_id The variable index. * @param entity The entity variable value. */ FLECS_API void ecs_iter_set_var( ecs_iter_t *it, int32_t var_id, ecs_entity_t entity); /** Same as ecs_iter_set_var(), but for a table. * This constrains the variable to all entities in a table. * * @param it The iterator. * @param var_id The variable index. * @param table The table variable value. */ FLECS_API void ecs_iter_set_var_as_table( ecs_iter_t *it, int32_t var_id, const ecs_table_t *table); /** Same as ecs_iter_set_var(), but for a range of entities * This constrains the variable to a range of entities in a table. * * @param it The iterator. * @param var_id The variable index. * @param range The range variable value. */ FLECS_API void ecs_iter_set_var_as_range( ecs_iter_t *it, int32_t var_id, const ecs_table_range_t *range); /** Get value of iterator variable as entity. * A variable can be interpreted as entity if it is set to an entity, or if it * is set to a table range with count 1. * * This operation can only be invoked on valid iterators. The variable index * must be smaller than the total number of variables provided by the iterator * (as set in ecs_iter_t::variable_count). * * @param it The iterator. * @param var_id The variable index. * @return The variable value. */ FLECS_API ecs_entity_t ecs_iter_get_var( ecs_iter_t *it, int32_t var_id); /** Get value of iterator variable as table. * A variable can be interpreted as table if it is set as table range with * both offset and count set to 0, or if offset is 0 and count matches the * number of elements in the table. * * This operation can only be invoked on valid iterators. The variable index * must be smaller than the total number of variables provided by the iterator * (as set in ecs_iter_t::variable_count). * * @param it The iterator. * @param var_id The variable index. * @return The variable value. */ FLECS_API ecs_table_t* ecs_iter_get_var_as_table( ecs_iter_t *it, int32_t var_id); /** Get value of iterator variable as table range. * A value can be interpreted as table range if it is set as table range, or if * it is set to an entity with a non-empty type (the entity must have at least * one component, tag or relationship in its type). * * This operation can only be invoked on valid iterators. The variable index * must be smaller than the total number of variables provided by the iterator * (as set in ecs_iter_t::variable_count). * * @param it The iterator. * @param var_id The variable index. * @return The variable value. */ FLECS_API ecs_table_range_t ecs_iter_get_var_as_range( ecs_iter_t *it, int32_t var_id); /** Returns whether variable is constrained. * This operation returns true for variables set by one of the ecs_iter_set_var* * operations. * * A constrained variable is guaranteed not to change values while results are * being iterated. * * @param it The iterator. * @param var_id The variable index. * @return Whether the variable is constrained to a specified value. */ FLECS_API bool ecs_iter_var_is_constrained( ecs_iter_t *it, int32_t var_id); /** Convert iterator to string. * Prints the contents of an iterator to a string. Useful for debugging and/or * testing the output of an iterator. * * The function only converts the currently iterated data to a string. To * convert all data, the application has to manually call the next function and * call ecs_iter_str() on each result. * * @param it The iterator. * @return A string representing the contents of the iterator. */ FLECS_API char* ecs_iter_str( const ecs_iter_t *it); /** Create a paged iterator. * Paged iterators limit the results to those starting from 'offset', and will * return at most 'limit' results. * * The iterator must be iterated with ecs_page_next(). * * A paged iterator acts as a passthrough for data exposed by the parent * iterator, so that any data provided by the parent will also be provided by * the paged iterator. * * @param it The source iterator. * @param offset The number of entities to skip. * @param limit The maximum number of entities to iterate. * @return A page iterator. */ FLECS_API ecs_iter_t ecs_page_iter( const ecs_iter_t *it, int32_t offset, int32_t limit); /** Progress a paged iterator. * Progresses an iterator created by ecs_page_iter(). * * @param it The iterator. * @return true if iterator has more results, false if not. */ FLECS_API bool ecs_page_next( ecs_iter_t *it); /** Create a worker iterator. * Worker iterators can be used to equally divide the number of matched entities * across N resources (usually threads). Each resource will process the total * number of matched entities divided by 'count'. * * Entities are distributed across resources such that the distribution is * stable between queries. Two queries that match the same table are guaranteed * to match the same entities in that table. * * The iterator must be iterated with ecs_worker_next(). * * A worker iterator acts as a passthrough for data exposed by the parent * iterator, so that any data provided by the parent will also be provided by * the worker iterator. * * @param it The source iterator. * @param index The index of the current resource. * @param count The total number of resources to divide entities between. * @return A worker iterator. */ FLECS_API ecs_iter_t ecs_worker_iter( const ecs_iter_t *it, int32_t index, int32_t count); /** Progress a worker iterator. * Progresses an iterator created by ecs_worker_iter(). * * @param it The iterator. * @return true if iterator has more results, false if not. */ FLECS_API bool ecs_worker_next( ecs_iter_t *it); /** Obtain data for a query field. * This operation retrieves a pointer to an array of data that belongs to the * term in the query. The index refers to the location of the term in the query, * and starts counting from one. * * For example, the query "Position, Velocity" will return the Position array * for index 1, and the Velocity array for index 2. * * When the specified field is not owned by the entity this function returns a * pointer instead of an array. This happens when the source of a field is not * the entity being iterated, such as a shared component (from a prefab), a * component from a parent, or another entity. The ecs_field_is_self() operation * can be used to test dynamically if a field is owned. * * The provided size must be either 0 or must match the size of the datatype * of the returned array. If the size does not match, the operation may assert. * The size can be dynamically obtained with ecs_field_size. * * @param it The iterator. * @param size The type size of the requested data. * @param index The index of the field in the iterator. * @return A pointer to the data of the field. */ FLECS_API void* ecs_field_w_size( const ecs_iter_t *it, size_t size, int32_t index); /** Test whether the field is readonly. * This operation returns whether the field is readonly. Readonly fields are * annotated with [in], or are added as a const type in the C++ API. * * @param it The iterator. * @param index The index of the field in the iterator. * @return Whether the field is readonly. */ FLECS_API bool ecs_field_is_readonly( const ecs_iter_t *it, int32_t index); /** Test whether the field is writeonly. * This operation returns whether this is a writeonly field. Writeonly terms are * annotated with [out]. * * Serializers are not required to serialize the values of a writeonly field. * * @param it The iterator. * @param index The index of the field in the iterator. * @return Whether the field is writeonly. */ FLECS_API bool ecs_field_is_writeonly( const ecs_iter_t *it, int32_t index); /** Test whether field is set. * * @param it The iterator. * @param index The index of the field in the iterator. * @return Whether the field is set. */ FLECS_API bool ecs_field_is_set( const ecs_iter_t *it, int32_t index); /** Return id matched for field. * * @param it The iterator. * @param index The index of the field in the iterator. * @return The id matched for the field. */ FLECS_API ecs_id_t ecs_field_id( const ecs_iter_t *it, int32_t index); /** Return index of matched table column. * This function only returns column indices for fields that have been matched * on the $this variable. Fields matched on other tables will return -1. * * @param it The iterator. * @param index The index of the field in the iterator. * @return The index of the matched column, -1 if not matched. */ FLECS_API int32_t ecs_field_column_index( const ecs_iter_t *it, int32_t index); /** Return field source. * The field source is the entity on which the field was matched. * * @param it The iterator. * @param index The index of the field in the iterator. * @return The source for the field. */ FLECS_API ecs_entity_t ecs_field_src( const ecs_iter_t *it, int32_t index); /** Return field type size. * Return type size of the field. Returns 0 if the field has no data. * * @param it The iterator. * @param index The index of the field in the iterator. * @return The type size for the field. */ FLECS_API size_t ecs_field_size( const ecs_iter_t *it, int32_t index); /** Test whether the field is matched on self. * This operation returns whether the field is matched on the currently iterated * entity. This function will return false when the field is owned by another * entity, such as a parent or a prefab. * * When this operation returns false, the field must be accessed as a single * value instead of an array. Fields for which this operation returns true * return arrays with it->count values. * * @param it The iterator. * @param index The index of the field in the iterator. * @return Whether the field is matched on self. */ FLECS_API bool ecs_field_is_self( const ecs_iter_t *it, int32_t index); /** @} */ /** * @defgroup tables Tables * Functions for working with `ecs_table_t`. * * @{ */ /** Get type for table. * The table type is a vector that contains all component, tag and pair ids. * * @param table The table. * @return The type of the table. */ FLECS_API const ecs_type_t* ecs_table_get_type( const ecs_table_t *table); /** Get type index for id. * This operation returns the index for an id in the table's type. * * @param world The world. * @param table The table. * @param id The id. * @return The index of the id in the table type, or -1 if not found. */ FLECS_API int32_t ecs_table_get_type_index( const ecs_world_t *world, const ecs_table_t *table, ecs_id_t id); /** Get column index for id. * This operation returns the column index for an id in the table's type. If the * id is not a component, the function will return -1. * * @param world The world. * @param table The table. * @param id The component id. * @return The column index of the id, or -1 if not found/not a component. */ FLECS_API int32_t ecs_table_get_column_index( const ecs_world_t *world, const ecs_table_t *table, ecs_id_t id); /** Return number of columns in table. * Similar to ecs_table_get_type(table)->count, except that the column count * only counts the number of components in a table. * * @param table The table. * @return The number of columns in the table. */ FLECS_API int32_t ecs_table_column_count( const ecs_table_t *table); /** Convert type index to column index. * Tables have an array of columns for each component in the table. This array * does not include elements for tags, which means that the index for a * component in the table type is not necessarily the same as the index in the * column array. This operation converts from an index in the table type to an * index in the column array. * * @param table The table. * @param index The index in the table type. * @return The index in the table column array. */ FLECS_API int32_t ecs_table_type_to_column_index( const ecs_table_t *table, int32_t index); /** Convert column index to type index. * Same as ecs_table_type_to_column_index(), but converts from an index in the * column array to an index in the table type. * * @param table The table. * @param index The column index. * @return The index in the table type. */ FLECS_API int32_t ecs_table_column_to_type_index( const ecs_table_t *table, int32_t index); /** Get column from table by column index. * This operation returns the component array for the provided index. * * @param table The table. * @param index The column index. * @param offset The index of the first row to return (0 for entire column). * @return The component array, or NULL if the index is not a component. */ FLECS_API void* ecs_table_get_column( const ecs_table_t *table, int32_t index, int32_t offset); /** Get column from table by component id. * This operation returns the component array for the provided component id. * * @param table The table. * @param id The component id for the column. * @param offset The index of the first row to return (0 for entire column). * @return The component array, or NULL if the index is not a component. */ FLECS_API void* ecs_table_get_id( const ecs_world_t *world, const ecs_table_t *table, ecs_id_t id, int32_t offset); /** Get column size from table. * This operation returns the component size for the provided index. * * @param table The table. * @param index The column index. * @return The component size, or 0 if the index is not a component. */ FLECS_API size_t ecs_table_get_column_size( const ecs_table_t *table, int32_t index); /** Returns the number of records in the table. * This operation returns the number of records that have been populated through * the regular (entity) API as well as the number of records that have been * inserted using the direct access API. * * @param table The table. * @return The number of records in a table. */ FLECS_API int32_t ecs_table_count( const ecs_table_t *table); /** Test if table has id. * Same as ecs_table_get_type_index(world, table, id) != -1. * * @param world The world. * @param table The table. * @param id The id. * @return True if the table has the id, false if the table doesn't. */ FLECS_API bool ecs_table_has_id( const ecs_world_t *world, const ecs_table_t *table, ecs_id_t id); /** Return depth for table in tree for relationship rel. * Depth is determined by counting the number of targets encountered while * traversing up the relationship tree for rel. Only acyclic relationships are * supported. * * @param world The world. * @param table The table. * @param rel The relationship. * @return The depth of the table in the tree. */ FLECS_API int32_t ecs_table_get_depth( const ecs_world_t *world, const ecs_table_t *table, ecs_entity_t rel); /** Get table that has all components of current table plus the specified id. * If the provided table already has the provided id, the operation will return * the provided table. * * @param world The world. * @param table The table. * @param id The id to add. * @result The resulting table. */ FLECS_API ecs_table_t* ecs_table_add_id( ecs_world_t *world, ecs_table_t *table, ecs_id_t id); /** Find table from id array. * This operation finds or creates a table with the specified array of * (component) ids. The ids in the array must be sorted, and it may not contain * duplicate elements. * * @param world The world. * @param ids The id array. * @param id_count The number of elements in the id array. * @return The table with the specified (component) ids. */ FLECS_API ecs_table_t* ecs_table_find( ecs_world_t *world, const ecs_id_t *ids, int32_t id_count); /** Get table that has all components of current table minus the specified id. * If the provided table doesn't have the provided id, the operation will return * the provided table. * * @param world The world. * @param table The table. * @param id The id to remove. * @result The resulting table. */ FLECS_API ecs_table_t* ecs_table_remove_id( ecs_world_t *world, ecs_table_t *table, ecs_id_t id); /** Lock a table. * When a table is locked, modifications to it will throw an assert. When the * table is locked recursively, it will take an equal amount of unlock * operations to actually unlock the table. * * Table locks can be used to build safe iterators where it is guaranteed that * the contents of a table are not modified while it is being iterated. * * The operation only works when called on the world, and has no side effects * when called on a stage. The assumption is that when called on a stage, * operations are deferred already. * * @param world The world. * @param table The table to lock. */ FLECS_API void ecs_table_lock( ecs_world_t *world, ecs_table_t *table); /** Unlock a table. * Must be called after calling ecs_table_lock(). * * @param world The world. * @param table The table to unlock. */ FLECS_API void ecs_table_unlock( ecs_world_t *world, ecs_table_t *table); /** Test table for flags. * Test if table has all of the provided flags. See * include/flecs/private/api_flags.h for a list of table flags that can be used * with this function. * * @param table The table. * @param flags The flags to test for. * @return Whether the specified flags are set for the table. */ FLECS_API bool ecs_table_has_flags( ecs_table_t *table, ecs_flags32_t flags); /** Swaps two elements inside the table. This is useful for implementing custom * table sorting algorithms. * @param world The world * @param table The table to swap elements in * @param row_1 Table element to swap with row_2 * @param row_2 Table element to swap with row_1 */ FLECS_API void ecs_table_swap_rows( ecs_world_t* world, ecs_table_t* table, int32_t row_1, int32_t row_2); /** Commit (move) entity to a table. * This operation moves an entity from its current table to the specified * table. This may cause the following actions: * - Ctor for each component in the target table * - Move for each overlapping component * - Dtor for each component in the source table. * - OnAdd triggers for non-overlapping components in the target table * - OnRemove triggers for non-overlapping components in the source table. * * This operation is a faster than adding/removing components individually. * * The application must explicitly provide the difference in components between * tables as the added/removed parameters. This can usually be derived directly * from the result of ecs_table_add_id() and ecs_table_remove_id(). These arrays are * required to properly execute OnAdd/OnRemove triggers. * * @param world The world. * @param entity The entity to commit. * @param record The entity's record (optional, providing it saves a lookup). * @param table The table to commit the entity to. * @return True if the entity got moved, false otherwise. */ FLECS_API bool ecs_commit( ecs_world_t *world, ecs_entity_t entity, ecs_record_t *record, ecs_table_t *table, const ecs_type_t *added, const ecs_type_t *removed); /** Find record for entity. */ FLECS_API ecs_record_t* ecs_record_find( const ecs_world_t *world, ecs_entity_t entity); /** Get component pointer from column/record. */ FLECS_API void* ecs_record_get_column( const ecs_record_t *r, int32_t column, size_t c_size); /** Search for component id in table type. * This operation returns the index of first occurrence of the id in the table * type. The id may be a wildcard. * * When id_out is provided, the function will assign it with the found id. The * found id may be different from the provided id if it is a wildcard. * * This is a constant time operation. * * @param world The world. * @param table The table. * @param id The id to search for. * @param id_out If provided, it will be set to the found id (optional). * @return The index of the id in the table type. */ FLECS_API int32_t ecs_search( const ecs_world_t *world, const ecs_table_t *table, ecs_id_t id, ecs_id_t *id_out); /** Search for component id in table type starting from an offset. * This operation is the same as ecs_search(), but starts searching from an offset * in the table type. * * This operation is typically called in a loop where the resulting index is * used in the next iteration as offset: * * @code * int32_t index = -1; * while ((index = ecs_search_offset(world, table, offset, id, NULL))) { * // do stuff * } * @endcode * * Depending on how the operation is used it is either linear or constant time. * When the id has the form (id) or (rel, *) and the operation is invoked as * in the above example, it is guaranteed to be constant time. * * If the provided id has the form (*, tgt) the operation takes linear time. The * reason for this is that ids for an target are not packed together, as they * are sorted relationship first. * * If the id at the offset does not match the provided id, the operation will do * a linear search to find a matching id. * * @param world The world. * @param table The table. * @param offset Offset from where to start searching. * @param id The id to search for. * @param id_out If provided, it will be set to the found id (optional). * @return The index of the id in the table type. */ FLECS_API int32_t ecs_search_offset( const ecs_world_t *world, const ecs_table_t *table, int32_t offset, ecs_id_t id, ecs_id_t *id_out); /** Search for component/relationship id in table type starting from an offset. * This operation is the same as ecs_search_offset(), but has the additional * capability of traversing relationships to find a component. For example, if * an application wants to find a component for either the provided table or a * prefab (using the IsA relationship) of that table, it could use the operation * like this: * * @code * int32_t index = ecs_search_relation( * world, // the world * table, // the table * 0, // offset 0 * ecs_id(Position), // the component id * EcsIsA, // the relationship to traverse * 0, // start at depth 0 (the table itself) * 0, // no depth limit * NULL, // (optional) entity on which component was found * NULL, // see above * NULL); // internal type with information about matched id * @endcode * * The operation searches depth first. If a table type has 2 IsA relationships, the * operation will first search the IsA tree of the first relationship. * * When choosing between ecs_search(), ecs_search_offset() and ecs_search_relation(), * the simpler the function the better its performance. * * @param world The world. * @param table The table. * @param offset Offset from where to start searching. * @param id The id to search for. * @param rel The relationship to traverse (optional). * @param flags Whether to search EcsSelf and/or EcsUp. * @param subject_out If provided, it will be set to the matched entity. * @param id_out If provided, it will be set to the found id (optional). * @param tr_out Internal datatype. * @return The index of the id in the table type. */ FLECS_API int32_t ecs_search_relation( const ecs_world_t *world, const ecs_table_t *table, int32_t offset, ecs_id_t id, ecs_entity_t rel, ecs_flags32_t flags, /* EcsSelf and/or EcsUp */ ecs_entity_t *subject_out, ecs_id_t *id_out, struct ecs_table_record_t **tr_out); /** @} */ /** * @defgroup values Values * Construct, destruct, copy and move dynamically created values. * * @{ */ /** Construct a value in existing storage * * @param world The world. * @param type The type of the value to create. * @param ptr Pointer to a value of type 'type' * @return Zero if success, nonzero if failed. */ FLECS_API int ecs_value_init( const ecs_world_t *world, ecs_entity_t type, void *ptr); /** Construct a value in existing storage * * @param world The world. * @param ti The type info of the type to create. * @param ptr Pointer to a value of type 'type' * @return Zero if success, nonzero if failed. */ FLECS_API int ecs_value_init_w_type_info( const ecs_world_t *world, const ecs_type_info_t *ti, void *ptr); /** Construct a value in new storage * * @param world The world. * @param type The type of the value to create. * @return Pointer to type if success, NULL if failed. */ FLECS_API void* ecs_value_new( ecs_world_t *world, ecs_entity_t type); /** Construct a value in new storage * * @param world The world. * @param ti The type info of the type to create. * @return Pointer to type if success, NULL if failed. */ void* ecs_value_new_w_type_info( ecs_world_t *world, const ecs_type_info_t *ti); /** Destruct a value * * @param world The world. * @param ti Type info of the value to destruct. * @param ptr Pointer to constructed value of type 'type'. * @return Zero if success, nonzero if failed. */ int ecs_value_fini_w_type_info( const ecs_world_t *world, const ecs_type_info_t *ti, void *ptr); /** Destruct a value * * @param world The world. * @param type The type of the value to destruct. * @param ptr Pointer to constructed value of type 'type'. * @return Zero if success, nonzero if failed. */ FLECS_API int ecs_value_fini( const ecs_world_t *world, ecs_entity_t type, void* ptr); /** Destruct a value, free storage * * @param world The world. * @param type The type of the value to destruct. * @return Zero if success, nonzero if failed. */ FLECS_API int ecs_value_free( ecs_world_t *world, ecs_entity_t type, void* ptr); /** Copy value. * * @param world The world. * @param ti Type info of the value to copy. * @param dst Pointer to the storage to copy to. * @param src Pointer to the value to copy. * @return Zero if success, nonzero if failed. */ FLECS_API int ecs_value_copy_w_type_info( const ecs_world_t *world, const ecs_type_info_t *ti, void* dst, const void *src); /** Copy value. * * @param world The world. * @param type The type of the value to copy. * @param dst Pointer to the storage to copy to. * @param src Pointer to the value to copy. * @return Zero if success, nonzero if failed. */ FLECS_API int ecs_value_copy( const ecs_world_t *world, ecs_entity_t type, void* dst, const void *src); /** Move value. * * @param world The world. * @param ti Type info of the value to move. * @param dst Pointer to the storage to move to. * @param src Pointer to the value to move. * @return Zero if success, nonzero if failed. */ int ecs_value_move_w_type_info( const ecs_world_t *world, const ecs_type_info_t *ti, void* dst, void *src); /** Move value. * * @param world The world. * @param type The type of the value to move. * @param dst Pointer to the storage to move to. * @param src Pointer to the value to move. * @return Zero if success, nonzero if failed. */ int ecs_value_move( const ecs_world_t *world, ecs_entity_t type, void* dst, void *src); /** Move construct value. * * @param world The world. * @param ti Type info of the value to move. * @param dst Pointer to the storage to move to. * @param src Pointer to the value to move. * @return Zero if success, nonzero if failed. */ int ecs_value_move_ctor_w_type_info( const ecs_world_t *world, const ecs_type_info_t *ti, void* dst, void *src); /** Move construct value. * * @param world The world. * @param type The type of the value to move. * @param dst Pointer to the storage to move to. * @param src Pointer to the value to move. * @return Zero if success, nonzero if failed. */ int ecs_value_move_ctor( const ecs_world_t *world, ecs_entity_t type, void* dst, void *src); /** @} */ /** @} */ /** * @defgroup c_addons Addons * @ingroup c * C APIs for addons. * * @{ * @} */ /** * @file addons/flecs_c.h * @brief Extends the core API with convenience macros for C applications. */ #ifndef FLECS_C_ #define FLECS_C_ /** * @defgroup flecs_c Macro API * @ingroup c * Convenience macro's for C API * * @{ */ /** * @defgroup flecs_c_creation Creation macro's * Convenience macro's for creating entities, components and observers * * @{ */ /* Use for declaring entity, tag, prefab / any other entity identifier */ #define ECS_DECLARE(id)\ ecs_entity_t id, ecs_id(id) /** Forward declare an entity. */ #define ECS_ENTITY_DECLARE ECS_DECLARE /** Define a forward declared entity. * * Example: * * @code * ECS_ENTITY_DEFINE(world, MyEntity, Position, Velocity); * @endcode */ #define ECS_ENTITY_DEFINE(world, id_, ...) \ { \ ecs_entity_desc_t desc = {0}; \ desc.id = id_; \ desc.name = #id_; \ desc.add_expr = #__VA_ARGS__; \ id_ = ecs_entity_init(world, &desc); \ ecs_id(id_) = id_; \ ecs_assert(id_ != 0, ECS_INVALID_PARAMETER, NULL); \ } \ (void)id_; \ (void)ecs_id(id_) /** Declare & define an entity. * * Example: * * @code * ECS_ENTITY(world, MyEntity, Position, Velocity); * @endcode */ #define ECS_ENTITY(world, id, ...) \ ecs_entity_t ecs_id(id); \ ecs_entity_t id = 0; \ ECS_ENTITY_DEFINE(world, id, __VA_ARGS__) /** Forward declare a tag. */ #define ECS_TAG_DECLARE ECS_DECLARE /** Define a forward declared tag. * * Example: * * @code * ECS_TAG_DEFINE(world, MyTag); * @endcode */ #define ECS_TAG_DEFINE(world, id) ECS_ENTITY_DEFINE(world, id, 0) /** Declare & define a tag. * * Example: * * @code * ECS_TAG(world, MyTag); * @endcode */ #define ECS_TAG(world, id) ECS_ENTITY(world, id, 0) /** Forward declare a prefab. */ #define ECS_PREFAB_DECLARE ECS_DECLARE /** Define a forward declared prefab. * * Example: * * @code * ECS_PREFAB_DEFINE(world, MyPrefab, Position, Velocity); * @endcode */ #define ECS_PREFAB_DEFINE(world, id, ...) ECS_ENTITY_DEFINE(world, id, Prefab, __VA_ARGS__) /** Declare & define a prefab. * * Example: * * @code * ECS_PREFAB(world, MyPrefab, Position, Velocity); * @endcode */ #define ECS_PREFAB(world, id, ...) ECS_ENTITY(world, id, Prefab, __VA_ARGS__) /** Forward declare a component. */ #define ECS_COMPONENT_DECLARE(id) ecs_entity_t ecs_id(id) /** Define a forward declared component. * * Example: * * @code * ECS_COMPONENT_DEFINE(world, Position); * @endcode */ #define ECS_COMPONENT_DEFINE(world, id_) \ {\ ecs_component_desc_t desc = {0}; \ ecs_entity_desc_t edesc = {0}; \ edesc.id = ecs_id(id_); \ edesc.use_low_id = true; \ edesc.name = #id_; \ edesc.symbol = #id_; \ desc.entity = ecs_entity_init(world, &edesc); \ desc.type.size = ECS_SIZEOF(id_); \ desc.type.alignment = ECS_ALIGNOF(id_); \ ecs_id(id_) = ecs_component_init(world, &desc);\ }\ ecs_assert(ecs_id(id_) != 0, ECS_INVALID_PARAMETER, NULL) /** Declare & define a component. * * Example: * * @code * ECS_COMPONENT(world, Position); * @endcode */ #define ECS_COMPONENT(world, id)\ ecs_entity_t ecs_id(id) = 0;\ ECS_COMPONENT_DEFINE(world, id);\ (void)ecs_id(id) /* Forward declare an observer. */ #define ECS_OBSERVER_DECLARE(id) ecs_entity_t ecs_id(id) /** Define a forward declared observer. * * Example: * * @code * ECS_OBSERVER_DEFINE(world, AddPosition, EcsOnAdd, Position); * @endcode */ #define ECS_OBSERVER_DEFINE(world, id_, kind, ...)\ {\ ecs_observer_desc_t desc = {0};\ ecs_entity_desc_t edesc = {0}; \ edesc.id = ecs_id(id_); \ edesc.name = #id_; \ desc.entity = ecs_entity_init(world, &edesc); \ desc.callback = id_;\ desc.filter.expr = #__VA_ARGS__;\ desc.events[0] = kind;\ ecs_id(id_) = ecs_observer_init(world, &desc);\ ecs_assert(ecs_id(id_) != 0, ECS_INVALID_PARAMETER, NULL);\ } /** Declare & define an observer. * * Example: * * @code * ECS_OBSERVER(world, AddPosition, EcsOnAdd, Position); * @endcode */ #define ECS_OBSERVER(world, id, kind, ...)\ ecs_entity_t ecs_id(id) = 0; \ ECS_OBSERVER_DEFINE(world, id, kind, __VA_ARGS__);\ ecs_entity_t id = ecs_id(id);\ (void)ecs_id(id);\ (void)id /** Shorthand for creating an entity with ecs_entity_init(). * * Example: * * @code * ecs_entity(world, { * .name = "MyEntity" * }); * @endcode */ #define ecs_entity(world, ...)\ ecs_entity_init(world, &(ecs_entity_desc_t) __VA_ARGS__ ) /** Shorthand for creating a component with ecs_component_init(). * * Example: * * @code * ecs_component(world, { * .type.size = 4, * .type.alignment = 4 * }); * @endcode */ #define ecs_component(world, ...)\ ecs_component_init(world, &(ecs_component_desc_t) __VA_ARGS__ ) /** Shorthand for creating a component from a type. * * Example: * * @code * ecs_component_t(world, Position); * @endcode */ #define ecs_component_t(world, T)\ ecs_component_init(world, &(ecs_component_desc_t) { \ .entity = ecs_entity(world, { \ .name = #T, \ .symbol = #T, \ .use_low_id = true \ }), \ .type.size = ECS_SIZEOF(T), \ .type.alignment = ECS_ALIGNOF(T) \ }) /** Shorthand for creating a filter with ecs_filter_init(). * * Example: * * @code * ecs_filter(world, { * .terms = {{ ecs_id(Position) }} * }); * @endcode */ #define ecs_filter(world, ...)\ ecs_filter_init(world, &(ecs_filter_desc_t) __VA_ARGS__ ) /** Shorthand for creating a query with ecs_query_init(). * * Example: * * @code * ecs_query(world, { * .filter.terms = {{ ecs_id(Position) }} * }); * @endcode */ #define ecs_query(world, ...)\ ecs_query_init(world, &(ecs_query_desc_t) __VA_ARGS__ ) /** Shorthand for creating an observer with ecs_observer_init(). * * Example: * * @code * ecs_observer(world, { * .filter.terms = {{ ecs_id(Position) }}, * .events = { EcsOnAdd }, * .callback = AddPosition * }); * @endcode */ #define ecs_observer(world, ...)\ ecs_observer_init(world, &(ecs_observer_desc_t) __VA_ARGS__ ) /** @} */ /** * @defgroup flecs_c_type_safe Type Safe API * Macro's that wrap around core functions to provide a "type safe" API in C * * @{ */ /** * @defgroup flecs_c_entities Entity API * @{ */ /** * @defgroup flecs_c_creation_deletion Creation & Deletion * @{ */ #define ecs_new(world, T) ecs_new_w_id(world, ecs_id(T)) #define ecs_new_w_pair(world, first, second)\ ecs_new_w_id(world, ecs_pair(first, second)) #define ecs_bulk_new(world, component, count)\ ecs_bulk_new_w_id(world, ecs_id(component), count) #define ecs_new_entity(world, n)\ ecs_entity_init(world, &(ecs_entity_desc_t){\ .name = n,\ }) #define ecs_new_prefab(world, n)\ ecs_entity_init(world, &(ecs_entity_desc_t){\ .name = n,\ .add = {EcsPrefab}\ }) #define ecs_delete_children(world, parent)\ ecs_delete_with(world, ecs_pair(EcsChildOf, parent)) /** @} */ /** * @defgroup flecs_c_adding_removing Adding & Removing * @{ */ #define ecs_add(world, entity, T)\ ecs_add_id(world, entity, ecs_id(T)) #define ecs_add_pair(world, subject, first, second)\ ecs_add_id(world, subject, ecs_pair(first, second)) #define ecs_remove(world, entity, T)\ ecs_remove_id(world, entity, ecs_id(T)) #define ecs_remove_pair(world, subject, first, second)\ ecs_remove_id(world, subject, ecs_pair(first, second)) #define ecs_override(world, entity, T)\ ecs_override_id(world, entity, ecs_id(T)) #define ecs_override_pair(world, subject, first, second)\ ecs_override_id(world, subject, ecs_pair(first, second)) /** @} */ /** * @defgroup flecs_c_getting_setting Getting & Setting * @{ */ /* set */ #define ecs_set_ptr(world, entity, component, ptr)\ ecs_set_id(world, entity, ecs_id(component), sizeof(component), ptr) #define ecs_set(world, entity, component, ...)\ ecs_set_id(world, entity, ecs_id(component), sizeof(component), &(component)__VA_ARGS__) #define ecs_set_pair(world, subject, First, second, ...)\ ecs_set_id(world, subject,\ ecs_pair(ecs_id(First), second),\ sizeof(First), &(First)__VA_ARGS__) #define ecs_set_pair_second(world, subject, first, Second, ...)\ ecs_set_id(world, subject,\ ecs_pair(first, ecs_id(Second)),\ sizeof(Second), &(Second)__VA_ARGS__) #define ecs_set_pair_object ecs_set_pair_second #define ecs_set_override(world, entity, T, ...)\ ecs_add_id(world, entity, ECS_OVERRIDE | ecs_id(T));\ ecs_set(world, entity, T, __VA_ARGS__) /* emplace */ #define ecs_emplace(world, entity, T)\ (ECS_CAST(T*, ecs_emplace_id(world, entity, ecs_id(T)))) #define ecs_emplace_pair(world, entity, First, second)\ (ECS_CAST(First*, ecs_emplace_id(world, entity, ecs_pair_t(First, second)))) /* get */ #define ecs_get(world, entity, T)\ (ECS_CAST(const T*, ecs_get_id(world, entity, ecs_id(T)))) #define ecs_get_pair(world, subject, First, second)\ (ECS_CAST(const First*, ecs_get_id(world, subject,\ ecs_pair(ecs_id(First), second)))) #define ecs_get_pair_second(world, subject, first, Second)\ (ECS_CAST(const Second*, ecs_get_id(world, subject,\ ecs_pair(first, ecs_id(Second))))) #define ecs_get_pair_object ecs_get_pair_second /* get_mut */ #define ecs_get_mut(world, entity, T)\ (ECS_CAST(T*, ecs_get_mut_id(world, entity, ecs_id(T)))) #define ecs_get_mut_pair(world, subject, First, second)\ (ECS_CAST(First*, ecs_get_mut_id(world, subject,\ ecs_pair(ecs_id(First), second)))) #define ecs_get_mut_pair_second(world, subject, first, Second)\ (ECS_CAST(Second*, ecs_get_mut_id(world, subject,\ ecs_pair(first, ecs_id(Second))))) #define ecs_get_mut_pair_object ecs_get_mut_pair_second #define ecs_get_mut(world, entity, T)\ (ECS_CAST(T*, ecs_get_mut_id(world, entity, ecs_id(T)))) /* ensure */ #define ecs_ensure(world, entity, T)\ (ECS_CAST(T*, ecs_ensure_id(world, entity, ecs_id(T)))) #define ecs_ensure_pair(world, subject, First, second)\ (ECS_CAST(First*, ecs_ensure_id(world, subject,\ ecs_pair(ecs_id(First), second)))) #define ecs_ensure_pair_second(world, subject, first, Second)\ (ECS_CAST(Second*, ecs_ensure_id(world, subject,\ ecs_pair(first, ecs_id(Second))))) #define ecs_ensure_pair_object ecs_ensure_pair_second #define ecs_ensure(world, entity, T)\ (ECS_CAST(T*, ecs_ensure_id(world, entity, ecs_id(T)))) #define ecs_ensure_pair(world, subject, First, second)\ (ECS_CAST(First*, ecs_ensure_id(world, subject,\ ecs_pair(ecs_id(First), second)))) #define ecs_ensure_pair_second(world, subject, first, Second)\ (ECS_CAST(Second*, ecs_ensure_id(world, subject,\ ecs_pair(first, ecs_id(Second))))) #define ecs_ensure_pair_object ecs_ensure_pair_second /* modified */ #define ecs_modified(world, entity, component)\ ecs_modified_id(world, entity, ecs_id(component)) #define ecs_modified_pair(world, subject, first, second)\ ecs_modified_id(world, subject, ecs_pair(first, second)) /* record */ #define ecs_record_get(world, record, T)\ (ECS_CAST(const T*, ecs_record_get_id(world, record, ecs_id(T)))) #define ecs_record_has(world, record, T)\ (ecs_record_has_id(world, record, ecs_id(T))) #define ecs_record_get_pair(world, record, First, second)\ (ECS_CAST(const First*, ecs_record_get_id(world, record, \ ecs_pair(ecs_id(First), second)))) #define ecs_record_get_pair_second(world, record, first, Second)\ (ECS_CAST(const Second*, ecs_record_get_id(world, record,\ ecs_pair(first, ecs_id(Second))))) #define ecs_record_ensure(world, record, T)\ (ECS_CAST(T*, ecs_record_ensure_id(world, record, ecs_id(T)))) #define ecs_record_ensure_pair(world, record, First, second)\ (ECS_CAST(First*, ecs_record_ensure_id(world, record, \ ecs_pair(ecs_id(First), second)))) #define ecs_record_ensure_pair_second(world, record, first, Second)\ (ECS_CAST(Second*, ecs_record_ensure_id(world, record,\ ecs_pair(first, ecs_id(Second))))) #define ecs_record_ensure_pair_object ecs_record_ensure_pair_second #define ecs_ref_init(world, entity, T)\ ecs_ref_init_id(world, entity, ecs_id(T)) #define ecs_ref_get(world, ref, T)\ (ECS_CAST(const T*, ecs_ref_get_id(world, ref, ecs_id(T)))) /** @} */ /** * @defgroup flecs_c_singletons Singletons * @{ */ #define ecs_singleton_add(world, comp)\ ecs_add(world, ecs_id(comp), comp) #define ecs_singleton_remove(world, comp)\ ecs_remove(world, ecs_id(comp), comp) #define ecs_singleton_get(world, comp)\ ecs_get(world, ecs_id(comp), comp) #define ecs_singleton_set_ptr(world, comp, ptr)\ ecs_set_ptr(world, ecs_id(comp), comp, ptr) #define ecs_singleton_set(world, comp, ...)\ ecs_set(world, ecs_id(comp), comp, __VA_ARGS__) #define ecs_singleton_ensure(world, comp)\ ecs_ensure(world, ecs_id(comp), comp) #define ecs_singleton_modified(world, comp)\ ecs_modified(world, ecs_id(comp), comp) /** @} */ /** * @defgroup flecs_c_has Has, Owns, Shares * @{ */ #define ecs_has(world, entity, T)\ ecs_has_id(world, entity, ecs_id(T)) #define ecs_has_pair(world, entity, first, second)\ ecs_has_id(world, entity, ecs_pair(first, second)) #define ecs_owns_pair(world, entity, first, second)\ ecs_owns_id(world, entity, ecs_pair(first, second)) #define ecs_owns(world, entity, T)\ ecs_owns_id(world, entity, ecs_id(T)) #define ecs_shares_id(world, entity, id)\ (ecs_search_relation(world, ecs_get_table(world, entity), 0, ecs_id(id), \ EcsIsA, 1, 0, 0, 0, 0) != -1) #define ecs_shares_pair(world, entity, first, second)\ (ecs_shares_id(world, entity, ecs_pair(first, second))) #define ecs_shares(world, entity, T)\ (ecs_shares_id(world, entity, ecs_id(T))) /** @} */ /** * @defgroup flecs_c_enable_disable Enabling & Disabling * @{ */ #define ecs_enable_component(world, entity, T, enable)\ ecs_enable_id(world, entity, ecs_id(T), enable) #define ecs_is_enabled_component(world, entity, T)\ ecs_is_enabled_id(world, entity, ecs_id(T)) #define ecs_enable_pair(world, entity, First, second, enable)\ ecs_enable_id(world, entity, ecs_pair(ecs_id(First), second), enable) #define ecs_is_enabled_pair(world, entity, First, second)\ ecs_is_enabled_id(world, entity, ecs_pair(ecs_id(First), second)) /** @} */ /** * @defgroup flecs_c_entity_names Entity Names * @{ */ #define ecs_lookup_path(world, parent, path)\ ecs_lookup_path_w_sep(world, parent, path, ".", NULL, true) /* Deprecated: use ecs_lookup instead */ #define ecs_lookup_fullpath(world, path)\ ecs_lookup(world, path) #define ecs_get_path(world, parent, child)\ ecs_get_path_w_sep(world, parent, child, ".", NULL) #define ecs_get_fullpath(world, child)\ ecs_get_path_w_sep(world, 0, child, ".", NULL) #define ecs_get_fullpath_buf(world, child, buf)\ ecs_get_path_w_sep_buf(world, 0, child, ".", NULL, buf) #define ecs_new_from_path(world, parent, path)\ ecs_new_from_path_w_sep(world, parent, path, ".", NULL) #define ecs_new_from_fullpath(world, path)\ ecs_new_from_path_w_sep(world, 0, path, ".", NULL) #define ecs_add_path(world, entity, parent, path)\ ecs_add_path_w_sep(world, entity, parent, path, ".", NULL) #define ecs_add_fullpath(world, entity, path)\ ecs_add_path_w_sep(world, entity, 0, path, ".", NULL) /** @} */ /** @} */ /** * @defgroup flecs_c_components Component API * @{ */ #define ecs_set_hooks(world, T, ...)\ ecs_set_hooks_id(world, ecs_id(T), &(ecs_type_hooks_t)__VA_ARGS__) #define ecs_get_hooks(world, T)\ ecs_get_hooks_id(world, ecs_id(T)); /** Declare a constructor. * Example: * * @code * ECS_CTOR(MyType, ptr, { ptr->value = NULL; }); * @endcode */ #define ECS_CTOR(type, var, ...)\ ECS_XTOR_IMPL(type, ctor, var, __VA_ARGS__) /** Declare a destructor. * Example: * * @code * ECS_DTOR(MyType, ptr, { free(ptr->value); }); * @endcode */ #define ECS_DTOR(type, var, ...)\ ECS_XTOR_IMPL(type, dtor, var, __VA_ARGS__) /** Declare a copy action. * Example: * * @code * ECS_COPY(MyType, dst, src, { dst->value = strdup(src->value); }); * @endcode */ #define ECS_COPY(type, dst_var, src_var, ...)\ ECS_COPY_IMPL(type, dst_var, src_var, __VA_ARGS__) /** Declare a move action. * Example: * * @code * ECS_MOVE(MyType, dst, src, { dst->value = src->value; src->value = 0; }); * @endcode */ #define ECS_MOVE(type, dst_var, src_var, ...)\ ECS_MOVE_IMPL(type, dst_var, src_var, __VA_ARGS__) /** Declare component hooks. * Example: * * @code * ECS_ON_SET(MyType, ptr, { printf("%d\n", ptr->value); }); * @endcode */ #define ECS_ON_ADD(type, ptr, ...)\ ECS_HOOK_IMPL(type, ecs_on_add(type), ptr, __VA_ARGS__) #define ECS_ON_REMOVE(type, ptr, ...)\ ECS_HOOK_IMPL(type, ecs_on_remove(type), ptr, __VA_ARGS__) #define ECS_ON_SET(type, ptr, ...)\ ECS_HOOK_IMPL(type, ecs_on_set(type), ptr, __VA_ARGS__) /* Map from typename to function name of component lifecycle action */ #define ecs_ctor(type) type##_ctor #define ecs_dtor(type) type##_dtor #define ecs_copy(type) type##_copy #define ecs_move(type) type##_move #define ecs_on_set(type) type##_on_set #define ecs_on_add(type) type##_on_add #define ecs_on_remove(type) type##_on_remove /** @} */ /** * @defgroup flecs_c_ids Id API * @{ */ #define ecs_count(world, type)\ ecs_count_id(world, ecs_id(type)) /** @} */ /** * @defgroup flecs_c_iterators Iterator API * @{ */ #define ecs_field(it, T, index)\ (ECS_CAST(T*, ecs_field_w_size(it, sizeof(T), index))) /** @} */ /** * @defgroup flecs_c_tables Table API * @{ */ #define ecs_table_get(world, table, T, offset)\ (ECS_CAST(T*, ecs_table_get_id(world, table, ecs_id(T), offset))) #define ecs_table_get_pair(world, table, First, second, offset)\ (ECS_CAST(First*, ecs_table_get_id(world, table, ecs_pair(ecs_id(First), second), offset))) #define ecs_table_get_pair_second(world, table, first, Second, offset)\ (ECS_CAST(Second*, ecs_table_get_id(world, table, ecs_pair(first, ecs_id(Second)), offset))) /** @} */ /** * @defgroup flecs_c_values Value API * @{ */ #define ecs_value(T, ptr) ((ecs_value_t){ecs_id(T), ptr}) #define ecs_value_new_t(world, T) ecs_value_new(world, ecs_id(T)) /** @} */ /** @} */ /** * @defgroup flecs_c_table_sorting Table sorting * Convenience macro's for sorting tables. * * @{ */ #define ecs_sort_table(id) ecs_id(id##_sort_table) #define ecs_compare(id) ecs_id(id##_compare_fn) /* Declare efficient table sorting operation that uses provided compare function. * For best results use LTO or make the function body visible in the same compilation unit. * Variadic arguments are prepended before generated functions, use it to declare static * or exported functions. * Parameters of the comparison function: * ecs_entity_t e1, const void* ptr1, * ecs_entity_t e2, const void* ptr2 * Parameters of the sort functions: * ecs_world_t *world * ecs_table_t *table * ecs_entity_t *entities * void *ptr * int32_t elem_size * int32_t lo * int32_t hi * ecs_order_by_action_t order_by - Pointer to the original comparison function. You are not supposed to use it. * Example: * * @code * int CompareMyType(ecs_entity_t e1, const void* ptr1, ecs_entity_t e2, const void* ptr2) { const MyType* p1 = ptr1; const MyType* p2 = ptr2; return p1->value - p2->value; } * ECS_SORT_TABLE_WITH_COMPARE(MyType, MyCustomCompare, CompareMyType) * @endcode */ #define ECS_SORT_TABLE_WITH_COMPARE(id, op_name, compare_fn, ...) \ static int32_t ECS_CONCAT(op_name, _partition)( \ ecs_world_t *world, \ ecs_table_t *table, \ ecs_entity_t *entities, \ void *ptr, \ int32_t elem_size, \ int32_t lo, \ int32_t hi, \ ecs_order_by_action_t order_by) \ { \ (void)(order_by); \ int32_t p = (hi + lo) / 2; \ void *pivot = ECS_ELEM(ptr, elem_size, p); \ ecs_entity_t pivot_e = entities[p]; \ int32_t i = lo - 1, j = hi + 1; \ void *el; \ repeat: \ { \ do { \ i ++; \ el = ECS_ELEM(ptr, elem_size, i); \ } while ( compare_fn(entities[i], el, pivot_e, pivot) < 0); \ do { \ j --; \ el = ECS_ELEM(ptr, elem_size, j); \ } while ( compare_fn(entities[j], el, pivot_e, pivot) > 0); \ if (i >= j) { \ return j; \ } \ ecs_table_swap_rows(world, table, i, j); \ if (p == i) { \ pivot = ECS_ELEM(ptr, elem_size, j); \ pivot_e = entities[j]; \ } else if (p == j) { \ pivot = ECS_ELEM(ptr, elem_size, i); \ pivot_e = entities[i]; \ } \ goto repeat; \ } \ } \ __VA_ARGS__ void op_name( \ ecs_world_t *world, \ ecs_table_t *table, \ ecs_entity_t *entities, \ void *ptr, \ int32_t size, \ int32_t lo, \ int32_t hi, \ ecs_order_by_action_t order_by) \ { \ if ((hi - lo) < 1) { \ return; \ } \ int32_t p = ECS_CONCAT(op_name, _partition)(world, table, entities, ptr, size, lo, hi, order_by); \ op_name(world, table, entities, ptr, size, lo, p, order_by); \ op_name(world, table, entities, ptr, size, p + 1, hi, order_by); \ } /* Declare efficient table sorting operation that uses default component comparison operator. * For best results use LTO or make the comparison operator visible in the same compilation unit. * Variadic arguments are prepended before generated functions, use it to declare static * or exported functions. * Example: * * @code * ECS_COMPARE(MyType, { const MyType* p1 = ptr1; const MyType* p2 = ptr2; return p1->value - p2->value; }); * ECS_SORT_TABLE(MyType) * @endcode */ #define ECS_SORT_TABLE(id, ...) \ ECS_SORT_TABLE_WITH_COMPARE(id, ecs_sort_table(id), ecs_compare(id), __VA_ARGS__) /* Declare component comparison operations. * Parameters: * ecs_entity_t e1, const void* ptr1, * ecs_entity_t e2, const void* ptr2 * Example: * * @code * ECS_COMPARE(MyType, { const MyType* p1 = ptr1; const MyType* p2 = ptr2; return p1->value - p2->value; }); * @endcode */ #define ECS_COMPARE(id, ...) \ int ecs_compare(id)(ecs_entity_t e1, const void* ptr1, ecs_entity_t e2, const void* ptr2) { \ __VA_ARGS__ \ } /** @} */ /** * @defgroup flecs_c_misc Misc * Misc convenience macro's. * * @{ */ #define ecs_isa(e) ecs_pair(EcsIsA, e) #define ecs_childof(e) ecs_pair(EcsChildOf, e) #define ecs_dependson(e) ecs_pair(EcsDependsOn, e) #define ecs_query_new(world, q_expr)\ ecs_query_init(world, &(ecs_query_desc_t){\ .filter.expr = q_expr\ }) #define ecs_rule_new(world, q_expr)\ ecs_rule_init(world, &(ecs_filter_desc_t){\ .expr = q_expr\ }) /** @} */ /** @} */ #endif // FLECS_C_ #ifdef __cplusplus } #endif /** * @file addons.h * @brief Include enabled addons. * * This file should only be included by the main flecs.h header. */ #ifndef FLECS_ADDONS_H #define FLECS_ADDONS_H /* Blacklist macros */ #ifdef FLECS_NO_CPP #undef FLECS_CPP #endif #ifdef FLECS_NO_MODULE #undef FLECS_MODULE #endif #ifdef FLECS_NO_PARSER #undef FLECS_PARSER #endif #ifdef FLECS_NO_PLECS #undef FLECS_PLECS #endif #ifdef FLECS_NO_RULES #undef FLECS_RULES #endif #ifdef FLECS_NO_SNAPSHOT #undef FLECS_SNAPSHOT #endif #ifdef FLECS_NO_MONITOR #undef FLECS_MONITOR #endif #ifdef FLECS_NO_STATS #undef FLECS_STATS #endif #ifdef FLECS_NO_SYSTEM #undef FLECS_SYSTEM #endif #ifdef FLECS_NO_PIPELINE #undef FLECS_PIPELINE #endif #ifdef FLECS_NO_TIMER #undef FLECS_TIMER #endif #ifdef FLECS_NO_META #undef FLECS_META #endif #ifdef FLECS_NO_META_C #undef FLECS_META_C #endif #ifdef FLECS_NO_UNITS #undef FLECS_UNITS #endif #ifdef FLECS_NO_EXPR #undef FLECS_EXPR #endif #ifdef FLECS_NO_JSON #undef FLECS_JSON #endif #ifdef FLECS_NO_DOC #undef FLECS_DOC #endif #ifdef FLECS_NO_LOG #undef FLECS_LOG #endif #ifdef FLECS_NO_APP #undef FLECS_APP #endif #ifdef FLECS_NO_OS_API_IMPL #undef FLECS_OS_API_IMPL #endif #ifdef FLECS_NO_HTTP #undef FLECS_HTTP #endif #ifdef FLECS_NO_REST #undef FLECS_REST #endif #ifdef FLECS_NO_JOURNAL #undef FLECS_JOURNAL #endif /* Always included, if disabled functions are replaced with dummy macros */ /** * @file addons/journal.h * @brief Journaling addon that logs API functions. * * The journaling addon traces API calls. The trace is formatted as runnable * C code, which allows for (partially) reproducing the behavior of an app * with the journaling trace. * * The journaling addon is disabled by default. Enabling it can have a * significant impact on performance. */ #ifdef FLECS_JOURNAL #ifndef FLECS_LOG #define FLECS_LOG #endif #ifndef FLECS_JOURNAL_H #define FLECS_JOURNAL_H /** * @defgroup c_addons_journal Journal * @ingroup c_addons * Journaling addon (disabled by default). * * * @{ */ /* Trace when log level is at or higher than level */ #define FLECS_JOURNAL_LOG_LEVEL (0) #ifdef __cplusplus extern "C" { #endif /* Journaling API, meant to be used by internals. */ typedef enum ecs_journal_kind_t { EcsJournalNew, EcsJournalMove, EcsJournalClear, EcsJournalDelete, EcsJournalDeleteWith, EcsJournalRemoveAll, EcsJournalTableEvents } ecs_journal_kind_t; FLECS_DBG_API void flecs_journal_begin( ecs_world_t *world, ecs_journal_kind_t kind, ecs_entity_t entity, ecs_type_t *add, ecs_type_t *remove); FLECS_DBG_API void flecs_journal_end(void); #define flecs_journal(...)\ flecs_journal_begin(__VA_ARGS__);\ flecs_journal_end(); #ifdef __cplusplus } #endif // __cplusplus /** @} */ #endif // FLECS_JOURNAL_H #else #define flecs_journal_begin(...) #define flecs_journal_end(...) #define flecs_journal(...) #endif // FLECS_JOURNAL /** * @file addons/log.h * @brief Logging addon. * * The logging addon provides an API for (debug) tracing and reporting errors * at various levels. When enabled, the logging addon can provide more detailed * information about the state of the ECS and any errors that may occur. * * The logging addon can be disabled to reduce footprint of the library, but * limits information logged to only file, line and error code. * * When enabled the logging addon can be configured to exclude levels of tracing * from the build to reduce the impact on performance. By default all debug * tracing is enabled for debug builds, tracing is enabled at release builds. * * Applications can change the logging level at runtime with ecs_log_set_level(), * but what is actually logged depends on what is compiled (when compiled * without debug tracing, setting the runtime level to debug won't have an * effect). * * The logging addon uses the OS API log_ function for all tracing. * * Note that even when the logging addon is not enabled, its header/source must * be included in a build. To prevent unused variable warnings in the code, some * API functions are included when the addon is disabled, but have empty bodies. */ #ifndef FLECS_LOG_H #define FLECS_LOG_H #ifdef __cplusplus extern "C" { #endif #ifdef FLECS_LOG /** * @defgroup c_addons_log Log * @ingroup c_addons * Logging functions. * * @{ */ //////////////////////////////////////////////////////////////////////////////// //// Tracing //////////////////////////////////////////////////////////////////////////////// FLECS_API void ecs_deprecated_( const char *file, int32_t line, const char *msg); /** Increase log stack. * This operation increases the indent_ value of the OS API and can be useful to * make nested behavior more visible. * * @param level The log level. */ FLECS_API void ecs_log_push_(int32_t level); /** Decrease log stack. * This operation decreases the indent_ value of the OS API and can be useful to * make nested behavior more visible. * * @param level The log level. */ FLECS_API void ecs_log_pop_(int32_t level); /** Should current level be logged. * This operation returns true when the specified log level should be logged * with the current log level. * * @param level The log level to check for. * @return Whether logging is enabled for the current level. */ FLECS_API bool ecs_should_log(int32_t level); //////////////////////////////////////////////////////////////////////////////// //// Error reporting //////////////////////////////////////////////////////////////////////////////// /** Get description for error code */ FLECS_API const char* ecs_strerror( int32_t error_code); #else // FLECS_LOG //////////////////////////////////////////////////////////////////////////////// //// Dummy macros for when logging is disabled //////////////////////////////////////////////////////////////////////////////// #define ecs_deprecated_(file, line, msg)\ (void)file;\ (void)line;\ (void)msg #define ecs_log_push_(level) #define ecs_log_pop_(level) #define ecs_should_log(level) false #define ecs_strerror(error_code)\ (void)error_code #endif // FLECS_LOG //////////////////////////////////////////////////////////////////////////////// //// Logging functions (do nothing when logging is enabled) //////////////////////////////////////////////////////////////////////////////// FLECS_API void ecs_print_( int32_t level, const char *file, int32_t line, const char *fmt, ...); FLECS_API void ecs_printv_( int level, const char *file, int32_t line, const char *fmt, va_list args); FLECS_API void ecs_log_( int32_t level, const char *file, int32_t line, const char *fmt, ...); FLECS_API void ecs_logv_( int level, const char *file, int32_t line, const char *fmt, va_list args); FLECS_API void ecs_abort_( int32_t error_code, const char *file, int32_t line, const char *fmt, ...); FLECS_API void ecs_assert_log_( int32_t error_code, const char *condition_str, const char *file, int32_t line, const char *fmt, ...); FLECS_API void ecs_parser_error_( const char *name, const char *expr, int64_t column, const char *fmt, ...); FLECS_API void ecs_parser_errorv_( const char *name, const char *expr, int64_t column, const char *fmt, va_list args); //////////////////////////////////////////////////////////////////////////////// //// Logging macros //////////////////////////////////////////////////////////////////////////////// #ifndef FLECS_LEGACY /* C89 doesn't support variadic macros */ /* Base logging function. Accepts a custom level */ #define ecs_print(level, ...)\ ecs_print_(level, __FILE__, __LINE__, __VA_ARGS__) #define ecs_printv(level, fmt, args)\ ecs_printv_(level, __FILE__, __LINE__, fmt, args) #define ecs_log(level, ...)\ ecs_log_(level, __FILE__, __LINE__, __VA_ARGS__) #define ecs_logv(level, fmt, args)\ ecs_logv_(level, __FILE__, __LINE__, fmt, args) /* Tracing. Used for logging of infrequent events */ #define ecs_trace_(file, line, ...) ecs_log_(0, file, line, __VA_ARGS__) #define ecs_trace(...) ecs_trace_(__FILE__, __LINE__, __VA_ARGS__) /* Warning. Used when an issue occurs, but operation is successful */ #define ecs_warn_(file, line, ...) ecs_log_(-2, file, line, __VA_ARGS__) #define ecs_warn(...) ecs_warn_(__FILE__, __LINE__, __VA_ARGS__) /* Error. Used when an issue occurs, and operation failed. */ #define ecs_err_(file, line, ...) ecs_log_(-3, file, line, __VA_ARGS__) #define ecs_err(...) ecs_err_(__FILE__, __LINE__, __VA_ARGS__) /* Fatal. Used when an issue occurs, and the application cannot continue. */ #define ecs_fatal_(file, line, ...) ecs_log_(-4, file, line, __VA_ARGS__) #define ecs_fatal(...) ecs_fatal_(__FILE__, __LINE__, __VA_ARGS__) /* Optionally include warnings about using deprecated features */ #ifndef FLECS_NO_DEPRECATED_WARNINGS #define ecs_deprecated(...)\ ecs_deprecated_(__FILE__, __LINE__, __VA_ARGS__) #else #define ecs_deprecated(...) #endif // FLECS_NO_DEPRECATED_WARNINGS /* If no tracing verbosity is defined, pick default based on build config */ #if !(defined(FLECS_LOG_0) || defined(FLECS_LOG_1) || defined(FLECS_LOG_2) || defined(FLECS_LOG_3)) #if !defined(FLECS_NDEBUG) #define FLECS_LOG_3 /* Enable all tracing in debug mode. May slow things down */ #else #define FLECS_LOG_0 /* Only enable infrequent tracing in release mode */ #endif // !defined(FLECS_NDEBUG) #endif // !(defined(FLECS_LOG_0) || defined(FLECS_LOG_1) || defined(FLECS_LOG_2) || defined(FLECS_LOG_3)) /* Define/undefine macros based on compiled-in tracing level. This can optimize * out tracing statements from a build, which improves performance. */ #if defined(FLECS_LOG_3) /* All debug tracing enabled */ #define ecs_dbg_1(...) ecs_log(1, __VA_ARGS__); #define ecs_dbg_2(...) ecs_log(2, __VA_ARGS__); #define ecs_dbg_3(...) ecs_log(3, __VA_ARGS__); #define ecs_log_push_1() ecs_log_push_(1); #define ecs_log_push_2() ecs_log_push_(2); #define ecs_log_push_3() ecs_log_push_(3); #define ecs_log_pop_1() ecs_log_pop_(1); #define ecs_log_pop_2() ecs_log_pop_(2); #define ecs_log_pop_3() ecs_log_pop_(3); #define ecs_should_log_1() ecs_should_log(1) #define ecs_should_log_2() ecs_should_log(2) #define ecs_should_log_3() ecs_should_log(3) #define FLECS_LOG_2 #define FLECS_LOG_1 #define FLECS_LOG_0 #elif defined(FLECS_LOG_2) /* Level 2 and below debug tracing enabled */ #define ecs_dbg_1(...) ecs_log(1, __VA_ARGS__); #define ecs_dbg_2(...) ecs_log(2, __VA_ARGS__); #define ecs_dbg_3(...) #define ecs_log_push_1() ecs_log_push_(1); #define ecs_log_push_2() ecs_log_push_(2); #define ecs_log_push_3() #define ecs_log_pop_1() ecs_log_pop_(1); #define ecs_log_pop_2() ecs_log_pop_(2); #define ecs_log_pop_3() #define ecs_should_log_1() ecs_should_log(1) #define ecs_should_log_2() ecs_should_log(2) #define ecs_should_log_3() false #define FLECS_LOG_1 #define FLECS_LOG_0 #elif defined(FLECS_LOG_1) /* Level 1 debug tracing enabled */ #define ecs_dbg_1(...) ecs_log(1, __VA_ARGS__); #define ecs_dbg_2(...) #define ecs_dbg_3(...) #define ecs_log_push_1() ecs_log_push_(1); #define ecs_log_push_2() #define ecs_log_push_3() #define ecs_log_pop_1() ecs_log_pop_(1); #define ecs_log_pop_2() #define ecs_log_pop_3() #define ecs_should_log_1() ecs_should_log(1) #define ecs_should_log_2() false #define ecs_should_log_3() false #define FLECS_LOG_0 #elif defined(FLECS_LOG_0) /* No debug tracing enabled */ #define ecs_dbg_1(...) #define ecs_dbg_2(...) #define ecs_dbg_3(...) #define ecs_log_push_1() #define ecs_log_push_2() #define ecs_log_push_3() #define ecs_log_pop_1() #define ecs_log_pop_2() #define ecs_log_pop_3() #define ecs_should_log_1() false #define ecs_should_log_2() false #define ecs_should_log_3() false #else /* No tracing enabled */ #undef ecs_trace #define ecs_trace(...) #define ecs_dbg_1(...) #define ecs_dbg_2(...) #define ecs_dbg_3(...) #define ecs_log_push_1() #define ecs_log_push_2() #define ecs_log_push_3() #define ecs_log_pop_1() #define ecs_log_pop_2() #define ecs_log_pop_3() #endif // defined(FLECS_LOG_3) /* Default debug tracing is at level 1 */ #define ecs_dbg ecs_dbg_1 /* Default level for push/pop is 0 */ #define ecs_log_push() ecs_log_push_(0) #define ecs_log_pop() ecs_log_pop_(0) /** Abort. * Unconditionally aborts process. */ #define ecs_abort(error_code, ...)\ ecs_abort_(error_code, __FILE__, __LINE__, __VA_ARGS__);\ ecs_os_abort(); abort(); /* satisfy compiler/static analyzers */ /** Assert. * Aborts if condition is false, disabled in debug mode. */ #if defined(FLECS_NDEBUG) && !defined(FLECS_KEEP_ASSERT) #define ecs_assert(condition, error_code, ...) #else #define ecs_assert(condition, error_code, ...)\ if (!(condition)) {\ ecs_assert_log_(error_code, #condition, __FILE__, __LINE__, __VA_ARGS__);\ ecs_os_abort();\ }\ assert(condition) /* satisfy compiler/static analyzers */ #endif // FLECS_NDEBUG #define ecs_assert_var(var, error_code, ...)\ ecs_assert(var, error_code, __VA_ARGS__);\ (void)var /** Debug assert. * Assert that is only valid in debug mode (ignores FLECS_KEEP_ASSERT) */ #ifndef FLECS_NDEBUG #define ecs_dbg_assert(condition, error_code, ...) ecs_assert(condition, error_code, __VA_ARGS__) #else #define ecs_dbg_assert(condition, error_code, ...) #endif /** Sanitize assert. * Assert that is only valid in sanitized mode (ignores FLECS_KEEP_ASSERT) */ #ifdef FLECS_SANITIZE #define ecs_san_assert(condition, error_code, ...) ecs_assert(condition, error_code, __VA_ARGS__) #else #define ecs_san_assert(condition, error_code, ...) #endif /* Silence dead code/unused label warnings when compiling without checks. */ #define ecs_dummy_check\ if ((false)) {\ goto error;\ } /** Check. * goto error if condition is false. */ #if defined(FLECS_NDEBUG) && !defined(FLECS_KEEP_ASSERT) #define ecs_check(condition, error_code, ...) ecs_dummy_check #else #ifdef FLECS_SOFT_ASSERT #define ecs_check(condition, error_code, ...)\ if (!(condition)) {\ ecs_assert_log_(error_code, #condition, __FILE__, __LINE__, __VA_ARGS__);\ goto error;\ } #else // FLECS_SOFT_ASSERT #define ecs_check(condition, error_code, ...)\ ecs_assert(condition, error_code, __VA_ARGS__);\ ecs_dummy_check #endif #endif // FLECS_NDEBUG /** Panic. * goto error when FLECS_SOFT_ASSERT is defined, otherwise abort */ #if defined(FLECS_NDEBUG) && !defined(FLECS_KEEP_ASSERT) #define ecs_throw(error_code, ...) ecs_dummy_check #else #ifdef FLECS_SOFT_ASSERT #define ecs_throw(error_code, ...)\ ecs_abort_(error_code, __FILE__, __LINE__, __VA_ARGS__);\ goto error; #else #define ecs_throw(error_code, ...)\ ecs_abort(error_code, __VA_ARGS__);\ ecs_dummy_check #endif #endif // FLECS_NDEBUG /** Parser error */ #define ecs_parser_error(name, expr, column, ...)\ ecs_parser_error_(name, expr, column, __VA_ARGS__) #define ecs_parser_errorv(name, expr, column, fmt, args)\ ecs_parser_errorv_(name, expr, column, fmt, args) #endif // FLECS_LEGACY //////////////////////////////////////////////////////////////////////////////// //// Functions that are always available //////////////////////////////////////////////////////////////////////////////// /** Enable or disable log. * This will enable builtin log. For log to work, it will have to be * compiled in which requires defining one of the following macros: * * FLECS_LOG_0 - All log is disabled * FLECS_LOG_1 - Enable log level 1 * FLECS_LOG_2 - Enable log level 2 and below * FLECS_LOG_3 - Enable log level 3 and below * * If no log level is defined and this is a debug build, FLECS_LOG_3 will * have been automatically defined. * * The provided level corresponds with the log level. If -1 is provided as * value, warnings are disabled. If -2 is provided, errors are disabled as well. * * @param level Desired tracing level. * @return Previous log level. */ FLECS_API int ecs_log_set_level( int level); /** Get current log level. * * @return Previous log level. */ FLECS_API int ecs_log_get_level(void); /** Enable/disable tracing with colors. * By default colors are enabled. * * @param enabled Whether to enable tracing with colors. * @return Previous color setting. */ FLECS_API bool ecs_log_enable_colors( bool enabled); /** Enable/disable logging timestamp. * By default timestamps are disabled. Note that enabling timestamps introduces * overhead as the logging code will need to obtain the current time. * * @param enabled Whether to enable tracing with timestamps. * @return Previous timestamp setting. */ FLECS_API bool ecs_log_enable_timestamp( bool enabled); /** Enable/disable logging time since last log. * By default deltatime is disabled. Note that enabling timestamps introduces * overhead as the logging code will need to obtain the current time. * * When enabled, this logs the amount of time in seconds passed since the last * log, when this amount is non-zero. The format is a '+' character followed by * the number of seconds: * * +1 trace: log message * * @param enabled Whether to enable tracing with timestamps. * @return Previous timestamp setting. */ FLECS_API bool ecs_log_enable_timedelta( bool enabled); /** Get last logged error code. * Calling this operation resets the error code. * * @return Last error, 0 if none was logged since last call to last_error. */ FLECS_API int ecs_log_last_error(void); //////////////////////////////////////////////////////////////////////////////// //// Error codes //////////////////////////////////////////////////////////////////////////////// #define ECS_INVALID_OPERATION (1) #define ECS_INVALID_PARAMETER (2) #define ECS_CONSTRAINT_VIOLATED (3) #define ECS_OUT_OF_MEMORY (4) #define ECS_OUT_OF_RANGE (5) #define ECS_UNSUPPORTED (6) #define ECS_INTERNAL_ERROR (7) #define ECS_ALREADY_DEFINED (8) #define ECS_MISSING_OS_API (9) #define ECS_OPERATION_FAILED (10) #define ECS_INVALID_CONVERSION (11) #define ECS_ID_IN_USE (12) #define ECS_CYCLE_DETECTED (13) #define ECS_LEAK_DETECTED (14) #define ECS_DOUBLE_FREE (15) #define ECS_INCONSISTENT_NAME (20) #define ECS_NAME_IN_USE (21) #define ECS_NOT_A_COMPONENT (22) #define ECS_INVALID_COMPONENT_SIZE (23) #define ECS_INVALID_COMPONENT_ALIGNMENT (24) #define ECS_COMPONENT_NOT_REGISTERED (25) #define ECS_INCONSISTENT_COMPONENT_ID (26) #define ECS_INCONSISTENT_COMPONENT_ACTION (27) #define ECS_MODULE_UNDEFINED (28) #define ECS_MISSING_SYMBOL (29) #define ECS_ALREADY_IN_USE (30) #define ECS_ACCESS_VIOLATION (40) #define ECS_COLUMN_INDEX_OUT_OF_RANGE (41) #define ECS_COLUMN_IS_NOT_SHARED (42) #define ECS_COLUMN_IS_SHARED (43) #define ECS_COLUMN_TYPE_MISMATCH (45) #define ECS_INVALID_WHILE_READONLY (70) #define ECS_LOCKED_STORAGE (71) #define ECS_INVALID_FROM_WORKER (72) //////////////////////////////////////////////////////////////////////////////// //// Used when logging with colors is enabled //////////////////////////////////////////////////////////////////////////////// #define ECS_BLACK "\033[1;30m" #define ECS_RED "\033[0;31m" #define ECS_GREEN "\033[0;32m" #define ECS_YELLOW "\033[0;33m" #define ECS_BLUE "\033[0;34m" #define ECS_MAGENTA "\033[0;35m" #define ECS_CYAN "\033[0;36m" #define ECS_WHITE "\033[1;37m" #define ECS_GREY "\033[0;37m" #define ECS_NORMAL "\033[0;49m" #define ECS_BOLD "\033[1;49m" #ifdef __cplusplus } #endif /** @} */ #endif // FLECS_LOG_H /* Handle addon dependencies that need declarations to be visible in header */ #ifdef FLECS_MONITOR #ifndef FLECS_STATS #define FLECS_STATS #endif #ifndef FLECS_SYSTEM #define FLECS_SYSTEM #endif #ifndef FLECS_TIMER #define FLECS_TIMER #endif #endif #ifdef FLECS_REST #ifndef FLECS_HTTP #define FLECS_HTTP #endif #endif #ifdef FLECS_PLECS #ifndef FLECS_EXPR #define FLECS_EXPR #endif #endif #ifdef FLECS_APP #ifdef FLECS_NO_APP #error "FLECS_NO_APP failed: APP is required by other addons" #endif /** * @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 * @ingroup c_addons * Optional addon for running the main application loop. * * @{ */ /** 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 #endif #ifdef FLECS_HTTP #ifdef FLECS_NO_HTTP #error "FLECS_NO_HTTP failed: HTTP is required by other addons" #endif /** * @file addons/http.h * @brief HTTP addon. * * Minimalistic HTTP server that can receive and reply to simple HTTP requests. * The main goal of this addon is to enable remotely connecting to a running * Flecs application (for example, with a web-based UI) and request/visualize * data from the ECS world. * * Each server instance creates a single thread used for receiving requests. * Receiving requests are enqueued and handled when the application calls * ecs_http_server_dequeue(). This increases latency of request handling vs. * responding directly in the receive thread, but is better suited for * retrieving data from ECS applications, as requests can be processed by an ECS * system without having to lock the world. * * This server is intended to be used in a development environment. */ #ifdef FLECS_HTTP /** * @defgroup c_addons_http Http * @ingroup c_addons * Simple HTTP server used for serving up REST API. * * @{ */ #if !defined(FLECS_OS_API_IMPL) && !defined(FLECS_NO_OS_API_IMPL) #define FLECS_OS_API_IMPL #endif #ifndef FLECS_HTTP_H #define FLECS_HTTP_H /* Maximum number of headers in request */ #define ECS_HTTP_HEADER_COUNT_MAX (32) /* Maximum number of query parameters in request */ #define ECS_HTTP_QUERY_PARAM_COUNT_MAX (32) #ifdef __cplusplus extern "C" { #endif /** HTTP server */ typedef struct ecs_http_server_t ecs_http_server_t; /** A connection manages communication with the remote host */ typedef struct { uint64_t id; ecs_http_server_t *server; char host[128]; char port[16]; } ecs_http_connection_t; /** Helper type used for headers & URL query parameters */ typedef struct { const char *key; const char *value; } ecs_http_key_value_t; /** Supported request methods */ typedef enum { EcsHttpGet, EcsHttpPost, EcsHttpPut, EcsHttpDelete, EcsHttpOptions, EcsHttpMethodUnsupported } ecs_http_method_t; /** A request */ typedef struct { uint64_t id; ecs_http_method_t method; char *path; char *body; ecs_http_key_value_t headers[ECS_HTTP_HEADER_COUNT_MAX]; ecs_http_key_value_t params[ECS_HTTP_HEADER_COUNT_MAX]; int32_t header_count; int32_t param_count; ecs_http_connection_t *conn; } ecs_http_request_t; /** A reply */ typedef struct { int code; /**< default = 200 */ ecs_strbuf_t body; /**< default = "" */ const char* status; /**< default = OK */ const char* content_type; /**< default = application/json */ ecs_strbuf_t headers; /**< default = "" */ } ecs_http_reply_t; #define ECS_HTTP_REPLY_INIT \ (ecs_http_reply_t){200, ECS_STRBUF_INIT, "OK", "application/json", ECS_STRBUF_INIT} /* Global statistics. */ extern int64_t ecs_http_request_received_count; extern int64_t ecs_http_request_invalid_count; extern int64_t ecs_http_request_handled_ok_count; extern int64_t ecs_http_request_handled_error_count; extern int64_t ecs_http_request_not_handled_count; extern int64_t ecs_http_request_preflight_count; extern int64_t ecs_http_send_ok_count; extern int64_t ecs_http_send_error_count; extern int64_t ecs_http_busy_count; /** Request callback. * Invoked for each valid request. The function should populate the reply and * return true. When the function returns false, the server will reply with a * 404 (Not found) code. */ typedef bool (*ecs_http_reply_action_t)( const ecs_http_request_t* request, ecs_http_reply_t *reply, void *ctx); /** Used with ecs_http_server_init(). */ typedef struct { ecs_http_reply_action_t callback; /**< Function called for each request */ void *ctx; /**< Passed to callback (optional) */ uint16_t port; /**< HTTP port */ const char *ipaddr; /**< Interface to listen on (optional) */ int32_t send_queue_wait_ms; /**< Send queue wait time when empty */ double cache_timeout; /**< Cache invalidation timeout (0 disables caching) */ double cache_purge_timeout; /**< Cache purge timeout (for purging cache entries) */ } ecs_http_server_desc_t; /** Create server. * Use ecs_http_server_start() to start receiving requests. * * @param desc Server configuration parameters. * @return The new server, or NULL if creation failed. */ FLECS_API ecs_http_server_t* ecs_http_server_init( const ecs_http_server_desc_t *desc); /** Destroy server. * This operation will stop the server if it was still running. * * @param server The server to destroy. */ FLECS_API void ecs_http_server_fini( ecs_http_server_t* server); /** Start server. * After this operation the server will be able to accept requests. * * @param server The server to start. * @return Zero if successful, non-zero if failed. */ FLECS_API int ecs_http_server_start( ecs_http_server_t* server); /** Process server requests. * This operation invokes the reply callback for each received request. No new * requests will be enqueued while processing requests. * * @param server The server for which to process requests. */ FLECS_API void ecs_http_server_dequeue( ecs_http_server_t* server, ecs_ftime_t delta_time); /** Stop server. * After this operation no new requests can be received. * * @param server The server. */ FLECS_API void ecs_http_server_stop( ecs_http_server_t* server); /** Emulate a request. * The request string must be a valid HTTP request. A minimal example: * * GET /entity/flecs/core/World?label=true HTTP/1.1 * * @param srv The server. * @param req The request. * @param len The length of the request (optional). * @return The reply. */ FLECS_API int ecs_http_server_http_request( ecs_http_server_t* srv, const char *req, ecs_size_t len, ecs_http_reply_t *reply_out); /** Convenience wrapper around ecs_http_server_http_request(). */ FLECS_API int ecs_http_server_request( ecs_http_server_t* srv, const char *method, const char *req, ecs_http_reply_t *reply_out); /** Get context provided in ecs_http_server_desc_t */ FLECS_API void* ecs_http_server_ctx( ecs_http_server_t* srv); /** Find header in request. * * @param req The request. * @param name name of the header to find * @return The header value, or NULL if not found. */ FLECS_API const char* ecs_http_get_header( const ecs_http_request_t* req, const char* name); /** Find query parameter in request. * * @param req The request. * @param name The parameter name. * @return The decoded parameter value, or NULL if not found. */ FLECS_API const char* ecs_http_get_param( const ecs_http_request_t* req, const char* name); #ifdef __cplusplus } #endif /** @} */ #endif // FLECS_HTTP_H #endif // FLECS_HTTP #endif #ifdef FLECS_REST #ifdef FLECS_NO_REST #error "FLECS_NO_REST failed: REST is required by other addons" #endif /** * @file addons/rest.h * @brief REST API addon. * * A small REST API that uses the HTTP server and JSON serializer to provide * access to application data for remote applications. * * A description of the API can be found in docs/RestApi.md */ #ifdef FLECS_REST /** * @defgroup c_addons_rest Rest * @ingroup c_addons * REST API for querying and mutating entities. * * @{ */ /* Used for the HTTP server */ #ifndef FLECS_HTTP #define FLECS_HTTP #endif /* Used for building the JSON replies */ #ifndef FLECS_JSON #define FLECS_JSON #endif /* Query engine used */ #ifndef FLECS_RULES #define FLECS_RULES #endif /* For the REST system */ #ifndef FLECS_PIPELINE #define FLECS_PIPELINE #endif #ifndef FLECS_REST_H #define FLECS_REST_H #ifdef __cplusplus extern "C" { #endif #define ECS_REST_DEFAULT_PORT (27750) /** Component that instantiates the REST API */ FLECS_API extern const ecs_entity_t ecs_id(EcsRest); typedef struct { uint16_t port; /**< Port of server (optional, default = 27750) */ char *ipaddr; /**< Interface address (optional, default = 0.0.0.0) */ void *impl; } EcsRest; /** Create HTTP server for REST API. * This allows for the creation of a REST server that can be managed by the * application without using Flecs systems. * * @param world The world. * @param desc The HTTP server descriptor. * @return The HTTP server, or NULL if failed. */ FLECS_API ecs_http_server_t* ecs_rest_server_init( ecs_world_t *world, const ecs_http_server_desc_t *desc); /** Cleanup REST HTTP server. * The server must have been created with ecs_rest_server_init(). */ FLECS_API void ecs_rest_server_fini( ecs_http_server_t *srv); /* Module import */ FLECS_API void FlecsRestImport( ecs_world_t *world); #ifdef __cplusplus } #endif #endif /** @} */ #endif #endif #ifdef FLECS_TIMER #ifdef FLECS_NO_TIMER #error "FLECS_NO_TIMER failed: TIMER is required by other addons" #endif /** * @file addons/timer.h * @brief Timer module. * * Timers can be used to trigger actions at periodic or one-shot intervals. They * are typically used together with systems and pipelines. */ #ifdef FLECS_TIMER /** * @defgroup c_addons_timer Timer * @ingroup c_addons * Run systems at a time interval. * * @{ */ #ifndef FLECS_MODULE #define FLECS_MODULE #endif #ifndef FLECS_PIPELINE #define FLECS_PIPELINE #endif #ifndef FLECS_TIMER_H #define FLECS_TIMER_H #ifdef __cplusplus extern "C" { #endif /** Component used for one shot/interval timer functionality */ typedef struct EcsTimer { ecs_ftime_t timeout; /**< Timer timeout period */ ecs_ftime_t time; /**< Incrementing time value */ ecs_ftime_t overshoot; /**< Used to correct returned interval time */ int32_t fired_count; /**< Number of times ticked */ bool active; /**< Is the timer active or not */ bool single_shot; /**< Is this a single shot timer */ } EcsTimer; /** Apply a rate filter to a tick source */ typedef struct EcsRateFilter { ecs_entity_t src; /**< Source of the rate filter */ int32_t rate; /**< Rate of the rate filter */ int32_t tick_count; /**< Number of times the rate filter ticked */ ecs_ftime_t time_elapsed; /**< Time elapsed since last tick */ } EcsRateFilter; /** Set timer timeout. * This operation executes any systems associated with the timer after the * specified timeout value. If the entity contains an existing timer, the * timeout value will be reset. The timer can be started and stopped with * ecs_start_timer() and ecs_stop_timer(). * * The timer is synchronous, and is incremented each frame by delta_time. * * The tick_source entity will be a tick source after this operation. Tick * sources can be read by getting the EcsTickSource component. If the tick * source ticked this frame, the 'tick' member will be true. When the tick * source is a system, the system will tick when the timer ticks. * * @param world The world. * @param tick_source The timer for which to set the timeout (0 to create one). * @param timeout The timeout value. * @return The timer entity. */ FLECS_API ecs_entity_t ecs_set_timeout( ecs_world_t *world, ecs_entity_t tick_source, ecs_ftime_t timeout); /** Get current timeout value for the specified timer. * This operation returns the value set by ecs_set_timeout(). If no timer is * active for this entity, the operation returns 0. * * After the timeout expires the EcsTimer component is removed from the entity. * This means that if ecs_get_timeout() is invoked after the timer is expired, the * operation will return 0. * * The timer is synchronous, and is incremented each frame by delta_time. * * The tick_source entity will be a tick source after this operation. Tick * sources can be read by getting the EcsTickSource component. If the tick * source ticked this frame, the 'tick' member will be true. When the tick * source is a system, the system will tick when the timer ticks. * * @param world The world. * @param tick_source The timer. * @return The current timeout value, or 0 if no timer is active. */ FLECS_API ecs_ftime_t ecs_get_timeout( const ecs_world_t *world, ecs_entity_t tick_source); /** Set timer interval. * This operation will continuously invoke systems associated with the timer * after the interval period expires. If the entity contains an existing timer, * the interval value will be reset. * * The timer is synchronous, and is incremented each frame by delta_time. * * The tick_source entity will be a tick source after this operation. Tick * sources can be read by getting the EcsTickSource component. If the tick * source ticked this frame, the 'tick' member will be true. When the tick * source is a system, the system will tick when the timer ticks. * * @param world The world. * @param tick_source The timer for which to set the interval (0 to create one). * @param interval The interval value. * @return The timer entity. */ FLECS_API ecs_entity_t ecs_set_interval( ecs_world_t *world, ecs_entity_t tick_source, ecs_ftime_t interval); /** Get current interval value for the specified timer. * This operation returns the value set by ecs_set_interval(). If the entity is * not a timer, the operation will return 0. * * @param world The world. * @param tick_source The timer for which to set the interval. * @return The current interval value, or 0 if no timer is active. */ FLECS_API ecs_ftime_t ecs_get_interval( const ecs_world_t *world, ecs_entity_t tick_source); /** Start timer. * This operation resets the timer and starts it with the specified timeout. * * @param world The world. * @param tick_source The timer to start. */ FLECS_API void ecs_start_timer( ecs_world_t *world, ecs_entity_t tick_source); /** Stop timer * This operation stops a timer from triggering. * * @param world The world. * @param tick_source The timer to stop. */ FLECS_API void ecs_stop_timer( ecs_world_t *world, ecs_entity_t tick_source); /** Reset time value of timer to 0. * This operation resets the timer value to 0. * * @param world The world. * @param tick_source The timer to reset. */ FLECS_API void ecs_reset_timer( ecs_world_t *world, ecs_entity_t tick_source); /** Enable randomizing initial time value of timers. * Initializes timers with a random time value, which can improve scheduling as * systems/timers for the same interval don't all happen on the same tick. * * @param world The world. */ FLECS_API void ecs_randomize_timers( ecs_world_t *world); /** Set rate filter. * This operation initializes a rate filter. Rate filters sample tick sources * and tick at a configurable multiple. A rate filter is a tick source itself, * which means that rate filters can be chained. * * Rate filters enable deterministic system execution which cannot be achieved * with interval timers alone. For example, if timer A has interval 2.0 and * timer B has interval 4.0, it is not guaranteed that B will tick at exactly * twice the multiple of A. This is partly due to the indeterministic nature of * timers, and partly due to floating point rounding errors. * * Rate filters can be combined with timers (or other rate filters) to ensure * that a system ticks at an exact multiple of a tick source (which can be * another system). If a rate filter is created with a rate of 1 it will tick * at the exact same time as its source. * * If no tick source is provided, the rate filter will use the frame tick as * source, which corresponds with the number of times ecs_progress() is called. * * The tick_source entity will be a tick source after this operation. Tick * sources can be read by getting the EcsTickSource component. If the tick * source ticked this frame, the 'tick' member will be true. When the tick * source is a system, the system will tick when the timer ticks. * * @param world The world. * @param tick_source The rate filter entity (0 to create one). * @param rate The rate to apply. * @param source The tick source (0 to use frames) * @return The filter entity. */ FLECS_API ecs_entity_t ecs_set_rate( ecs_world_t *world, ecs_entity_t tick_source, int32_t rate, ecs_entity_t source); /** Assign tick source to system. * Systems can be their own tick source, which can be any of the tick sources * (one shot timers, interval times and rate filters). However, in some cases it * is must be guaranteed that different systems tick on the exact same frame. * * This cannot be guaranteed by giving two systems the same interval/rate filter * as it is possible that one system is (for example) disabled, which would * cause the systems to go out of sync. To provide these guarantees, systems * must use the same tick source, which is what this operation enables. * * When two systems share the same tick source, it is guaranteed that they tick * in the same frame. The provided tick source can be any entity that is a tick * source, including another system. If the provided entity is not a tick source * the system will not be ran. * * To disassociate a tick source from a system, use 0 for the tick_source * parameter. * * @param world The world. * @param system The system to associate with the timer. * @param tick_source The tick source to associate with the system. */ FLECS_API void ecs_set_tick_source( ecs_world_t *world, ecs_entity_t system, ecs_entity_t tick_source); //////////////////////////////////////////////////////////////////////////////// //// Module //////////////////////////////////////////////////////////////////////////////// FLECS_API void FlecsTimerImport( ecs_world_t *world); #ifdef __cplusplus } #endif #endif /** @} */ #endif #endif #ifdef FLECS_PIPELINE #ifdef FLECS_NO_PIPELINE #error "FLECS_NO_PIPELINE failed: PIPELINE is required by other addons" #endif /** * @file addons/pipeline.h * @brief Pipeline module. * * The pipeline module provides support for running systems automatically and * on multiple threads. A pipeline is a collection of tags that can be added to * systems. When ran, a pipeline will query for all systems that have the tags * that belong to a pipeline, and run them. * * The module defines a number of builtin tags (EcsPreUpdate, EcsOnUpdate, * EcsPostUpdate etc.) that are registered with the builtin pipeline. The * builtin pipeline is ran by default when calling ecs_progress(). An * application can set a custom pipeline with the ecs_set_pipeline() function. */ #ifdef FLECS_PIPELINE /** * @defgroup c_addons_pipeline Pipeline * @ingroup c_addons * Pipelines order and schedule systems for execution. * * @{ */ #ifndef FLECS_MODULE #define FLECS_MODULE #endif #ifndef FLECS_SYSTEM #define FLECS_SYSTEM #endif #if !defined(FLECS_OS_API_IMPL) && !defined(FLECS_NO_OS_API_IMPL) #define FLECS_OS_API_IMPL #endif #ifndef FLECS_PIPELINE_H #define FLECS_PIPELINE_H #ifdef __cplusplus extern "C" { #endif #ifndef FLECS_LEGACY #define ECS_PIPELINE_DEFINE(world, id_, ...) \ { \ ecs_pipeline_desc_t desc = {0}; \ ecs_entity_desc_t edesc = {0}; \ edesc.id = id_;\ edesc.name = #id_;\ desc.entity = ecs_entity_init(world, &edesc);\ desc.query.filter.expr = #__VA_ARGS__; \ id_ = ecs_pipeline_init(world, &desc); \ ecs_id(id_) = id_;\ } \ ecs_assert(id_ != 0, ECS_INVALID_PARAMETER, NULL); #define ECS_PIPELINE(world, id, ...) \ ecs_entity_t id = 0, ecs_id(id) = 0; ECS_PIPELINE_DEFINE(world, id, __VA_ARGS__);\ (void)id;\ (void)ecs_id(id); #define ecs_pipeline(world, ...)\ ecs_pipeline_init(world, &(ecs_pipeline_desc_t) __VA_ARGS__ ) #endif /* Pipeline descriptor (used with ecs_pipeline_init()) */ typedef struct ecs_pipeline_desc_t { /* Existing entity to associate with pipeline (optional) */ ecs_entity_t entity; /* Query descriptor. The first term of the query must match the EcsSystem * component. */ ecs_query_desc_t query; } ecs_pipeline_desc_t; /** Create a custom pipeline. */ FLECS_API ecs_entity_t ecs_pipeline_init( ecs_world_t *world, const ecs_pipeline_desc_t *desc); /** Set a custom pipeline. * This operation sets the pipeline to run when ecs_progress() is invoked. * * @param world The world. * @param pipeline The pipeline to set. */ FLECS_API void ecs_set_pipeline( ecs_world_t *world, ecs_entity_t pipeline); /** Get the current pipeline. * This operation gets the current pipeline. * * @param world The world. * @return The current pipeline. */ FLECS_API ecs_entity_t ecs_get_pipeline( const ecs_world_t *world); /** Progress a world. * This operation progresses the world by running all systems that are both * enabled and periodic on their matching entities. * * An application can pass a delta_time into the function, which is the time * passed since the last frame. This value is passed to systems so they can * update entity values proportional to the elapsed time since their last * invocation. * * When an application passes 0 to delta_time, ecs_progress() will automatically * measure the time passed since the last frame. If an application does not uses * time management, it should pass a non-zero value for delta_time (1.0 is * recommended). That way, no time will be wasted measuring the time. * * @param world The world to progress. * @param delta_time The time passed since the last frame. * @return false if ecs_quit() has been called, true otherwise. */ FLECS_API bool ecs_progress( ecs_world_t *world, ecs_ftime_t delta_time); /** Set time scale. * Increase or decrease simulation speed by the provided multiplier. * * @param world The world. * @param scale The scale to apply (default = 1). */ FLECS_API void ecs_set_time_scale( ecs_world_t *world, ecs_ftime_t scale); /** Reset world clock. * Reset the clock that keeps track of the total time passed in the simulation. * * @param world The world. */ FLECS_API void ecs_reset_clock( ecs_world_t *world); /** Run pipeline. * This will run all systems in the provided pipeline. This operation may be * invoked from multiple threads, and only when staging is disabled, as the * pipeline manages staging and, if necessary, synchronization between threads. * * If 0 is provided for the pipeline id, the default pipeline will be ran (this * is either the builtin pipeline or the pipeline set with set_pipeline()). * * When using progress() this operation will be invoked automatically for the * default pipeline (either the builtin pipeline or the pipeline set with * set_pipeline()). An application may run additional pipelines. * * @param world The world. * @param pipeline The pipeline to run. */ FLECS_API void ecs_run_pipeline( ecs_world_t *world, ecs_entity_t pipeline, ecs_ftime_t delta_time); //////////////////////////////////////////////////////////////////////////////// //// Threading //////////////////////////////////////////////////////////////////////////////// /** Set number of worker threads. * Setting this value to a value higher than 1 will start as many threads and * will cause systems to evenly distribute matched entities across threads. The * operation may be called multiple times to reconfigure the number of threads * used, but never while running a system / pipeline. * Calling ecs_set_threads() will also end the use of task threads setup with * ecs_set_task_threads() and vice-versa */ FLECS_API void ecs_set_threads( ecs_world_t *world, int32_t threads); /** Set number of worker task threads. * ecs_set_task_threads() is similar to ecs_set_threads(), except threads are treated * as short-lived tasks and will be created and joined around each update of the world. * Creation and joining of these tasks will use the os_api_t tasks APIs rather than the * the standard thread API functions, although they may be the same if desired. * This function is useful for multithreading world updates using an external * asynchronous job system rather than long running threads by providing the APIs * to create tasks for your job system and then wait on their conclusion. * The operation may be called multiple times to reconfigure the number of task threads * used, but never while running a system / pipeline. * Calling ecs_set_task_threads() will also end the use of threads setup with * ecs_set_threads() and vice-versa */ FLECS_API void ecs_set_task_threads( ecs_world_t *world, int32_t task_threads); /** Returns true if task thread use have been requested. */ FLECS_API bool ecs_using_task_threads( ecs_world_t *world); //////////////////////////////////////////////////////////////////////////////// //// Module //////////////////////////////////////////////////////////////////////////////// FLECS_API void FlecsPipelineImport( ecs_world_t *world); #ifdef __cplusplus } #endif #endif /** @} */ #endif #endif #ifdef FLECS_SYSTEM #ifdef FLECS_NO_SYSTEM #error "FLECS_NO_SYSTEM failed: SYSTEM is required by other addons" #endif /** * @file addons/system.h * @brief System module. * * The system module allows for creating and running systems. A system is a * query in combination with a callback function. In addition systems have * support for time management and can be monitored by the stats addon. */ #ifdef FLECS_SYSTEM /** * @defgroup c_addons_system System * @ingroup c_addons * Systems are a query + function that can be ran manually or by a pipeline. * * @{ */ #ifndef FLECS_MODULE #define FLECS_MODULE #endif #ifndef FLECS_SYSTEM_H #define FLECS_SYSTEM_H #ifdef __cplusplus extern "C" { #endif /** Component used to provide a tick source to systems */ typedef struct EcsTickSource { bool tick; /**< True if providing tick */ ecs_ftime_t time_elapsed; /**< Time elapsed since last tick */ } EcsTickSource; /** Use with ecs_system_init() */ typedef struct ecs_system_desc_t { int32_t _canary; /** Existing entity to associate with system (optional) */ ecs_entity_t entity; /** System query parameters */ ecs_query_desc_t query; /** Callback that is invoked when a system is ran. * When left to NULL, the default system runner is used, which calls the * "callback" action for each result returned from the system's query. * * It should not be assumed that the input iterator can always be iterated * with ecs_query_next(). When a system is multithreaded and/or paged, the * iterator can be either a worker or paged iterator. Future use cases may * introduce additional inputs for a system, such as rules and filters. The * correct function to use for iteration is ecs_iter_next(). * * An implementation can test whether the iterator is a query iterator by * testing whether the it->next value is equal to ecs_query_next(). */ ecs_run_action_t run; /** Callback that is ran for each result returned by the system's query. This * means that this callback can be invoked multiple times per system per * frame, typically once for each matching table. */ ecs_iter_action_t callback; /** Context to be passed to callback (as ecs_iter_t::param) */ void *ctx; /** Binding context, for when system is implemented in other language */ void *binding_ctx; /** Functions that are invoked during system cleanup to free context data. * When set, functions are called unconditionally, even when the ctx * pointers are NULL. */ ecs_ctx_free_t ctx_free; ecs_ctx_free_t binding_ctx_free; /** Interval in seconds at which the system should run */ ecs_ftime_t interval; /** Rate at which the system should run */ int32_t rate; /** External tick source that determines when system ticks */ ecs_entity_t tick_source; /** If true, system will be ran on multiple threads */ bool multi_threaded; /** If true, system will have access to the actual world. Cannot be true at the * same time as multi_threaded. */ bool no_readonly; } ecs_system_desc_t; /** Create a system */ FLECS_API ecs_entity_t ecs_system_init( ecs_world_t *world, const ecs_system_desc_t *desc); #ifndef FLECS_LEGACY /** Forward declare a system. */ #define ECS_SYSTEM_DECLARE(id) ecs_entity_t ecs_id(id) /** Define a forward declared system. * * Example: * * @code * ECS_SYSTEM_DEFINE(world, Move, EcsOnUpdate, Position, Velocity); * @endcode */ #define ECS_SYSTEM_DEFINE(world, id_, phase, ...) \ { \ ecs_system_desc_t desc = {0}; \ ecs_entity_desc_t edesc = {0}; \ edesc.id = ecs_id(id_);\ edesc.name = #id_;\ edesc.add[0] = ((phase) ? ecs_pair(EcsDependsOn, (phase)) : 0); \ edesc.add[1] = (phase); \ desc.entity = ecs_entity_init(world, &edesc);\ desc.query.filter.expr = #__VA_ARGS__; \ desc.callback = id_; \ ecs_id(id_) = ecs_system_init(world, &desc); \ } \ ecs_assert(ecs_id(id_) != 0, ECS_INVALID_PARAMETER, NULL) /** Declare & define a system. * * Example: * * @code * ECS_SYSTEM(world, Move, EcsOnUpdate, Position, Velocity); * @endcode */ #define ECS_SYSTEM(world, id, phase, ...) \ ecs_entity_t ecs_id(id) = 0; ECS_SYSTEM_DEFINE(world, id, phase, __VA_ARGS__);\ ecs_entity_t id = ecs_id(id);\ (void)ecs_id(id);\ (void)id /** Shorthand for creating a system with ecs_system_init(). * * Example: * * @code * ecs_system(world, { * .entity = ecs_entity(world, { * .name = "MyEntity", * .add = { ecs_dependson(EcsOnUpdate) } * }), * .query.filter.terms = { * { ecs_id(Position) }, * { ecs_id(Velocity) } * }, * .callback = Move * }); * @endcode */ #define ecs_system(world, ...)\ ecs_system_init(world, &(ecs_system_desc_t) __VA_ARGS__ ) #endif /** Run a specific system manually. * This operation runs a single system manually. It is an efficient way to * invoke logic on a set of entities, as manual systems are only matched to * tables at creation time or after creation time, when a new table is created. * * Manual systems are useful to evaluate lists of pre-matched entities at * application defined times. Because none of the matching logic is evaluated * before the system is invoked, manual systems are much more efficient than * manually obtaining a list of entities and retrieving their components. * * An application may pass custom data to a system through the param parameter. * This data can be accessed by the system through the param member in the * ecs_iter_t value that is passed to the system callback. * * Any system may interrupt execution by setting the interrupted_by member in * the ecs_iter_t value. This is particularly useful for manual systems, where * the value of interrupted_by is returned by this operation. This, in * combination with the param argument lets applications use manual systems * to lookup entities: once the entity has been found its handle is passed to * interrupted_by, which is then subsequently returned. * * @param world The world. * @param system The system to run. * @param delta_time The time passed since the last system invocation. * @param param A user-defined parameter to pass to the system. * @return handle to last evaluated entity if system was interrupted. */ FLECS_API ecs_entity_t ecs_run( ecs_world_t *world, ecs_entity_t system, ecs_ftime_t delta_time, void *param); /** Same as ecs_run(), but subdivides entities across number of provided stages. * * @param world The world. * @param system The system to run. * @param stage_current The id of the current stage. * @param stage_count The total number of stages. * @param delta_time The time passed since the last system invocation. * @param param A user-defined parameter to pass to the system. * @return handle to last evaluated entity if system was interrupted. */ FLECS_API ecs_entity_t ecs_run_worker( ecs_world_t *world, ecs_entity_t system, int32_t stage_current, int32_t stage_count, ecs_ftime_t delta_time, void *param); /** Run system with offset/limit and type filter. * This operation is the same as ecs_run(), but filters the entities that will be * iterated by the system. * * Entities can be filtered in two ways. Offset and limit control the range of * entities that is iterated over. The range is applied to all entities matched * with the system, thus may cover multiple archetypes. * * The type filter controls which entity types the system will evaluate. Only * types that contain all components in the type filter will be iterated over. A * type filter is only evaluated once per table, which makes filtering cheap if * the number of entities is large and the number of tables is small, but not as * cheap as filtering in the system signature. * * @param world The world. * @param system The system to invoke. * @param delta_time The time passed since the last system invocation. * @param param A user-defined parameter to pass to the system. * @return handle to last evaluated entity if system was interrupted. */ FLECS_API ecs_entity_t ecs_run_w_filter( ecs_world_t *world, ecs_entity_t system, ecs_ftime_t delta_time, int32_t offset, int32_t limit, void *param); /** Get the query object for a system. * Systems use queries under the hood. This enables an application to get access * to the underlying query object of a system. This can be useful when, for * example, an application needs to enable sorting for a system. * * @param world The world. * @param system The system from which to obtain the query. * @return The query. */ FLECS_API ecs_query_t* ecs_system_get_query( const ecs_world_t *world, ecs_entity_t system); /** Get system context. * This operation returns the context pointer set for the system. If * the provided entity is not a system, the function will return NULL. * * @param world The world. * @param system The system from which to obtain the context. * @return The context. */ FLECS_API void* ecs_system_get_ctx( const ecs_world_t *world, ecs_entity_t system); /** Get system binding context. * The binding context is a context typically used to attach any language * binding specific data that is needed when invoking a callback that is * implemented in another language. * * @param world The world. * @param system The system from which to obtain the context. * @return The context. */ FLECS_API void* ecs_system_get_binding_ctx( const ecs_world_t *world, ecs_entity_t system); FLECS_API void FlecsSystemImport( ecs_world_t *world); #ifdef __cplusplus } #endif #endif /** @} */ #endif #endif #ifdef FLECS_STATS #ifdef FLECS_NO_STATS #error "FLECS_NO_STATS failed: STATS is required by other addons" #endif /** * @file addons/stats.h * @brief Statistics addon. * * The statistics addon enables an application to obtain detailed metrics about * the storage, systems and operations of a world. */ #ifdef FLECS_STATS /** * @defgroup c_addons_stats Stats * @ingroup c_addons * Collection of statistics for world, queries, systems and pipelines. * * @{ */ #ifndef FLECS_STATS_H #define FLECS_STATS_H #ifdef __cplusplus extern "C" { #endif #define ECS_STAT_WINDOW (60) /** Simple value that indicates current state */ typedef struct ecs_gauge_t { ecs_float_t avg[ECS_STAT_WINDOW]; ecs_float_t min[ECS_STAT_WINDOW]; ecs_float_t max[ECS_STAT_WINDOW]; } ecs_gauge_t; /** Monotonically increasing counter */ typedef struct ecs_counter_t { ecs_gauge_t rate; /**< Keep track of deltas too */ double value[ECS_STAT_WINDOW]; } ecs_counter_t; /** Make all metrics the same size, so we can iterate over fields */ typedef union ecs_metric_t { ecs_gauge_t gauge; ecs_counter_t counter; } ecs_metric_t; typedef struct ecs_world_stats_t { int64_t first_; /* Entities */ struct { ecs_metric_t count; /**< Number of entities */ ecs_metric_t not_alive_count; /**< Number of not alive (recyclable) entity ids */ } entities; /* Component ids */ struct { ecs_metric_t tag_count; /**< Number of tag ids (ids without data) */ ecs_metric_t component_count; /**< Number of components ids (ids with data) */ ecs_metric_t pair_count; /**< Number of pair ids */ ecs_metric_t type_count; /**< Number of registered types */ ecs_metric_t create_count; /**< Number of times id has been created */ ecs_metric_t delete_count; /**< Number of times id has been deleted */ } components; /* Tables */ struct { ecs_metric_t count; /**< Number of tables */ ecs_metric_t empty_count; /**< Number of empty tables */ ecs_metric_t create_count; /**< Number of times table has been created */ ecs_metric_t delete_count; /**< Number of times table has been deleted */ } tables; /* Queries & events */ struct { ecs_metric_t query_count; /**< Number of queries */ ecs_metric_t observer_count; /**< Number of observers */ ecs_metric_t system_count; /**< Number of systems */ } queries; /* Commands */ struct { ecs_metric_t add_count; ecs_metric_t remove_count; ecs_metric_t delete_count; ecs_metric_t clear_count; ecs_metric_t set_count; ecs_metric_t ensure_count; ecs_metric_t modified_count; ecs_metric_t other_count; ecs_metric_t discard_count; ecs_metric_t batched_entity_count; ecs_metric_t batched_count; } commands; /* Frame data */ struct { ecs_metric_t frame_count; /**< Number of frames processed. */ ecs_metric_t merge_count; /**< Number of merges executed. */ ecs_metric_t rematch_count; /**< Number of query rematches */ ecs_metric_t pipeline_build_count; /**< Number of system pipeline rebuilds (occurs when an inactive system becomes active). */ ecs_metric_t systems_ran; /**< Number of systems ran. */ ecs_metric_t observers_ran; /**< Number of times an observer was invoked. */ ecs_metric_t event_emit_count; /**< Number of events emitted */ } frame; /* Timing */ struct { ecs_metric_t world_time_raw; /**< Actual time passed since simulation start (first time progress() is called) */ ecs_metric_t world_time; /**< Simulation time passed since simulation start. Takes into account time scaling */ ecs_metric_t frame_time; /**< Time spent processing a frame. Smaller than world_time_total when load is not 100% */ ecs_metric_t system_time; /**< Time spent on running systems. */ ecs_metric_t emit_time; /**< Time spent on notifying observers. */ ecs_metric_t merge_time; /**< Time spent on merging commands. */ ecs_metric_t rematch_time; /**< Time spent on rematching. */ ecs_metric_t fps; /**< Frames per second. */ ecs_metric_t delta_time; /**< Delta_time. */ } performance; struct { /* Memory allocation data */ ecs_metric_t alloc_count; /**< Allocs per frame */ ecs_metric_t realloc_count; /**< Reallocs per frame */ ecs_metric_t free_count; /**< Frees per frame */ ecs_metric_t outstanding_alloc_count; /**< Difference between allocs & frees */ /* Memory allocator data */ ecs_metric_t block_alloc_count; /**< Block allocations per frame */ ecs_metric_t block_free_count; /**< Block frees per frame */ ecs_metric_t block_outstanding_alloc_count; /**< Difference between allocs & frees */ ecs_metric_t stack_alloc_count; /**< Page allocations per frame */ ecs_metric_t stack_free_count; /**< Page frees per frame */ ecs_metric_t stack_outstanding_alloc_count; /**< Difference between allocs & frees */ } memory; /* HTTP statistics */ struct { ecs_metric_t request_received_count; ecs_metric_t request_invalid_count; ecs_metric_t request_handled_ok_count; ecs_metric_t request_handled_error_count; ecs_metric_t request_not_handled_count; ecs_metric_t request_preflight_count; ecs_metric_t send_ok_count; ecs_metric_t send_error_count; ecs_metric_t busy_count; } http; int64_t last_; /** Current position in ring buffer */ int32_t t; } ecs_world_stats_t; /** Statistics for a single query (use ecs_query_stats_get()) */ typedef struct ecs_query_stats_t { int64_t first_; ecs_metric_t matched_table_count; /**< Matched non-empty tables */ ecs_metric_t matched_empty_table_count; /**< Matched empty tables */ ecs_metric_t matched_entity_count; /**< Number of matched entities */ ecs_metric_t eval_count; /**< Number of times query is evaluated */ int64_t last_; /** Current position in ring buffer */ int32_t t; } ecs_query_stats_t; /** Statistics for a single system (use ecs_system_stats_get()) */ typedef struct ecs_system_stats_t { int64_t first_; ecs_metric_t time_spent; /**< Time spent processing a system */ int64_t last_; bool task; /**< Is system a task */ ecs_query_stats_t query; } ecs_system_stats_t; /** Statistics for sync point */ typedef struct ecs_sync_stats_t { int64_t first_; ecs_metric_t time_spent; ecs_metric_t commands_enqueued; int64_t last_; int32_t system_count; bool multi_threaded; bool no_readonly; } ecs_sync_stats_t; /** Statistics for all systems in a pipeline. */ typedef struct ecs_pipeline_stats_t { /* Allow for initializing struct with {0} */ int8_t canary_; /** Vector with system ids of all systems in the pipeline. The systems are * stored in the order they are executed. Merges are represented by a 0. */ ecs_vec_t systems; /** Vector with sync point stats */ ecs_vec_t sync_points; /** Map with system statistics. For each system in the systems vector, an * entry in the map exists of type ecs_system_stats_t. */ ecs_map_t system_stats; /** Current position in ring buffer */ int32_t t; int32_t system_count; /**< Number of systems in pipeline */ int32_t active_system_count; /**< Number of active systems in pipeline */ int32_t rebuild_count; /**< Number of times pipeline has rebuilt */ } ecs_pipeline_stats_t; /** Get world statistics. * * @param world The world. * @param stats Out parameter for statistics. */ FLECS_API void ecs_world_stats_get( const ecs_world_t *world, ecs_world_stats_t *stats); /** Reduce source measurement window into single destination measurement. */ FLECS_API void ecs_world_stats_reduce( ecs_world_stats_t *dst, const ecs_world_stats_t *src); /** Reduce last measurement into previous measurement, restore old value. */ FLECS_API void ecs_world_stats_reduce_last( ecs_world_stats_t *stats, const ecs_world_stats_t *old, int32_t count); /** Repeat last measurement. */ FLECS_API void ecs_world_stats_repeat_last( ecs_world_stats_t *stats); /** Copy last measurement from source to destination. */ FLECS_API void ecs_world_stats_copy_last( ecs_world_stats_t *dst, const ecs_world_stats_t *src); FLECS_API void ecs_world_stats_log( const ecs_world_t *world, const ecs_world_stats_t *stats); /** Get query statistics. * Obtain statistics for the provided query. * * @param world The world. * @param query The query. * @param stats Out parameter for statistics. */ FLECS_API void ecs_query_stats_get( const ecs_world_t *world, const ecs_query_t *query, ecs_query_stats_t *stats); /** Reduce source measurement window into single destination measurement. */ FLECS_API void ecs_query_stats_reduce( ecs_query_stats_t *dst, const ecs_query_stats_t *src); /** Reduce last measurement into previous measurement, restore old value. */ FLECS_API void ecs_query_stats_reduce_last( ecs_query_stats_t *stats, const ecs_query_stats_t *old, int32_t count); /** Repeat last measurement. */ FLECS_API void ecs_query_stats_repeat_last( ecs_query_stats_t *stats); /** Copy last measurement from source to destination. */ FLECS_API void ecs_query_stats_copy_last( ecs_query_stats_t *dst, const ecs_query_stats_t *src); #ifdef FLECS_SYSTEM /** Get system statistics. * Obtain statistics for the provided system. * * @param world The world. * @param system The system. * @param stats Out parameter for statistics. * @return true if success, false if not a system. */ FLECS_API bool ecs_system_stats_get( const ecs_world_t *world, ecs_entity_t system, ecs_system_stats_t *stats); /** Reduce source measurement window into single destination measurement */ FLECS_API void ecs_system_stats_reduce( ecs_system_stats_t *dst, const ecs_system_stats_t *src); /** Reduce last measurement into previous measurement, restore old value. */ FLECS_API void ecs_system_stats_reduce_last( ecs_system_stats_t *stats, const ecs_system_stats_t *old, int32_t count); /** Repeat last measurement. */ FLECS_API void ecs_system_stats_repeat_last( ecs_system_stats_t *stats); /** Copy last measurement from source to destination. */ FLECS_API void ecs_system_stats_copy_last( ecs_system_stats_t *dst, const ecs_system_stats_t *src); #endif #ifdef FLECS_PIPELINE /** Get pipeline statistics. * Obtain statistics for the provided pipeline. * * @param world The world. * @param pipeline The pipeline. * @param stats Out parameter for statistics. * @return true if success, false if not a pipeline. */ FLECS_API bool ecs_pipeline_stats_get( ecs_world_t *world, ecs_entity_t pipeline, ecs_pipeline_stats_t *stats); /** Free pipeline stats. * * @param stats The stats to free. */ FLECS_API void ecs_pipeline_stats_fini( ecs_pipeline_stats_t *stats); /** Reduce source measurement window into single destination measurement */ FLECS_API void ecs_pipeline_stats_reduce( ecs_pipeline_stats_t *dst, const ecs_pipeline_stats_t *src); /** Reduce last measurement into previous measurement, restore old value. */ FLECS_API void ecs_pipeline_stats_reduce_last( ecs_pipeline_stats_t *stats, const ecs_pipeline_stats_t *old, int32_t count); /** Repeat last measurement. */ FLECS_API void ecs_pipeline_stats_repeat_last( ecs_pipeline_stats_t *stats); /** Copy last measurement to destination. * This operation copies the last measurement into the destination. It does not * modify the cursor. * * @param dst The metrics. * @param src The metrics to copy. */ FLECS_API void ecs_pipeline_stats_copy_last( ecs_pipeline_stats_t *dst, const ecs_pipeline_stats_t *src); #endif /** Reduce all measurements from a window into a single measurement. */ FLECS_API void ecs_metric_reduce( ecs_metric_t *dst, const ecs_metric_t *src, int32_t t_dst, int32_t t_src); /** Reduce last measurement into previous measurement */ FLECS_API void ecs_metric_reduce_last( ecs_metric_t *m, int32_t t, int32_t count); /** Copy measurement */ FLECS_API void ecs_metric_copy( ecs_metric_t *m, int32_t dst, int32_t src); #ifdef __cplusplus } #endif #endif /** @} */ #endif #endif #ifdef FLECS_METRICS #ifdef FLECS_NO_METRICS #error "FLECS_NO_METRICS failed: METRICS is required by other addons" #endif /** * @file addons/metrics.h * @brief Metrics module. * * The metrics module extracts metrics from components and makes them available * through a unified component interface. */ #ifdef FLECS_METRICS /** * @defgroup c_addons_metrics Metrics * @ingroup c_addons * Collect user-defined metrics from ECS data. * * @{ */ #ifndef FLECS_METRICS_H #define FLECS_METRICS_H #ifndef FLECS_META #define FLECS_META #endif #ifndef FLECS_UNITS #define FLECS_UNITS #endif #ifndef FLECS_PIPELINE #define FLECS_PIPELINE #endif #ifdef __cplusplus extern "C" { #endif FLECS_API extern ECS_COMPONENT_DECLARE(FlecsMetrics); /** Tag added to metrics, and used as first element of metric kind pair */ FLECS_API extern ECS_TAG_DECLARE(EcsMetric); /** Metric that has monotonically increasing value */ FLECS_API extern ECS_TAG_DECLARE(EcsCounter); /** Counter metric that is auto-incremented by source value */ FLECS_API extern ECS_TAG_DECLARE(EcsCounterIncrement); /** Counter metric that counts the number of entities with an id */ FLECS_API extern ECS_TAG_DECLARE(EcsCounterId); /** Metric that represents current value */ FLECS_API extern ECS_TAG_DECLARE(EcsGauge); /** Tag added to metric instances */ FLECS_API extern ECS_TAG_DECLARE(EcsMetricInstance); /** Component with metric instance value */ FLECS_API extern ECS_COMPONENT_DECLARE(EcsMetricValue); /** Component with entity source of metric instance */ FLECS_API extern ECS_COMPONENT_DECLARE(EcsMetricSource); typedef struct EcsMetricValue { double value; } EcsMetricValue; typedef struct EcsMetricSource { ecs_entity_t entity; } EcsMetricSource; typedef struct ecs_metric_desc_t { int32_t _canary; /** Entity associated with metric */ ecs_entity_t entity; /** Entity associated with member that stores metric value. Must not be set * at the same time as id. Cannot be combined with EcsCounterId. */ ecs_entity_t member; /* Member dot expression. Can be used instead of member and supports nested * members. Must be set together with id and should not be set at the same * time as member. */ const char *dotmember; /** Tracks whether entities have the specified component id. Must not be set * at the same time as member. */ ecs_id_t id; /** If id is a (R, *) wildcard and relationship R has the OneOf property, * setting this value to true will track individual targets. * If the kind is EcsCountId and the id is a (R, *) wildcard, this value * will create a metric per target. */ bool targets; /** Must be EcsGauge, EcsCounter, EcsCounterIncrement or EcsCounterId */ ecs_entity_t kind; /** Description of metric. Will only be set if FLECS_DOC addon is enabled */ const char *brief; } ecs_metric_desc_t; /** Create a new metric. * Metrics are entities that store values measured from a range of different * properties in the ECS storage. Metrics provide a single unified interface to * discovering and reading these values, which can be useful for monitoring * utilities, or for debugging. * * Examples of properties that can be measured by metrics are: * - Component member values * - How long an entity has had a specific component * - How long an entity has had a specific target for a relationship * - How many entities have a specific component * * Metrics can either be created as a "gauge" or "counter". A gauge is a metric * that represents the value of something at a specific point in time, for * example "velocity". A counter metric represents a value that is monotonically * increasing, for example "miles driven". * * There are three different kinds of counter metric kinds: * - EcsCounter * When combined with a member, this will store the actual value of the member * in the metric. This is useful for values that are already counters, such as * a MilesDriven component. * This kind creates a metric per entity that has the member/id. * * - EcsCounterIncrement * When combined with a member, this will increment the value of the metric by * the value of the member * delta_time. This is useful for values that are * not counters, such as a Velocity component. * This kind creates a metric per entity that has the member. * * - EcsCounterId * This metric kind will count the number of entities with a specific * (component) id. This kind creates a single metric instance for regular ids, * and a metric instance per target for wildcard ids when targets is set. * * @param world The world. * @param desc Metric description. * @return The metric entity. */ FLECS_API ecs_entity_t ecs_metric_init( ecs_world_t *world, const ecs_metric_desc_t *desc); /** Shorthand for creating a metric with ecs_metric_init(). * * Example: * * @code * ecs_metric(world, { * .member = ecs_lookup(world, "Position.x") * .kind = EcsGauge * }); * @endcode */ #define ecs_metric(world, ...)\ ecs_metric_init(world, &(ecs_metric_desc_t) __VA_ARGS__ ) /* Module import */ FLECS_API void FlecsMetricsImport( ecs_world_t *world); #ifdef __cplusplus } #endif #endif /** @} */ #endif #endif #ifdef FLECS_ALERTS #ifdef FLECS_NO_ALERTS #error "FLECS_NO_ALERTS failed: ALERTS is required by other addons" #endif /** * @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 * @ingroup c_addons * Create alerts from monitoring queries. * * @{ */ #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 #endif #ifdef FLECS_MONITOR #ifdef FLECS_NO_MONITOR #error "FLECS_NO_MONITOR failed: MONITOR is required by other addons" #endif /** * @file addons/monitor.h * @brief Doc module. * * The monitor module automatically tracks statistics from the stats addon and * stores them in components. */ #ifdef FLECS_MONITOR /** * @defgroup c_addons_monitor Monitor * @ingroup c_addons * The monitor addon periodically tracks statistics for the world and systems. * * @{ */ #ifndef FLECS_MONITOR_H #define FLECS_MONITOR_H #ifndef FLECS_MODULE #define FLECS_MODULE #endif #ifndef FLECS_STATS #define FLECS_STATS #endif #ifdef __cplusplus extern "C" { #endif FLECS_API extern ECS_COMPONENT_DECLARE(FlecsMonitor); FLECS_API extern ECS_COMPONENT_DECLARE(EcsWorldStats); FLECS_API extern ECS_COMPONENT_DECLARE(EcsWorldSummary); FLECS_API extern ECS_COMPONENT_DECLARE(EcsPipelineStats); FLECS_API extern ecs_entity_t EcsPeriod1s; FLECS_API extern ecs_entity_t EcsPeriod1m; FLECS_API extern ecs_entity_t EcsPeriod1h; FLECS_API extern ecs_entity_t EcsPeriod1d; FLECS_API extern ecs_entity_t EcsPeriod1w; typedef struct { ecs_ftime_t elapsed; int32_t reduce_count; } EcsStatsHeader; typedef struct { EcsStatsHeader hdr; ecs_world_stats_t stats; } EcsWorldStats; typedef struct { EcsStatsHeader hdr; ecs_pipeline_stats_t stats; } EcsPipelineStats; typedef struct { /* Target FPS */ double target_fps; /**< Target FPS */ /* Total time */ double frame_time_total; /**< Total time spent processing a frame */ double system_time_total; /**< Total time spent in systems */ double merge_time_total; /**< Total time spent in merges */ /* Last frame time */ double frame_time_last; /**< Time spent processing a frame */ double system_time_last; /**< Time spent in systems */ double merge_time_last; /**< Time spent in merges */ int64_t frame_count; /**< Number of frames processed */ int64_t command_count; /**< Number of commands processed */ /* Build info */ ecs_build_info_t build_info; /**< Build info */ } EcsWorldSummary; /* Module import */ FLECS_API void FlecsMonitorImport( ecs_world_t *world); #ifdef __cplusplus } #endif #endif /** @} */ #endif #endif #ifdef FLECS_DOC #ifdef FLECS_NO_DOC #error "FLECS_NO_DOC failed: DOC is required by other addons" #endif /** * @file addons/doc.h * @brief Doc module. * * The doc module allows for documenting entities (and thus components, systems) * by adding brief and/or detailed descriptions as components. Documentation * added with the doc module can be retrieved at runtime, and can be used by * tooling such as UIs or documentation frameworks. */ #ifdef FLECS_DOC #ifndef FLECS_DOC_H #define FLECS_DOC_H #ifndef FLECS_MODULE #define FLECS_MODULE #endif #ifdef __cplusplus extern "C" { #endif /** * @defgroup c_addons_doc Doc * @ingroup c_addons * Utilities for documenting entities, components and systems. * * @{ */ FLECS_API extern const ecs_entity_t ecs_id(EcsDocDescription); FLECS_API extern const ecs_entity_t EcsDocBrief; FLECS_API extern const ecs_entity_t EcsDocDetail; FLECS_API extern const ecs_entity_t EcsDocLink; FLECS_API extern const ecs_entity_t EcsDocColor; typedef struct EcsDocDescription { char *value; } EcsDocDescription; /** Add human-readable name to entity. * Contrary to entity names, human readable names do not have to be unique and * can contain special characters used in the query language like '*'. * * @param world The world. * @param entity The entity to which to add the name. * @param name The name to add. * * @see ecs_doc_get_name() * @see flecs::doc::set_name() * @see flecs::entity_builder::set_doc_name() */ FLECS_API void ecs_doc_set_name( ecs_world_t *world, ecs_entity_t entity, const char *name); /** Add brief description to entity. * * @param world The world. * @param entity The entity to which to add the description. * @param description The description to add. * * @see ecs_doc_get_brief() * @see flecs::doc::set_brief() * @see flecs::entity_builder::set_doc_brief() */ FLECS_API void ecs_doc_set_brief( ecs_world_t *world, ecs_entity_t entity, const char *description); /** Add detailed description to entity. * * @param world The world. * @param entity The entity to which to add the description. * @param description The description to add. * * @see ecs_doc_get_detail() * @see flecs::doc::set_detail() * @see flecs::entity_builder::set_doc_detail() */ FLECS_API void ecs_doc_set_detail( ecs_world_t *world, ecs_entity_t entity, const char *description); /** Add link to external documentation to entity. * * @param world The world. * @param entity The entity to which to add the link. * @param link The link to add. * * @see ecs_doc_get_link() * @see flecs::doc::set_link() * @see flecs::entity_builder::set_doc_link() */ FLECS_API void ecs_doc_set_link( ecs_world_t *world, ecs_entity_t entity, const char *link); /** Add color to entity. * UIs can use color as hint to improve visualizing entities. * * @param world The world. * @param entity The entity to which to add the link. * @param color The color to add. * * @see ecs_doc_get_color() * @see flecs::doc::set_color() * @see flecs::entity_builder::set_doc_color() */ FLECS_API void ecs_doc_set_color( ecs_world_t *world, ecs_entity_t entity, const char *color); /** Get human readable name from entity. * If entity does not have an explicit human readable name, this operation will * return the entity name. * * To test if an entity has a human readable name, use: * * @code * ecs_has_pair(world, e, ecs_id(EcsDocDescription), EcsName); * @endcode * * Or in C++: * * @code * e.has(flecs::Name); * @endcode * * @param world The world. * @param entity The entity from which to get the name. * @return The name. * * @see ecs_doc_set_name() * @see flecs::doc::get_name() * @see flecs::entity_view::get_doc_name() */ FLECS_API const char* ecs_doc_get_name( const ecs_world_t *world, ecs_entity_t entity); /** Get brief description from entity. * * @param world The world. * @param entity The entity from which to get the description. * @return The description. * * @see ecs_doc_set_brief() * @see flecs::doc::get_brief() * @see flecs::entity_view::get_doc_brief() */ FLECS_API const char* ecs_doc_get_brief( const ecs_world_t *world, ecs_entity_t entity); /** Get detailed description from entity. * * @param world The world. * @param entity The entity from which to get the description. * @return The description. * * @see ecs_doc_set_detail() * @see flecs::doc::get_detail() * @see flecs::entity_view::get_doc_detail() */ FLECS_API const char* ecs_doc_get_detail( const ecs_world_t *world, ecs_entity_t entity); /** Get link to external documentation from entity. * * @param world The world. * @param entity The entity from which to get the link. * @return The link. * * @see ecs_doc_set_link() * @see flecs::doc::get_link() * @see flecs::entity_view::get_doc_link() */ FLECS_API const char* ecs_doc_get_link( const ecs_world_t *world, ecs_entity_t entity); /** Get color from entity. * * @param world The world. * @param entity The entity from which to get the color. * @return The color. * * @see ecs_doc_set_color() * @see flecs::doc::get_color() * @see flecs::entity_view::get_doc_color() */ FLECS_API const char* ecs_doc_get_color( const ecs_world_t *world, ecs_entity_t entity); /* Module import */ FLECS_API void FlecsDocImport( ecs_world_t *world); /** @} */ #ifdef __cplusplus } #endif #endif #endif #endif #ifdef FLECS_JSON #ifdef FLECS_NO_JSON #error "FLECS_NO_JSON failed: JSON is required by other addons" #endif /** * @file addons/json.h * @brief JSON parser addon. * * Parse expression strings into component values. Entity identifiers, * enumerations and bitmasks are encoded as strings. * * See docs/JsonFormat.md for a description of the JSON format. */ #ifdef FLECS_JSON #ifndef FLECS_EXPR #define FLECS_EXPR #endif #ifndef FLECS_JSON_H #define FLECS_JSON_H /** * @defgroup c_addons_json Json * @ingroup c_addons * Functions for serializing to/from JSON. * * @{ */ #ifdef __cplusplus extern "C" { #endif /** Used with ecs_ptr_from_json(), ecs_entity_from_json(). */ typedef struct ecs_from_json_desc_t { const char *name; /**< Name of expression (used for logging) */ const char *expr; /**< Full expression (used for logging) */ /** Callback that allows for specifying a custom lookup function. The * default behavior uses ecs_lookup() */ ecs_entity_t (*lookup_action)( const ecs_world_t*, const char *value, void *ctx); void *lookup_ctx; /** Require components to be registered with reflection data. When not * in strict mode, values for components without reflection are ignored. */ bool strict; } ecs_from_json_desc_t; /** Parse JSON string into value. * This operation parses a JSON expression into the provided pointer. The * memory pointed to must be large enough to contain a value of the used type. * * @param world The world. * @param type The type of the expression to parse. * @param ptr Pointer to the memory to write to. * @param json The JSON expression to parse. * @param desc Configuration parameters for deserializer. * @return Pointer to the character after the last one read, or NULL if failed. */ FLECS_API const char* ecs_ptr_from_json( const ecs_world_t *world, ecs_entity_t type, void *ptr, const char *json, const ecs_from_json_desc_t *desc); /** Parse JSON object with multiple component values into entity. The format * is the same as the one outputted by ecs_entity_to_json(), but at the moment * only supports the "ids" and "values" member. * * @param world The world. * @param entity The entity to serialize to. * @param json The JSON expression to parse (see entity in JSON format manual). * @param desc Configuration parameters for deserializer. * @return Pointer to the character after the last one read, or NULL if failed. */ FLECS_API const char* ecs_entity_from_json( ecs_world_t *world, ecs_entity_t entity, const char *json, const ecs_from_json_desc_t *desc); /** Parse JSON object with multiple entities into the world. The format is the * same as the one outputted by ecs_world_to_json(). * * @param world The world. * @param json The JSON expression to parse (see iterator in JSON format manual). * @param desc Deserialization parameters. * @return Last deserialized character, NULL if failed. */ FLECS_API const char* ecs_world_from_json( ecs_world_t *world, const char *json, const ecs_from_json_desc_t *desc); /** Same as ecs_world_from_json(), but loads JSON from file. * * @param world The world. * @param filename The file from which to load the JSON. * @param desc Deserialization parameters. * @return Last deserialized character, NULL if failed. */ FLECS_API const char* ecs_world_from_json_file( ecs_world_t *world, const char *filename, const ecs_from_json_desc_t *desc); /** Serialize array into JSON string. * This operation serializes a value of the provided type to a JSON string. The * memory pointed to must be large enough to contain a value of the used type. * * If count is 0, the function will serialize a single value, not wrapped in * array brackets. If count is >= 1, the operation will serialize values to a * a comma-separated list inside of array brackets. * * @param world The world. * @param type The type of the value to serialize. * @param data The value to serialize. * @param count The number of elements to serialize. * @return String with JSON expression, or NULL if failed. */ FLECS_API char* ecs_array_to_json( const ecs_world_t *world, ecs_entity_t type, const void *data, int32_t count); /** Serialize array into JSON string buffer. * Same as ecs_array_to_json(), but serializes to an ecs_strbuf_t instance. * * @param world The world. * @param type The type of the value to serialize. * @param data The value to serialize. * @param count The number of elements to serialize. * @param buf_out The strbuf to append the string to. * @return Zero if success, non-zero if failed. */ FLECS_API int ecs_array_to_json_buf( const ecs_world_t *world, ecs_entity_t type, const void *data, int32_t count, ecs_strbuf_t *buf_out); /** Serialize value into JSON string. * Same as ecs_array_to_json(), with count = 0. * * @param world The world. * @param type The type of the value to serialize. * @param data The value to serialize. * @return String with JSON expression, or NULL if failed. */ FLECS_API char* ecs_ptr_to_json( const ecs_world_t *world, ecs_entity_t type, const void *data); /** Serialize value into JSON string buffer. * Same as ecs_ptr_to_json(), but serializes to an ecs_strbuf_t instance. * * @param world The world. * @param type The type of the value to serialize. * @param data The value to serialize. * @param buf_out The strbuf to append the string to. * @return Zero if success, non-zero if failed. */ FLECS_API int ecs_ptr_to_json_buf( const ecs_world_t *world, ecs_entity_t type, const void *data, ecs_strbuf_t *buf_out); /** Serialize type info to JSON. * This serializes type information to JSON, and can be used to store/transmit * the structure of a (component) value. * * If the provided type does not have reflection data, "0" will be returned. * * @param world The world. * @param type The type to serialize to JSON. * @return A JSON string with the serialized type info, or NULL if failed. */ FLECS_API char* ecs_type_info_to_json( const ecs_world_t *world, ecs_entity_t type); /** Serialize type info into JSON string buffer. * Same as ecs_type_info_to_json(), but serializes to an ecs_strbuf_t instance. * * @param world The world. * @param type The type to serialize. * @param buf_out The strbuf to append the string to. * @return Zero if success, non-zero if failed. */ FLECS_API int ecs_type_info_to_json_buf( const ecs_world_t *world, ecs_entity_t type, ecs_strbuf_t *buf_out); /** Used with ecs_iter_to_json(). */ typedef struct ecs_entity_to_json_desc_t { bool serialize_path; /**< Serialize full pathname */ bool serialize_label; /**< Serialize doc name */ bool serialize_brief; /**< Serialize brief doc description */ bool serialize_link; /**< Serialize doc link (URL) */ bool serialize_color; /**< Serialize doc color */ bool serialize_ids; /**< Serialize (component) ids */ bool serialize_id_labels; /**< Serialize labels of (component) ids */ bool serialize_base; /**< Serialize base components */ bool serialize_private; /**< Serialize private components */ bool serialize_hidden; /**< Serialize ids hidden by override */ bool serialize_values; /**< Serialize component values */ bool serialize_type_info; /**< Serialize type info (requires serialize_values) */ bool serialize_alerts; /**< Serialize active alerts for entity */ ecs_entity_t serialize_refs; /**< Serialize references (incoming edges) for relationship */ bool serialize_matches; /**< Serialize which queries entity matches with */ } ecs_entity_to_json_desc_t; #define ECS_ENTITY_TO_JSON_INIT (ecs_entity_to_json_desc_t){true, false,\ false, false, false, true, false, true, false, false, false, false, false,\ false, false } /** Serialize entity into JSON string. * This creates a JSON object with the entity's (path) name, which components * and tags the entity has, and the component values. * * The operation may fail if the entity contains components with invalid values. * * @param world The world. * @param entity The entity to serialize to JSON. * @return A JSON string with the serialized entity data, or NULL if failed. */ FLECS_API char* ecs_entity_to_json( const ecs_world_t *world, ecs_entity_t entity, const ecs_entity_to_json_desc_t *desc); /** Serialize entity into JSON string buffer. * Same as ecs_entity_to_json(), but serializes to an ecs_strbuf_t instance. * * @param world The world. * @param entity The entity to serialize. * @param buf_out The strbuf to append the string to. * @return Zero if success, non-zero if failed. */ FLECS_API int ecs_entity_to_json_buf( const ecs_world_t *world, ecs_entity_t entity, ecs_strbuf_t *buf_out, const ecs_entity_to_json_desc_t *desc); /** Used with ecs_iter_to_json(). */ typedef struct ecs_iter_to_json_desc_t { bool serialize_term_ids; /**< Serialize query term component ids */ bool serialize_term_labels; /**< Serialize query term component id labels */ bool serialize_ids; /**< Serialize actual (matched) component ids */ bool serialize_id_labels; /**< Serialize actual (matched) component id labels */ bool serialize_sources; /**< Serialize sources */ bool serialize_variables; /**< Serialize variables */ bool serialize_is_set; /**< Serialize is_set (for optional terms) */ bool serialize_values; /**< Serialize component values */ bool serialize_private; /**< Serialize component values */ bool serialize_entities; /**< Serialize entities (for This terms) */ bool serialize_entity_labels; /**< Serialize doc name for entities */ bool serialize_entity_ids; /**< Serialize numerical ids for entities */ bool serialize_entity_names; /**< Serialize names (not paths) for entities */ bool serialize_variable_labels; /**< Serialize doc name for variables */ bool serialize_variable_ids; /**< Serialize numerical ids for variables */ bool serialize_colors; /**< Serialize doc color for entities */ bool measure_eval_duration; /**< Serialize evaluation duration */ bool serialize_type_info; /**< Serialize type information */ bool serialize_table; /**< Serialize entire table vs. matched components */ bool serialize_rows; /**< Use row-based serialization, with entities in separate elements */ bool serialize_field_info; /**< Serialize metadata for fields returned by query */ bool serialize_query_info; /**< Serialize query terms */ bool serialize_query_plan; /**< Serialize query plan */ bool serialize_query_profile; /**< Profile query performance */ bool dont_serialize_results; /**< If true, query won't be evaluated */ ecs_poly_t *query; /**< Query object (required for serialize_query_[plan|profile]). */ } ecs_iter_to_json_desc_t; #define ECS_ITER_TO_JSON_INIT (ecs_iter_to_json_desc_t){\ .serialize_term_ids = true, \ .serialize_term_labels = false, \ .serialize_ids = true, \ .serialize_id_labels = false, \ .serialize_sources = true, \ .serialize_variables = true, \ .serialize_is_set = true, \ .serialize_values = true, \ .serialize_entities = true, \ .serialize_entity_labels = false, \ .serialize_entity_ids = false, \ .serialize_entity_names = false, \ .serialize_variable_labels = false, \ .serialize_variable_ids = false, \ .serialize_colors = false, \ .measure_eval_duration = false, \ .serialize_type_info = false, \ .serialize_table = false, \ .serialize_rows = false, \ .serialize_field_info = false, \ .serialize_query_info = false, \ .serialize_query_plan = false, \ .serialize_query_profile = false, \ .dont_serialize_results = false, \ } /** Serialize iterator into JSON string. * This operation will iterate the contents of the iterator and serialize them * to JSON. The function accepts iterators from any source. * * @param world The world. * @param iter The iterator to serialize to JSON. * @return A JSON string with the serialized iterator data, or NULL if failed. */ FLECS_API char* ecs_iter_to_json( const ecs_world_t *world, ecs_iter_t *iter, const ecs_iter_to_json_desc_t *desc); /** Serialize iterator into JSON string buffer. * Same as ecs_iter_to_json(), but serializes to an ecs_strbuf_t instance. * * @param world The world. * @param iter The iterator to serialize. * @param buf_out The strbuf to append the string to. * @return Zero if success, non-zero if failed. */ FLECS_API int ecs_iter_to_json_buf( const ecs_world_t *world, ecs_iter_t *iter, ecs_strbuf_t *buf_out, const ecs_iter_to_json_desc_t *desc); /** Used with ecs_iter_to_json(). */ typedef struct ecs_world_to_json_desc_t { bool serialize_builtin; /**< Exclude flecs modules & contents */ bool serialize_modules; /**< Exclude modules & contents */ } ecs_world_to_json_desc_t; /** Serialize world into JSON string. * This operation iterates the contents of the world to JSON. The operation is * equivalent to the following code: * * @code * ecs_filter_t *f = ecs_filter(world, { * .terms = {{ .id = EcsAny }} * }); * * ecs_iter_t it = ecs_filter_init(world, &f); * ecs_iter_to_json_desc_t desc = { .serialize_table = true }; * ecs_iter_to_json(world, iter, &desc); * @endcode * * @param world The world to serialize. * @return A JSON string with the serialized iterator data, or NULL if failed. */ FLECS_API char* ecs_world_to_json( ecs_world_t *world, const ecs_world_to_json_desc_t *desc); /** Serialize world into JSON string buffer. * Same as ecs_world_to_json(), but serializes to an ecs_strbuf_t instance. * * @param world The world to serialize. * @param buf_out The strbuf to append the string to. * @return Zero if success, non-zero if failed. */ FLECS_API int ecs_world_to_json_buf( ecs_world_t *world, ecs_strbuf_t *buf_out, const ecs_world_to_json_desc_t *desc); #ifdef __cplusplus } #endif #endif /** @} */ #endif #endif #if defined(FLECS_EXPR) || defined(FLECS_META_C) #ifndef FLECS_META #define FLECS_META #endif #endif #ifdef FLECS_UNITS #ifdef FLECS_NO_UNITS #error "FLECS_NO_UNITS failed: UNITS is required by other addons" #endif /** * @file addons/units.h * @brief Units module. * * Builtin standard units. The units addon is not imported by default, even if * the addon is included in the build. To import the module, do: * * In C: * * @code * ECS_IMPORT(world, FlecsUnits); * @endcode * * In C++: * * @code * world.import(); * @endcode * * As a result this module behaves just like an application-defined module, * which means that the ids generated for the entities inside the module are not * fixed, and depend on the order in which the module is imported. */ #ifdef FLECS_UNITS /** * @defgroup c_addons_units Units. * @ingroup c_addons * Common unit annotations for reflection framework. * * @{ */ #ifndef FLECS_MODULE #define FLECS_MODULE #endif #ifndef FLECS_META #define FLECS_META #endif #ifndef FLECS_UNITS_H #define FLECS_UNITS_H #ifdef __cplusplus extern "C" { #endif /** * @defgroup c_addons_units_prefixes Prefixes * @ingroup c_addons_units * Prefixes to indicate unit count (e.g. Kilo, Mega) * * @{ */ FLECS_API extern ECS_DECLARE(EcsUnitPrefixes); /* Parent scope for prefixes */ FLECS_API extern ECS_DECLARE(EcsYocto); FLECS_API extern ECS_DECLARE(EcsZepto); FLECS_API extern ECS_DECLARE(EcsAtto); FLECS_API extern ECS_DECLARE(EcsFemto); FLECS_API extern ECS_DECLARE(EcsPico); FLECS_API extern ECS_DECLARE(EcsNano); FLECS_API extern ECS_DECLARE(EcsMicro); FLECS_API extern ECS_DECLARE(EcsMilli); FLECS_API extern ECS_DECLARE(EcsCenti); FLECS_API extern ECS_DECLARE(EcsDeci); FLECS_API extern ECS_DECLARE(EcsDeca); FLECS_API extern ECS_DECLARE(EcsHecto); FLECS_API extern ECS_DECLARE(EcsKilo); FLECS_API extern ECS_DECLARE(EcsMega); FLECS_API extern ECS_DECLARE(EcsGiga); FLECS_API extern ECS_DECLARE(EcsTera); FLECS_API extern ECS_DECLARE(EcsPeta); FLECS_API extern ECS_DECLARE(EcsExa); FLECS_API extern ECS_DECLARE(EcsZetta); FLECS_API extern ECS_DECLARE(EcsYotta); FLECS_API extern ECS_DECLARE(EcsKibi); FLECS_API extern ECS_DECLARE(EcsMebi); FLECS_API extern ECS_DECLARE(EcsGibi); FLECS_API extern ECS_DECLARE(EcsTebi); FLECS_API extern ECS_DECLARE(EcsPebi); FLECS_API extern ECS_DECLARE(EcsExbi); FLECS_API extern ECS_DECLARE(EcsZebi); FLECS_API extern ECS_DECLARE(EcsYobi); /** @} */ /** * @defgroup c_addons_units_duration Duration * @ingroup c_addons_units * @{ */ FLECS_API extern ECS_DECLARE(EcsDuration); FLECS_API extern ECS_DECLARE(EcsPicoSeconds); FLECS_API extern ECS_DECLARE(EcsNanoSeconds); FLECS_API extern ECS_DECLARE(EcsMicroSeconds); FLECS_API extern ECS_DECLARE(EcsMilliSeconds); FLECS_API extern ECS_DECLARE(EcsSeconds); FLECS_API extern ECS_DECLARE(EcsMinutes); FLECS_API extern ECS_DECLARE(EcsHours); FLECS_API extern ECS_DECLARE(EcsDays); /** @} */ /** * @defgroup c_addons_units_time Time * @ingroup c_addons_units * @{ */ FLECS_API extern ECS_DECLARE(EcsTime); FLECS_API extern ECS_DECLARE(EcsDate); /** @} */ /** * @defgroup c_addons_units_mass Mass * @ingroup c_addons_units * @{ */ FLECS_API extern ECS_DECLARE(EcsMass); FLECS_API extern ECS_DECLARE(EcsGrams); FLECS_API extern ECS_DECLARE(EcsKiloGrams); /** @} */ /** * @defgroup c_addons_units_electric_Current Electric Current * @ingroup c_addons_units * @{ */ FLECS_API extern ECS_DECLARE(EcsElectricCurrent); FLECS_API extern ECS_DECLARE(EcsAmpere); /** @} */ /** * @defgroup c_addons_units_amount Amount * @ingroup c_addons_units * @{ */ FLECS_API extern ECS_DECLARE(EcsAmount); FLECS_API extern ECS_DECLARE(EcsMole); /** @} */ /** * @defgroup c_addons_units_luminous_intensity Luminous Intensity * @ingroup c_addons_units * @{ */ FLECS_API extern ECS_DECLARE(EcsLuminousIntensity); FLECS_API extern ECS_DECLARE(EcsCandela); /** @} */ /** * @defgroup c_addons_units_force Force * @ingroup c_addons_units * @{ */ FLECS_API extern ECS_DECLARE(EcsForce); FLECS_API extern ECS_DECLARE(EcsNewton); /** @} */ /** * @defgroup c_addons_units_length Length * @ingroup c_addons_units * @{ */ FLECS_API extern ECS_DECLARE(EcsLength); FLECS_API extern ECS_DECLARE(EcsMeters); FLECS_API extern ECS_DECLARE(EcsPicoMeters); FLECS_API extern ECS_DECLARE(EcsNanoMeters); FLECS_API extern ECS_DECLARE(EcsMicroMeters); FLECS_API extern ECS_DECLARE(EcsMilliMeters); FLECS_API extern ECS_DECLARE(EcsCentiMeters); FLECS_API extern ECS_DECLARE(EcsKiloMeters); FLECS_API extern ECS_DECLARE(EcsMiles); FLECS_API extern ECS_DECLARE(EcsPixels); /** @} */ /** * @defgroup c_addons_units_pressure Pressure * @ingroup c_addons_units * @{ */ FLECS_API extern ECS_DECLARE(EcsPressure); FLECS_API extern ECS_DECLARE(EcsPascal); FLECS_API extern ECS_DECLARE(EcsBar); /** @} */ /** * @defgroup c_addons_units_speed Speed * @ingroup c_addons_units * @{ */ FLECS_API extern ECS_DECLARE(EcsSpeed); FLECS_API extern ECS_DECLARE(EcsMetersPerSecond); FLECS_API extern ECS_DECLARE(EcsKiloMetersPerSecond); FLECS_API extern ECS_DECLARE(EcsKiloMetersPerHour); FLECS_API extern ECS_DECLARE(EcsMilesPerHour); /** @} */ /** * @defgroup c_addons_units_temperature Temperature * @ingroup c_addons_units * @{ */ FLECS_API extern ECS_DECLARE(EcsTemperature); FLECS_API extern ECS_DECLARE(EcsKelvin); FLECS_API extern ECS_DECLARE(EcsCelsius); FLECS_API extern ECS_DECLARE(EcsFahrenheit); /** @} */ /** * @defgroup c_addons_units_data Data * @ingroup c_addons_units * @{ */ FLECS_API extern ECS_DECLARE(EcsData); FLECS_API extern ECS_DECLARE(EcsBits); FLECS_API extern ECS_DECLARE(EcsKiloBits); FLECS_API extern ECS_DECLARE(EcsMegaBits); FLECS_API extern ECS_DECLARE(EcsGigaBits); FLECS_API extern ECS_DECLARE(EcsBytes); FLECS_API extern ECS_DECLARE(EcsKiloBytes); FLECS_API extern ECS_DECLARE(EcsMegaBytes); FLECS_API extern ECS_DECLARE(EcsGigaBytes); FLECS_API extern ECS_DECLARE(EcsKibiBytes); FLECS_API extern ECS_DECLARE(EcsMebiBytes); FLECS_API extern ECS_DECLARE(EcsGibiBytes); /** @} */ /** * @defgroup c_addons_units_datarate Data Rate * @ingroup c_addons_units * @{ */ FLECS_API extern ECS_DECLARE(EcsDataRate); FLECS_API extern ECS_DECLARE(EcsBitsPerSecond); FLECS_API extern ECS_DECLARE(EcsKiloBitsPerSecond); FLECS_API extern ECS_DECLARE(EcsMegaBitsPerSecond); FLECS_API extern ECS_DECLARE(EcsGigaBitsPerSecond); FLECS_API extern ECS_DECLARE(EcsBytesPerSecond); FLECS_API extern ECS_DECLARE(EcsKiloBytesPerSecond); FLECS_API extern ECS_DECLARE(EcsMegaBytesPerSecond); FLECS_API extern ECS_DECLARE(EcsGigaBytesPerSecond); /** @} */ /** * @defgroup c_addons_units_duration Duration * @ingroup c_addons_units * @{ */ FLECS_API extern ECS_DECLARE(EcsAngle); FLECS_API extern ECS_DECLARE(EcsRadians); FLECS_API extern ECS_DECLARE(EcsDegrees); /** @} */ /** * @defgroup c_addons_units_angle Angle * @ingroup c_addons_units * @{ */ FLECS_API extern ECS_DECLARE(EcsFrequency); FLECS_API extern ECS_DECLARE(EcsHertz); FLECS_API extern ECS_DECLARE(EcsKiloHertz); FLECS_API extern ECS_DECLARE(EcsMegaHertz); FLECS_API extern ECS_DECLARE(EcsGigaHertz); /** @} */ /** * @defgroup c_addons_units_uri Uri * @ingroup c_addons_units * @{ */ FLECS_API extern ECS_DECLARE(EcsUri); FLECS_API extern ECS_DECLARE(EcsUriHyperlink); FLECS_API extern ECS_DECLARE(EcsUriImage); FLECS_API extern ECS_DECLARE(EcsUriFile); /** @} */ FLECS_API extern ECS_DECLARE(EcsAcceleration); FLECS_API extern ECS_DECLARE(EcsPercentage); FLECS_API extern ECS_DECLARE(EcsBel); FLECS_API extern ECS_DECLARE(EcsDeciBel); //////////////////////////////////////////////////////////////////////////////// //// Module //////////////////////////////////////////////////////////////////////////////// FLECS_API void FlecsUnitsImport( ecs_world_t *world); #ifdef __cplusplus } #endif #endif /** @} */ #endif #endif #ifdef FLECS_META #ifdef FLECS_NO_META #error "FLECS_NO_META failed: META is required by other addons" #endif /** * @file addons/meta.h * @brief Meta addon. * * The meta addon enables reflecting on component data. Types are stored as * entities, with components that store the reflection data. A type has at least * two components: * * - EcsComponent: core component, contains size & alignment * - EcsMetaType: component that indicates what kind of type the entity is * * Additionally the type may have an additional component that contains the * reflection data for the type. For example, structs have these components: * * - EcsComponent * - EcsMetaType * - EcsStruct * * Structs can be populated by adding child entities with the EcsMember * component. Adding a child with a Member component to an entity will * automatically add the EcsStruct component to the parent. * * Enums/bitmasks can be populated by adding child entities with the Constant * tag. By default constants are automatically assigned values when they are * added to the enum/bitmask. The parent entity must have the EcsEnum or * EcsBitmask component before adding the constants. * * To create enum constants with a manual value, set (Constant, i32) to the * desired value. To create bitmask constants with a manual value, set * (Constant, u32) to the desired value. Constants with manual values should not * conflict with other constants. * * The _init APIs are convenience wrappers around creating the entities and * components for the types. * * When a type is created it automatically receives the EcsComponent and * EcsMetaType components. The former means that the resulting type can be * used as a regular component: * * @code * // Create Position type * ecs_entity_t pos = ecs_struct_init(world, &(ecs_struct_desc_t){ * .entity.name = "Position", * .members = { * {"x", ecs_id(ecs_f32_t)}, * {"y", ecs_id(ecs_f32_t)} * } * }); * * // Create entity with Position component * ecs_entity_t e = ecs_new_w_id(world, pos); * @endcode * * Type entities do not have to be named. */ #ifdef FLECS_META /** * @defgroup c_addons_meta Meta * @ingroup c_addons * Flecs reflection framework. * * @{ */ #include #ifndef FLECS_MODULE #define FLECS_MODULE #endif #ifndef FLECS_META_H #define FLECS_META_H #ifdef __cplusplus extern "C" { #endif #define ECS_MEMBER_DESC_CACHE_SIZE (32) /** Primitive type definitions. * These typedefs allow the builtin primitives to be used as regular components: * * @code * ecs_set(world, e, ecs_i32_t, {10}); * @endcode * * Or a more useful example (create an enum constant with a manual value): * * @code * ecs_set_pair_object(world, e, EcsConstant, ecs_i32_t, {10}); * @endcode */ typedef bool ecs_bool_t; typedef char ecs_char_t; typedef unsigned char ecs_byte_t; typedef uint8_t ecs_u8_t; typedef uint16_t ecs_u16_t; typedef uint32_t ecs_u32_t; typedef uint64_t ecs_u64_t; typedef uintptr_t ecs_uptr_t; typedef int8_t ecs_i8_t; typedef int16_t ecs_i16_t; typedef int32_t ecs_i32_t; typedef int64_t ecs_i64_t; typedef intptr_t ecs_iptr_t; typedef float ecs_f32_t; typedef double ecs_f64_t; typedef char* ecs_string_t; /* Meta module component ids */ FLECS_API extern const ecs_entity_t ecs_id(EcsMetaType); FLECS_API extern const ecs_entity_t ecs_id(EcsMetaTypeSerialized); FLECS_API extern const ecs_entity_t ecs_id(EcsPrimitive); FLECS_API extern const ecs_entity_t ecs_id(EcsEnum); FLECS_API extern const ecs_entity_t ecs_id(EcsBitmask); FLECS_API extern const ecs_entity_t ecs_id(EcsMember); FLECS_API extern const ecs_entity_t ecs_id(EcsMemberRanges); FLECS_API extern const ecs_entity_t ecs_id(EcsStruct); FLECS_API extern const ecs_entity_t ecs_id(EcsArray); FLECS_API extern const ecs_entity_t ecs_id(EcsVector); FLECS_API extern const ecs_entity_t ecs_id(EcsOpaque); FLECS_API extern const ecs_entity_t ecs_id(EcsUnit); FLECS_API extern const ecs_entity_t ecs_id(EcsUnitPrefix); FLECS_API extern const ecs_entity_t EcsConstant; FLECS_API extern const ecs_entity_t EcsQuantity; /* Primitive type component ids */ FLECS_API extern const ecs_entity_t ecs_id(ecs_bool_t); FLECS_API extern const ecs_entity_t ecs_id(ecs_char_t); FLECS_API extern const ecs_entity_t ecs_id(ecs_byte_t); FLECS_API extern const ecs_entity_t ecs_id(ecs_u8_t); FLECS_API extern const ecs_entity_t ecs_id(ecs_u16_t); FLECS_API extern const ecs_entity_t ecs_id(ecs_u32_t); FLECS_API extern const ecs_entity_t ecs_id(ecs_u64_t); FLECS_API extern const ecs_entity_t ecs_id(ecs_uptr_t); FLECS_API extern const ecs_entity_t ecs_id(ecs_i8_t); FLECS_API extern const ecs_entity_t ecs_id(ecs_i16_t); FLECS_API extern const ecs_entity_t ecs_id(ecs_i32_t); FLECS_API extern const ecs_entity_t ecs_id(ecs_i64_t); FLECS_API extern const ecs_entity_t ecs_id(ecs_iptr_t); FLECS_API extern const ecs_entity_t ecs_id(ecs_f32_t); FLECS_API extern const ecs_entity_t ecs_id(ecs_f64_t); FLECS_API extern const ecs_entity_t ecs_id(ecs_string_t); FLECS_API extern const ecs_entity_t ecs_id(ecs_entity_t); FLECS_API extern const ecs_entity_t ecs_id(ecs_id_t); /** Type kinds supported by meta addon */ typedef enum ecs_type_kind_t { EcsPrimitiveType, EcsBitmaskType, EcsEnumType, EcsStructType, EcsArrayType, EcsVectorType, EcsOpaqueType, EcsTypeKindLast = EcsOpaqueType } ecs_type_kind_t; /** Component that is automatically added to every type with the right kind. */ typedef struct EcsMetaType { ecs_type_kind_t kind; bool existing; /**< Did the type exist or is it populated from reflection */ bool partial; /**< Is the reflection data a partial type description */ } EcsMetaType; /** Primitive type kinds supported by meta addon */ typedef enum ecs_primitive_kind_t { EcsBool = 1, EcsChar, EcsByte, EcsU8, EcsU16, EcsU32, EcsU64, EcsI8, EcsI16, EcsI32, EcsI64, EcsF32, EcsF64, EcsUPtr, EcsIPtr, EcsString, EcsEntity, EcsId, EcsPrimitiveKindLast = EcsId } ecs_primitive_kind_t; /** Component added to primitive types */ typedef struct EcsPrimitive { ecs_primitive_kind_t kind; } EcsPrimitive; /** Component added to member entities */ typedef struct EcsMember { ecs_entity_t type; int32_t count; ecs_entity_t unit; int32_t offset; } EcsMember; /** Type expressing a range for a member value */ typedef struct ecs_member_value_range_t { double min; double max; } ecs_member_value_range_t; /** Component added to member entities to express valid value ranges */ typedef struct EcsMemberRanges { ecs_member_value_range_t value; ecs_member_value_range_t warning; ecs_member_value_range_t error; } EcsMemberRanges; /** Element type of members vector in EcsStruct */ typedef struct ecs_member_t { /** Must be set when used with ecs_struct_desc_t */ const char *name; ecs_entity_t type; /** May be set when used with ecs_struct_desc_t */ int32_t count; int32_t offset; /** May be set when used with ecs_struct_desc_t, will be auto-populated if * type entity is also a unit */ ecs_entity_t unit; /** Numerical range that specifies which values member can assume. This * range may be used by UI elements such as a progress bar or slider. The * value of a member should not exceed this range. */ ecs_member_value_range_t range; /** Numerical range outside of which the value represents an error. This * range may be used by UI elements to style a value. */ ecs_member_value_range_t error_range; /** Numerical range outside of which the value represents an warning. This * range may be used by UI elements to style a value. */ ecs_member_value_range_t warning_range; /** Should not be set by ecs_struct_desc_t */ ecs_size_t size; ecs_entity_t member; } ecs_member_t; /** Component added to struct type entities */ typedef struct EcsStruct { /** Populated from child entities with Member component */ ecs_vec_t members; /* vector */ } EcsStruct; typedef struct ecs_enum_constant_t { /** Must be set when used with ecs_enum_desc_t */ const char *name; /** May be set when used with ecs_enum_desc_t */ int32_t value; /** Should not be set by ecs_enum_desc_t */ ecs_entity_t constant; } ecs_enum_constant_t; /** Component added to enum type entities */ typedef struct EcsEnum { /** Populated from child entities with Constant component */ ecs_map_t constants; /* map */ } EcsEnum; typedef struct ecs_bitmask_constant_t { /** Must be set when used with ecs_bitmask_desc_t */ const char *name; /** May be set when used with ecs_bitmask_desc_t */ ecs_flags32_t value; /** Should not be set by ecs_bitmask_desc_t */ ecs_entity_t constant; } ecs_bitmask_constant_t; /** Component added to bitmask type entities */ typedef struct EcsBitmask { /* Populated from child entities with Constant component */ ecs_map_t constants; /* map */ } EcsBitmask; /** Component added to array type entities */ typedef struct EcsArray { ecs_entity_t type; /**< Element type */ int32_t count; /**< Number of elements */ } EcsArray; /** Component added to vector type entities */ typedef struct EcsVector { ecs_entity_t type; /**< Element type */ } EcsVector; /* Opaque type support */ #if !defined(__cplusplus) || !defined(FLECS_CPP) /** Serializer interface */ typedef struct ecs_serializer_t { /* Serialize value */ int (*value)( const struct ecs_serializer_t *ser, /**< Serializer */ ecs_entity_t type, /**< Type of the value to serialize */ const void *value); /**< Pointer to the value to serialize */ /* Serialize member */ int (*member)( const struct ecs_serializer_t *ser, /**< Serializer */ const char *member); /**< Member name */ const ecs_world_t *world; void *ctx; } ecs_serializer_t; #elif defined(__cplusplus) } /* extern "C" { */ /** Serializer interface (same layout as C, but with convenience methods) */ typedef struct ecs_serializer_t { /* Serialize value */ int (*value_)( const struct ecs_serializer_t *ser, ecs_entity_t type, const void *value); /* Serialize member */ int (*member_)( const struct ecs_serializer_t *ser, const char *name); /* Serialize value */ int value(ecs_entity_t type, const void *value) const; /* Serialize value */ template int value(const T& value) const; /* Serialize member */ int member(const char *name) const; const ecs_world_t *world; void *ctx; } ecs_serializer_t; extern "C" { #endif /** Callback invoked serializing an opaque type. */ typedef int (*ecs_meta_serialize_t)( const ecs_serializer_t *ser, const void *src); /**< Pointer to value to serialize */ typedef struct EcsOpaque { ecs_entity_t as_type; /**< Type that describes the serialized output */ ecs_meta_serialize_t serialize; /**< Serialize action */ /* Deserializer interface * Only override the callbacks that are valid for the opaque type. If a * deserializer attempts to assign a value type that is not supported by the * interface, a conversion error is thrown. */ /** Assign bool value */ void (*assign_bool)( void *dst, bool value); /** Assign char value */ void (*assign_char)( void *dst, char value); /** Assign int value */ void (*assign_int)( void *dst, int64_t value); /** Assign unsigned int value */ void (*assign_uint)( void *dst, uint64_t value); /** Assign float value */ void (*assign_float)( void *dst, double value); /** Assign string value */ void (*assign_string)( void *dst, const char *value); /** Assign entity value */ void (*assign_entity)( void *dst, ecs_world_t *world, ecs_entity_t entity); /** Assign (component) id value */ void (*assign_id)( void *dst, ecs_world_t *world, ecs_id_t id); /** Assign null value */ void (*assign_null)( void *dst); /** Clear collection elements */ void (*clear)( void *dst); /** Ensure & get collection element */ void* (*ensure_element)( void *dst, size_t elem); /** Ensure & get element */ void* (*ensure_member)( void *dst, const char *member); /** Return number of elements */ size_t (*count)( const void *dst); /** Resize to number of elements */ void (*resize)( void *dst, size_t count); } EcsOpaque; /* Units */ /* Helper type to describe translation between two units. Note that this * is not intended as a generic approach to unit conversions (e.g. from celsius * to fahrenheit) but to translate between units that derive from the same base * (e.g. meters to kilometers). * * Note that power is applied to the factor. When describing a translation of * 1000, either use {factor = 1000, power = 1} or {factor = 1, power = 3}. */ typedef struct ecs_unit_translation_t { int32_t factor; /**< Factor to apply (e.g. "1000", "1000000", "1024") */ int32_t power; /**< Power to apply to factor (e.g. "1", "3", "-9") */ } ecs_unit_translation_t; typedef struct EcsUnit { char *symbol; ecs_entity_t prefix; /**< Order of magnitude prefix relative to derived */ ecs_entity_t base; /**< Base unit (e.g. "meters") */ ecs_entity_t over; /**< Over unit (e.g. "per second") */ ecs_unit_translation_t translation; /**< Translation for derived unit */ } EcsUnit; typedef struct EcsUnitPrefix { char *symbol; /**< Symbol of prefix (e.g. "K", "M", "Ki") */ ecs_unit_translation_t translation; /**< Translation of prefix */ } EcsUnitPrefix; /* Serializer utilities */ typedef enum ecs_meta_type_op_kind_t { EcsOpArray, EcsOpVector, EcsOpOpaque, EcsOpPush, EcsOpPop, EcsOpScope, /**< Marks last constant that can open/close a scope */ EcsOpEnum, EcsOpBitmask, EcsOpPrimitive, /**< Marks first constant that's a primitive */ EcsOpBool, EcsOpChar, EcsOpByte, EcsOpU8, EcsOpU16, EcsOpU32, EcsOpU64, EcsOpI8, EcsOpI16, EcsOpI32, EcsOpI64, EcsOpF32, EcsOpF64, EcsOpUPtr, EcsOpIPtr, EcsOpString, EcsOpEntity, EcsOpId, EcsMetaTypeOpKindLast = EcsOpId } ecs_meta_type_op_kind_t; typedef struct ecs_meta_type_op_t { ecs_meta_type_op_kind_t kind; ecs_size_t offset; /**< Offset of current field */ int32_t count; const char *name; /**< Name of value (only used for struct members) */ int32_t op_count; /**< Number of operations until next field or end */ ecs_size_t size; /**< Size of type of operation */ ecs_entity_t type; /**< Type entity */ int32_t member_index; /**< Index of member in struct */ ecs_hashmap_t *members; /**< string -> member index (structs only) */ } ecs_meta_type_op_t; typedef struct EcsMetaTypeSerialized { ecs_vec_t ops; /**< vector */ } EcsMetaTypeSerialized; /* Deserializer utilities */ #define ECS_META_MAX_SCOPE_DEPTH (32) /* >32 levels of nesting is not sane */ typedef struct ecs_meta_scope_t { ecs_entity_t type; /**< The type being iterated */ ecs_meta_type_op_t *ops; /**< The type operations (see ecs_meta_type_op_t) */ int32_t op_count; /**< Number of operations in ops array to process */ int32_t op_cur; /**< Current operation */ int32_t elem_cur; /**< Current element (for collections) */ int32_t prev_depth; /**< Depth to restore, in case dotmember was used */ void *ptr; /**< Pointer to the value being iterated */ const EcsComponent *comp; /**< Pointer to component, in case size/alignment is needed */ const EcsOpaque *opaque; /**< Opaque type interface */ ecs_vec_t *vector; /**< Current vector, in case a vector is iterated */ ecs_hashmap_t *members; /**< string -> member index */ bool is_collection; /**< Is the scope iterating elements? */ bool is_inline_array; /**< Is the scope iterating an inline array? */ bool is_empty_scope; /**< Was scope populated (for collections) */ } ecs_meta_scope_t; /** Type that enables iterating/populating a value using reflection data */ typedef struct ecs_meta_cursor_t { const ecs_world_t *world; ecs_meta_scope_t scope[ECS_META_MAX_SCOPE_DEPTH]; int32_t depth; bool valid; bool is_primitive_scope; /**< If in root scope, this allows for a push for primitive types */ /* Custom entity lookup action for overriding default ecs_lookup */ ecs_entity_t (*lookup_action)(const ecs_world_t*, const char*, void*); void *lookup_ctx; } ecs_meta_cursor_t; FLECS_API ecs_meta_cursor_t ecs_meta_cursor( const ecs_world_t *world, ecs_entity_t type, void *ptr); /** Get pointer to current field */ FLECS_API void* ecs_meta_get_ptr( ecs_meta_cursor_t *cursor); /** Move cursor to next field */ FLECS_API int ecs_meta_next( ecs_meta_cursor_t *cursor); /** Move cursor to a element */ FLECS_API int ecs_meta_elem( ecs_meta_cursor_t *cursor, int32_t elem); /** Move cursor to member */ FLECS_API int ecs_meta_member( ecs_meta_cursor_t *cursor, const char *name); /** Move cursor to member, supports dot-separated nested members */ FLECS_API int ecs_meta_dotmember( ecs_meta_cursor_t *cursor, const char *name); /** Push a scope (required/only valid for structs & collections) */ FLECS_API int ecs_meta_push( ecs_meta_cursor_t *cursor); /** Pop a struct or collection scope (must follow a push) */ FLECS_API int ecs_meta_pop( ecs_meta_cursor_t *cursor); /** Is the current scope a collection? */ FLECS_API bool ecs_meta_is_collection( const ecs_meta_cursor_t *cursor); /** Get type of current element. */ FLECS_API ecs_entity_t ecs_meta_get_type( const ecs_meta_cursor_t *cursor); /** Get unit of current element. */ FLECS_API ecs_entity_t ecs_meta_get_unit( const ecs_meta_cursor_t *cursor); /** Get member name of current member */ FLECS_API const char* ecs_meta_get_member( const ecs_meta_cursor_t *cursor); /** Get member entity of current member */ FLECS_API ecs_entity_t ecs_meta_get_member_id( const ecs_meta_cursor_t *cursor); /* The set functions assign the field with the specified value. If the value * does not have the same type as the field, it will be cased to the field type. * If no valid conversion is available, the operation will fail. */ /** Set field with boolean value */ FLECS_API int ecs_meta_set_bool( ecs_meta_cursor_t *cursor, bool value); /** Set field with char value */ FLECS_API int ecs_meta_set_char( ecs_meta_cursor_t *cursor, char value); /** Set field with int value */ FLECS_API int ecs_meta_set_int( ecs_meta_cursor_t *cursor, int64_t value); /** Set field with uint value */ FLECS_API int ecs_meta_set_uint( ecs_meta_cursor_t *cursor, uint64_t value); /** Set field with float value */ FLECS_API int ecs_meta_set_float( ecs_meta_cursor_t *cursor, double value); /** Set field with string value */ FLECS_API int ecs_meta_set_string( ecs_meta_cursor_t *cursor, const char *value); /** Set field with string literal value (has enclosing "") */ FLECS_API int ecs_meta_set_string_literal( ecs_meta_cursor_t *cursor, const char *value); /** Set field with entity value */ FLECS_API int ecs_meta_set_entity( ecs_meta_cursor_t *cursor, ecs_entity_t value); /** Set field with (component) id value */ FLECS_API int ecs_meta_set_id( ecs_meta_cursor_t *cursor, ecs_id_t value); /** Set field with null value */ FLECS_API int ecs_meta_set_null( ecs_meta_cursor_t *cursor); /** Set field with dynamic value */ FLECS_API int ecs_meta_set_value( ecs_meta_cursor_t *cursor, const ecs_value_t *value); /* Functions for getting members. */ /** Get field value as boolean. */ FLECS_API bool ecs_meta_get_bool( const ecs_meta_cursor_t *cursor); /** Get field value as char. */ FLECS_API char ecs_meta_get_char( const ecs_meta_cursor_t *cursor); /** Get field value as signed integer. */ FLECS_API int64_t ecs_meta_get_int( const ecs_meta_cursor_t *cursor); /** Get field value as unsigned integer. */ FLECS_API uint64_t ecs_meta_get_uint( const ecs_meta_cursor_t *cursor); /** Get field value as float. */ FLECS_API double ecs_meta_get_float( const ecs_meta_cursor_t *cursor); /** Get field value as string. * This operation does not perform conversions. If the field is not a string, * this operation will fail. */ FLECS_API const char* ecs_meta_get_string( const ecs_meta_cursor_t *cursor); /** Get field value as entity. * This operation does not perform conversions. */ FLECS_API ecs_entity_t ecs_meta_get_entity( const ecs_meta_cursor_t *cursor); /** Get field value as (component) id. * This operation can convert from an entity. */ ecs_id_t ecs_meta_get_id( const ecs_meta_cursor_t *cursor); /** Convert pointer of primitive kind to float. */ FLECS_API double ecs_meta_ptr_to_float( ecs_primitive_kind_t type_kind, const void *ptr); /* API functions for creating meta types */ /** Used with ecs_primitive_init(). */ typedef struct ecs_primitive_desc_t { ecs_entity_t entity; /**< Existing entity to use for type (optional) */ ecs_primitive_kind_t kind; } ecs_primitive_desc_t; /** Create a new primitive type */ FLECS_API ecs_entity_t ecs_primitive_init( ecs_world_t *world, const ecs_primitive_desc_t *desc); /** Used with ecs_enum_init(). */ typedef struct ecs_enum_desc_t { ecs_entity_t entity; /**< Existing entity to use for type (optional) */ ecs_enum_constant_t constants[ECS_MEMBER_DESC_CACHE_SIZE]; } ecs_enum_desc_t; /** Create a new enum type */ FLECS_API ecs_entity_t ecs_enum_init( ecs_world_t *world, const ecs_enum_desc_t *desc); /** Used with ecs_bitmask_init(). */ typedef struct ecs_bitmask_desc_t { ecs_entity_t entity; /**< Existing entity to use for type (optional) */ ecs_bitmask_constant_t constants[ECS_MEMBER_DESC_CACHE_SIZE]; } ecs_bitmask_desc_t; /** Create a new bitmask type */ FLECS_API ecs_entity_t ecs_bitmask_init( ecs_world_t *world, const ecs_bitmask_desc_t *desc); /** Used with ecs_array_init(). */ typedef struct ecs_array_desc_t { ecs_entity_t entity; /**< Existing entity to use for type (optional) */ ecs_entity_t type; int32_t count; } ecs_array_desc_t; /** Create a new array type */ FLECS_API ecs_entity_t ecs_array_init( ecs_world_t *world, const ecs_array_desc_t *desc); /** Used with ecs_vector_init(). */ typedef struct ecs_vector_desc_t { ecs_entity_t entity; /**< Existing entity to use for type (optional) */ ecs_entity_t type; } ecs_vector_desc_t; /** Create a new vector type */ FLECS_API ecs_entity_t ecs_vector_init( ecs_world_t *world, const ecs_vector_desc_t *desc); /** Used with ecs_struct_init(). */ typedef struct ecs_struct_desc_t { ecs_entity_t entity; /**< Existing entity to use for type (optional) */ ecs_member_t members[ECS_MEMBER_DESC_CACHE_SIZE]; } ecs_struct_desc_t; /** Create a new struct type */ FLECS_API ecs_entity_t ecs_struct_init( ecs_world_t *world, const ecs_struct_desc_t *desc); /** Used with ecs_opaque_init(). */ typedef struct ecs_opaque_desc_t { ecs_entity_t entity; EcsOpaque type; } ecs_opaque_desc_t; /** Create a new opaque type. * Opaque types are types of which the layout doesn't match what can be modelled * with the primitives of the meta framework, but which have a structure * that can be described with meta primitives. Typical examples are STL types * such as std::string or std::vector, types with a nontrivial layout, and types * that only expose getter/setter methods. * * An opaque type is a combination of a serialization function, and a handle to * a meta type which describes the structure of the serialized output. For * example, an opaque type for std::string would have a serializer function that * accesses .c_str(), and with type ecs_string_t. * * The serializer callback accepts a serializer object and a pointer to the * value of the opaque type to be serialized. The serializer has two methods: * * - value, which serializes a value (such as .c_str()) * - member, which specifies a member to be serialized (in the case of a struct) */ FLECS_API ecs_entity_t ecs_opaque_init( ecs_world_t *world, const ecs_opaque_desc_t *desc); /** Used with ecs_unit_init(). */ typedef struct ecs_unit_desc_t { /** Existing entity to associate with unit (optional) */ ecs_entity_t entity; /** Unit symbol, e.g. "m", "%", "g". (optional) */ const char *symbol; /** Unit quantity, e.g. distance, percentage, weight. (optional) */ ecs_entity_t quantity; /** Base unit, e.g. "meters" (optional) */ ecs_entity_t base; /** Over unit, e.g. "per second" (optional) */ ecs_entity_t over; /** Translation to apply to derived unit (optional) */ ecs_unit_translation_t translation; /** Prefix indicating order of magnitude relative to the derived unit. If set * together with "translation", the values must match. If translation is not * set, setting prefix will auto-populate it. * Additionally, setting the prefix will enforce that the symbol (if set) * is consistent with the prefix symbol + symbol of the derived unit. If the * symbol is not set, it will be auto populated. */ ecs_entity_t prefix; } ecs_unit_desc_t; /** Create a new unit */ FLECS_API ecs_entity_t ecs_unit_init( ecs_world_t *world, const ecs_unit_desc_t *desc); /** Used with ecs_unit_prefix_init(). */ typedef struct ecs_unit_prefix_desc_t { /** Existing entity to associate with unit prefix (optional) */ ecs_entity_t entity; /** Unit symbol, e.g. "m", "%", "g". (optional) */ const char *symbol; /** Translation to apply to derived unit (optional) */ ecs_unit_translation_t translation; } ecs_unit_prefix_desc_t; /** Create a new unit prefix */ FLECS_API ecs_entity_t ecs_unit_prefix_init( ecs_world_t *world, const ecs_unit_prefix_desc_t *desc); /** Create a new quantity */ FLECS_API ecs_entity_t ecs_quantity_init( ecs_world_t *world, const ecs_entity_desc_t *desc); /* Convenience macros */ #define ecs_primitive(world, ...)\ ecs_primitive_init(world, &(ecs_primitive_desc_t) __VA_ARGS__ ) #define ecs_enum(world, ...)\ ecs_enum_init(world, &(ecs_enum_desc_t) __VA_ARGS__ ) #define ecs_bitmask(world, ...)\ ecs_bitmask_init(world, &(ecs_bitmask_desc_t) __VA_ARGS__ ) #define ecs_array(world, ...)\ ecs_array_init(world, &(ecs_array_desc_t) __VA_ARGS__ ) #define ecs_vector(world, ...)\ ecs_vector_init(world, &(ecs_vector_desc_t) __VA_ARGS__ ) #define ecs_opaque(world, ...)\ ecs_opaque_init(world, &(ecs_opaque_desc_t) __VA_ARGS__ ) #define ecs_struct(world, ...)\ ecs_struct_init(world, &(ecs_struct_desc_t) __VA_ARGS__ ) #define ecs_unit(world, ...)\ ecs_unit_init(world, &(ecs_unit_desc_t) __VA_ARGS__ ) #define ecs_unit_prefix(world, ...)\ ecs_unit_prefix_init(world, &(ecs_unit_prefix_desc_t) __VA_ARGS__ ) #define ecs_quantity(world, ...)\ ecs_quantity_init(world, &(ecs_entity_desc_t) __VA_ARGS__ ) /* Module import */ FLECS_API void FlecsMetaImport( ecs_world_t *world); #ifdef __cplusplus } #endif #endif /** @} */ #endif #endif #ifdef FLECS_EXPR #ifdef FLECS_NO_EXPR #error "FLECS_NO_EXPR failed: EXPR is required by other addons" #endif /** * @file addons/expr.h * @brief Flecs expression parser addon. * * Parse expression strings into component values. The notation is similar to * JSON but with a smaller footprint, native support for (large) integer types, * character types, enumerations, bitmasks and entity identifiers. * * Examples: * * Member names: * * {x: 10, y: 20} * * No member names (uses member ordering): * * {10, 20} * * Enum values: * * {color: Red} * * Bitmask values: * * {toppings: Lettuce|Tomato} * * Collections: * * {points: [10, 20, 30]} * * Nested objects: * * {start: {x: 10, y: 20}, stop: {x: 30, y: 40}} * */ #ifdef FLECS_EXPR #ifndef FLECS_META #define FLECS_META #endif #ifndef FLECS_PARSER #define FLECS_PARSER #endif #ifndef FLECS_EXPR_H #define FLECS_EXPR_H #ifdef __cplusplus extern "C" { #endif /** * @defgroup c_addons_expr Expr * @ingroup c_addons * Serialize/deserialize values to string. * * @{ */ /** Write an escaped character. * Write a character to an output string, insert escape character if necessary. * * @param out The string to write the character to. * @param in The input character. * @param delimiter The delimiter used (for example '"') * @return Pointer to the character after the last one written. */ FLECS_API char* ecs_chresc( char *out, char in, char delimiter); /** Parse an escaped character. * Parse a character with a potential escape sequence. * * @param in Pointer to character in input string. * @param out Output string. * @return Pointer to the character after the last one read. */ const char* ecs_chrparse( const char *in, char *out); /** Write an escaped string. * Write an input string to an output string, escape characters where necessary. * To determine the size of the output string, call the operation with a NULL * argument for 'out', and use the returned size to allocate a string that is * large enough. * * @param out Pointer to output string (must be). * @param size Maximum number of characters written to output. * @param delimiter The delimiter used (for example '"'). * @param in The input string. * @return The number of characters that (would) have been written. */ FLECS_API ecs_size_t ecs_stresc( char *out, ecs_size_t size, char delimiter, const char *in); /** Return escaped string. * Return escaped version of input string. Same as ecs_stresc(), but returns an * allocated string of the right size. * * @param delimiter The delimiter used (for example '"'). * @param in The input string. * @return Escaped string. */ FLECS_API char* ecs_astresc( char delimiter, const char *in); /** Storage for parser variables. Variables make it possible to parameterize * expression strings, and are referenced with the $ operator (e.g. $var). */ typedef struct ecs_expr_var_t { char *name; ecs_value_t value; bool owned; /* Set to false if ecs_vars_t should not take ownership of var */ } ecs_expr_var_t; typedef struct ecs_expr_var_scope_t { ecs_hashmap_t var_index; ecs_vec_t vars; struct ecs_expr_var_scope_t *parent; } ecs_expr_var_scope_t; typedef struct ecs_vars_t { ecs_world_t *world; ecs_expr_var_scope_t root; ecs_expr_var_scope_t *cur; } ecs_vars_t; /** Init variable storage */ FLECS_API void ecs_vars_init( ecs_world_t *world, ecs_vars_t *vars); /** Cleanup variable storage */ FLECS_API void ecs_vars_fini( ecs_vars_t *vars); /** Push variable scope */ FLECS_API void ecs_vars_push( ecs_vars_t *vars); /** Pop variable scope */ FLECS_API int ecs_vars_pop( ecs_vars_t *vars); /** Declare variable in current scope */ FLECS_API ecs_expr_var_t* ecs_vars_declare( ecs_vars_t *vars, const char *name, ecs_entity_t type); /** Declare variable in current scope from value. * This operation takes ownership of the value. The value pointer must be * allocated with ecs_value_new(). */ FLECS_API ecs_expr_var_t* ecs_vars_declare_w_value( ecs_vars_t *vars, const char *name, ecs_value_t *value); /** Lookup variable in scope and parent scopes */ FLECS_API ecs_expr_var_t* ecs_vars_lookup( const ecs_vars_t *vars, const char *name); /** Used with ecs_parse_expr(). */ typedef struct ecs_parse_expr_desc_t { const char *name; const char *expr; ecs_entity_t (*lookup_action)( const ecs_world_t*, const char *value, void *ctx); void *lookup_ctx; ecs_vars_t *vars; } ecs_parse_expr_desc_t; /** Parse expression into value. * This operation parses a flecs expression into the provided pointer. The * memory pointed to must be large enough to contain a value of the used type. * * If no type and pointer are provided for the value argument, the operation * will discover the type from the expression and allocate storage for the * value. The allocated value must be freed with ecs_value_free(). * * @param world The world. * @param ptr The pointer to the expression to parse. * @param value The value containing type & pointer to write to. * @param desc Configuration parameters for deserializer. * @return Pointer to the character after the last one read, or NULL if failed. */ FLECS_API const char* ecs_parse_expr( ecs_world_t *world, const char *ptr, ecs_value_t *value, const ecs_parse_expr_desc_t *desc); /** Serialize value into expression string. * This operation serializes a value of the provided type to a string. The * memory pointed to must be large enough to contain a value of the used type. * * @param world The world. * @param type The type of the value to serialize. * @param data The value to serialize. * @return String with expression, or NULL if failed. */ FLECS_API char* ecs_ptr_to_expr( const ecs_world_t *world, ecs_entity_t type, const void *data); /** Serialize value into expression buffer. * Same as ecs_ptr_to_expr(), but serializes to an ecs_strbuf_t instance. * * @param world The world. * @param type The type of the value to serialize. * @param data The value to serialize. * @param buf The strbuf to append the string to. * @return Zero if success, non-zero if failed. */ FLECS_API int ecs_ptr_to_expr_buf( const ecs_world_t *world, ecs_entity_t type, const void *data, ecs_strbuf_t *buf); /** Similar as ecs_ptr_to_expr(), but serializes values to string. * Whereas the output of ecs_ptr_to_expr() is a valid expression, the output of * ecs_ptr_to_str() is a string representation of the value. In most cases the * output of the two operations is the same, but there are some differences: * - Strings are not quoted * * @param world The world. * @param type The type of the value to serialize. * @param data The value to serialize. * @return String with result, or NULL if failed. */ FLECS_API char* ecs_ptr_to_str( const ecs_world_t *world, ecs_entity_t type, const void *data); /** Serialize value into string buffer. * Same as ecs_ptr_to_str(), but serializes to an ecs_strbuf_t instance. * * @param world The world. * @param type The type of the value to serialize. * @param data The value to serialize. * @param buf The strbuf to append the string to. * @return Zero if success, non-zero if failed. */ FLECS_API int ecs_ptr_to_str_buf( const ecs_world_t *world, ecs_entity_t type, const void *data, ecs_strbuf_t *buf); /** Serialize primitive value into string buffer. * Serializes a primitive value to an ecs_strbuf_t instance. This operation can * be reused by other serializers to avoid having to write boilerplate code that * serializes primitive values to a string. * * @param world The world. * @param kind The kind of primitive value. * @param data The value to serialize * @param buf The strbuf to append the string to. * @return Zero if success, non-zero if failed. */ FLECS_API int ecs_primitive_to_expr_buf( const ecs_world_t *world, ecs_primitive_kind_t kind, const void *data, ecs_strbuf_t *buf); /** Parse expression token. * Expression tokens can contain more characters (such as '|') than tokens * parsed by the query (term) parser. * * @param name The name of the expression (used for debug logs). * @param expr The full expression (used for debug logs). * @param ptr The pointer to the expression to parse. * @param token The buffer to write to (must have size ECS_MAX_TOKEN_SIZE) * @return Pointer to the character after the last one read, or NULL if failed. */ FLECS_API const char *ecs_parse_expr_token( const char *name, const char *expr, const char *ptr, char *token); /** Evaluate interpolated expressions in string. * This operation evaluates expressions in a string, and replaces them with * their evaluated result. Supported expression formats are: * - $variable_name * - {expression} * * The $, { and } characters can be escaped with a backslash (\). * * @param world The world. * @param str The string to evaluate. * @param vars The variables to use for evaluation. */ FLECS_API char* ecs_interpolate_string( ecs_world_t *world, const char *str, const ecs_vars_t *vars); /** Convert iterator to vars * This operation converts an iterator to a variable array. This allows for * using iterator results in expressions. The operation only converts a * single result at a time, and does not progress the iterator. * * Iterator fields with data will be made available as variables with as name * the field index (e.g. "$1"). The operation does not check if reflection data * is registered for a field type. If no reflection data is registered for the * type, using the field variable in expressions will fail. * * Field variables will only contain single elements, even if the iterator * returns component arrays. The offset parameter can be used to specify which * element in the component arrays to return. The offset parameter must be * smaller than it->count. * * The operation will create a variable for query variables that contain a * single entity. * * The operation will attempt to use existing variables. If a variable does not * yet exist, the operation will create it. If an existing variable exists with * a mismatching type, the operation will fail. * * Accessing variables after progressing the iterator or after the iterator is * destroyed will result in undefined behavior. * * If vars contains a variable that is not present in the iterator, the variable * will not be modified. * * @param it The iterator to convert to variables. * @param vars The variables to write to. * @param offset The offset to the current element. */ FLECS_API void ecs_iter_to_vars( const ecs_iter_t *it, ecs_vars_t *vars, int offset); /** @} */ #ifdef __cplusplus } #endif #endif #endif #endif #ifdef FLECS_META_C #ifdef FLECS_NO_META_C #error "FLECS_NO_META_C failed: META_C is required by other addons" #endif /** * @file addons/meta_c.h * @brief Utility macros for populating reflection data in C. */ #ifdef FLECS_META_C /** * @defgroup c_addons_meta_c Meta Utilities * @ingroup c_addons * Macro utilities to automatically insert reflection data. * * @{ */ #ifndef FLECS_META #define FLECS_META #endif #ifndef FLECS_PARSER #define FLECS_PARSER #endif #ifndef FLECS_META_C_H #define FLECS_META_C_H #ifdef __cplusplus extern "C" { #endif /* Macro that controls behavior of API. Usually set in module header. When the * macro is not defined, it defaults to IMPL. */ /* Define variables used by reflection utilities. This should only be defined * by the module itself, not by the code importing the module */ /* #define ECS_META_IMPL IMPL */ /* Don't define variables used by reflection utilities but still declare the * variable for the component id. This enables the reflection utilities to be * used for global component variables, even if no reflection is used. */ /* #define ECS_META_IMPL DECLARE */ /* Don't define variables used by reflection utilities. This generates an extern * variable for the component identifier. */ /* #define ECS_META_IMPL EXTERN */ /** Declare component with descriptor */ #define ECS_META_COMPONENT(world, name)\ ECS_COMPONENT_DEFINE(world, name);\ ecs_meta_from_desc(world, ecs_id(name),\ FLECS__##name##_kind, FLECS__##name##_desc) /** ECS_STRUCT(name, body) */ #define ECS_STRUCT(name, ...)\ ECS_META_IMPL_CALL(ECS_STRUCT_, ECS_META_IMPL, name, #__VA_ARGS__);\ ECS_STRUCT_TYPE(name, __VA_ARGS__) /** ECS_ENUM(name, body) */ #define ECS_ENUM(name, ...)\ ECS_META_IMPL_CALL(ECS_ENUM_, ECS_META_IMPL, name, #__VA_ARGS__);\ ECS_ENUM_TYPE(name, __VA_ARGS__) /** ECS_BITMASK(name, body) */ #define ECS_BITMASK(name, ...)\ ECS_META_IMPL_CALL(ECS_BITMASK_, ECS_META_IMPL, name, #__VA_ARGS__);\ ECS_ENUM_TYPE(name, __VA_ARGS__) /** Macro used to mark part of type for which no reflection data is created */ #define ECS_PRIVATE /** Populate meta information from type descriptor. */ FLECS_API int ecs_meta_from_desc( ecs_world_t *world, ecs_entity_t component, ecs_type_kind_t kind, const char *desc); /* Private API */ /* Utilities to switch between IMPL, DECLARE and EXTERN variants */ #define ECS_META_IMPL_CALL_INNER(base, impl, name, type_desc)\ base ## impl(name, type_desc) #define ECS_META_IMPL_CALL(base, impl, name, type_desc)\ ECS_META_IMPL_CALL_INNER(base, impl, name, type_desc) /* ECS_STRUCT implementation */ #define ECS_STRUCT_TYPE(name, ...)\ typedef struct __VA_ARGS__ name #define ECS_STRUCT_ECS_META_IMPL ECS_STRUCT_IMPL #define ECS_STRUCT_IMPL(name, type_desc)\ extern ECS_COMPONENT_DECLARE(name);\ static const char *FLECS__##name##_desc = type_desc;\ static ecs_type_kind_t FLECS__##name##_kind = EcsStructType;\ ECS_COMPONENT_DECLARE(name) = 0 #define ECS_STRUCT_DECLARE(name, type_desc)\ extern ECS_COMPONENT_DECLARE(name);\ ECS_COMPONENT_DECLARE(name) = 0 #define ECS_STRUCT_EXTERN(name, type_desc)\ extern ECS_COMPONENT_DECLARE(name) /* ECS_ENUM implementation */ #define ECS_ENUM_TYPE(name, ...)\ typedef enum __VA_ARGS__ name #define ECS_ENUM_ECS_META_IMPL ECS_ENUM_IMPL #define ECS_ENUM_IMPL(name, type_desc)\ extern ECS_COMPONENT_DECLARE(name);\ static const char *FLECS__##name##_desc = type_desc;\ static ecs_type_kind_t FLECS__##name##_kind = EcsEnumType;\ ECS_COMPONENT_DECLARE(name) = 0 #define ECS_ENUM_DECLARE(name, type_desc)\ extern ECS_COMPONENT_DECLARE(name);\ ECS_COMPONENT_DECLARE(name) = 0 #define ECS_ENUM_EXTERN(name, type_desc)\ extern ECS_COMPONENT_DECLARE(name) /* ECS_BITMASK implementation */ #define ECS_BITMASK_TYPE(name, ...)\ typedef enum __VA_ARGS__ name #define ECS_BITMASK_ECS_META_IMPL ECS_BITMASK_IMPL #define ECS_BITMASK_IMPL(name, type_desc)\ extern ECS_COMPONENT_DECLARE(name);\ static const char *FLECS__##name##_desc = type_desc;\ static ecs_type_kind_t FLECS__##name##_kind = EcsBitmaskType;\ ECS_COMPONENT_DECLARE(name) = 0 #define ECS_BITMASK_DECLARE(name, type_desc)\ extern ECS_COMPONENT_DECLARE(name);\ ECS_COMPONENT_DECLARE(name) = 0 #define ECS_BITMASK_EXTERN(name, type_desc)\ extern ECS_COMPONENT_DECLARE(name) #ifdef __cplusplus } #endif #endif // FLECS_META_C_H /** @} */ #endif // FLECS_META_C #endif #ifdef FLECS_PLECS #ifdef FLECS_NO_PLECS #error "FLECS_NO_PLECS failed: PLECS is required by other addons" #endif /** * @file addons/plecs.h * @brief Flecs script module. * * For script, see examples/plecs. */ #ifdef FLECS_PLECS /** * @defgroup c_addons_plecs Flecs script * @ingroup c_addons * Data definition format for loading entity data. * * @{ */ #ifndef FLECS_MODULE #define FLECS_MODULE #endif #ifndef FLECS_PARSER #define FLECS_PARSER #endif #ifndef FLECS_EXPR #define FLECS_EXPR #endif #ifndef FLECS_PLECS_H #define FLECS_PLECS_H #ifdef __cplusplus extern "C" { #endif FLECS_API extern ECS_COMPONENT_DECLARE(EcsScript); /* Script component */ typedef struct EcsScript { ecs_vec_t using_; char *script; ecs_vec_t prop_defaults; ecs_world_t *world; } EcsScript; /** Parse plecs string. * This parses a plecs string and instantiates the entities in the world. * * @param world The world. * @param name The script name (typically the file). * @param str The plecs string. * @return Zero if success, non-zero otherwise. */ FLECS_API int ecs_plecs_from_str( ecs_world_t *world, const char *name, const char *str); /** Parse plecs file. * This parses a plecs file and instantiates the entities in the world. This * operation is equivalent to loading the file contents and passing it to * ecs_plecs_from_str(). * * @param world The world. * @param filename The plecs file name. * @return Zero if success, non-zero otherwise. */ FLECS_API int ecs_plecs_from_file( ecs_world_t *world, const char *filename); /** Used with ecs_script_init() */ typedef struct ecs_script_desc_t { ecs_entity_t entity; /* Set to customize entity handle associated with script */ const char *filename; /* Set to load script from file */ const char *str; /* Set to parse script from string */ } ecs_script_desc_t; /** Load managed script. * A managed script tracks which entities it creates, and keeps those entities * synchronized when the contents of the script are updated. When the script is * updated, entities that are no longer in the new version will be deleted. * * This feature is experimental. * * @param world The world. * @param desc Script descriptor. */ FLECS_API ecs_entity_t ecs_script_init( ecs_world_t *world, const ecs_script_desc_t *desc); #define ecs_script(world, ...)\ ecs_script_init(world, &(ecs_script_desc_t) __VA_ARGS__) /** Update script with new code. * * @param world The world. * @param script The script entity. * @param instance An assembly instance (optional). * @param str The script code. * @param vars Optional preset variables for script parameterization. */ FLECS_API int ecs_script_update( ecs_world_t *world, ecs_entity_t script, ecs_entity_t instance, const char *str, ecs_vars_t *vars); /** Clear all entities associated with script. * * @param world The world. * @param script The script entity. * @param instance The script instance. */ FLECS_API void ecs_script_clear( ecs_world_t *world, ecs_entity_t script, ecs_entity_t instance); /* Module import */ FLECS_API void FlecsScriptImport( ecs_world_t *world); #ifdef __cplusplus } #endif #endif /** @} */ #endif #endif #ifdef FLECS_RULES #ifdef FLECS_NO_RULES #error "FLECS_NO_RULES failed: RULES is required by other addons" #endif /** * @file addons/rules.h * @brief Rule query engine addon. * * Rules are advanced queries that in addition to the capabilities of regular * queries and filters have the following features: * * - query for all components of an entity (vs. all entities for a component) * - query for all relationship pairs of an entity * - support for query variables that are resolved at evaluation time * - automatic traversal of transitive relationships */ #ifdef FLECS_RULES /** * @defgroup c_addons_rules Rules * @ingroup c_addons * Rules are an advanced query engine for matching against entity graphs. * * @{ */ #ifndef FLECS_RULES_H #define FLECS_RULES_H #ifdef __cplusplus extern "C" { #endif /** Convenience macro for rule creation */ #define ecs_rule(world, ...)\ ecs_rule_init(world, &(ecs_filter_desc_t) __VA_ARGS__ ) /** Create a rule. * A rule accepts the same descriptor as a filter, but has the additional * ability to use query variables. * * Query variables can be used to constrain wildcards across multiple terms to * the same entity. Regular ECS queries do this in a limited form, as querying * for Position, Velocity only returns entities that have both components. * * Query variables expand this to constrain entities that are resolved while the * query is being matched. Consider a query for all entities and the mission * they are on: * (Mission, *) * * If an entity is on multiple missions, the wildcard will match it multiple * times. Now say we want to only list combat missions. Naively we could try: * (Mission, *), CombatMission(*) * * But this doesn't work, as term 1 returns entities with missions, and term 2 * returns all combat missions for all entities. Query variables make it * possible to apply CombatMission to the found mission: * (Mission, $M), CombatMission($M) * * By using the same variable ('M') we ensure that CombatMission is applied to * the mission found in the current result. * * Variables can be used in each part of the term (predicate, subject, object). * This is a valid query: * Likes($X, $Y), Likes($Y, $X) * * This is also a valid query: * _Component, Serializable(_Component) * * In the query expression syntax, variables are prefixed with a $. When using * the descriptor, specify the variable kind: * desc.terms[0].second = { .name = "X", .var = EcsVarIsVariable } * * Different terms with the same variable name are automatically correlated by * the query engine. * * A rule needs to be explicitly deleted with ecs_rule_fini(). * * @param world The world. * @param desc The descriptor (see ecs_filter_desc_t) * @return The rule. */ FLECS_API ecs_rule_t* ecs_rule_init( ecs_world_t *world, const ecs_filter_desc_t *desc); /** Delete a rule. * * @param rule The rule. */ FLECS_API void ecs_rule_fini( ecs_rule_t *rule); /** Obtain filter from rule. * This operation returns the filter with which the rule was created. * * @param rule The rule. * @return The filter. */ FLECS_API const ecs_filter_t* ecs_rule_get_filter( const ecs_rule_t *rule); /** Return number of variables in rule. * * @param rule The rule. * @return The number of variables/ */ FLECS_API int32_t ecs_rule_var_count( const ecs_rule_t *rule); /** Find variable index. * This operation looks up the index of a variable in the rule. This index can * be used in operations like ecs_iter_set_var() and ecs_iter_get_var(). * * @param rule The rule. * @param name The variable name. * @return The variable index. */ FLECS_API int32_t ecs_rule_find_var( const ecs_rule_t *rule, const char *name); /** Get variable name. * This operation returns the variable name for an index. * * @param rule The rule. * @param var_id The variable index. */ FLECS_API const char* ecs_rule_var_name( const ecs_rule_t *rule, int32_t var_id); /** Test if variable is an entity. * Internally the rule engine has entity variables and table variables. When * iterating through rule variables (by using ecs_rule_variable_count()) only * the values for entity variables are accessible. This operation enables an * application to check if a variable is an entity variable. * * @param rule The rule. * @param var_id The variable id. */ FLECS_API bool ecs_rule_var_is_entity( const ecs_rule_t *rule, int32_t var_id); /** Iterate a rule. * Note that rule iterators may allocate memory, and that unless the iterator * is iterated until completion, it may still hold resources. When stopping * iteration before ecs_rule_next() has returned false, use ecs_iter_fini() to * cleanup any remaining resources. * * @param world The world. * @param rule The rule. * @return An iterator. */ FLECS_API ecs_iter_t ecs_rule_iter( const ecs_world_t *world, const ecs_rule_t *rule); /** Progress rule iterator. * * @param it The iterator. */ FLECS_API bool ecs_rule_next( ecs_iter_t *it); /** Progress instanced iterator. * Should not be called unless you know what you're doing :-) * * @param it The iterator. */ FLECS_API bool ecs_rule_next_instanced( ecs_iter_t *it); /** Convert rule to a string. * This will convert the rule program to a string which can aid in debugging * the behavior of a rule. * * The returned string must be freed with ecs_os_free(). * * @param rule The rule. * @return The string */ FLECS_API char* ecs_rule_str( const ecs_rule_t *rule); /** Convert rule to string with profile. * To use this you must set the EcsIterProfile flag on an iterator before * starting iteration: * it.flags |= EcsIterProfile * * @param rule The rule. * @return The string */ FLECS_API char* ecs_rule_str_w_profile( const ecs_rule_t *rule, const ecs_iter_t *it); /** Populate variables from key-value string. * Convenience function to set rule variables from a key-value string separated * by comma's. The string must have the following format: * var_a: value, var_b: value * * The key-value list may optionally be enclosed in parenthesis. * * @param rule The rule. * @param it The iterator for which to set the variables. * @param expr The key-value expression. */ FLECS_API const char* ecs_rule_parse_vars( ecs_rule_t *rule, ecs_iter_t *it, const char *expr); #ifdef __cplusplus } #endif #endif // FLECS_RULES_H /** @} */ #endif // FLECS_RULES #endif #ifdef FLECS_SNAPSHOT #ifdef FLECS_NO_SNAPSHOT #error "FLECS_NO_SNAPSHOT failed: SNAPSHOT is required by other addons" #endif /** * @file addons/snapshot.h * @brief Snapshot addon. * * A snapshot records the state of a world in a way so that it can be restored * later. Snapshots work with POD components and non-POD components, provided * that the appropriate lifecycle actions are registered for non-POD components. * * A snapshot is tightly coupled to a world. It is not possible to restore a * snapshot from world A into world B. */ #ifdef FLECS_SNAPSHOT /** * @defgroup c_addons_snapshot Snapshot * @ingroup c_addons * @brief Save & restore world. * * @{ */ #ifndef FLECS_SNAPSHOT_H #define FLECS_SNAPSHOT_H #ifdef __cplusplus extern "C" { #endif /** A snapshot stores the state of a world in a particular point in time. */ typedef struct ecs_snapshot_t ecs_snapshot_t; /** Create a snapshot. * This operation makes a copy of the current state of the world. * * @param world The world to snapshot. * @return The snapshot. */ FLECS_API ecs_snapshot_t* ecs_snapshot_take( ecs_world_t *world); /** Create a filtered snapshot. * This operation is the same as ecs_snapshot_take(), but accepts an iterator so * an application can control what is stored by the snapshot. * * @param iter An iterator to the data to be stored by the snapshot. * @return The snapshot. */ FLECS_API ecs_snapshot_t* ecs_snapshot_take_w_iter( ecs_iter_t *iter); /** Restore a snapshot. * This operation restores the world to the state it was in when the specified * snapshot was taken. A snapshot can only be used once for restoring, as its * data replaces the data that is currently in the world. * This operation also resets the last issued entity handle, so any calls to * ecs_new() may return entity ids that have been issued before restoring the * snapshot. * * The world in which the snapshot is restored must be the same as the world in * which the snapshot is taken. * * @param world The world to restore the snapshot to. * @param snapshot The snapshot to restore. */ FLECS_API void ecs_snapshot_restore( ecs_world_t *world, ecs_snapshot_t *snapshot); /** Obtain iterator to snapshot data. * * @param snapshot The snapshot to iterate over. * @return Iterator to snapshot data. */ FLECS_API ecs_iter_t ecs_snapshot_iter( ecs_snapshot_t *snapshot); /** Progress snapshot iterator. * * @param iter The snapshot iterator. * @return True if more data is available, otherwise false. */ FLECS_API bool ecs_snapshot_next( ecs_iter_t *iter); /** Free snapshot resources. * This frees resources associated with a snapshot without restoring it. * * @param snapshot The snapshot to free. */ FLECS_API void ecs_snapshot_free( ecs_snapshot_t *snapshot); #ifdef __cplusplus } #endif #endif /** @} */ #endif #endif #ifdef FLECS_PARSER #ifdef FLECS_NO_PARSER #error "FLECS_NO_PARSER failed: PARSER is required by other addons" #endif /** * @file addons/parser.h * @brief Parser addon. * * The parser addon parses string expressions into lists of terms, and can be * used to construct filters, queries and types. */ #ifdef FLECS_PARSER /** * @defgroup c_addons_parser Parser * @ingroup c_addons * Query DSL parser and parsing utilities. * * @{ */ #ifndef FLECS_PARSER_H #define FLECS_PARSER_H /** Maximum number of extra arguments in term expression */ #define ECS_PARSER_MAX_ARGS (16) #ifdef __cplusplus extern "C" { #endif /** Skip whitespace characters. * This function skips whitespace characters. Does not skip newlines. * * @param ptr Pointer to (potential) whitespaces to skip. * @return Pointer to the next non-whitespace character. */ FLECS_API const char* ecs_parse_ws( const char *ptr); /** Skip whitespace and newline characters. * This function skips whitespace characters. * * @param ptr Pointer to (potential) whitespaces to skip. * @return Pointer to the next non-whitespace character. */ FLECS_API const char* ecs_parse_ws_eol( const char *ptr); /** Utility function to parse an identifier */ const char* ecs_parse_identifier( const char *name, const char *expr, const char *ptr, char *token_out); /** Parse digit. * This function will parse until the first non-digit character is found. The * provided expression must contain at least one digit character. * * @param ptr The expression to parse. * @param token The output buffer. * @return Pointer to the first non-digit character. */ FLECS_API const char* ecs_parse_digit( const char *ptr, char *token); /** Parse a single token. * This function can be used as simple tokenizer by other parsers. * * @param name of program (used for logging). * @param expr pointer to token to parse. * @param ptr pointer to first character to parse. * @param token_out Parsed token (buffer should be ECS_MAX_TOKEN_SIZE large) * @return Pointer to the next token, or NULL if error occurred. */ FLECS_API const char* ecs_parse_token( const char *name, const char *expr, const char *ptr, char *token_out, char delim); /** Parse term in expression. * This operation parses a single term in an expression and returns a pointer * to the next term expression. * * If the returned pointer points to the 0-terminator, the expression is fully * parsed. The function would typically be called in a while loop: * * @code * const char *ptr = expr; * while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term))) { } * @endcode * * The operation does not attempt to find entity ids from the names in the * expression. Use the ecs_term_resolve_ids() function to resolve the identifiers * in the parsed term. * * The returned term will in most cases contain allocated resources, which * should freed (or used) by the application. To free the resources for a term, * use the ecs_term_free() function. * * The parser accepts expressions in the legacy string format. * * @param world The world. * @param name The name of the expression (optional, improves error logs) * @param expr The expression to parse (optional, improves error logs) * @param ptr The pointer to the current term (must be in expr). * @param term_out Out parameter for the term. * @param extra_args Out array for extra args, must be of size ECS_PARSER_MAX_ARGS. * @return pointer to next term if successful, NULL if failed. */ FLECS_API char* ecs_parse_term( const ecs_world_t *world, const char *name, const char *expr, const char *ptr, ecs_term_t *term_out, ecs_oper_kind_t *extra_oper, ecs_term_id_t *extra_args, bool allow_newline); #ifdef __cplusplus } #endif // __cplusplus #endif // FLECS_PARSER_H /** @} */ #endif // FLECS_PARSER #endif #ifdef FLECS_OS_API_IMPL #ifdef FLECS_NO_OS_API_IMPL #error "FLECS_NO_OS_API_IMPL failed: OS_API_IMPL is required by other addons" #endif /** * @file addons/os_api_impl.h * @brief Default OS API implementation. */ #ifdef FLECS_OS_API_IMPL /** * @defgroup c_addons_os_api_impl OS API Implementation * @ingroup c_addons * Default implementation for OS API interface. * * @{ */ #ifndef FLECS_OS_API_IMPL_H #define FLECS_OS_API_IMPL_H #ifdef __cplusplus extern "C" { #endif FLECS_API void ecs_set_os_api_impl(void); #ifdef __cplusplus } #endif #endif // FLECS_OS_API_IMPL_H /** @} */ #endif // FLECS_OS_API_IMPL #endif #ifdef FLECS_MODULE #ifdef FLECS_NO_MODULE #error "FLECS_NO_MODULE failed: MODULE is required by other addons" #endif /** * @file addons/module.h * @brief Module addon. * * The module addon allows for creating and importing modules. Flecs modules * enable applications to organize components and systems into reusable units of * code that can easily be across projects. */ #ifdef FLECS_MODULE /** * @defgroup c_addons_module Module * @ingroup c_addons * Modules organize components, systems and more in reusable units of code. * * @{ */ #ifndef FLECS_MODULE_H #define FLECS_MODULE_H #ifdef __cplusplus extern "C" { #endif /** Import a module. * This operation will load a modules and store the public module handles in the * handles_out out parameter. The module name will be used to verify if the * module was already loaded, in which case it won't be reimported. The name * will be translated from PascalCase to an entity path (pascal.case) before the * lookup occurs. * * Module contents will be stored as children of the module entity. This * prevents modules from accidentally defining conflicting identifiers. This is * enforced by setting the scope before and after loading the module to the * module entity id. * * A more convenient way to import a module is by using the ECS_IMPORT macro. * * @param world The world. * @param module The module import function. * @param module_name The name of the module. * @return The module entity. */ FLECS_API ecs_entity_t ecs_import( ecs_world_t *world, ecs_module_action_t module, const char *module_name); /** Same as ecs_import(), but with name to scope conversion. * PascalCase names are automatically converted to scoped names. * * @param world The world. * @param module The module import function. * @param module_name_c The name of the module. * @return The module entity. */ FLECS_API ecs_entity_t ecs_import_c( ecs_world_t *world, ecs_module_action_t module, const char *module_name_c); /** Import a module from a library. * Similar to ecs_import(), except that this operation will attempt to load the * module from a dynamic library. * * A library may contain multiple modules, which is why both a library name and * a module name need to be provided. If only a library name is provided, the * library name will be reused for the module name. * * The library will be looked up using a canonical name, which is in the same * form as a module, like `flecs.components.transform`. To transform this * identifier to a platform specific library name, the operation relies on the * module_to_dl callback of the os_api which the application has to override if * the default does not yield the correct library name. * * @param world The world. * @param library_name The name of the library to load. * @param module_name The name of the module to load. */ FLECS_API ecs_entity_t ecs_import_from_library( ecs_world_t *world, const char *library_name, const char *module_name); /** Register a new module. */ FLECS_API ecs_entity_t ecs_module_init( ecs_world_t *world, const char *c_name, const ecs_component_desc_t *desc); /** Define module. */ #define ECS_MODULE_DEFINE(world, id)\ {\ ecs_component_desc_t desc = {0};\ desc.entity = ecs_id(id);\ ecs_id(id) = ecs_module_init(world, #id, &desc);\ ecs_set_scope(world, ecs_id(id));\ } #define ECS_MODULE(world, id)\ ecs_entity_t ecs_id(id) = 0; ECS_MODULE_DEFINE(world, id)\ (void)ecs_id(id) /** Wrapper around ecs_import(). * This macro provides a convenient way to load a module with the world. It can * be used like this: * * @code * ECS_IMPORT(world, FlecsSystemsPhysics); * @endcode */ #define ECS_IMPORT(world, id) ecs_import_c(world, id##Import, #id) #ifdef __cplusplus } #endif #endif /** @} */ #endif #endif #ifdef FLECS_CPP #ifdef FLECS_NO_CPP #error "FLECS_NO_CPP failed: CPP is required by other addons" #endif /** * @file addons/flecs_cpp.h * @brief C++ utility functions * * This header contains utility functions that are accessible from both C and * C++ code. These functions are not part of the public API and are not meant * to be used directly by applications. */ #ifdef FLECS_CPP #ifndef FLECS_CPP_H #define FLECS_CPP_H #ifdef __cplusplus extern "C" { #endif // The functions in this file can be used from C or C++, but these macros are only relevant to C++. #ifdef __cplusplus #if defined(__clang__) #define ECS_FUNC_NAME_FRONT(type, name) ((sizeof(#type) + sizeof(" flecs::_::() [T = ") + sizeof(#name)) - 3u) #define ECS_FUNC_NAME_BACK (sizeof("]") - 1u) #define ECS_FUNC_NAME __PRETTY_FUNCTION__ #elif defined(__GNUC__) #define ECS_FUNC_NAME_FRONT(type, name) ((sizeof(#type) + sizeof(" flecs::_::() [with T = ") + sizeof(#name)) - 3u) #define ECS_FUNC_NAME_BACK (sizeof("]") - 1u) #define ECS_FUNC_NAME __PRETTY_FUNCTION__ #elif defined(_WIN32) #define ECS_FUNC_NAME_FRONT(type, name) ((sizeof(#type) + sizeof(" __cdecl flecs::_::<") + sizeof(#name)) - 3u) #define ECS_FUNC_NAME_BACK (sizeof(">(void)") - 1u) #define ECS_FUNC_NAME __FUNCSIG__ #else #error "implicit component registration not supported" #endif #define ECS_FUNC_TYPE_LEN(type, name, str)\ (flecs::string::length(str) - (ECS_FUNC_NAME_FRONT(type, name) + ECS_FUNC_NAME_BACK)) #endif FLECS_API char* ecs_cpp_get_type_name( char *type_name, const char *func_name, size_t len, size_t front_len); FLECS_API char* ecs_cpp_get_symbol_name( char *symbol_name, const char *type_name, size_t len); FLECS_API char* ecs_cpp_get_constant_name( char *constant_name, const char *func_name, size_t len, size_t back_len); FLECS_API const char* ecs_cpp_trim_module( ecs_world_t *world, const char *type_name); FLECS_API void ecs_cpp_component_validate( ecs_world_t *world, ecs_entity_t id, const char *name, const char *symbol, size_t size, size_t alignment, bool implicit_name); FLECS_API ecs_entity_t ecs_cpp_component_register( ecs_world_t *world, ecs_entity_t id, const char *name, const char *symbol, ecs_size_t size, ecs_size_t alignment, bool implicit_name, bool *existing_out); FLECS_API ecs_entity_t ecs_cpp_component_register_explicit( ecs_world_t *world, ecs_entity_t s_id, ecs_entity_t id, const char *name, const char *type_name, const char *symbol, size_t size, size_t alignment, bool is_component, bool *existing_out); FLECS_API void ecs_cpp_enum_init( ecs_world_t *world, ecs_entity_t id); FLECS_API ecs_entity_t ecs_cpp_enum_constant_register( ecs_world_t *world, ecs_entity_t parent, ecs_entity_t id, const char *name, int value); FLECS_API int32_t ecs_cpp_reset_count_get(void); FLECS_API int32_t ecs_cpp_reset_count_inc(void); #ifdef FLECS_META FLECS_API const ecs_member_t* ecs_cpp_last_member( const ecs_world_t *world, ecs_entity_t type); #endif #ifdef __cplusplus } #endif #endif // FLECS_CPP_H #endif // FLECS_CPP #ifdef __cplusplus /** * @file addons/cpp/flecs.hpp * @brief Flecs C++11 API. */ #pragma once // STL includes #include /** * @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 struct component; namespace _ { template struct cpp_type; template struct each_delegate; } // namespace _ } // namespace flecs // Types imported from C API /** * @file addons/cpp/c_types.hpp * @brief Aliases for types/constants from C API */ #pragma once namespace flecs { /** * @defgroup cpp_globals API Types & Globals * @ingroup cpp_core * Types & constants bridged from C API. * * @{ */ 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 Iterable = EcsIterable; using Poly = EcsPoly; using FlattenTarget = EcsFlattenTarget; /* 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 AlwaysOverride = EcsAlwaysOverride; 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; static const flecs::entity_t Trait = EcsTrait; static const flecs::entity_t Relationship = EcsRelationship; static const flecs::entity_t Target = EcsTarget; /* 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; /** @} */ } // C++ utilities /** * @file addons/cpp/utils/utils.hpp * @brief Flecs STL (FTL?) * * Flecs STL (FTL?) * Minimalistic utilities that allow for STL like functionality without having * to depend on the actual STL. */ // Macros so that C++ new calls can allocate using ecs_os_api memory allocation functions // Rationale: // - Using macros here instead of a templated function bc clients might override ecs_os_malloc // to contain extra debug info like source tracking location. Using a template function // in that scenario would collapse all source location into said function vs. the // actual call site // - FLECS_PLACEMENT_NEW(): exists to remove any naked new calls/make it easy to identify any regressions // by grepping for new/delete #define FLECS_PLACEMENT_NEW(_ptr, _type) ::new(flecs::_::placement_new_tag, _ptr) _type #define FLECS_NEW(_type) FLECS_PLACEMENT_NEW(ecs_os_malloc(sizeof(_type)), _type) #define FLECS_DELETE(_ptr) \ do { \ if (_ptr) { \ flecs::_::destruct_obj(_ptr); \ ecs_os_free(_ptr); \ } \ } while (false) /* Faster (compile time) alternatives to std::move / std::forward. From: * https://www.foonathan.net/2020/09/move-forward/ */ #define FLECS_MOV(...) \ static_cast&&>(__VA_ARGS__) #define FLECS_FWD(...) \ static_cast(__VA_ARGS__) namespace flecs { namespace _ { // Dummy Placement new tag to disambiguate from any other operator new overrides struct placement_new_tag_t{}; constexpr placement_new_tag_t placement_new_tag{}; template inline void destruct_obj(Ty* _ptr) { _ptr->~Ty(); } template inline void free_obj(Ty* _ptr) { if (_ptr) { destruct_obj(_ptr); ecs_os_free(_ptr); } } } // namespace _ } // namespace flecs // Allows overriding flecs_static_assert, which is useful when testing #ifndef flecs_static_assert #define flecs_static_assert(cond, str) static_assert(cond, str) #endif inline void* operator new(size_t, flecs::_::placement_new_tag_t, void* _ptr) noexcept { return _ptr; } inline void operator delete(void*, flecs::_::placement_new_tag_t, void*) noexcept { } namespace flecs { // C++11/C++14 convenience template replacements template using conditional_t = typename std::conditional::type; template using decay_t = typename std::decay::type; template using enable_if_t = typename std::enable_if::type; template using remove_pointer_t = typename std::remove_pointer::type; template using remove_reference_t = typename std::remove_reference::type; template using underlying_type_t = typename std::underlying_type::type; using std::is_base_of; using std::is_empty; using std::is_const; using std::is_pointer; using std::is_reference; using std::is_volatile; using std::is_same; using std::is_enum; // Determine constness even if T is a pointer type template using is_const_p = is_const< remove_pointer_t >; // Apply cv modifiers from source type to destination type // (from: https://stackoverflow.com/questions/52559336/add-const-to-type-if-template-arg-is-const) template using transcribe_const_t = conditional_t::value, Dst const, Dst>; template using transcribe_volatile_t = conditional_t::value, Dst volatile, Dst>; template using transcribe_cv_t = transcribe_const_t< Src, transcribe_volatile_t< Src, Dst> >; template using transcribe_pointer_t = conditional_t::value, Dst*, Dst>; template using transcribe_cvp_t = transcribe_cv_t< Src, transcribe_pointer_t< Src, Dst> >; // More convenience templates. The if_*_t templates use int as default type // instead of void. This enables writing code that's a bit less cluttered when // the templates are used in a template declaration: // // enable_if_t* = nullptr // vs: // if_t = 0 template using if_t = enable_if_t; template using if_not_t = enable_if_t; namespace _ { // Utility to prevent static assert from immediately triggering template struct always_false { static const bool value = false; }; } // namespace _ } // namespace flecs #include /** * @file addons/cpp/utils/array.hpp * @brief Array class. * * Array class. Simple std::array like utility that is mostly there to aid * template code where template expansion would lead to an array with size 0. */ namespace flecs { template struct array_iterator { explicit array_iterator(T* value, int index) { m_value = value; m_index = index; } bool operator!=(array_iterator const& other) const { return m_index != other.m_index; } T & operator*() const { return m_value[m_index]; } array_iterator& operator++() { ++m_index; return *this; } private: T* m_value; int m_index; }; template struct array final { }; template struct array > final { array() {}; array(const T (&elems)[Size]) { int i = 0; for (auto it = this->begin(); it != this->end(); ++ it) { *it = elems[i ++]; } } T& operator[](int index) { return m_array[index]; } T& operator[](size_t index) { return m_array[index]; } array_iterator begin() { return array_iterator(m_array, 0); } array_iterator end() { return array_iterator(m_array, Size); } size_t size() { return Size; } T* ptr() { return m_array; } template void each(const Func& func) { for (auto& elem : *this) { func(elem); } } private: T m_array[Size]; }; template array to_array(const T (&elems)[Size]) { return array(elems); } // Specialized class for zero-sized array template struct array> final { array() {}; array(const T* (&elems)) { (void)elems; } T operator[](size_t index) { ecs_os_abort(); (void)index; return T(); } array_iterator begin() { return array_iterator(nullptr, 0); } array_iterator end() { return array_iterator(nullptr, 0); } size_t size() { return 0; } T* ptr() { return NULL; } }; } /** * @file addons/cpp/utils/string.hpp * @brief String utility that doesn't implicitly allocate memory. */ namespace flecs { struct string_view; // This removes dependencies on std::string (and therefore STL) and allows the // API to return allocated strings without incurring additional allocations when // wrapping in an std::string. struct string { explicit string() : m_str(nullptr) , m_const_str("") , m_length(0) { } explicit string(char *str) : m_str(str) , m_const_str(str ? str : "") , m_length(str ? ecs_os_strlen(str) : 0) { } ~string() { // If flecs is included in a binary but is not used, it is possible that // the OS API is not initialized. Calling ecs_os_free in that case could // crash the application during exit. However, if a string has been set // flecs has been used, and OS API should have been initialized. if (m_str) { ecs_os_free(m_str); } } string(string&& str) noexcept { ecs_os_free(m_str); m_str = str.m_str; m_const_str = str.m_const_str; m_length = str.m_length; str.m_str = nullptr; } operator const char*() const { return m_const_str; } string& operator=(string&& str) noexcept { ecs_os_free(m_str); m_str = str.m_str; m_const_str = str.m_const_str; m_length = str.m_length; str.m_str = nullptr; return *this; } // Ban implicit copies/allocations string& operator=(const string& str) = delete; string(const string& str) = delete; bool operator==(const flecs::string& str) const { if (str.m_const_str == m_const_str) { return true; } if (!m_const_str || !str.m_const_str) { return false; } if (str.m_length != m_length) { return false; } return ecs_os_strcmp(str, m_const_str) == 0; } bool operator!=(const flecs::string& str) const { return !(*this == str); } bool operator==(const char *str) const { if (m_const_str == str) { return true; } if (!m_const_str || !str) { return false; } return ecs_os_strcmp(str, m_const_str) == 0; } bool operator!=(const char *str) const { return !(*this == str); } const char* c_str() const { return m_const_str; } std::size_t length() const { return static_cast(m_length); } template static constexpr size_t length( char const (&)[N] ) { return N - 1; } std::size_t size() const { return length(); } void clear() { ecs_os_free(m_str); m_str = nullptr; m_const_str = nullptr; } bool contains(const char *substr) { if (m_const_str) { return strstr(m_const_str, substr) != nullptr; } else { return false; } } protected: // Must be constructed through string_view. This allows for using the string // class for both owned and non-owned strings, which can reduce allocations // when code conditionally should store a literal or an owned string. // Making this constructor private forces the code to explicitly create a // string_view which emphasizes that the string won't be freed by the class. string(const char *str) : m_str(nullptr) , m_const_str(str ? str : "") , m_length(str ? ecs_os_strlen(str) : 0) { } char *m_str = nullptr; const char *m_const_str; ecs_size_t m_length; }; // For consistency, the API returns a string_view where it could have returned // a const char*, so an application won't have to think about whether to call // c_str() or not. The string_view is a thin wrapper around a string that forces // the API to indicate explicitly when a string is owned or not. struct string_view : string { explicit string_view(const char *str) : string(str) { } }; } /** * @file addons/cpp/utils/enum.hpp * @brief Compile time enum reflection utilities. * * Discover at compile time valid enumeration constants for an enumeration type * and their names. This is used to automatically register enum constants. */ #include #include #define FLECS_ENUM_MAX(T) _::to_constant::value #define FLECS_ENUM_MAX_COUNT (FLECS_ENUM_MAX(int) + 1) #ifndef FLECS_CPP_ENUM_REFLECTION_SUPPORT #if !defined(__clang__) && defined(__GNUC__) #if __GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ >= 5) #define FLECS_CPP_ENUM_REFLECTION_SUPPORT 1 #else #define FLECS_CPP_ENUM_REFLECTION_SUPPORT 0 #endif #else #define FLECS_CPP_ENUM_REFLECTION_SUPPORT 1 #endif #endif namespace flecs { /** Int to enum */ namespace _ { template Value> struct to_constant { #if defined(__clang__) && __clang_major__ >= 16 // https://reviews.llvm.org/D130058, https://reviews.llvm.org/D131307 static constexpr E value = __builtin_bit_cast(E, Value); #else static constexpr E value = static_cast(Value); #endif }; template Value> constexpr E to_constant::value; } /** Convenience type with enum reflection data */ template struct enum_data; template static enum_data enum_type(flecs::world_t *world); template struct enum_last { static constexpr E value = FLECS_ENUM_MAX(E); }; /* Utility macro to override enum_last trait */ #define FLECS_ENUM_LAST(T, Last)\ namespace flecs {\ template<>\ struct enum_last {\ static constexpr T value = Last;\ };\ } namespace _ { #if INTPTR_MAX == INT64_MAX #ifdef ECS_TARGET_MSVC #if _MSC_VER >= 1929 #define ECS_SIZE_T_STR "unsigned __int64" #else #define ECS_SIZE_T_STR "unsigned int" #endif #elif defined(__clang__) #define ECS_SIZE_T_STR "size_t" #else #ifdef ECS_TARGET_WINDOWS #define ECS_SIZE_T_STR "constexpr size_t; size_t = long long unsigned int" #else #define ECS_SIZE_T_STR "constexpr size_t; size_t = long unsigned int" #endif #endif #else #ifdef ECS_TARGET_MSVC #if _MSC_VER >= 1929 #define ECS_SIZE_T_STR "unsigned __int32" #else #define ECS_SIZE_T_STR "unsigned int" #endif #elif defined(__clang__) #define ECS_SIZE_T_STR "size_t" #else #ifdef ECS_TARGET_WINDOWS #define ECS_SIZE_T_STR "constexpr size_t; size_t = unsigned int" #else #define ECS_SIZE_T_STR "constexpr size_t; size_t = unsigned int" #endif #endif #endif template constexpr size_t enum_type_len() { return ECS_FUNC_TYPE_LEN(, enum_type_len, ECS_FUNC_NAME) - (sizeof(ECS_SIZE_T_STR) - 1u); } /** Test if value is valid for enumeration. * This function leverages that when a valid value is provided, * __PRETTY_FUNCTION__ contains the enumeration name, whereas if a value is * invalid, the string contains a number or a negative (-) symbol. */ #if defined(ECS_TARGET_CLANG) #if ECS_CLANG_VERSION < 13 template constexpr bool enum_constant_is_valid() { return !(( (ECS_FUNC_NAME[ECS_FUNC_NAME_FRONT(bool, enum_constant_is_valid) + enum_type_len() + 6 /* ', C = ' */] >= '0') && (ECS_FUNC_NAME[ECS_FUNC_NAME_FRONT(bool, enum_constant_is_valid) + enum_type_len() + 6 /* ', C = ' */] <= '9')) || (ECS_FUNC_NAME[ECS_FUNC_NAME_FRONT(bool, enum_constant_is_valid) + enum_type_len() + 6 /* ', C = ' */] == '-')); } #else template constexpr bool enum_constant_is_valid() { return (ECS_FUNC_NAME[ECS_FUNC_NAME_FRONT(bool, enum_constant_is_valid) + enum_type_len() + 6 /* ', E C = ' */] != '('); } #endif #elif defined(ECS_TARGET_GNU) template constexpr bool enum_constant_is_valid() { return (ECS_FUNC_NAME[ECS_FUNC_NAME_FRONT(constexpr bool, enum_constant_is_valid) + enum_type_len() + 8 /* ', E C = ' */] != '('); } #else /* Use different trick on MSVC, since it uses hexadecimal representation for * invalid enum constants. We can leverage that msvc inserts a C-style cast * into the name, and the location of its first character ('(') is known. */ template constexpr bool enum_constant_is_valid() { return ECS_FUNC_NAME[ECS_FUNC_NAME_FRONT(bool, enum_constant_is_valid) + enum_type_len() + 1] != '('; } #endif template struct enum_is_valid { static constexpr bool value = enum_constant_is_valid(); }; /** Extract name of constant from string */ template static const char* enum_constant_to_name() { static const size_t len = ECS_FUNC_TYPE_LEN(const char*, enum_constant_to_name, ECS_FUNC_NAME); static char result[len + 1] = {}; return ecs_cpp_get_constant_name( result, ECS_FUNC_NAME, string::length(ECS_FUNC_NAME), ECS_FUNC_NAME_BACK); } /** Enumeration constant data */ template struct enum_constant_data { flecs::entity_t id; T offset; }; /** * @brief Provides utilities for enum reflection. * * This struct provides static functions for enum reflection, including conversion * between enum values and their underlying integral types, and iteration over enum * values. * * @tparam E The enum type. * @tparam Handler The handler for enum reflection operations. */ template class Handler> struct enum_reflection { template static constexpr underlying_type_t to_int() { return static_cast>(Value); } template Value> static constexpr E from_int() { return to_constant::value; } template static constexpr underlying_type_t is_not_0() { return static_cast>(Value != from_int<0>()); } /** * @brief Iterates over the range [Low, High] of enum values between Low and High. * * Recursively divide and conquers the search space to reduce the template-depth. Once * recursive division is complete, calls Handle::handle_constant in ascending order, * passing the values computed up the chain. * * @tparam Low The lower bound of the search range, inclusive. * @tparam High The upper bound of the search range, inclusive. * @tparam Args Additional arguments to be passed through to Handler::handle_constant * @param last_value The last value processed in the iteration. * @param args Additional arguments to be passed through to Handler::handle_constant * @return constexpr underlying_type_t The result of the iteration. */ template static constexpr underlying_type_t each_enum_range(underlying_type_t last_value, Args... args) { return to_int() - to_int() <= 1 ? to_int() == to_int() ? Handler::template handle_constant(last_value, args...) : Handler::template handle_constant(Handler::template handle_constant(last_value, args...), args...) : each_enum_range()+to_int()) / 2 + 1>(), High>( each_enum_range()+to_int()) / 2>()>(last_value, args...), args... ); } /** * @brief Iterates over the mask range (Low, High] of enum values between Low and High. * * Recursively iterates the search space, looking for enums defined as multiple-of-2 * bitmasks. Each iteration, shifts bit to the right until it hits Low, then calls * Handler::handle_constant for each bitmask in ascending order. * * @tparam Low The lower bound of the search range, not inclusive * @tparam High The upper bound of the search range, inclusive. * @tparam Args Additional arguments to be passed through to Handler::handle_constant * @param last_value The last value processed in the iteration. * @param args Additional arguments to be passed through to Handler::handle_constant * @return constexpr underlying_type_t The result of the iteration. */ template static constexpr underlying_type_t each_mask_range(underlying_type_t last_value, Args... args) { // If Low shares any bits with Current Flag, or if High is less than/equal to Low (and High isn't negative because max-flag signed) return (to_int() & to_int()) || (to_int() <= to_int() && to_int() != high_bit) ? last_value : Handler::template handle_constant( each_mask_range() >> 1) & ~high_bit)>()>(last_value, args...), args... ); } /** * @brief Handles enum iteration for gathering reflection data. * * Iterates over all enum values up to a specified maximum value * (each_enum_range<0, Value>), then iterates the rest of the possible bitmasks * (each_mask_range). * * @tparam Value The maximum enum value to iterate up to. * @tparam Args Additional arguments to be passed through to Handler::handle_constant * @param args Additional arguments to be passed through to Handler::handle_constant * @return constexpr underlying_type_t The result of the iteration. */ template static constexpr underlying_type_t each_enum(Args... args) { return each_mask_range()>(each_enum_range(), Value>(0, args...), args...); } static const underlying_type_t high_bit = static_cast>(1) << (sizeof(underlying_type_t) * 8 - 1); }; /** Enumeration type data */ template struct enum_data_impl { private: /** * @brief Handler struct for generating compile-time count of enum constants. */ template struct reflection_count { template () > = 0> static constexpr underlying_type_t handle_constant(underlying_type_t last_value) { return last_value; } template () > = 0> static constexpr underlying_type_t handle_constant(underlying_type_t last_value) { return 1 + last_value; } }; public: flecs::entity_t id; int min; int max; bool has_contiguous; // If enum constants start not-sparse, contiguous_until will be the index of the first sparse value, or end of the constants array underlying_type_t contiguous_until; // Compile-time generated count of enum constants. static constexpr unsigned int constants_size = enum_reflection::template each_enum< enum_last::value >(); // Constants array is sized to the number of found-constants, or 1 (to avoid 0-sized array) enum_constant_data> constants[constants_size? constants_size: 1]; }; /** Class that scans an enum for constants, extracts names & creates entities */ template struct enum_type { private: /** * @brief Helper struct for filling enum_type's static `enum_data_impl` member with reflection data. * * Because reflection occurs in-order, we can use current value/last value to determine continuity, and * use that as a lookup heuristic later on. * * @tparam Enum The enum type. */ template struct reflection_init { template () > = 0> static underlying_type_t handle_constant(underlying_type_t last_value, flecs::world_t*) { // Search for constant failed. Pass last valid value through. return last_value; } template () > = 0> static underlying_type_t handle_constant(underlying_type_t last_value, flecs::world_t *world) { // Constant is valid, so fill reflection data. auto v = enum_reflection::template to_int(); const char *name = enum_constant_to_name(); ++enum_type::data.max; // Increment cursor as we build constants array. // If the enum was previously contiguous, and continues to be through the current value... if (enum_type::data.has_contiguous && static_cast>(enum_type::data.max) == v && enum_type::data.contiguous_until == v) { ++enum_type::data.contiguous_until; } // else, if the enum was never contiguous and hasn't been set as not contiguous... else if (!enum_type::data.contiguous_until && enum_type::data.has_contiguous) { enum_type::data.has_contiguous = false; } ecs_assert(!(last_value > 0 && v < std::numeric_limits>::min() + last_value), ECS_UNSUPPORTED, "Signed integer enums causes integer overflow when recording offset from high positive to" " low negative. Consider using unsigned integers as underlying type."); enum_type::data.constants[enum_type::data.max].offset = v - last_value; enum_type::data.constants[enum_type::data.max].id = ecs_cpp_enum_constant_register( world, enum_type::data.id, 0, name, static_cast(v)); return v; } }; public: static enum_data_impl data; static enum_type& get() { static _::enum_type instance; return instance; } flecs::entity_t entity(E value) const { int index = index_by_value(value); if (index >= 0) { return data.constants[index].id; } return 0; } void init(flecs::world_t *world, flecs::entity_t id) { #if !FLECS_CPP_ENUM_REFLECTION_SUPPORT ecs_abort(ECS_UNSUPPORTED, "enum reflection requires gcc 7.5 or higher") #endif // Initialize/reset reflection data values to default state. data.min = 0; data.max = -1; data.has_contiguous = true; data.contiguous_until = 0; ecs_log_push(); ecs_cpp_enum_init(world, id); data.id = id; // Generate reflection data enum_reflection::template each_enum< enum_last::value >(world); ecs_log_pop(); } }; template enum_data_impl enum_type::data; template ::value > = 0> inline static void init_enum(flecs::world_t *world, flecs::entity_t id) { _::enum_type::get().init(world, id); } template ::value > = 0> inline static void init_enum(flecs::world_t*, flecs::entity_t) { } } // namespace _ /** Enumeration type data wrapper with world pointer */ template struct enum_data { enum_data(flecs::world_t *world, _::enum_data_impl& impl) : world_(world) , impl_(impl) { } /** * @brief Checks if a given integral value is a valid enum value. * * @param value The integral value. * @return true If the value is a valid enum value. * @return false If the value is not a valid enum value. */ bool is_valid(underlying_type_t value) { int index = index_by_value(value); if (index < 0) { return false; } return impl_.constants[index].id != 0; } /** * @brief Checks if a given enum value is valid. * * @param value The enum value. * @return true If the value is valid. * @return false If the value is not valid. */ bool is_valid(E value) { return is_valid(static_cast>(value)); } /** * @brief Finds the index into the constants array for a value, if one exists * * @param value The enum value. * @return int The index of the enum value. */ int index_by_value(underlying_type_t value) const { if (!impl_.max) { return -1; } // Check if value is in contiguous lookup section if (impl_.has_contiguous && value < impl_.contiguous_until && value >= 0) { return static_cast(value); } underlying_type_t accumulator = impl_.contiguous_until? impl_.contiguous_until - 1: 0; for (int i = static_cast(impl_.contiguous_until); i <= impl_.max; ++i) { accumulator += impl_.constants[i].offset; if (accumulator == value) { return i; } } return -1; } /** * @brief Finds the index into the constants array for an enum value, if one exists * * @param value The enum value. * @return int The index of the enum value. */ int index_by_value(E value) const { return index_by_value(static_cast>(value)); } int first() const { return impl_.min; } int last() const { return impl_.max; } int next(int cur) const { return cur + 1; } flecs::entity entity() const; flecs::entity entity(underlying_type_t value) const; flecs::entity entity(E value) const; flecs::world_t *world_; _::enum_data_impl& impl_; }; /** Convenience function for getting enum reflection data */ template enum_data enum_type(flecs::world_t *world) { _::cpp_type::id(world); // Ensure enum is registered auto& ref = _::enum_type::get(); return enum_data(world, ref.data); } } // namespace flecs /** * @file addons/cpp/utils/stringstream.hpp * @brief Wrapper around ecs_strbuf_t that provides a simple stringstream like API. */ namespace flecs { struct stringstream { explicit stringstream() : m_buf({}) { } ~stringstream() { ecs_strbuf_reset(&m_buf); } stringstream(stringstream&& str) noexcept { ecs_strbuf_reset(&m_buf); m_buf = str.m_buf; str.m_buf = {}; } stringstream& operator=(stringstream&& str) noexcept { ecs_strbuf_reset(&m_buf); m_buf = str.m_buf; str.m_buf = {}; return *this; } // Ban implicit copies/allocations stringstream& operator=(const stringstream& str) = delete; stringstream(const stringstream& str) = delete; stringstream& operator<<(const char* str) { ecs_strbuf_appendstr(&m_buf, str); return *this; } flecs::string str() { return flecs::string(ecs_strbuf_get(&m_buf)); } private: ecs_strbuf_t m_buf; }; } /** * @file addons/cpp/utils/function_traits.hpp * @brief Compile time utilities to inspect properties of functions. * * Code from: https://stackoverflow.com/questions/27024238/c-template-mechanism-to-get-the-number-of-function-arguments-which-would-work */ namespace flecs { namespace _ { template struct arg_list { }; // Base type that contains the traits template struct function_traits_defs { static constexpr bool is_callable = true; static constexpr size_t arity = sizeof...(Args); using return_type = ReturnType; using args = arg_list; }; // Primary template for function_traits_impl template struct function_traits_impl { static constexpr bool is_callable = false; }; // Template specializations for the different kinds of function types (whew) template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; // Primary template for function_traits_no_cv. If T is not a function, the // compiler will attempt to instantiate this template and fail, because its base // is undefined. template struct function_traits_no_cv : function_traits_impl {}; // Specialized template for function types template struct function_traits_no_cv : function_traits_impl {}; // Front facing template that decays T before ripping it apart. template struct function_traits : function_traits_no_cv< decay_t > {}; } // _ template struct is_callable { static constexpr bool value = _::function_traits::is_callable; }; template struct arity { static constexpr int value = _::function_traits::arity; }; template using return_type_t = typename _::function_traits::return_type; template using arg_list_t = typename _::function_traits::args; // First arg template struct first_arg_impl; template struct first_arg_impl > { using type = T; }; template struct first_arg { using type = typename first_arg_impl>::type; }; template using first_arg_t = typename first_arg::type; // Last arg template struct second_arg_impl; template struct second_arg_impl > { using type = T; }; template struct second_arg { using type = typename second_arg_impl>::type; }; template using second_arg_t = typename second_arg::type; } // flecs // Mixin forward declarations /** * @file addons/cpp/mixins/id/decl.hpp * @brief Id class. */ #pragma once namespace flecs { struct id; struct entity; /** * @defgroup cpp_ids Ids * @ingroup cpp_core * Class for working with entity, component, tag and pair ids. * * @{ */ /** 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; }; /** @} */ } /** * @file addons/cpp/mixins/term/decl.hpp * @brief Term declarations. */ #pragma once namespace flecs { /** * @ingroup cpp_core_filters * * @{ */ struct term; struct term_builder; /** @} */ } /** * @file addons/cpp/mixins/filter/decl.hpp * @brief Filter declarations. */ #pragma once namespace flecs { /** * @defgroup cpp_core_filters Filters * @ingroup cpp_core * Filters are cheaper to create, but slower to iterate than flecs::query. * * @{ */ struct filter_base; template struct filter; template struct filter_builder; /** @} */ } /** * @file addons/cpp/mixins/event/decl.hpp * @brief Event declarations. */ #pragma once /** * @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 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 Base& id() { m_ids.array = m_ids_array; m_ids.array[m_ids.count] = _::cpp_type().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 Base& id() { return id( ecs_pair(_::cpp_type::id(this->m_world), _::cpp_type::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 Base& id(entity_t second) { return id(ecs_pair(_::cpp_type::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.const_param = ptr; return *this; } /* Set event data */ Base& ctx(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(ecs_get_world(m_world)); ecs_emit(m_world, &m_desc); } void enqueue() { m_ids.array = m_ids_array; m_desc.ids = &m_ids; m_desc.observable = const_cast(ecs_get_world(m_world)); ecs_enqueue(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(this); } }; struct event_builder : event_builder_base { using event_builder_base::event_builder_base; }; template struct event_builder_typed : event_builder_base, E> { private: using Class = event_builder_typed; public: using event_builder_base::event_builder_base; /* Set event data */ Class& ctx(const E& ptr) { this->m_desc.const_param = &ptr; return *this; } /* Set event data */ Class& ctx(E&& ptr) { this->m_desc.param = &ptr; return *this; } }; /** @} */ } namespace flecs { namespace _ { // Utility to derive event type from function template struct event_from_func; // Specialization for observer callbacks with a single argument template struct event_from_func::value == 1>> { using type = decay_t>; }; // Specialization for observer callbacks with an initial entity src argument template struct event_from_func::value == 2>> { using type = decay_t>; }; template using event_from_func_t = typename event_from_func::type; } } /** * @file addons/cpp/mixins/query/decl.hpp * @brief Query declarations. */ #pragma once namespace flecs { /** * @defgroup cpp_core_queries Queries * @ingroup cpp_core * Cached query implementation. Fast to iterate, but slower to create than flecs::filter. * * @{ */ struct query_base; template struct query; template struct query_builder; /** @} */ } /** * @file addons/cpp/mixins/observer/decl.hpp * @brief Observer declarations. */ #pragma once namespace flecs { /** * @defgroup cpp_observers Observers * @ingroup cpp_core * Observers let applications register callbacks for ECS events. * * @{ */ struct observer; template struct observer_builder; /** @} */ } #ifdef FLECS_SYSTEM /** * @file addons/cpp/mixins/system/decl.hpp * @brief System module declarations. */ #pragma once namespace flecs { /** * @defgroup cpp_addons_systems Systems * @ingroup cpp_addons * Systems are a query + function that can be ran manually or by a pipeline. * * @{ */ using TickSource = EcsTickSource; struct system; template struct system_builder; namespace _ { void system_init(flecs::world& world); /** @} */ } // namespace _ } // namespace flecs #endif #ifdef FLECS_PIPELINE /** * @file addons/cpp/mixins/pipeline/decl.hpp * @brief Pipeline module declarations. */ #pragma once namespace flecs { /** * @defgroup cpp_pipelines Pipelines * @ingroup cpp_addons * Pipelines order and schedule systems for execution. * * @{ */ template struct pipeline; template 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; /** @} */ } #endif #ifdef FLECS_TIMER /** * @file addons/cpp/mixins/timer/decl.hpp * @brief Timer module declarations. */ #pragma once namespace flecs { /** * @defgroup cpp_addons_timer Timer * @ingroup cpp_addons * Run systems at a time interval. * * @{ */ using Timer = EcsTimer; using RateFilter = EcsRateFilter; struct timer; /** @} */ namespace _ { void timer_init(flecs::world& world); } // namespace _ } // namespace flecs #endif #ifdef FLECS_SNAPSHOT /** * @file addons/cpp/mixins/snapshot/decl.hpp * @brief Snapshot module declarations. */ #pragma once namespace flecs { /** * @defgroup cpp_addons_snapshots Snapshots * @ingroup cpp_addons * Save & restore world. * * @{ */ using snapshot_t = ecs_snapshot_t; struct snapshot; /** @} */ } #endif #ifdef FLECS_DOC /** * @file addons/cpp/mixins/doc/decl.hpp * @brief Doc mixin declarations. */ #pragma once namespace flecs { namespace doc { /** * @defgroup cpp_addons_doc Doc * @ingroup cpp_addons * Utilities for documenting entities, components and systems. * * @{ */ /** 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; /** @private */ namespace _ { /** @private */ void init(flecs::world& world); } /** @} */ } } #endif #ifdef FLECS_REST /** * @file addons/cpp/mixins/rest/decl.hpp * @brief Rest module declarations. */ #pragma once namespace flecs { /** * @defgroup cpp_addons_rest Rest * @ingroup cpp_addons * REST API for querying and mutating entities. * * @{ */ using Rest = EcsRest; namespace rest { namespace _ { void init(flecs::world& world); } } /** @} */ } #endif #ifdef FLECS_RULES /** * @file addons/cpp/mixins/rule/decl.hpp * @brief Rule declarations. */ #pragma once namespace flecs { /** * @defgroup cpp_addons_rules Rules * @ingroup cpp_addons * Rules are an advanced query engine for matching against entity graphs. * * @{ */ struct rule_base; template struct rule; template struct rule_builder; /** @} */ } #endif #ifdef FLECS_META /** * @file addons/cpp/mixins/meta/decl.hpp * @brief Meta declarations. */ #pragma once namespace flecs { /** * @defgroup cpp_addons_meta Meta * @ingroup cpp_addons * Flecs reflection framework. * * @{ */ /* 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 /** * @file addons/cpp/mixins/meta/opaque.hpp * @brief Helpers for opaque type registration. */ #pragma once namespace flecs { /** * @defgroup cpp_addons_meta Meta * @ingroup cpp_addons * Flecs reflection framework. * * @{ */ /** 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 (component) id value */ int set_id(flecs::id_t value) { return ecs_meta_set_id(&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; }; /** @} */ } /** * @file addons/cpp/mixins/meta/opaque.hpp * @brief Helpers for opaque type registration. */ #pragma once #include namespace flecs { /** * @defgroup cpp_addons_meta Meta * @ingroup cpp_addons * Flecs reflection framework. * * @{ */ /** 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 using serialize = int(*)(const serializer *, const T*); /** Type safe interface for opaque types */ template struct opaque { opaque(flecs::world_t *w = nullptr) : world(w) { if (world) { desc.entity = _::cpp_type::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 func) { this->desc.type.serialize = reinterpret_castdesc.type.serialize)>(func); return *this; } /** Assign bool value */ opaque& assign_bool(void (*func)(T *dst, bool value)) { this->desc.type.assign_bool = reinterpret_castdesc.type.assign_bool)>(func); return *this; } /** Assign char value */ opaque& assign_char(void (*func)(T *dst, char value)) { this->desc.type.assign_char = reinterpret_castdesc.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_castdesc.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_castdesc.type.assign_uint)>(func); return *this; } /** Assign float value */ opaque& assign_float(void (*func)(T *dst, double value)) { this->desc.type.assign_float = reinterpret_castdesc.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_castdesc.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_castdesc.type.assign_entity)>(func); return *this; } /** Assign (component) id value */ opaque& assign_id( void (*func)(T *dst, ecs_world_t *world, ecs_id_t id)) { this->desc.type.assign_id = reinterpret_castdesc.type.assign_id)>(func); return *this; } /** Assign null value */ opaque& assign_null(void (*func)(T *dst)) { this->desc.type.assign_null = reinterpret_castdesc.type.assign_null)>(func); return *this; } /** Clear collection elements */ opaque& clear(void (*func)(T *dst)) { this->desc.type.clear = reinterpret_castdesc.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_castdesc.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_castdesc.type.ensure_member)>(func); return *this; } /** Return number of elements */ opaque& count(size_t (*func)(const T *dst)) { this->desc.type.count = reinterpret_castdesc.type.count)>(func); return *this; } /** Resize to number of elements */ opaque& resize(void (*func)(T *dst, size_t count)) { this->desc.type.resize = reinterpret_castdesc.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 = {}; }; /** @} */ } #endif #ifdef FLECS_UNITS /** * @file addons/cpp/mixins/units/decl.hpp * @brief Units module declarations. */ #pragma once namespace flecs { struct units { /** * @defgroup cpp_addons_units Units * @ingroup cpp_addons * Common unit annotations for reflection framework. * * @{ */ struct Prefixes { }; /** * @defgroup cpp_addons_units_prefixes Prefixes * @ingroup cpp_addons_units * Prefixes to indicate unit count (e.g. Kilo, Mega) * * @{ */ struct Yocto { }; struct Zepto { }; struct Atto { }; struct Femto { }; struct Pico { }; struct Nano { }; struct Micro { }; struct Milli { }; struct Centi { }; struct Deci { }; struct Deca { }; struct Hecto { }; struct Kilo { }; struct Mega { }; struct Giga { }; struct Tera { }; struct Peta { }; struct Exa { }; struct Zetta { }; struct Yotta { }; struct Kibi { }; struct Mebi { }; struct Gibi { }; struct Tebi { }; struct Pebi { }; struct Exbi { }; struct Zebi { }; struct Yobi { }; /** @} */ /** * @defgroup cpp_addons_units_quantities Quantities * @ingroup cpp_addons_units * Quantities that group units (e.g. Length) * * @{ */ struct Duration { }; struct Time { }; struct Mass { }; struct ElectricCurrent { }; struct LuminousIntensity { }; struct Force { }; struct Amount { }; struct Length { }; struct Pressure { }; struct Speed { }; struct Temperature { }; struct Data { }; struct DataRate { }; struct Angle { }; struct Frequency { }; struct Uri { }; /** @} */ struct duration { /** * @defgroup cpp_addons_units_duration Duration * @ingroup cpp_addons_units * @{ */ struct PicoSeconds { }; struct NanoSeconds { }; struct MicroSeconds { }; struct MilliSeconds { }; struct Seconds { }; struct Minutes { }; struct Hours { }; struct Days { }; /** @} */ }; struct angle { /** * @defgroup cpp_addons_units_angle Angle * @ingroup cpp_addons_units * @{ */ struct Radians { }; struct Degrees { }; /** @} */ }; struct time { /** * @defgroup cpp_addons_units_time Time * @ingroup cpp_addons_units * @{ */ struct Date { }; /** @} */ }; struct mass { /** * @defgroup cpp_addons_units_mass Mass * @ingroup cpp_addons_units * @{ */ struct Grams { }; struct KiloGrams { }; /** @} */ }; struct electric_current { /** * @defgroup cpp_addons_units_electric_current Electric Current * @ingroup cpp_addons_units * @{ */ struct Ampere { }; /** @} */ }; struct amount { /** * @defgroup cpp_addons_units_amount Amount * @ingroup cpp_addons_units * @{ */ struct Mole { }; /** @} */ }; struct luminous_intensity { /** * @defgroup cpp_addons_units_luminous_intensity Luminous Intensity * @ingroup cpp_addons_units * @{ */ struct Candela { }; /** @} */ }; struct force { /** * @defgroup cpp_addons_units_force Force * @ingroup cpp_addons_units * @{ */ struct Newton { }; /** @} */ }; struct length { /** * @defgroup cpp_addons_units_length Length * @ingroup cpp_addons_units * @{ */ struct Meters { }; struct PicoMeters { }; struct NanoMeters { }; struct MicroMeters { }; struct MilliMeters { }; struct CentiMeters { }; struct KiloMeters { }; struct Miles { }; struct Pixels { }; /** @} */ }; struct pressure { /** * @defgroup cpp_addons_units_pressure Pressure * @ingroup cpp_addons_units * @{ */ struct Pascal { }; struct Bar { }; /** @} */ }; struct speed { /** * @defgroup cpp_addons_units_speed Speed * @ingroup cpp_addons_units * @{ */ struct MetersPerSecond { }; struct KiloMetersPerSecond { }; struct KiloMetersPerHour { }; struct MilesPerHour { }; /** @} */ }; struct temperature { /** * @defgroup cpp_addons_units_temperature Temperature * @ingroup cpp_addons_units * @{ */ struct Kelvin { }; struct Celsius { }; struct Fahrenheit { }; /** @} */ }; struct data { /** * @defgroup cpp_addons_units_data Data * @ingroup cpp_addons_units * @{ */ struct Bits { }; struct KiloBits { }; struct MegaBits { }; struct GigaBits { }; struct Bytes { }; struct KiloBytes { }; struct MegaBytes { }; struct GigaBytes { }; struct KibiBytes { }; struct MebiBytes { }; struct GibiBytes { }; /** @} */ }; struct datarate { /** * @defgroup cpp_addons_units_datarate Data Rate * @ingroup cpp_addons_units * @{ */ struct BitsPerSecond { }; struct KiloBitsPerSecond { }; struct MegaBitsPerSecond { }; struct GigaBitsPerSecond { }; struct BytesPerSecond { }; struct KiloBytesPerSecond { }; struct MegaBytesPerSecond { }; struct GigaBytesPerSecond { }; /** @} */ }; struct frequency { /** * @defgroup cpp_addons_units_frequency Frequency * @ingroup cpp_addons_units * @{ */ struct Hertz { }; struct KiloHertz { }; struct MegaHertz { }; struct GigaHertz { }; /** @} */ }; struct uri { /** * @defgroup cpp_addons_units_uri Uri * @ingroup cpp_addons_units * @{ */ struct Hyperlink { }; struct Image { }; struct File { }; /** @} */ }; struct Percentage { }; struct Bel { }; struct DeciBel { }; units(flecs::world& world); /** @} */ }; } #endif #ifdef FLECS_MONITOR /** * @file addons/cpp/mixins/monitor/decl.hpp * @brief Monitor module declarations. */ #pragma once namespace flecs { /** * @defgroup cpp_addons_monitor Monitor * @ingroup cpp_addons * The monitor addon periodically tracks statistics for the world and systems. * * @{ */ /** Component that stores world statistics */ using WorldStats = EcsWorldStats; /** Component that stores system/pipeline statistics */ using PipelineStats = EcsPipelineStats; /** Component with world summary stats */ using WorldSummary = EcsWorldSummary; struct monitor { monitor(flecs::world& world); }; /** @} */ } #endif #ifdef FLECS_METRICS /** * @file addons/cpp/mixins/metrics/decl.hpp * @brief Metrics declarations. */ #pragma once /** * @file addons/cpp/mixins/metrics/builder.hpp * @brief Metric builder. */ #pragma once #define ECS_EVENT_DESC_ID_COUNT_MAX (8) namespace flecs { /** * @ingroup cpp_addons_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 metric_builder& member(const char *name); metric_builder& dotmember(const char *name); template 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 metric_builder& id() { return id(_::cpp_type::id(m_world)); } template metric_builder& id(flecs::entity_t second) { return id(_::cpp_type::id(m_world), second); } template metric_builder& id_second(flecs::entity_t first) { return id(first, _::cpp_type::id(m_world)); } template metric_builder& id() { return id(_::cpp_type::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 metric_builder& kind() { return kind(_::cpp_type::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; }; /** * @} */ } namespace flecs { /** * @defgroup cpp_addons_metrics Metrics * @ingroup cpp_addons * The metrics module extracts metrics from components and makes them available * through a unified component interface. * * @{ */ struct metrics { using Value = EcsMetricValue; using Source = EcsMetricSource; struct Instance { }; struct Metric { }; struct Counter { }; struct CounterIncrement { }; struct CounterId { }; struct Gauge { }; metrics(flecs::world& world); }; /** @} */ } #endif #ifdef FLECS_ALERTS /** * @file addons/cpp/mixins/alerts/decl.hpp * @brief Alert declarations. */ #pragma once namespace flecs { /** * @defgroup cpp_addons_alerts Alerts * @ingroup cpp_addons * Alert implementation. * * @{ */ /** Module */ struct alerts { using AlertsActive = EcsAlertsActive; using Instance = EcsAlertInstance; struct Alert { }; struct Info { }; struct Warning { }; struct Error { }; alerts(flecs::world& world); }; template struct alert; template struct alert_builder; /** @} */ } #endif #ifdef FLECS_JSON /** * @file addons/cpp/mixins/json/decl.hpp * @brief JSON addon declarations. */ #pragma once namespace flecs { /** * @defgroup cpp_addons_json Json * @ingroup cpp_addons * Functions for serializing to/from JSON. * * @{ */ 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; /** @} */ } #endif #ifdef FLECS_APP /** * @file addons/cpp/mixins/app/decl.hpp * @brief App addon declarations. */ #pragma once /** * @file addons/cpp/mixins/app/builder.hpp * @brief App builder. */ #pragma once namespace flecs { /** * @defgroup cpp_addons_app App * @ingroup cpp_addons * Optional addon for running the main application loop. * * @{ */ /** 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; }; /** @} */ } #endif /** * @file addons/cpp/log.hpp * @brief Logging functions. */ #pragma once namespace flecs { namespace log { /** * @defgroup cpp_log Logging * @ingroup cpp_addons * Logging functions. * * @{ */ /** Set log level */ inline void set_level(int level) { ecs_log_set_level(level); } inline int get_level() { 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(); } /** @} */ } } /** * @file addons/cpp/pair.hpp * @brief Utilities for working with compile time pairs. */ #pragma once namespace flecs { namespace _ { struct pair_base { }; } // _ /** * @defgroup cpp_pair_type Pair type * @ingroup cpp_core * Compile time utilities for working with relationship pairs. * * @{ */ /** Type that represents a pair. * The pair type can be used to represent a pair at compile time, and is able * to automatically derive the storage type associated with the pair, accessible * through pair::type. * * The storage type is derived using the following rules: * - if pair::first is non-empty, the storage type is pair::first * - if pair::first is empty and pair::second is non-empty, the storage type is pair::second * * The pair type can hold a temporary value so that it can be used in the * signatures of queries */ template struct pair : _::pair_base { using type = conditional_t::value || is_empty::value, First, Second>; using first = First; using second = Second; pair(type& v) : ref_(v) { } // This allows the class to be used as a temporary object pair(const type& v) : ref_(const_cast(v)) { } operator type&() { return ref_; } operator const type&() const { return ref_; } type* operator->() { return &ref_; } const type* operator->() const { return &ref_; } type& operator*() { return ref_; } const type& operator*() const { return ref_; } private: type& ref_; }; template ::value> = 0> using pair_object = pair; template using raw_type_t = remove_pointer_t>; /** Test if type is a pair. */ template struct is_pair { static constexpr bool value = is_base_of<_::pair_base, raw_type_t >::value; }; /** Get pair::first from pair while preserving cv qualifiers. */ template using pair_first_t = transcribe_cv_t, typename raw_type_t

::first>; /** Get pair::second from pair while preserving cv qualifiers. */ template using pair_second_t = transcribe_cv_t, typename raw_type_t

::second>; /** Get pair::type type from pair while preserving cv qualifiers and pointer type. */ template using pair_type_t = transcribe_cvp_t, typename raw_type_t

::type>; /** Get actual type from a regular type or pair. */ template struct actual_type; template struct actual_type::value >> { using type = T; }; template struct actual_type::value >> { using type = pair_type_t; }; template using actual_type_t = typename actual_type::type; // Get type without const, *, & template struct base_type { using type = decay_t< actual_type_t >; }; template using base_type_t = typename base_type::type; // Get type without *, & (retains const which is useful for function args) template struct base_arg_type { using type = remove_pointer_t< remove_reference_t< actual_type_t > >; }; template using base_arg_type_t = typename base_arg_type::type; // Test if type is the same as its actual type template struct is_actual { static constexpr bool value = std::is_same >::value && !is_enum::value; }; } // flecs /** * @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 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(ptr); for (int i = 0; i < count; i ++) { FLECS_PLACEMENT_NEW(&arr[i], T); } } // ~T() template 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(ptr); for (int i = 0; i < count; i ++) { arr[i].~T(); } } // T& operator=(const T&) template 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(dst_ptr); const T *src_arr = static_cast(src_ptr); for (int i = 0; i < count; i ++) { dst_arr[i] = src_arr[i]; } } // T& operator=(T&&) template 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(dst_ptr); T *src_arr = static_cast(src_ptr); for (int i = 0; i < count; i ++) { dst_arr[i] = FLECS_MOV(src_arr[i]); } } // T(T&) template 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(dst_ptr); const T *src_arr = static_cast(src_ptr); for (int i = 0; i < count; i ++) { FLECS_PLACEMENT_NEW(&dst_arr[i], T(src_arr[i])); } } // T(T&&) template 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(dst_ptr); T *src_arr = static_cast(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 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(dst_ptr); T *src_arr = static_cast(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 assignment) // Typically used when moving a component to a deleted component template ::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(dst_ptr); T *src_arr = static_cast(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 assignment) // Typically used when moving a component to a deleted component template ::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(dst_ptr); T *src_arr = static_cast(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 struct is_flecs_constructible { static constexpr bool value = std::is_default_constructible>::value; }; namespace _ { // Trivially constructible template ::value > = 0> ecs_xtor_t ctor() { return nullptr; } // Not constructible by flecs template ::value > = 0> ecs_xtor_t ctor() { return ecs_ctor_illegal; } // Default constructible template ::value && std::is_default_constructible::value > = 0> ecs_xtor_t ctor() { return ctor_impl; } // No dtor template ::value > = 0> ecs_xtor_t dtor() { return nullptr; } // Dtor template ::value && ! std::is_trivially_destructible::value > = 0> ecs_xtor_t dtor() { return dtor_impl; } // Assert when the type cannot be destructed template ::value > = 0> ecs_xtor_t dtor() { flecs_static_assert(always_false::value, "component type must be destructible"); return ecs_dtor_illegal; } // Trivially copyable template ::value > = 0> ecs_copy_t copy() { return nullptr; } // Not copyable template ::value && ! std::is_copy_assignable::value > = 0> ecs_copy_t copy() { return ecs_copy_illegal; } // Copy assignment template ::value && ! std::is_trivially_copyable::value > = 0> ecs_copy_t copy() { return copy_impl; } // Trivially move assignable template ::value > = 0> ecs_move_t move() { return nullptr; } // Component types must be move assignable template ::value > = 0> ecs_move_t move() { flecs_static_assert(always_false::value, "component type must be move assignable"); return ecs_move_illegal; } // Move assignment template ::value && ! std::is_trivially_move_assignable::value > = 0> ecs_move_t move() { return move_impl; } // Trivially copy constructible template ::value > = 0> ecs_copy_t copy_ctor() { return nullptr; } // No copy ctor template ::value > = 0> ecs_copy_t copy_ctor() { return ecs_copy_ctor_illegal; } // Copy ctor template ::value && ! std::is_trivially_copy_constructible::value > = 0> ecs_copy_t copy_ctor() { return copy_ctor_impl; } // Trivially move constructible template ::value > = 0> ecs_move_t move_ctor() { return nullptr; } // Component types must be move constructible template ::value > = 0> ecs_move_t move_ctor() { flecs_static_assert(always_false::value, "component type must be move constructible"); return ecs_move_ctor_illegal; } // Move ctor template ::value && ! std::is_trivially_move_constructible::value > = 0> ecs_move_t move_ctor() { return move_ctor_impl; } // Trivial merge (move assign + dtor) template ::value && std::is_trivially_destructible::value > = 0> ecs_move_t ctor_move_dtor() { return nullptr; } // Component types must be move constructible and destructible template ::value || ! std::is_destructible::value > = 0> ecs_move_t ctor_move_dtor() { flecs_static_assert(always_false::value, "component type must be move constructible and destructible"); return ecs_move_ctor_illegal; } // Merge ctor + dtor template ::value && std::is_trivially_destructible::value) && std::is_move_constructible::value && std::is_destructible::value > = 0> ecs_move_t ctor_move_dtor() { return ctor_move_dtor_impl; } // Trivial merge (move assign + dtor) template ::value && std::is_trivially_destructible::value > = 0> ecs_move_t move_dtor() { return nullptr; } // Component types must be move constructible and destructible template ::value || ! std::is_destructible::value > = 0> ecs_move_t move_dtor() { flecs_static_assert(always_false::value, "component type must be move constructible and destructible"); return ecs_move_ctor_illegal; } // Merge assign + dtor template ::value && std::is_trivially_destructible::value) && std::is_move_assignable::value && std::is_destructible::value > = 0> ecs_move_t move_dtor() { return move_dtor_impl; } } // _ } // flecs /** * @file addons/cpp/ref.hpp * @brief Class that caches data to speedup get operations. */ #pragma once namespace flecs { /** * @defgroup cpp_ref Refs * @ingroup cpp_core * Refs are a fast mechanism for referring to a specific entity/component. * * @{ */ /** Component reference. * Reference to a component from a specific entity. */ template struct ref { ref() : m_world(nullptr), m_ref{} { } ref(world_t *world, entity_t entity, flecs::id_t id = 0) : m_ref() { // the world we were called with may be a stage; convert it to a world // here if that is the case m_world = world ? const_cast(ecs_get_world(world)) : nullptr; if (!id) { id = _::cpp_type::id(world); } ecs_assert(_::cpp_type::size() != 0, ECS_INVALID_PARAMETER, NULL); m_ref = ecs_ref_init_id(m_world, entity, id); } T* operator->() { T* result = static_cast(ecs_ref_get_id( m_world, &m_ref, this->m_ref.id)); ecs_assert(result != NULL, ECS_INVALID_PARAMETER, NULL); return result; } T* get() { return static_cast(ecs_ref_get_id( m_world, &m_ref, this->m_ref.id)); } T* try_get() { if (!m_world || !m_ref.entity) { return nullptr; } return get(); } flecs::entity entity() const; private: world_t *m_world; flecs::ref_t m_ref; }; /** @} */ } /** * @file addons/cpp/world.hpp * @brief World class. */ #pragma once namespace flecs { /* Static helper functions to assign a component value */ // set(T&&), T = constructible template ::value > = 0> inline void set(world_t *world, flecs::entity_t entity, T&& value, flecs::id_t id) { ecs_assert(_::cpp_type::size() != 0, ECS_INVALID_PARAMETER, NULL); if (!ecs_is_deferred(world)) { T& dst = *static_cast(ecs_ensure_id(world, entity, id)); dst = FLECS_MOV(value); ecs_modified_id(world, entity, id); } else { T& dst = *static_cast(ecs_ensure_modified_id(world, entity, id)); dst = FLECS_MOV(value); } } // set(const T&), T = constructible template ::value > = 0> inline void set(world_t *world, flecs::entity_t entity, const T& value, flecs::id_t id) { ecs_assert(_::cpp_type::size() != 0, ECS_INVALID_PARAMETER, NULL); if (!ecs_is_deferred(world)) { T& dst = *static_cast(ecs_ensure_id(world, entity, id)); dst = FLECS_MOV(value); ecs_modified_id(world, entity, id); } else { T& dst = *static_cast(ecs_ensure_modified_id(world, entity, id)); dst = FLECS_MOV(value); } } // set(T&&), T = not constructible template ::value > = 0> inline void set(world_t *world, flecs::entity_t entity, T&& value, flecs::id_t id) { ecs_assert(_::cpp_type::size() != 0, ECS_INVALID_PARAMETER, NULL); if (!ecs_is_deferred(world)) { T& dst = *static_cast*>(ecs_ensure_id(world, entity, id)); dst = FLECS_MOV(value); ecs_modified_id(world, entity, id); } else { T& dst = *static_cast*>(ecs_ensure_modified_id(world, entity, id)); dst = FLECS_MOV(value); } } // set(const T&), T = not constructible template ::value > = 0> inline void set(world_t *world, flecs::entity_t entity, const T& value, flecs::id_t id) { ecs_assert(_::cpp_type::size() != 0, ECS_INVALID_PARAMETER, NULL); if (!ecs_is_deferred(world)) { T& dst = *static_cast*>(ecs_ensure_id(world, entity, id)); dst = FLECS_MOV(value); ecs_modified_id(world, entity, id); } else { T& dst = *static_cast*>(ecs_ensure_modified_id(world, entity, id)); dst = FLECS_MOV(value); } } // emplace for T(Args...) template , Args...>::value || std::is_default_constructible>::value > = 0> inline void emplace(world_t *world, flecs::entity_t entity, flecs::id_t id, Args&&... args) { ecs_assert(_::cpp_type::size() != 0, ECS_INVALID_PARAMETER, NULL); T& dst = *static_cast(ecs_emplace_id(world, entity, id)); FLECS_PLACEMENT_NEW(&dst, T{FLECS_FWD(args)...}); ecs_modified_id(world, entity, id); } // set(T&&) template inline void set(world_t *world, entity_t entity, A&& value) { id_t id = _::cpp_type::id(world); flecs::set(world, entity, FLECS_FWD(value), id); } // set(const T&) template inline void set(world_t *world, entity_t entity, const A& value) { id_t id = _::cpp_type::id(world); flecs::set(world, entity, value, id); } /** Return id without generation. * * @see ecs_strip_generation */ inline flecs::id_t strip_generation(flecs::entity_t e) { return ecs_strip_generation(e); } /** Return entity generation. */ inline uint32_t get_generation(flecs::entity_t e) { return ECS_GENERATION(e); } struct scoped_world; /** * @defgroup cpp_world World * @ingroup cpp_core * World operations. * * @{ */ /** The world. * The world is the container of all ECS data and systems. If the world is * deleted, all data in the world will be deleted as well. */ struct world { /** Create world. */ explicit world() : m_world( ecs_init() ) , m_owned( true ) { init_builtin_components(); } /** Create world with command line arguments. * Currently command line arguments are not interpreted, but they may be * used in the future to configure Flecs parameters. */ explicit world(int argc, char *argv[]) : m_world( ecs_init_w_args(argc, argv) ) , m_owned( true ) { init_builtin_components(); } /** Create world from C world. */ explicit world(world_t *w) : m_world( w ) , m_owned( false ) { } /** Not allowed to copy a world. May only take a reference. */ world(const world& obj) = delete; world(world&& obj) noexcept { m_world = obj.m_world; m_owned = obj.m_owned; obj.m_world = nullptr; obj.m_owned = false; } /* Implicit conversion to world_t* */ operator world_t*() const { return m_world; } /** Not allowed to copy a world. May only take a reference. */ world& operator=(const world& obj) = delete; world& operator=(world&& obj) noexcept { this->~world(); m_world = obj.m_world; m_owned = obj.m_owned; obj.m_world = nullptr; obj.m_owned = false; return *this; } ~world() { if (m_owned && ecs_stage_is_async(m_world)) { ecs_async_stage_free(m_world); } else if (m_owned && m_world) { ecs_fini(m_world); } } /** Deletes and recreates the world. */ void reset() { // Can only reset the world if we own the world object. ecs_assert(this->m_owned, ECS_INVALID_OPERATION, NULL); ecs_fini(m_world); m_world = ecs_init(); } /** Obtain pointer to C world object. */ world_t* c_ptr() const { return m_world; } /** Signal application should quit. * After calling this operation, the next call to progress() returns false. */ void quit() const { ecs_quit(m_world); } /** Register action to be executed when world is destroyed. */ void atfini(ecs_fini_action_t action, void *ctx = nullptr) const { ecs_atfini(m_world, action, ctx); } /** Test if quit() has been called. */ bool should_quit() const { return ecs_should_quit(m_world); } /** Begin frame. * When an application does not use progress() to control the main loop, it * can still use Flecs features such as FPS limiting and time measurements. * This operation needs to be invoked whenever a new frame is about to get * processed. * * Calls to frame_begin must always be followed by frame_end. * * The function accepts a delta_time parameter, which will get passed to * systems. This value is also used to compute the amount of time the * function needs to sleep to ensure it does not exceed the target_fps, when * it is set. When 0 is provided for delta_time, the time will be measured. * * This function should only be ran from the main thread. * * @param delta_time Time elapsed since the last frame. * @return The provided delta_time, or measured time if 0 was provided. */ ecs_ftime_t frame_begin(float delta_time = 0) const { return ecs_frame_begin(m_world, delta_time); } /** End frame. * This operation must be called at the end of the frame, and always after * ecs_frame_begin. * * This function should only be ran from the main thread. */ void frame_end() const { ecs_frame_end(m_world); } /** Begin readonly mode. * * @see ecs_readonly_begin * * @return Whether world is currently staged. */ bool readonly_begin(bool multi_threaded = false) const { return ecs_readonly_begin(m_world, multi_threaded); } /** End readonly mode. * * @see ecs_readonly_end */ void readonly_end() const { ecs_readonly_end(m_world); } /** Defer operations until end of frame. * When this operation is invoked while iterating, operations inbetween the * defer_begin and defer_end operations are executed at the end of the frame. * * This operation is thread safe. */ bool defer_begin() const { return ecs_defer_begin(m_world); } /** End block of operations to defer. * See defer_begin. * * This operation is thread safe. */ bool defer_end() const { return ecs_defer_end(m_world); } /** Test whether deferring is enabled. */ bool is_deferred() const { return ecs_is_deferred(m_world); } /** Configure world to have N stages. * This initializes N stages, which allows applications to defer operations to * multiple isolated defer queues. This is typically used for applications with * multiple threads, where each thread gets its own queue, and commands are * merged when threads are synchronized. * * Note that set_threads() already creates the appropriate number of stages. * The set_stage_count() operation is useful for applications that want to manage * their own stages and/or threads. * * @param stages The number of stages. */ void set_stage_count(int32_t stages) const { ecs_set_stage_count(m_world, stages); } /** Get number of configured stages. * Return number of stages set by set_stage_count. * * @return The number of stages used for threading. */ int32_t get_stage_count() const { return ecs_get_stage_count(m_world); } /** Get current stage id. * The stage id can be used by an application to learn about which stage it * is using, which typically corresponds with the worker thread id. * * @return The stage id. */ int32_t get_stage_id() const { return ecs_get_stage_id(m_world); } /** Test if is a stage. * If this function returns false, it is guaranteed that this is a valid * world object. * * @return True if the world is a stage, false if not. */ bool is_stage() const { ecs_assert( ecs_poly_is(m_world, ecs_world_t) || ecs_poly_is(m_world, ecs_stage_t), ECS_INVALID_PARAMETER, NULL); return ecs_poly_is(m_world, ecs_stage_t); } /** Enable/disable auto-merging for world or stage. * When auto-merging is enabled, staged data will automatically be merged * with the world when staging ends. This happens at the end of progress(), * at a sync point or when readonly_end() is called. * * Applications can exercise more control over when data from a stage is * merged by disabling auto-merging. This requires an application to * explicitly call merge() on the stage. * * When this function is invoked on the world, it sets all current stages to * the provided value and sets the default for new stages. When this * function is invoked on a stage, auto-merging is only set for that specific * stage. * * @param automerge Whether to enable or disable auto-merging. */ void set_automerge(bool automerge) const { ecs_set_automerge(m_world, automerge); } /** Merge world or stage. * When automatic merging is disabled, an application can call this * operation on either an individual stage, or on the world which will merge * all stages. This operation may only be called when staging is not enabled * (either after progress() or after readonly_end()). * * This operation may be called on an already merged stage or world. */ void merge() const { ecs_merge(m_world); } /** Get stage-specific world pointer. * Flecs threads can safely invoke the API as long as they have a private * context to write to, also referred to as the stage. This function returns a * pointer to a stage, disguised as a world pointer. * * Note that this function does not(!) create a new world. It simply wraps the * existing world in a thread-specific context, which the API knows how to * unwrap. The reason the stage is returned as an ecs_world_t is so that it * can be passed transparently to the existing API functions, vs. having to * create a dediated API for threading. * * @param stage_id The index of the stage to retrieve. * @return A thread-specific pointer to the world. */ flecs::world get_stage(int32_t stage_id) const { return flecs::world(ecs_get_stage(m_world, stage_id)); } /** Create asynchronous stage. * An asynchronous stage can be used to asynchronously queue operations for * later merging with the world. An asynchronous stage is similar to a regular * stage, except that it does not allow reading from the world. * * Asynchronous stages are never merged automatically, and must therefore be * manually merged with the ecs_merge function. It is not necessary to call * defer_begin or defer_end before and after enqueuing commands, as an * asynchronous stage unconditionally defers operations. * * The application must ensure that no commands are added to the stage while the * stage is being merged. * * An asynchronous stage must be cleaned up by ecs_async_stage_free. * * @return The stage. */ flecs::world async_stage() const { auto result = flecs::world(ecs_async_stage_new(m_world)); result.m_owned = true; return result; } /** Get actual world. * If the current object points to a stage, this operation will return the * actual world. * * @return The actual world. */ flecs::world get_world() const { /* Safe cast, mutability is checked */ return flecs::world( m_world ? const_cast(ecs_get_world(m_world)) : nullptr); } /** Test whether the current world object is readonly. * This function allows the code to test whether the currently used world * object is readonly or whether it allows for writing. * * @return True if the world or stage is readonly. */ bool is_readonly() const { return ecs_stage_is_readonly(m_world); } /** Set world context. * Set a context value that can be accessed by anyone that has a reference * to the world. * * @param ctx The world context. */ void set_ctx(void* ctx, ecs_ctx_free_t ctx_free = nullptr) const { ecs_set_ctx(m_world, ctx, ctx_free); } /** Get world context. * * @return The configured world context. */ void* get_ctx() const { return ecs_get_ctx(m_world); } /** Set world binding context. * Set a context value that can be accessed by anyone that has a reference * to the world. * * @param ctx The world context. */ void set_binding_ctx(void* ctx, ecs_ctx_free_t ctx_free = nullptr) const { ecs_set_binding_ctx(m_world, ctx, ctx_free); } /** Get world binding context. * * @return The configured world context. */ void* get_binding_ctx() const { return ecs_get_binding_ctx(m_world); } /** Preallocate memory for number of entities. * This function preallocates memory for the entity index. * * @param entity_count Number of entities to preallocate memory for. */ void dim(int32_t entity_count) const { ecs_dim(m_world, entity_count); } /** Set entity range. * This function limits the range of issued entity ids between min and max. * * @param min Minimum entity id issued. * @param max Maximum entity id issued. */ void set_entity_range(entity_t min, entity_t max) const { ecs_set_entity_range(m_world, min, max); } /** Enforce that operations cannot modify entities outside of range. * This function ensures that only entities within the specified range can * be modified. Use this function if specific parts of the code only are * allowed to modify a certain set of entities, as could be the case for * networked applications. * * @param enabled True if range check should be enabled, false if not. */ void enable_range_check(bool enabled) const { ecs_enable_range_check(m_world, enabled); } /** Set current scope. * * @param scope The scope to set. * @return The current scope; * @see ecs_set_scope */ flecs::entity set_scope(const flecs::entity_t scope) const; /** Get current scope. * * @return The current scope. * * @see ecs_get_scope */ flecs::entity get_scope() const; /** Same as set_scope but with type. * * @see ecs_set_scope */ template flecs::entity set_scope() const; /** Set search path. * @see ecs_set_lookup_path */ flecs::entity_t* set_lookup_path(const flecs::entity_t *search_path) const { return ecs_set_lookup_path(m_world, search_path); } /** Lookup entity by name. * * @param name Entity name. * @param search_path When false, only the current scope is searched. * @result The entity if found, or 0 if not found. */ flecs::entity lookup(const char *name, bool search_path = true) const; /** Set singleton component. */ template ::value > = 0> void set(const T& value) const { flecs::set(m_world, _::cpp_type::id(m_world), value); } /** Set singleton component. */ template ::value > = 0> void set(T&& value) const { flecs::set(m_world, _::cpp_type::id(m_world), FLECS_FWD(value)); } /** Set singleton pair. */ template , typename A = actual_type_t

, if_not_t< flecs::is_pair::value> = 0> void set(const A& value) const { flecs::set

(m_world, _::cpp_type::id(m_world), value); } /** Set singleton pair. */ template , typename A = actual_type_t

, if_not_t< flecs::is_pair::value> = 0> void set(A&& value) const { flecs::set

(m_world, _::cpp_type::id(m_world), FLECS_FWD(value)); } /** Set singleton pair. */ template void set(Second second, const First& value) const; /** Set singleton pair. */ template void set(Second second, First&& value) const; /** Set singleton component inside a callback. */ template ::value > = 0 > void set(const Func& func) const; template void emplace(Args&&... args) const { flecs::id_t component_id = _::cpp_type::id(m_world); flecs::emplace(m_world, component_id, component_id, FLECS_FWD(args)...); } /** Ensure singleton component. */ #ifndef ensure template T& ensure() const; #endif /** Mark singleton component as modified. */ template void modified() const; /** Get ref singleton component. */ template ref get_ref() const; /** Get singleton component. */ template const T* get() const; /** Get singleton pair. */ template , typename A = actual_type_t

> const A* get() const; /** Get singleton pair. */ template const First* get(Second second) const; /** Get singleton component inside a callback. */ template ::value > = 0 > void get(const Func& func) const; /** Get mutable singleton component. */ template T* get_mut() const; /** Get mutable singleton pair. */ template , typename A = actual_type_t

> A* get_mut() const; /** Get mutable singleton pair. */ template First* get_mut(Second second) const; /** Test if world has singleton component. */ template bool has() const; /** Test if world has the provided pair. * * @tparam First The first element of the pair * @tparam Second The second element of the pair */ template bool has() const; /** Test if world has the provided pair. * * @tparam First The first element of the pair * @param second The second element of the pair. */ template bool has(flecs::id_t second) const; /** Test if world has the provided pair. * * @param first The first element of the pair * @param second The second element of the pair */ bool has(flecs::id_t first, flecs::id_t second) const; /** Add singleton component. */ template void add() const; /** Adds a pair to the singleton component. * * @tparam First The first element of the pair * @tparam Second The second element of the pair */ template void add() const; /** Adds a pair to the singleton component. * * @tparam First The first element of the pair * @param second The second element of the pair. */ template void add(flecs::entity_t second) const; /** Adds a pair to the singleton entity. * * @param first The first element of the pair * @param second The second element of the pair */ void add(flecs::entity_t first, flecs::entity_t second) const; /** Remove singleton component. */ template void remove() const; /** Removes the pair singleton component. * * @tparam First The first element of the pair * @tparam Second The second element of the pair */ template void remove() const; /** Removes the pair singleton component. * * @tparam First The first element of the pair * @param second The second element of the pair. */ template void remove(flecs::entity_t second) const; /** Removes the pair singleton component. * * @param first The first element of the pair * @param second The second element of the pair */ void remove(flecs::entity_t first, flecs::entity_t second) const; /** Iterate entities in root of world * Accepts a callback with the following signature: * * @code * void(*)(flecs::entity e); * @endcode */ template void children(Func&& f) const; /** Get singleton entity for type. */ template flecs::entity singleton() const; /** Get target for a given pair from a singleton entity. * 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 flecs::entity target(int32_t index = 0) const; /** Get target for a given pair from a singleton entity. * 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). */ template flecs::entity target(flecs::entity_t first, int32_t index = 0) const; /** Get target for a given pair from a singleton entity. * 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; /** Create alias for component. * * @tparam T to create an alias for. * @param alias Alias for the component. * @return Entity representing the component. */ template flecs::entity use(const char *alias = nullptr) const; /** Create alias for entity. * * @param name Name of the entity. * @param alias Alias for the entity. */ flecs::entity use(const char *name, const char *alias = nullptr) const; /** Create alias for entity. * * @param entity Entity for which to create the alias. * @param alias Alias for the entity. */ void use(flecs::entity entity, const char *alias = nullptr) const; /** Count entities matching a component. * * @param component_id The component id. */ int count(flecs::id_t component_id) const { return ecs_count_id(m_world, component_id); } /** Count entities matching a pair. * * @param first The first element of the pair. * @param second The second element of the pair. */ int count(flecs::entity_t first, flecs::entity_t second) const { return ecs_count_id(m_world, ecs_pair(first, second)); } /** Count entities matching a component. * * @tparam T The component type. */ template int count() const { return count(_::cpp_type::id(m_world)); } /** Count entities matching a pair. * * @tparam First The first element of the pair. * @param second The second element of the pair. */ template int count(flecs::entity_t second) const { return count(_::cpp_type::id(m_world), second); } /** Count entities matching a pair. * * @tparam First The first element of the pair. * @tparam Second The second element of the pair. */ template int count() const { return count( _::cpp_type::id(m_world), _::cpp_type::id(m_world)); } /** All entities created in function are created with id. */ template void with(id_t with_id, const Func& func) const { ecs_id_t prev = ecs_set_with(m_world, with_id); func(); ecs_set_with(m_world, prev); } /** All entities created in function are created with type. */ template void with(const Func& func) const { with(this->id(), func); } /** All entities created in function are created with pair. */ template void with(const Func& func) const { with(ecs_pair(this->id(), this->id()), func); } /** All entities created in function are created with pair. */ template void with(id_t second, const Func& func) const { with(ecs_pair(this->id(), second), func); } /** All entities created in function are created with pair. */ template void with(id_t first, id_t second, const Func& func) const { with(ecs_pair(first, second), func); } /** All entities created in function are created in scope. All operations * called in function (such as lookup) are relative to scope. */ template void scope(id_t parent, const Func& func) const { ecs_entity_t prev = ecs_set_scope(m_world, parent); func(); ecs_set_scope(m_world, prev); } /** Same as scope(parent, func), but with T as parent. */ template void scope(const Func& func) const { flecs::id_t parent = _::cpp_type::id(m_world); scope(parent, func); } /** Use provided scope for operations ran on returned world. * Operations need to be ran in a single statement. */ flecs::scoped_world scope(id_t parent) const; template flecs::scoped_world scope() const; flecs::scoped_world scope(const char* name) const; /** Delete all entities with specified id. */ void delete_with(id_t the_id) const { ecs_delete_with(m_world, the_id); } /** Delete all entities with specified pair. */ void delete_with(entity_t first, entity_t second) const { delete_with(ecs_pair(first, second)); } /** Delete all entities with specified component. */ template void delete_with() const { delete_with(_::cpp_type::id(m_world)); } /** Delete all entities with specified pair. */ template void delete_with() const { delete_with(_::cpp_type::id(m_world), _::cpp_type::id(m_world)); } /** Delete all entities with specified pair. */ template void delete_with(entity_t second) const { delete_with(_::cpp_type::id(m_world), second); } /** Remove all instances of specified id. */ void remove_all(id_t the_id) const { ecs_remove_all(m_world, the_id); } /** Remove all instances of specified pair. */ void remove_all(entity_t first, entity_t second) const { remove_all(ecs_pair(first, second)); } /** Remove all instances of specified component. */ template void remove_all() const { remove_all(_::cpp_type::id(m_world)); } /** Remove all instances of specified pair. */ template void remove_all() const { remove_all(_::cpp_type::id(m_world), _::cpp_type::id(m_world)); } /** Remove all instances of specified pair. */ template void remove_all(entity_t second) const { remove_all(_::cpp_type::id(m_world), second); } /** Defer all operations called in function. If the world is already in * deferred mode, do nothing. */ template void defer(const Func& func) const { ecs_defer_begin(m_world); func(); ecs_defer_end(m_world); } /** Suspend deferring operations. * * @see ecs_defer_suspend */ void defer_suspend() const { ecs_defer_suspend(m_world); } /** Resume deferring operations. * * @see ecs_defer_suspend */ void defer_resume() const { ecs_defer_resume(m_world); } /** Check if entity id exists in the world. * * @see ecs_exists */ bool exists(flecs::entity_t e) const { return ecs_exists(m_world, e); } /** Check if entity id exists in the world. * * @see ecs_is_alive */ bool is_alive(flecs::entity_t e) const { return ecs_is_alive(m_world, e); } /** Check if entity id is valid. * Invalid entities cannot be used with API functions. * * @see ecs_is_valid */ bool is_valid(flecs::entity_t e) const { return ecs_is_valid(m_world, e); } /** Get alive entity for id. * Returns the entity with the current generation. * * @see ecs_get_alive */ flecs::entity get_alive(flecs::entity_t e) const; flecs::entity make_alive(flecs::entity_t e) const; /* Run callback after completing frame */ void run_post_frame(ecs_fini_action_t action, void *ctx) const { ecs_run_post_frame(m_world, action, ctx); } /** Get the world info. * @see ecs_get_world_info */ const flecs::world_info_t* get_info() const{ return ecs_get_world_info(m_world); } /** Get delta_time */ ecs_ftime_t delta_time() const { return get_info()->delta_time; } /** * @file addons/cpp/mixins/id/mixin.inl * @brief Id world mixin. */ /** Get id from a type. * * @memberof flecs::world */ template flecs::id id() const; /** Id factory. * * @memberof flecs::world */ template flecs::id id(Args&&... args) const; /** Get pair id from relationship, object. * * @memberof flecs::world */ template flecs::id pair() const; /** Get pair id from relationship, object. * * @memberof flecs::world */ template 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; /** * @file addons/cpp/mixins/component/mixin.inl * @brief Component mixin. */ /** Find or register component. * * @ingroup cpp_components * @memberof flecs::world */ template flecs::component component(Args &&... args) const; /** Find or register untyped component. * Method available on flecs::world class. * * @ingroup cpp_components * @memberof flecs::world */ template flecs::untyped_component component(Args &&... args) const; /** * @file addons/cpp/mixins/entity/mixin.inl * @brief Entity world mixin. */ /** Create an entity. * * @memberof flecs::world * @ingroup cpp_entities */ template flecs::entity entity(Args &&... args) const; /** Convert enum constant to entity. * * @memberof flecs::world * @ingroup cpp_entities */ template ::value > = 0> flecs::id id(E value) const; /** Convert enum constant to entity. * * @memberof flecs::world * @ingroup cpp_entities */ template ::value > = 0> flecs::entity entity(E value) const; /** Create a prefab. * * @memberof flecs::world * @ingroup cpp_entities */ template flecs::entity prefab(Args &&... args) const; /** Create an entity that's associated with a type. * * @memberof flecs::world * @ingroup cpp_entities */ template flecs::entity entity(const char *name = nullptr) const; /** Create a prefab that's associated with a type. * * @memberof flecs::world * @ingroup cpp_entities */ template flecs::entity prefab(const char *name = nullptr) const; /** * @file addons/cpp/mixins/event/mixin.inl * @brief Event world mixin. */ /** * @defgroup cpp_addons_event Events * @ingroup cpp_addons * API for emitting events. * * @{ */ /** 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 flecs::event_builder_typed event() const; /** @} */ /** * @file addons/cpp/mixins/term/mixin.inl * @brief Term world mixin. */ /** * @memberof flecs::world * @ingroup cpp_core_filters * * @{ */ /** Create a term. * */ template flecs::term term(Args &&... args) const; /** Create a term for a (component) type. */ template flecs::term term() const; /** Create a term for a pair. */ template flecs::term term() const; /** @} */ /** * @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 flecs::filter filter(Args &&... args) const; /** Create a filter builder. * * @see ecs_filter_init */ template flecs::filter_builder filter_builder(Args &&... args) const; /** Iterate over all entities with components in argument list of function. * The function parameter must match the following signature: * * @code * void(*)(T&, U&, ...) * @endcode * * or: * * @code * void(*)(flecs::entity, T&, U&, ...) * @endcode * */ template void each(Func&& func) const; /** Iterate over all entities with provided component. * The function parameter must match the following signature: * * @code * void(*)(T&) * @endcode * * or: * * @code * void(*)(flecs::entity, T&) * @endcode * */ template void each(Func&& func) const; /** Iterate over all entities with provided (component) id. */ template void each(flecs::id_t term_id, Func&& func) const; /** @} */ /** * @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 flecs::observer_builder observer(Args &&... args) const; /** @} */ /** * @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 flecs::query query(Args &&... args) const; /** Create a subquery. * @see ecs_query_init */ template flecs::query query(flecs::query_base& parent, Args &&... args) const; /** Create a query builder. * @see ecs_query_init */ template flecs::query_builder query_builder(Args &&... args) const; /** @} */ /** * @file addons/cpp/mixins/enum/mixin.inl * @brief Enum world mixin. */ /** Convert enum constant to entity. * * @memberof flecs::world * @ingroup cpp_entities */ template ::value > = 0> flecs::entity to_entity(E constant) const; # ifdef FLECS_MODULE /** * @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 flecs::entity module(const char *name = nullptr) const; /** Import a module. * * @tparam Module module class. * @return Module entity. */ template flecs::entity import(); /** @} */ # endif # ifdef FLECS_PIPELINE /** * @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 ::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 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 ::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; /** @} */ # endif # ifdef FLECS_SNAPSHOT /** * @file addons/cpp/mixins/snapshot/mixin.inl * @brief Snapshot world mixin. */ /** * @memberof flecs::world * @ingroup cpp_addons_snapshots * * @{ */ /** Create a snapshot. */ template flecs::snapshot snapshot(Args &&... args) const; /** @} */ # endif # ifdef FLECS_SYSTEM /** * @file addons/cpp/mixins/system/mixin.inl * @brief System module world mixin. */ /** * @memberof flecs::world * @ingroup cpp_addons_systems * * @{ */ /** Upcast entity to a system. * The provided entity must be a system. * * @param e The entity. * @return A system object. */ flecs::system system(flecs::entity e) const; /** Create a new system. * * @tparam Components The components to match on. * @tparam Args Arguments passed to the constructor of flecs::system_builder. * @return System builder. */ template flecs::system_builder system(Args &&... args) const; /** @} */ # endif # ifdef FLECS_TIMER /** * @file addons/cpp/mixins/timer/mixin.inl * @brief Timer module mixin. */ /** * @memberof flecs::world * @ingroup cpp_addons_timer */ /** Find or register a singleton timer. */ template flecs::timer timer() const; /** Find or register a timer. */ template flecs::timer timer(Args &&... args) const; /** Enable randomization of initial time values for timers. * @see ecs_randomize_timers */ void randomize_timers() const; # endif # ifdef FLECS_RULES /** * @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 flecs::rule rule(Args &&... args) const; /** Create a subrule. * @see ecs_rule_init */ template flecs::rule rule(flecs::rule_base& parent, Args &&... args) const; /** Create a rule builder. * @see ecs_rule_init */ template flecs::rule_builder rule_builder(Args &&... args) const; /** @} */ # endif # ifdef FLECS_PLECS /** * @file addons/cpp/mixins/plecs/mixin.inl * @brief Plecs world mixin. */ /** * @defgroup cpp_addons_plecs Plecs * @ingroup cpp_addons * Data definition format for loading entity data. * * @{ */ /** 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); } /** @} */ # endif # ifdef FLECS_META /** * @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 flecs::string to_expr(const T* value) { flecs::entity_t tid = _::cpp_type::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 flecs::cursor cursor(void *ptr) { flecs::entity_t tid = _::cpp_type::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 flecs::entity array(int32_t array_count); /** Create vector type. */ flecs::entity vector(flecs::entity_t elem_id); /** Create vector type. */ template flecs::entity vector(); /** @} */ # endif # ifdef FLECS_JSON /** * @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 flecs::string to_json(const T* value) { flecs::entity_t tid = _::cpp_type::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 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::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); } /** Deserialize JSON file into world. * * @memberof flecs::world * @ingroup cpp_addons_json */ const char* from_json_file(const char *json, flecs::from_json_desc_t *desc = nullptr) { return ecs_world_from_json_file(m_world, json, desc); } # endif # ifdef FLECS_APP /** * @file addons/cpp/mixins/app/mixin.inl * @brief App world addon mixin. */ /** * @ingroup cpp_addons_app * @memberof flecs::world * * @{ */ /** 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. */ flecs::app_builder app() { m_owned = false; // App takes ownership of world return flecs::app_builder(m_world); } /** @} */ # endif # ifdef FLECS_METRICS /** Create metric. * * @ingroup cpp_addons_metrics * @memberof flecs::world */ template flecs::metric_builder metric(Args &&... args) const; # endif # ifdef FLECS_ALERTS /** Create alert. * * @ingroup cpp_addons_alerts * @memberof flecs::world */ template flecs::alert_builder alert(Args &&... args) const; # endif public: void init_builtin_components(); world_t *m_world; bool m_owned; }; /** Scoped world. * Utility class used by the world::scope method to create entities in a scope. */ struct scoped_world : world { scoped_world( flecs::world_t *w, flecs::entity_t s) : world(nullptr) { m_prev_scope = ecs_set_scope(w, s); m_world = w; m_owned = false; } ~scoped_world() { ecs_set_scope(m_world, m_prev_scope); } scoped_world(const scoped_world& obj) : world(nullptr) { m_prev_scope = obj.m_prev_scope; m_world = obj.m_world; m_owned = obj.m_owned; } flecs::entity_t m_prev_scope; }; /** @} */ } // namespace flecs /** * @file addons/cpp/field.hpp * @brief Wrapper classes for fields returned by flecs::iter. */ #pragma once /** * @defgroup cpp_field Fields * @ingroup cpp_core * Field helper types. * * @{ */ namespace flecs { /** Unsafe wrapper class around a field. * This class can be used when a system does not know the type of a field at * compile time. * * @ingroup cpp_iterator */ struct untyped_field { untyped_field(void* array, size_t size, size_t count, bool is_shared = false) : m_data(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 field is not shared. * * @param index Index of element. * @return Reference to element. */ void* operator[](size_t index) const { ecs_assert(!m_is_shared, ECS_INVALID_PARAMETER, "invalid usage of [] operator for shared component field"); ecs_assert(index < m_count, ECS_COLUMN_INDEX_OUT_OF_RANGE, "index %d out of range for field", index); return ECS_OFFSET(m_data, m_size * index); } protected: void* m_data; size_t m_size; size_t m_count; bool m_is_shared; }; /** Wrapper class around a field. * * @tparam T component type of the field. * * @ingroup cpp_iterator */ template struct field { static_assert(std::is_empty::value == false, "invalid type for field, cannot iterate empty type"); /** Create field 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. */ field(T* array, size_t count, bool is_shared = false) : m_data(array) , m_count(count) , m_is_shared(is_shared) {} /** Create field from iterator. * * @param iter Iterator object. * @param field Index of the signature of the query being iterated over. */ field(iter &iter, int field); /** Return element in component array. * This operator may only be used if the field is not shared. * * @param index Index of element. * @return Reference to element. */ T& operator[](size_t index) const; /** Return first element of component array. * This operator is typically used when the field is shared. * * @return Reference to the first element. */ T& operator*() const; /** Return first element of component array. * This operator is typically used when the field is shared. * * @return Pointer to the first element. */ T* operator->() const; protected: T* m_data; size_t m_count; bool m_is_shared; }; } /** * @file addons/cpp/iter.hpp * @brief Wrapper classes for ecs_iter_t and component arrays. */ #pragma once /** * @defgroup cpp_iterator Iterators * @ingroup cpp_core * Iterator operations. * * @{ */ namespace flecs { //////////////////////////////////////////////////////////////////////////////// namespace _ { //////////////////////////////////////////////////////////////////////////////// /** Iterate over an integer range (used to iterate over entity range). * * @tparam T of the iterator */ template 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; 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(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(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 T* ctx() { return static_cast(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 T* param() { /* TODO: type check */ return static_cast(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 iterator. */ 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 std::enable_if::value, void>::type* = nullptr> flecs::field field(int32_t index) const; /** 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 std::enable_if< std::is_const::value == false, void>::type* = nullptr> flecs::field field(int32_t index) const; /** 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_field field(int32_t index) const { ecs_assert(!(m_iter->flags & EcsIterCppEach), ECS_INVALID_OPERATION, "cannot .field from .each, use .field_at(%d, row) instead", index); return get_unchecked_field(index); } /** Get pointer to field at row. */ void* field_at(int32_t index, size_t row) const { return get_unchecked_field(index)[row]; } /** Get reference to field at row. */ template , typename std::enable_if::value, void>::type* = nullptr> const A& field_at(int32_t index, size_t row) const { return get_field(index)[row]; } /** Get reference to field at row. */ template , typename std::enable_if< std::is_const::value == false, void>::type* = nullptr> A& field_at(int32_t index, size_t row) const { ecs_assert(!ecs_field_is_readonly(m_iter, index), ECS_ACCESS_VIOLATION, NULL); return get_field(index)[row]; } /** Get readonly access to entity ids. * * @return The entity ids. */ flecs::field entities() const { return flecs::field(m_iter->entities, static_cast(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 > flecs::field 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::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(m_iter->count); } return flecs::field( static_cast(ecs_field_w_size(m_iter, sizeof(A), index)), count, is_shared); } flecs::untyped_field 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(m_iter->count); } return flecs::untyped_field( 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 /** @} */ /** * @file addons/cpp/entity.hpp * @brief Entity class. * * This class provides read/write access to entities. */ #pragma once /** * @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(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 flecs::string path_from(const char *sep = "::", const char *init_sep = "::") const { return path_from(_::cpp_type::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: * * @code * void(*)(flecs::id id) * @endcode * * @param func The function invoked for each id. */ template void each(const Func& func) const; /** Iterate matching pair ids of an entity. * The function parameter must match the following signature: * * @code * void(*)(flecs::id id) * @endcode * * @param func The function invoked for each id. */ template 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: * * @code * void(*)(flecs::entity target) * @endcode * * @param rel The relationship for which to iterate the targets. * @param func The function invoked for each target. */ template 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: * * @code * void(*)(flecs::entity target) * @endcode * * @tparam First The relationship for which to iterate the targets. * @param func The function invoked for each target. */ template void each(const Func& func) const { return each(_::cpp_type::id(m_world), func); } /** Iterate children for entity. * The function parameter must match the following signature: * * @code * void(*)(flecs::entity target) * @endcode * * @param rel The relationship to follow. * @param func The function invoked for each child. */ template 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; } ecs_iter_t it = flecs_children(m_world, rel, m_id); while (ecs_children_next(&it)) { _::each_delegate(FLECS_MOV(func)).invoke(&it); } } /** Iterate children for entity. * The function parameter must match the following signature: * * @code * void(*)(flecs::entity target) * @endcode * * @tparam Rel The relationship to follow. * @param func The function invoked for each child. */ template void children(Func&& func) const { children(_::cpp_type::id(m_world), FLECS_MOV(func)); } /** Iterate children for entity. * The function parameter must match the following signature: * * @code * void(*)(flecs::entity target) * @endcode * * This operation follows the ChildOf relationship. * * @param func The function invoked for each child. */ template 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 ::value > = 0> const T* get() const { auto comp_id = _::cpp_type::id(m_world); ecs_assert(_::cpp_type::size() != 0, ECS_INVALID_PARAMETER, NULL); return static_cast(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 , if_t< flecs::is_pair::value > = 0> const A* get() const { auto comp_id = _::cpp_type::id(m_world); ecs_assert(_::cpp_type::size() != 0, ECS_INVALID_PARAMETER, NULL); return static_cast(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 A = actual_type_t

, if_not_t< flecs::is_pair::value > = 0> const A* get() const { return this->get

(); } /** 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::value> = 0> const First* get(Second second) const { auto comp_id = _::cpp_type::id(m_world); ecs_assert(_::cpp_type::size() != 0, ECS_INVALID_PARAMETER, NULL); return static_cast( 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::value> = 0> const First* get(Second constant) const { const auto& et = enum_type(this->m_world); flecs::entity_t target = et.entity(constant); return get(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: * * @code * 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; * }); * @endcode * * @param func The callback to invoke. * @return True if the entity has all components, false if not. */ template ::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 ::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 const Second* get_second(flecs::entity_t first) const { auto second = _::cpp_type::id(m_world); ecs_assert(_::cpp_type::size() != 0, ECS_INVALID_PARAMETER, NULL); return static_cast( 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 const Second* get_second() const { return get>(); } /** Get mutable component value. * * @tparam T The component to get. * @return Pointer to the component value, nullptr if the entity does not * have the component. */ template ::value > = 0> T* get_mut() const { auto comp_id = _::cpp_type::id(m_world); ecs_assert(_::cpp_type::size() != 0, ECS_INVALID_PARAMETER, NULL); return static_cast(ecs_get_mut_id(m_world, m_id, comp_id)); } /** Get mutable 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 , if_t< flecs::is_pair::value > = 0> A* get_mut() const { auto comp_id = _::cpp_type::id(m_world); ecs_assert(_::cpp_type::size() != 0, ECS_INVALID_PARAMETER, NULL); return static_cast(ecs_get_mut_id(m_world, m_id, comp_id)); } /** Get a mutable 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 A = actual_type_t

, if_not_t< flecs::is_pair::value > = 0> A* get_mut() const { return this->get_mut

(); } /** Get a mutable 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::value> = 0> First* get_mut(Second second) const { auto comp_id = _::cpp_type::id(m_world); ecs_assert(_::cpp_type::size() != 0, ECS_INVALID_PARAMETER, NULL); return static_cast( ecs_get_mut_id(m_world, m_id, ecs_pair(comp_id, second))); } /** Get a mutable 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::value> = 0> First* get_mut(Second constant) const { const auto& et = enum_type(this->m_world); flecs::entity_t target = et.entity(constant); return get_mut(target); } /** Get mutable component value (untyped). * * @param comp The component to get. * @return Pointer to the component value, nullptr if the entity does not * have the component. */ void* get_mut(flecs::id_t comp) const { return ecs_get_mut_id(m_world, m_id, comp); } /** Get a mutable 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. */ void* get_mut(flecs::entity_t first, flecs::entity_t second) const { return ecs_get_mut_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 Second the second element of a pair. * @param first The first part of the pair. */ template Second* get_mut_second(flecs::entity_t first) const { auto second = _::cpp_type::id(m_world); ecs_assert(_::cpp_type::size() != 0, ECS_INVALID_PARAMETER, NULL); return static_cast( ecs_get_mut_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 Second* get_mut_second() const { return get_mut>(); } /** 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 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: * * @code * // Is Position provided by the entity or one of its base entities? * ecs_get_target_for_id(world, entity, EcsIsA, ecs_id(Position)) * @endcode * * @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 flecs::entity target_for(flecs::entity_t relationship) const; template 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 int32_t depth() const { return this->depth(_::cpp_type::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 bool has() const { flecs::id_t cid = _::cpp_type::id(m_world); bool result = ecs_has_id(m_world, m_id, cid); if (result) { return result; } if (is_enum::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 ::value > = 0> bool has(E value) const { auto r = _::cpp_type::id(m_world); auto o = enum_type(m_world).entity(value); ecs_assert(o, ECS_INVALID_PARAMETER, "Constant was not found in Enum reflection data." " Did you mean to use has() instead of has(E)?"); 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 bool has() const { return this->has(_::cpp_type::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::value > = 0> bool has(Second second) const { auto comp_id = _::cpp_type::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 bool has_second(flecs::entity_t first) const { return this->has(first, _::cpp_type::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::value > = 0> bool has(E value) const { const auto& et = enum_type(this->m_world); flecs::entity_t second = et.entity(value); return has(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 bool owns(flecs::id_t second) const { auto comp_id = _::cpp_type::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 bool owns() const { return owns(_::cpp_type::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 bool owns() const { return owns( _::cpp_type::id(m_world), _::cpp_type::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 bool enabled() const { return this->enabled(_::cpp_type::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 bool enabled(flecs::id_t second) const { return this->enabled(_::cpp_type::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 bool enabled() const { return this->enabled(_::cpp_type::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 /** * @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) const { char *json = ecs_entity_to_json(m_world, m_id, desc); return flecs::string(json); } # endif # ifdef FLECS_DOC /** * @file addons/cpp/mixins/doc/entity_view.inl * @brief Doc entity view mixin. */ /** Get human readable name. * * @see ecs_doc_get_name() * @see flecs::doc::get_name() * @see flecs::entity_builder::set_doc_name() * * @memberof flecs::entity_view * @ingroup cpp_addons_doc */ const char* doc_name() const { return ecs_doc_get_name(m_world, m_id); } /** Get brief description. * * @see ecs_doc_get_brief() * @see flecs::doc::get_brief() * @see flecs::entity_builder::set_doc_brief() * * @memberof flecs::entity_view * @ingroup cpp_addons_doc */ const char* doc_brief() const { return ecs_doc_get_brief(m_world, m_id); } /** Get detailed description. * * @see ecs_doc_get_detail() * @see flecs::doc::get_detail() * @see flecs::entity_builder::set_doc_detail() * * @memberof flecs::entity_view * @ingroup cpp_addons_doc */ const char* doc_detail() const { return ecs_doc_get_detail(m_world, m_id); } /** Get link to external documentation. * * @see ecs_doc_get_link() * @see flecs::doc::get_link() * @see flecs::entity_builder::set_doc_link() * * @memberof flecs::entity_view * @ingroup cpp_addons_doc */ const char* doc_link() const { return ecs_doc_get_link(m_world, m_id); } /** Get color. * * @see ecs_doc_get_color() * @see flecs::doc::get_color() * @see flecs::entity_builder::set_doc_color() * * @memberof flecs::entity_view * @ingroup cpp_addons_doc */ const char* doc_color() const { return ecs_doc_get_color(m_world, m_id); } # endif # ifdef FLECS_ALERTS /** * @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); } # endif /** * @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 E to_constant() const; /** * @file addons/cpp/mixins/event/entity_view.inl * @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 ::value> = 0> void emit() { this->emit(_::cpp_type::id(m_world)); } /** Emit event with payload for entity. * * @memberof flecs::entity_view * * @tparam Evt The event to emit. */ template ::value> = 0> void emit(const Evt& payload) { flecs::world(m_world) .event(_::cpp_type::id(m_world)) .entity(m_id) .ctx(&payload) .emit(); } /** Enqueue event for entity. * * @memberof flecs::entity_view * * @param evt The event to enqueue. */ void enqueue(flecs::entity_t evt) { flecs::world(m_world) .event(evt) .entity(m_id) .enqueue(); } /** Enqueue event for entity. * * @memberof flecs::entity_view * * @param evt The event to enqueue. */ void enqueue(flecs::entity evt); /** Enqueue event for entity. * * @memberof flecs::entity_view * * @tparam Evt The event to enqueue. */ template ::value> = 0> void enqueue() { this->enqueue(_::cpp_type::id(m_world)); } /** Enqueue event with payload for entity. * * @memberof flecs::entity_view * * @tparam Evt The event to enqueue. */ template ::value> = 0> void enqueue(const Evt& payload) { flecs::world(m_world) .event(_::cpp_type::id(m_world)) .entity(m_id) .ctx(&payload) .enqueue(); } private: flecs::entity set_stage(world_t *stage); }; } /** @} */ /** * @file addons/cpp/mixins/entity/builder.hpp * @brief Entity builder. */ #pragma once namespace flecs { /** Entity builder. * @ingroup cpp_entities */ template 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 Self& add() { flecs_static_assert(is_flecs_constructible::value, "cannot default construct type: add T::T() or use emplace()"); ecs_add_id(this->m_world, this->m_id, _::cpp_type::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 ::value > = 0> Self& add(E value) { flecs::entity_t first = _::cpp_type::id(this->m_world); const auto& et = enum_type(this->m_world); flecs::entity_t second = et.entity(value); ecs_assert(second, ECS_INVALID_PARAMETER, "Component was not found in reflection data."); 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 Self& add() { return this->add(_::cpp_type::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::value > = 0> Self& add(Second second) { flecs_static_assert(is_flecs_constructible::value, "cannot default construct type: add T::T() or use emplace()"); return this->add(_::cpp_type::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::value > = 0> Self& add(Second constant) { flecs_static_assert(is_flecs_constructible::value, "cannot default construct type: add T::T() or use emplace()"); const auto& et = enum_type(this->m_world); return this->add(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 Self& add_second(flecs::entity_t first) { return this->add(first, _::cpp_type::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 Self& add_if(bool cond) { if (cond) { return this->add(); } else { return this->remove(); } } /** 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 Self& add_if(bool cond, flecs::entity_t second) { return this->add_if(cond, _::cpp_type::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 Self& add_if(bool cond) { return this->add_if(cond, _::cpp_type::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 ::value > = 0> Self& add_if(bool cond, E constant) { const auto& et = enum_type(this->m_world); return this->add_if(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 Self& is_a() { return this->add(flecs::IsA, _::cpp_type::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(DependsOn, entity). * * @param second The second element of the pair. */ template ::value> = 0> Self& depends_on(E second) { const auto& et = enum_type(this->m_world); flecs::entity_t target = et.entity(second); return depends_on(target); } /** 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 Self& child_of() { return this->child_of(_::cpp_type::id(this->m_world)); } /** Shortcut for add(DependsOn, entity). * * @tparam T the type associated with the entity. */ template Self& depends_on() { return this->depends_on(_::cpp_type::id(this->m_world)); } /** Shortcut for add(SlotOf, entity). * * @tparam T the type associated with the entity. */ template Self& slot_of() { return this->slot_of(_::cpp_type::id(this->m_world)); } /** Remove a component from an entity. * * @tparam T the type of the component to remove. */ template ::value > = 0> Self& remove() { ecs_remove_id(this->m_world, this->m_id, _::cpp_type::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 ::value > = 0> Self& remove() { flecs::entity_t first = _::cpp_type::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 Self& remove() { return this->remove(_::cpp_type::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::value > = 0> Self& remove(Second second) { return this->remove(_::cpp_type::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 Self& remove_second(flecs::entity_t first) { return this->remove(first, _::cpp_type::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::value > = 0> Self& remove(Second constant) { const auto& et = enum_type(this->m_world); flecs::entity_t second = et.entity(constant); return this->remove(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 Self& override() { return this->override(_::cpp_type::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 Self& override(flecs::entity_t second) { return this->override(_::cpp_type::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 Self& override() { return this->override(_::cpp_type::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 Self& set_override(const T& val) { this->override(); return this->set(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 Self& set_override(T&& val) { this->override(); return this->set(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 Self& set_override(flecs::entity_t second, const First& val) { this->override(second); return this->set(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 Self& set_override(flecs::entity_t second, First&& val) { this->override(second); return this->set(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 A = actual_type_t

, if_not_t< flecs::is_pair::value> = 0> Self& set_override(const A& val) { this->override(); return this->set(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 A = actual_type_t

, if_not_t< flecs::is_pair::value> = 0> Self& set_override(A&& val) { this->override(); return this->set(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 Self& emplace_override(Args&&... args) { this->override(); flecs::emplace(this->m_world, this->m_id, _::cpp_type::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 A = actual_type_t

, if_not_t< flecs::is_pair::value> = 0, typename ... Args> Self& emplace_override(Args&&... args) { this->override(); flecs::emplace(this->m_world, this->m_id, ecs_pair(_::cpp_type::id(this->m_world), _::cpp_type::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 Self& enable() { return this->enable(_::cpp_type::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 Self& enable(flecs::id_t second) { return this->enable(_::cpp_type::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 Self& enable() { return this->enable(_::cpp_type::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 Self& disable() { return this->disable(_::cpp_type::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 Self& disable(flecs::id_t second) { return this->disable(_::cpp_type::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 Self& disable() { return this->disable(_::cpp_type::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::value && is_actual::value> = 0 > Self& set(T&& value) { flecs::set(this->m_world, this->m_id, FLECS_FWD(value)); return to_base(); } template::value && is_actual::value > = 0> Self& set(const T& value) { flecs::set(this->m_world, this->m_id, value); return to_base(); } template, if_not_t< is_callable::value || is_actual::value > = 0> Self& set(A&& value) { flecs::set(this->m_world, this->m_id, FLECS_FWD(value)); return to_base(); } template, if_not_t< is_callable::value || is_actual::value > = 0> Self& set(const A& value) { flecs::set(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 A = actual_type_t

, if_not_t< flecs::is_pair::value> = 0> Self& set(A&& value) { flecs::set

(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 A = actual_type_t

, if_not_t< flecs::is_pair::value> = 0> Self& set(const A& value) { flecs::set

(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 ::value > = 0> Self& set(Second second, const First& value) { auto first = _::cpp_type::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 ::value > = 0> Self& set(Second second, First&& value) { auto first = _::cpp_type::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 ::value > = 0> Self& set(Second constant, const First& value) { const auto& et = enum_type(this->m_world); flecs::entity_t second = et.entity(constant); return set(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 Self& set_second(entity_t first, const Second& value) { auto second = _::cpp_type::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 Self& set_second(entity_t first, Second&& value) { auto second = _::cpp_type::id(this->m_world); flecs::set(this->m_world, this->m_id, FLECS_FWD(value), ecs_pair(first, second)); return to_base(); } template Self& set_second(const Second& value) { flecs::set>(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 ensure * 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 ::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: * * @code * T{Args...} * T{flecs::entity, Args...} * @endcode * * 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> Self& emplace(Args&&... args) { flecs::emplace(this->m_world, this->m_id, _::cpp_type::id(this->m_world), FLECS_FWD(args)...); return to_base(); } template , typename A = actual_type_t

, if_not_t< flecs::is_pair::value> = 0> Self& emplace(Args&&... args) { flecs::emplace(this->m_world, this->m_id, ecs_pair(_::cpp_type::id(this->m_world), _::cpp_type::id(this->m_world)), FLECS_FWD(args)...); return to_base(); } template Self& emplace_first(flecs::entity_t second, Args&&... args) { flecs::emplace(this->m_world, this->m_id, ecs_pair(_::cpp_type::id(this->m_world), second), FLECS_FWD(args)...); return to_base(); } template Self& emplace_second(flecs::entity_t first, Args&&... args) { flecs::emplace(this->m_world, this->m_id, ecs_pair(first, _::cpp_type::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 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 Self& with(const Func& func) { with(_::cpp_type::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 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 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 /** * @file addons/cpp/mixins/doc/entity_builder.inl * @brief Doc entity builder mixin. */ /** Set human readable name. * This adds `(flecs.doc.Description, flecs.Name)` to the entity. * * @see ecs_doc_set_name() * @see flecs::doc::set_name() * @see flecs::entity_view::doc_name() * * @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 brief description. * This adds `(flecs.doc.Description, flecs.doc.Brief)` to the entity. * * @see ecs_doc_set_brief() * @see flecs::doc::set_brief() * @see flecs::entity_view::doc_brief() * * @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 detailed description. * This adds `(flecs.doc.Description, flecs.doc.Detail)` to the entity. * * @see ecs_doc_set_detail() * @see flecs::doc::set_detail() * @see flecs::entity_view::doc_detail() * * @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 link to external documentation. * This adds `(flecs.doc.Description, flecs.doc.Link)` to the entity. * * @see ecs_doc_set_link() * @see flecs::doc::set_link() * @see flecs::entity_view::doc_link() * * @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. * * @see ecs_doc_set_color() * @see flecs::doc::set_color() * @see flecs::entity_view::doc_color() * * @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(); } # endif # ifdef FLECS_META /** * @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(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(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 Self& quantity() { return this->quantity(_::cpp_type::id(this->world())); } /** Make entity a quantity */ Self& quantity() { ecs_add_id(this->world(), this->id(), flecs::Quantity); return to_base(); } /** @} */ # endif # ifdef FLECS_JSON /** * @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_ensure_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 Self& set_json( const char *json, flecs::from_json_desc_t *desc = nullptr) { return set_json(_::cpp_type::id(m_world), json, desc); } /** Set pair from JSON. * * @memberof flecs::entity_builder * @ingroup cpp_addons_json */ template Self& set_json( const char *json, flecs::from_json_desc_t *desc = nullptr) { return set_json( _::cpp_type::id(m_world), _::cpp_type::id(m_world), json, desc); } /** Set pair from JSON. * * @memberof flecs::entity_builder * @ingroup cpp_addons_json */ template Self& set_json( flecs::entity_t t, const char *json, flecs::from_json_desc_t *desc = nullptr) { return set_json( _::cpp_type::id(m_world), t, json, desc); } /** Set pair from JSON. * * @memberof flecs::entity_builder * @ingroup cpp_addons_json */ template Self& set_json_second( flecs::entity_t r, const char *json, flecs::from_json_desc_t *desc = nullptr) { return set_json( r, _::cpp_type::id(m_world), json, desc); } # endif /** * @file addons/cpp/mixins/event/entity_builder.inl * @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 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 Self& observe(Func&& callback); /** Observe event on entity * * @memberof flecs::entity_builder * * @param callback The observer callback. * @return Event builder. */ template Self& observe(Func&& callback); protected: Self& to_base() { return *static_cast(this); } }; } /** * @defgroup cpp_entities Entities * @ingroup cpp_core * Entity operations. * * @{ */ namespace flecs { /** Entity. * Class with read/write operations for entities. * * @ingroup cpp_entities */ struct entity : entity_builder { entity() : entity_builder() { } /** 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::entity_t id) { m_world = const_cast(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 ) { } #ifndef ensure /** 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 T& ensure() const { auto comp_id = _::cpp_type::id(m_world); ecs_assert(_::cpp_type::size() != 0, ECS_INVALID_PARAMETER, NULL); return *static_cast(ecs_ensure_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* ensure(entity_t comp) const { return ecs_ensure_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 A = actual_type_t

, if_not_t< flecs::is_pair::value> = 0> A& ensure() const { return *static_cast(ecs_ensure_id(m_world, m_id, ecs_pair( _::cpp_type::id(m_world), _::cpp_type::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 First& ensure(entity_t second) const { auto comp_id = _::cpp_type::id(m_world); ecs_assert(_::cpp_type::size() != 0, ECS_INVALID_PARAMETER, NULL); return *static_cast( ecs_ensure_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* ensure(entity_t first, entity_t second) const { return ecs_ensure_id(m_world, m_id, ecs_pair(first, second)); } #endif /** 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 Second& ensure_second(entity_t first) const { auto second = _::cpp_type::id(m_world); ecs_assert(_::cpp_type::size() != 0, ECS_INVALID_PARAMETER, NULL); return *static_cast( ecs_ensure_id(m_world, m_id, ecs_pair(first, second))); } /** Signal that component was modified. * * @tparam T component that was modified. */ template void modified() const { auto comp_id = _::cpp_type::id(m_world); ecs_assert(_::cpp_type::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 void modified() const { this->modified(_::cpp_type::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 void modified(entity_t second) const { auto first = _::cpp_type::id(m_world); ecs_assert(_::cpp_type::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 ::value > = 0> ref get_ref() const { return ref(m_world, m_id, _::cpp_type::id(m_world)); } /** Get reference to component. * Overload for when T is not the same as the actual type, which happens * when using pair types. * 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 , if_t< flecs::is_pair::value > = 0> ref get_ref() const { return ref(m_world, m_id, ecs_pair(_::cpp_type::id(m_world), _::cpp_type::id(m_world))); } template , typename A = actual_type_t

> ref get_ref() const { return ref(m_world, m_id, ecs_pair(_::cpp_type::id(m_world), _::cpp_type::id(m_world))); } template ref get_ref(flecs::entity_t second) const { return ref(m_world, m_id, ecs_pair(_::cpp_type::id(m_world), second)); } template ref get_ref_second(flecs::entity_t first) const { return ref(m_world, m_id, ecs_pair(first, _::cpp_type::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(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(world); return result; } static flecs::entity null() { return flecs::entity(); } # ifdef FLECS_JSON /** 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); } # endif }; } // namespace flecs /** @} */ /** * @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 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> *>(nullptr)...); } array m_terms; private: /* Populate terms array without checking for references */ bool populate(const ecs_iter_t*, size_t) { return false; } template 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 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 struct each_column::value && !is_empty>::value && is_actual::value > > : each_column_base { each_column(const _::term_ptr& term, size_t row) : each_column_base(term, row) { } T& get_row() { return static_cast(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 struct each_column::value && !is_empty>::value && !is_actual::value> > : each_column_base { each_column(const _::term_ptr& term, size_t row) : each_column_base(term, row) { } T get_row() { return static_cast*>(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 struct each_column>::value && !is_pointer::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(); } }; // If type is a pointer (indicating an optional value) return the type as is template struct each_column::value && !is_empty>::value > > : each_column_base { each_column(const _::term_ptr& term, size_t row) : each_column_base(term, row) { } actual_type_t get_row() { if (this->m_term.ptr) { return &static_cast>(this->m_term.ptr)[this->m_row]; } else { // optional argument doesn't have a value return nullptr; } } }; // If the query contains component references to other entities, check if the // current argument is one. template struct each_ref_column : public each_column { each_ref_column(const _::term_ptr& term, size_t row) : each_column(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 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::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::value); static_assert(arity::value > 0, "each() must have at least one argument"); using Terms = typename term_ptrs::array; template < if_not_t< is_same< decay_t, decay_t& >::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 terms; iter->flags |= EcsIterCppEach; 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(iter->binding_ctx); ecs_assert(self != nullptr, ECS_INTERNAL_ERROR, NULL); self->invoke(iter); } // Create instance of delegate static each_delegate* make(const Func& func) { return FLECS_NEW(each_delegate)(func); } // Function that can be used as callback to free delegate static void destruct(void *obj) { _::free_obj(static_cast(obj)); } // Static function to call for component on_add hook static void run_add(ecs_iter_t *iter) { component_binding_ctx *ctx = reinterpret_cast( 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( 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( 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 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(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 >(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 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(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 >(comps, i) .get_row())...); } ECS_TABLE_UNLOCK(iter->world, iter->table); } // Number of function arguments is equal to number of components, no entity template 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(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 >(comps, i) .get_row())...); } ECS_TABLE_UNLOCK(iter->world, iter->table); } template 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( iter, func, index + 1, columns, comps..., columns[index]); } Func m_func; }; template 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::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::value); static_assert(arity::value > 0, "each() must have at least one argument"); using Terms = typename term_ptrs::array; template < if_not_t< is_same< decay_t, decay_t& >::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 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 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(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 >(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 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(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 >(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 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(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 >(comps, i) .get_row())...)) { result = flecs::entity(iter->world, iter->entities[i]); break; } } ECS_TABLE_UNLOCK(iter->world, iter->table); return result; } template 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( iter, func, index + 1, columns, comps..., columns[index]); } Func m_func; }; //////////////////////////////////////////////////////////////////////////////// //// Utility class to invoke a system iterate action //////////////////////////////////////////////////////////////////////////////// template struct iter_delegate : delegate { private: static constexpr bool IterOnly = arity::value == 1; using Terms = typename term_ptrs::array; public: template < if_not_t< is_same< decay_t, decay_t& >::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 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(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 = 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 = 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 > >* > (comps.ptr))...); ECS_TABLE_UNLOCK(iter->world, iter->table); } template = 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 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(iter); } private: template ::value == 1> = 0> static void invoke(ecs_iter_t *iter) { auto self = static_cast(iter->binding_ctx); ecs_assert(self != nullptr, ECS_INTERNAL_ERROR, NULL); self->m_func(flecs::entity(iter->world, ecs_field_src(iter, 1))); } template ::value == 0> = 0> static void invoke(ecs_iter_t *iter) { auto self = static_cast(iter->binding_ctx); ecs_assert(self != nullptr, ECS_INTERNAL_ERROR, NULL); self->m_func(); } Func m_func; }; template 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(iter); } private: template ::value == 1> = 0> static void invoke(ecs_iter_t *iter) { auto self = static_cast( 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(iter->param); self->m_func(*data); } template ::value == 2> = 0> static void invoke(ecs_iter_t *iter) { auto self = static_cast( 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(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 struct entity_with_delegate_impl; template struct entity_with_delegate_impl> { using ColumnArray = flecs::array; using ArrayType = flecs::array; using DummyArray = flecs::array; using IdArray = flecs::array; static bool const_args() { static flecs::array is_const_args ({ flecs::is_const>::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().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 ensure_ptrs(world_t *world, ecs_entity_t e, ArrayType& ptrs) { /* Get pointers w/ensure */ size_t i = 0; DummyArray dummy ({ (ptrs[i ++] = ecs_ensure_id(world, e, _::cpp_type().id(world)), 0)... }); return true; } template 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 = get_ptrs(world, r, table, ptrs); if (has_components) { invoke_callback(func, 0, ptrs); } ecs_read_end(r); return has_components; } template 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 = get_ptrs(world, r, table, ptrs); if (has_components) { invoke_callback(func, 0, ptrs); } ecs_write_end(r); return has_components; } template 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 static bool invoke_ensure(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()), elem = store_added(added, elem, prev, next, w.id()), 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(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 ensure } else { ensure_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()), 0)... }); (void)dummy_after; return true; } private: template = 0> static void invoke_callback( const Func& f, size_t, ArrayType&, TArgs&& ... comps) { f(*static_cast::type*>(comps)...); } template = 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 struct entity_with_delegate { static_assert(function_traits::value, "type is not callable"); }; template struct entity_with_delegate::value > > : entity_with_delegate_impl< arg_list_t > { static_assert(function_traits::arity > 0, "function must have at least one argument"); }; } // namespace _ // Experimental: allows using the each delegate for use cases outside of flecs template using delegate = _::each_delegate::type, Args...>; } // namespace flecs /** * @file addons/cpp/utils/iterable.hpp * @brief Base class for iterable objects, like queries. */ namespace flecs { template struct iter_iterable; template struct page_iterable; template struct worker_iterable; template struct iterable { /** Each iterator. * The "each" iterator accepts a function that is invoked for each matching * entity. The following function signatures are valid: * - func(flecs::entity e, Components& ...) * - func(flecs::iter& it, size_t index, Components& ....) * - func(Components& ...) * * Each iterators are automatically instanced. */ template void each(Func&& func) const { each(nullptr, FLECS_FWD(func)); } template void each(flecs::world_t *world, Func&& func) const { iterate<_::each_delegate>(world, FLECS_FWD(func), this->next_each_action()); } template void each(flecs::iter& it, Func&& func) const { iterate<_::each_delegate>(it.world(), FLECS_FWD(func), this->next_each_action()); } template void each(flecs::entity e, Func&& func) const { iterate<_::each_delegate>(e.world(), FLECS_FWD(func), this->next_each_action()); } template flecs::entity find(Func&& func) const { return iterate_find<_::find_delegate>(nullptr, FLECS_FWD(func), this->next_each_action()); } /** Iter iterator. * The "iter" iterator accepts a function that is invoked for each matching * table. The following function signatures are valid: * - func(flecs::iter& it, Components* ...) * - func(Components& ...) * * Iter iterators are not automatically instanced. When a result contains * shared components, entities of the result will be iterated one by one. * This ensures that applications can't accidentally read out of bounds by * accessing a shared component as an array. */ template void iter(Func&& func) const { iterate<_::iter_delegate>(nullptr, FLECS_FWD(func), this->next_action()); } template void iter(flecs::world_t *world, Func&& func) const { iterate<_::iter_delegate>(world, FLECS_FWD(func), this->next_action()); } template void iter(flecs::iter& it, Func&& func) const { iterate<_::iter_delegate>(it.world(), FLECS_FWD(func), this->next_action()); } template void iter(flecs::entity e, Func&& func) const { iterate<_::iter_delegate>(e.world(), FLECS_FWD(func), this->next_action()); } /** Create iterator. * Create an iterator object that can be modified before iterating. */ iter_iterable iter(flecs::world_t *world = nullptr) const; /** Page iterator. * Create an iterator that limits the returned entities with offset/limit. * * @param offset How many entities to skip. * @param limit The maximum number of entities to return. * @return Iterable that can be iterated with each/iter. */ page_iterable page(int32_t offset, int32_t limit); /** Worker iterator. * Create an iterator that divides the number of matched entities across * a number of resources. * * @param index The index of the current resource. * @param count The total number of resources to divide entities between. * @return Iterable that can be iterated with each/iter. */ worker_iterable worker(int32_t index, int32_t count); /** Return number of entities matched by iterable. */ int32_t count() const { return this->iter().count(); } /** Return whether iterable has any matches. */ bool is_true() const { return this->iter().is_true(); } /** Return first entity matched by iterable. */ flecs::entity first() const { return this->iter().first(); } virtual ~iterable() { } protected: friend iter_iterable; friend page_iterable; friend worker_iterable; virtual ecs_iter_t get_iter(flecs::world_t *stage) const = 0; virtual ecs_iter_next_action_t next_action() const = 0; virtual ecs_iter_next_action_t next_each_action() const = 0; template < template class Delegate, typename Func, typename NextFunc, typename ... Args> void iterate(flecs::world_t *stage, Func&& func, NextFunc next, Args &&... args) const { ecs_iter_t it = this->get_iter(stage); if (Delegate::instanced()) { ECS_BIT_SET(it.flags, EcsIterIsInstanced); } while (next(&it, FLECS_FWD(args)...)) { Delegate(func).invoke(&it); } } template < template class Delegate, typename Func, typename NextFunc, typename ... Args> flecs::entity iterate_find(flecs::world_t *stage, Func&& func, NextFunc next, Args &&... args) const { ecs_iter_t it = this->get_iter(stage); if (Delegate::instanced()) { ECS_BIT_SET(it.flags, EcsIterIsInstanced); } flecs::entity result; while (!result && next(&it, FLECS_FWD(args)...)) { result = Delegate(func).invoke(&it); } if (result) { ecs_iter_fini(&it); } return result; } }; template struct iter_iterable final : iterable { template iter_iterable(Iterable *it, flecs::world_t *world) { m_it = it->get_iter(world); m_next = it->next_action(); m_next_each = it->next_action(); } iter_iterable& set_var(int var_id, flecs::entity_t value) { ecs_assert(var_id != -1, ECS_INVALID_PARAMETER, 0); ecs_iter_set_var(&m_it, var_id, value); return *this; } # ifdef FLECS_RULES /** * @file addons/cpp/mixins/rule/iterable.inl * @brief Rule iterable mixin. */ /** * @memberof flecs::iter * @ingroup cpp_addons_rules * * @{ */ iter_iterable& 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; } /** @} */ # endif # ifdef FLECS_JSON /** * @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); } # endif // Return total number of entities in result. int32_t count() { int32_t result = 0; while (m_next_each(&m_it)) { result += m_it.count; } return result; } // Returns true if iterator yields at least once result. bool is_true() { bool result = m_next_each(&m_it); if (result) { ecs_iter_fini(&m_it); } return result; } // Return first matching entity. flecs::entity first() { flecs::entity result; if (m_next_each(&m_it) && m_it.count) { result = flecs::entity(m_it.world, m_it.entities[0]); ecs_iter_fini(&m_it); } return result; } // Limit results to tables with specified group id (grouped queries only) iter_iterable& set_group(uint64_t group_id) { ecs_query_set_group(&m_it, group_id); return *this; } // Limit results to tables with specified group id (grouped queries only) template iter_iterable& set_group() { ecs_query_set_group(&m_it, _::cpp_type().id(m_it.real_world)); return *this; } protected: ecs_iter_t get_iter(flecs::world_t *world) const { if (world) { ecs_iter_t result = m_it; result.world = world; return result; } return m_it; } ecs_iter_next_action_t next_action() const { return m_next; } ecs_iter_next_action_t next_each_action() const { return m_next_each; } private: ecs_iter_t m_it; ecs_iter_next_action_t m_next; ecs_iter_next_action_t m_next_each; }; template iter_iterable iterable::iter(flecs::world_t *world) const { return iter_iterable(this, world); } template struct page_iterable final : iterable { template page_iterable(int32_t offset, int32_t limit, Iterable *it) : m_offset(offset) , m_limit(limit) { m_chain_it = it->get_iter(nullptr); } protected: ecs_iter_t get_iter(flecs::world_t*) const { return ecs_page_iter(&m_chain_it, m_offset, m_limit); } ecs_iter_next_action_t next_action() const { return ecs_page_next; } ecs_iter_next_action_t next_each_action() const { return ecs_page_next; } private: ecs_iter_t m_chain_it; int32_t m_offset; int32_t m_limit; }; template page_iterable iterable::page( int32_t offset, int32_t limit) { return page_iterable(offset, limit, this); } template struct worker_iterable final : iterable { worker_iterable(int32_t offset, int32_t limit, iterable *it) : m_offset(offset) , m_limit(limit) { m_chain_it = it->get_iter(nullptr); } protected: ecs_iter_t get_iter(flecs::world_t*) const { return ecs_worker_iter(&m_chain_it, m_offset, m_limit); } ecs_iter_next_action_t next_action() const { return ecs_worker_next; } ecs_iter_next_action_t next_each_action() const { return ecs_worker_next; } private: ecs_iter_t m_chain_it; int32_t m_offset; int32_t m_limit; }; template worker_iterable iterable::worker( int32_t index, int32_t count) { return worker_iterable(index, count, this); } } /** * @file addons/cpp/component.hpp * @brief Registering/obtaining info from components. */ #pragma once #include #include /** * @defgroup cpp_components Components * @ingroup cpp_core * Registering and working with components. * * @{ */ 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 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 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(), len); } template <> inline const char* symbol_name() { return "u8"; } template <> inline const char* symbol_name() { return "u16"; } template <> inline const char* symbol_name() { return "u32"; } template <> inline const char* symbol_name() { return "u64"; } template <> inline const char* symbol_name() { return "i8"; } template <> inline const char* symbol_name() { return "i16"; } template <> inline const char* symbol_name() { return "i32"; } template <> inline const char* symbol_name() { return "i64"; } template <> inline const char* symbol_name() { return "f32"; } template <> inline const char* symbol_name() { 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::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::value == false >* = nullptr> void register_lifecycle_actions( ecs_world_t *world, ecs_entity_t component) { ecs_type_hooks_t cl{}; cl.ctor = ctor(); cl.dtor = dtor(); cl.copy = copy(); cl.copy_ctor = copy_ctor(); cl.move = move(); cl.move_ctor = move_ctor(); cl.ctor_move_dtor = ctor_move_dtor(); cl.move_dtor = move_dtor(); 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 struct cpp_type_impl { static_assert(is_pointer::value == false, "pointer types are not allowed for components"); // 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()); 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::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(); } entity_t entity = ecs_cpp_component_register_explicit( world, s_id, id, name, type_name(), 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(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. #ifndef FLECS_CPP_NO_AUTO_REGISTRATION 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(world, s_id); } if (prev_with) { ecs_set_with(world, prev_with); } if (prev_scope) { ecs_set_scope(world, prev_scope); } } #else (void)world; (void)name; (void)allow_tag; ecs_assert(registered(world), ECS_INVALID_OPERATION, "component '%s' was not registered before use", type_name()); #endif // 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 entity_t cpp_type_impl::s_id; template size_t cpp_type_impl::s_size; template size_t cpp_type_impl::s_alignment; template bool cpp_type_impl::s_allow_tag( true ); template int32_t cpp_type_impl::s_reset_count; // Front facing class for implicitly registering a component & obtaining // static component data // Regular type template struct cpp_type::value >> : cpp_type_impl> { }; // Pair type template struct cpp_type::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 >::id(world), cpp_type< pair_second_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 /** * @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(offset); e.set(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 untyped_component& member(const char *name, int32_t count = 0, size_t offset = 0) { flecs::entity_t type_id = _::cpp_type::id(m_world); return member(type_id, name, count, offset); } /** Add member with unit. */ template 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::id(m_world); return member(type_id, unit, name, count, offset); } /** Add member with unit. */ template untyped_component& member(const char *name, int32_t count = 0, size_t offset = 0) { flecs::entity_t type_id = _::cpp_type::id(m_world); flecs::entity_t unit_id = _::cpp_type::id(m_world); return member(type_id, unit_id, name, count, offset); } /** Add member using pointer-to-member. */ template ::type> untyped_component& member(const char* name, const MemberType ComponentType::* ptr) { flecs::entity_t type_id = _::cpp_type::id(m_world); size_t offset = reinterpret_cast(&(static_cast(nullptr)->*ptr)); return member(type_id, name, std::extent::value, offset); } /** Add member with unit using pointer-to-member. */ template ::type> untyped_component& member(flecs::entity_t unit, const char* name, const MemberType ComponentType::* ptr) { flecs::entity_t type_id = _::cpp_type::id(m_world); size_t offset = reinterpret_cast(&(static_cast(nullptr)->*ptr)); return member(type_id, unit, name, std::extent::value, offset); } /** Add member with unit using pointer-to-member. */ template ::type> untyped_component& member(const char* name, const MemberType ComponentType::* ptr) { flecs::entity_t type_id = _::cpp_type::id(m_world); flecs::entity_t unit_id = _::cpp_type::id(m_world); size_t offset = reinterpret_cast(&(static_cast(nullptr)->*ptr)); return member(type_id, unit_id, name, std::extent::value, offset); } /** Add constant. */ untyped_component& constant(const char *name, int32_t value) { ecs_add_id(m_world, m_id, _::cpp_type::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::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 untyped_component& array(int32_t elem_count) { ecs_array_desc_t desc = {}; desc.entity = m_id; desc.type = _::cpp_type::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); // Don't use C++ ensure because Unreal defines a macro called ensure flecs::MemberRanges *mr = static_cast( ecs_ensure_id(w, me, w.id())); mr->value.min = min; mr->value.max = max; me.modified(); 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); // Don't use C++ ensure because Unreal defines a macro called ensure flecs::MemberRanges *mr = static_cast( ecs_ensure_id(w, me, w.id())); mr->warning.min = min; mr->warning.max = max; me.modified(); 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); // Don't use C++ ensure because Unreal defines a macro called ensure flecs::MemberRanges *mr = static_cast(ecs_ensure_id( w, me, w.id())); mr->error.min = min; mr->error.max = max; me.modified(); return *this; } /** @} */ # endif # ifdef FLECS_METRICS /** * @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). */ template untyped_component& metric( flecs::entity_t parent = 0, const char *brief = nullptr, const char *name = nullptr); /** @} */ # endif }; /** Component class. * Class used to register components and component metadata. * * @ingroup cpp_components */ template 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(); /* 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::registered(world)) { /* Obtain component id. Because the component is already registered, * this operation does nothing besides returning the existing id */ id = _::cpp_type::id_explicit(world, name, allow_tag, id); ecs_cpp_component_validate(world, id, n, _::symbol_name(), _::cpp_type::size(), _::cpp_type::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; } } if (last_elem) { name = last_elem + 1; } } /* Find or register component */ bool existing; id = ecs_cpp_component_register(world, id, n, _::symbol_name(), ECS_SIZEOF(T), ECS_ALIGNOF(T), implicit_name, &existing); /* Initialize static component data */ id = _::cpp_type::id_explicit(world, name, allow_tag, id); /* Initialize lifecycle actions (ctor, dtor, copy, move) */ if (_::cpp_type::size() && !existing) { _::register_lifecycle_actions(world, id); } } m_world = world; m_id = id; } /** Register on_add hook. */ template component& on_add(Func&& func) { using Delegate = typename _::each_delegate::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( _::free_obj); ecs_set_hooks_id(m_world, m_id, &h); return *this; } /** Register on_remove hook. */ template component& on_remove(Func&& func) { using Delegate = typename _::each_delegate< typename std::decay::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( _::free_obj); ecs_set_hooks_id(m_world, m_id, &h); return *this; } /** Register on_set hook. */ template component& on_set(Func&& func) { using Delegate = typename _::each_delegate< typename std::decay::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( _::free_obj); ecs_set_hooks_id(m_world, m_id, &h); return *this; } # ifdef FLECS_META /** Register opaque type interface */ template component& opaque(const Func& type_support) { flecs::world world(m_world); auto ts = type_support(world); ts.desc.entity = _::cpp_type::id(m_world); ecs_opaque_init(m_world, &ts.desc); return *this; } flecs::opaque opaque(flecs::entity_t as_type) { return flecs::opaque(m_world).as_type(as_type); } flecs::opaque opaque(flecs::entity as_type) { return this->opaque(as_type.id()); } flecs::opaque opaque(flecs::untyped_component as_type) { return this->opaque(as_type.id()); } /** Return opaque type builder for collection type */ template flecs::opaque opaque(flecs::id_t as_type) { return flecs::opaque(m_world).as_type(as_type); } /** Add constant. */ component& constant(const char *name, T value) { int32_t v = static_cast(value); untyped_component::constant(name, v); return *this; } # endif private: using BindingCtx = _::component_binding_ctx; BindingCtx* get_binding_ctx(flecs::type_hooks_t& h){ BindingCtx *result = static_cast(h.binding_ctx); if (!result) { result = FLECS_NEW(BindingCtx); h.binding_ctx = result; h.binding_ctx_free = reinterpret_cast( _::free_obj); } 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 flecs::entity_t type_id() { if (_::cpp_type::s_reset_count == ecs_cpp_reset_count_get()) { return _::cpp_type::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(); } } /** @} */ /** * @file addons/cpp/type.hpp * @brief Utility functions for id vector. */ #pragma once namespace flecs { /** * @defgroup cpp_types Types * @ingroup cpp_core * @brief Type operations. * * @{ */ /** Type class. * A type is a vector of component ids which can be requested from entities or tables. */ struct type { type() : m_world(nullptr), m_type(nullptr) { } type(world_t *world, const type_t *t) : m_world(world) , m_type(t) { } /** Convert type to comma-separated string */ flecs::string str() const { return flecs::string(ecs_type_str(m_world, m_type)); } /** Return number of ids in type */ int32_t count() const { if (!m_type) { return 0; } return m_type->count; } /** Return pointer to array. */ flecs::id_t* array() const { if (!m_type) { return nullptr; } return m_type->array; } /** Get id at specified index in type */ flecs::id get(int32_t index) const { ecs_assert(m_type != NULL, ECS_INVALID_PARAMETER, NULL); ecs_assert(m_type->count > index, ECS_OUT_OF_RANGE, NULL); if (!m_type) { return flecs::id(); } return flecs::id(m_world, m_type->array[index]); } flecs::id_t* begin() const { return m_type->array; } flecs::id_t* end() const { return &m_type->array[m_type->count]; } /** Implicit conversion to type_t */ operator const type_t*() const { return m_type; } private: world_t *m_world; const type_t *m_type; }; /** #} */ } /** * @file addons/cpp/table.hpp * @brief Direct access to table data. */ #pragma once namespace flecs { /** * @defgroup cpp_tables Tables * @ingroup cpp_core * Table operations. * * @{ */ struct table { table() : m_world(nullptr), m_table(nullptr) { } table(world_t *world, table_t *t) : m_world(world) , m_table(t) { } virtual ~table() { } /** Convert table type to string. */ flecs::string str() const { return flecs::string(ecs_table_str(m_world, m_table)); } /** Get table type. */ flecs::type type() const { return flecs::type(m_world, ecs_table_get_type(m_table)); } /** Get table count. */ int32_t count() const { return ecs_table_count(m_table); } /** Find type index for (component) id. * * @param id The (component) id. * @return The index of the id in the table type, -1 if not found/ */ int32_t type_index(flecs::id_t id) const { return ecs_table_get_type_index(m_world, m_table, id); } /** Find type index for type. * * @tparam T The type. * @return True if the table has the type, false if not. */ template int32_t type_index() const { return type_index(_::cpp_type::id(m_world)); } /** Find type index for pair. * @param first First element of pair. * @param second Second element of pair. * @return True if the table has the pair, false if not. */ int32_t type_index(flecs::entity_t first, flecs::entity_t second) const { return type_index(ecs_pair(first, second)); } /** Find type index for pair. * @tparam First First element of pair. * @param second Second element of pair. * @return True if the table has the pair, false if not. */ template int32_t type_index(flecs::entity_t second) const { return type_index(_::cpp_type::id(m_world), second); } /** Find type index for pair. * @tparam First First element of pair. * @tparam Second Second element of pair. * @return True if the table has the pair, false if not. */ template int32_t type_index() const { return type_index(_::cpp_type::id(m_world)); } /** Find column index for (component) id. * * @param id The (component) id. * @return The index of the id in the table type, -1 if not found/ */ int32_t column_index(flecs::id_t id) const { return ecs_table_get_column_index(m_world, m_table, id); } /** Find column index for type. * * @tparam T The type. * @return True if the table has the type, false if not. */ template int32_t column_index() const { return column_index(_::cpp_type::id(m_world)); } /** Find column index for pair. * @param first First element of pair. * @param second Second element of pair. * @return True if the table has the pair, false if not. */ int32_t column_index(flecs::entity_t first, flecs::entity_t second) const { return column_index(ecs_pair(first, second)); } /** Find column index for pair. * @tparam First First element of pair. * @param second Second element of pair. * @return True if the table has the pair, false if not. */ template int32_t column_index(flecs::entity_t second) const { return column_index(_::cpp_type::id(m_world), second); } /** Find column index for pair. * @tparam First First element of pair. * @tparam Second Second element of pair. * @return True if the table has the pair, false if not. */ template int32_t column_index() const { return column_index(_::cpp_type::id(m_world)); } /** Test if table has (component) id. * * @param id The (component) id. * @return True if the table has the id, false if not. */ bool has(flecs::id_t id) const { return type_index(id) != -1; } /** Test if table has the type. * * @tparam T The type. * @return True if the table has the type, false if not. */ template bool has() const { return type_index() != -1; } /** Test if table has the pair. * * @param first First element of pair. * @param second Second element of pair. * @return True if the table has the pair, false if not. */ bool has(flecs::entity_t first, flecs::entity_t second) const { return type_index(first, second) != -1; } /** Test if table has the pair. * * @tparam First First element of pair. * @param second Second element of pair. * @return True if the table has the pair, false if not. */ template bool has(flecs::entity_t second) const { return type_index(second) != -1; } /** Test if table has the pair. * * @tparam First First element of pair. * @tparam Second Second element of pair. * @return True if the table has the pair, false if not. */ template bool has() const { return type_index() != -1; } /** Get pointer to component array by column index. * * @param index The column index. * @return Pointer to the column, NULL if not a component. */ virtual void* get_column(int32_t index) const { return ecs_table_get_column(m_table, index, 0); } /** Get pointer to component array by component. * * @param id The component id. * @return Pointer to the column, NULL if not found. */ void* get(flecs::id_t id) const { int32_t index = column_index(id); if (index == -1) { return NULL; } return get_column(index); } /** Get pointer to component array by pair. * * @param first The first element of the pair. * @param second The second element of the pair. * @return Pointer to the column, NULL if not found. */ void* get(flecs::entity_t first, flecs::entity_t second) const { return get(ecs_pair(first, second)); } /** Get pointer to component array by component. * * @tparam T The component. * @return Pointer to the column, NULL if not found. */ template ::value > = 0> T* get() const { return static_cast(get(_::cpp_type::id(m_world))); } /** Get pointer to component array by (enum) component. * * @tparam T The (enum) component. * @return Pointer to the column, NULL if not found. */ template ::value > = 0> T* get() const { return static_cast(get(_::cpp_type::id(m_world))); } /** Get pointer to component array by component. * * @tparam T The component. * @return Pointer to the column, NULL if not found. */ template , if_t< flecs::is_pair::value > = 0> A* get() const { return static_cast(get(_::cpp_type::id(m_world))); } /** Get pointer to component array by pair. * * @tparam First The first element of the pair. * @param second The second element of the pair. * @return Pointer to the column, NULL if not found. */ template First* get(flecs::entity_t second) const { return static_cast(get(_::cpp_type::id(m_world), second)); } /** Get pointer to component array by pair. * * @tparam First The first element of the pair. * @tparam Second The second element of the pair. * @return Pointer to the column, NULL if not found. */ template , typename A = actual_type_t

, if_not_t< flecs::is_pair::value> = 0> A* get() const { return static_cast(get(_::cpp_type::id(m_world))); } /** Get column size */ size_t column_size(int32_t index) { return ecs_table_get_column_size(m_table, index); } /** Get depth for given relationship. * * @param rel The relationship. * @return The depth. */ int32_t depth(flecs::entity_t rel) { return ecs_table_get_depth(m_world, m_table, rel); } /** Get depth for given relationship. * * @tparam Rel The relationship. * @return The depth. */ template int32_t depth() { return depth(_::cpp_type::id(m_world)); } /* Implicit conversion to table_t */ operator table_t*() const { return m_table; } protected: world_t *m_world; table_t *m_table; }; struct table_range : table { table_range() : table() , m_offset(0) , m_count(0) { } table_range(world_t *world, table_t *t, int32_t offset, int32_t count) : table(world, t) , m_offset(offset) , m_count(count) { } int32_t offset() const { return m_offset; } int32_t count() const { return m_count; } /** Get pointer to component array by column index. * * @param index The column index. * @return Pointer to the column, NULL if not a component. */ void* get_column(int32_t index) const override { return ecs_table_get_column(m_table, index, m_offset); } private: int32_t m_offset = 0; int32_t m_count = 0; }; /** @} */ } // Mixin implementations /** * @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(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 inline flecs::id world::id() const { return flecs::id(m_world, _::cpp_type::id(m_world)); } template inline flecs::id world::id(Args&&... args) const { return flecs::id(m_world, FLECS_FWD(args)...); } template inline flecs::id world::pair() const { return flecs::id( m_world, ecs_pair( _::cpp_type::id(m_world), _::cpp_type::id(m_world))); } template 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::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)); } } /** * @file addons/cpp/mixins/entity/impl.hpp * @brief Entity implementation. */ #pragma once namespace flecs { template flecs::entity ref::entity() const { return flecs::entity(m_world, m_ref.entity); } template template ::value > > inline Self& entity_builder::set(const Func& func) { _::entity_with_delegate::invoke_ensure( this->m_world, this->m_id, func); return to_base(); } template ::value > > const T* entity_view::get() const { entity_t r = _::cpp_type::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(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(ecs_get_id(m_world, m_id, r)); } } template inline flecs::entity entity_view::target(int32_t index) const { return flecs::entity(m_world, ecs_get_target(m_world, m_id, _::cpp_type::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 inline flecs::entity entity_view::target_for(flecs::entity_t relationship) const { return target_for(relationship, _::cpp_type::id(m_world)); } template inline flecs::entity entity_view::target_for(flecs::entity_t relationship) const { return target_for(relationship, _::cpp_type::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 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 inline void entity_view::each(flecs::id_t pred, flecs::id_t obj, const Func& func) const { flecs::world_t *real_world = const_cast( 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 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 ::value > > inline bool entity_view::get(const Func& func) const { return _::entity_with_delegate::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 inline flecs::entity world::entity(Args &&... args) const { return flecs::entity(m_world, FLECS_FWD(args)...); } template ::value >> inline flecs::id world::id(E value) const { flecs::entity_t constant = enum_type(m_world).entity(value); return flecs::id(m_world, constant); } template ::value >> inline flecs::entity world::entity(E value) const { flecs::entity_t constant = enum_type(m_world).entity(value); return flecs::entity(m_world, constant); } template inline flecs::entity world::entity(const char *name) const { return flecs::entity(m_world, _::cpp_type::id_explicit(m_world, name, true, 0, false) ); } template 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 inline flecs::entity world::prefab(const char *name) const { flecs::entity result = flecs::component(m_world, name, true); result.add(flecs::Prefab); return result; } } /** * @file addons/cpp/mixins/component/impl.hpp * @brief Component mixin implementation */ #pragma once namespace flecs { template inline flecs::component world::component(Args &&... args) const { return flecs::component(m_world, FLECS_FWD(args)...); } template inline flecs::untyped_component world::component(Args &&... args) const { return flecs::untyped_component(m_world, FLECS_FWD(args)...); } } // namespace flecs /** * @file addons/cpp/mixins/term/impl.hpp * @brief Term implementation. */ #pragma once /** * @file addons/cpp/mixins/term/builder_i.hpp * @brief Term builder interface. */ #pragma once /** * @file addons/cpp/utils/signature.hpp * @brief Compile time utilities for deriving query attributes from param pack. */ #pragma once #include namespace flecs { namespace _ { template ::value > = 0> static constexpr flecs::inout_kind_t type_to_inout() { return flecs::In; } template ::value > = 0> static constexpr flecs::inout_kind_t type_to_inout() { return flecs::Out; } template ::value || is_reference::value > = 0> static constexpr flecs::inout_kind_t type_to_inout() { return flecs::InOutDefault; } template ::value > = 0> static constexpr flecs::oper_kind_t type_to_oper() { return flecs::Optional; } template ::value > = 0> static constexpr flecs::oper_kind_t type_to_oper() { return flecs::And; } template struct sig { sig(flecs::world_t *world) : m_world(world) , ids({ (_::cpp_type>::id(world))... }) , inout ({ (type_to_inout())... }) , oper ({ (type_to_oper())... }) { } flecs::world_t *m_world; flecs::array ids; flecs::array inout; flecs::array oper; template void populate(const Builder& b) { size_t i = 0; for (auto id : ids) { if (!(id & ECS_ID_FLAGS_MASK)) { const flecs::type_info_t *ti = ecs_get_type_info(m_world, id); if (ti) { // Union relationships always return a value of type // flecs::entity_t which holds the target id of the // union relationship. // If a union component with a non-zero size (like an // enum) is added to the query signature, the each/iter // functions would accept a parameter of the component // type instead of flecs::entity_t, which would cause // an assert. ecs_assert(!ti->size || !ecs_has_id(m_world, id, flecs::Union), ECS_INVALID_PARAMETER, "use term() method to add union relationship"); } } b->term(id).inout(inout[i]).oper(oper[i]); i ++; } } }; } // namespace _ } // namespace flecs namespace flecs { /** Term identifier builder. * A term identifier describes a single identifier in a term. Identifier * descriptions can reference entities by id, name or by variable, which means * the entity will be resolved when the term is evaluated. * * @ingroup cpp_core_filters */ template struct term_id_builder_i { term_id_builder_i() : m_term_id(nullptr) { } virtual ~term_id_builder_i() { } /* The self flag indicates the term identifier itself is used */ Base& self() { this->assert_term_id(); m_term_id->flags |= flecs::Self; return *this; } /* The up flag indicates that the term identifier may be substituted by * traversing a relationship upwards. For example: substitute the identifier * with its parent by traversing the ChildOf relationship. */ Base& up(flecs::entity_t trav = 0) { this->assert_term_id(); m_term_id->flags |= flecs::Up; if (trav) { m_term_id->trav = trav; } return *this; } template Base& up() { return this->up(_::cpp_type::id(this->world_v())); } /* The cascade flag is like up, but returns results in breadth-first order. * Only supported for flecs::query */ Base& cascade(flecs::entity_t trav = 0) { this->assert_term_id(); m_term_id->flags |= flecs::Cascade; if (trav) { m_term_id->trav = trav; } return *this; } template Base& cascade() { return this->cascade(_::cpp_type::id(this->world_v())); } /* Use with cascade to iterate results in descending (bottom -> top) order */ Base& desc() { this->assert_term_id(); m_term_id->flags |= flecs::Desc; return *this; } /* The parent flag is short for up(flecs::ChildOf) */ Base& parent() { this->assert_term_id(); m_term_id->flags |= flecs::Parent; return *this; } /* Specify relationship to traverse, and flags to indicate direction */ Base& trav(flecs::entity_t trav, flecs::flags32_t flags = 0) { this->assert_term_id(); m_term_id->trav = trav; m_term_id->flags |= flags; return *this; } /* Specify value of identifier by id */ Base& id(flecs::entity_t id) { this->assert_term_id(); m_term_id->id = id; return *this; } /* Specify value of identifier by id. Almost the same as id(entity), but this * operation explicitly sets the flecs::IsEntity flag. This forces the id to * be interpreted as entity, whereas not setting the flag would implicitly * convert ids for builtin variables such as flecs::This to a variable. * * This function can also be used to disambiguate id(0), which would match * both id(entity_t) and id(const char*). */ Base& entity(flecs::entity_t entity) { this->assert_term_id(); m_term_id->flags = flecs::IsEntity; m_term_id->id = entity; return *this; } /* Specify value of identifier by name */ Base& name(const char *name) { this->assert_term_id(); m_term_id->flags |= flecs::IsEntity; m_term_id->name = const_cast(name); return *this; } /* Specify identifier is a variable (resolved at query evaluation time) */ Base& var(const char *var_name) { this->assert_term_id(); m_term_id->flags |= flecs::IsVariable; m_term_id->name = const_cast(var_name); return *this; } /* Override term id flags */ Base& flags(flecs::flags32_t flags) { this->assert_term_id(); m_term_id->flags = flags; return *this; } ecs_term_id_t *m_term_id; protected: virtual flecs::world_t* world_v() = 0; private: void assert_term_id() { ecs_assert(m_term_id != NULL, ECS_INVALID_PARAMETER, "no active term (call .term() first)"); } operator Base&() { return *static_cast(this); } }; /** Term builder interface. * A term is a single element of a query expression. * * @ingroup cpp_core_filters */ template struct term_builder_i : term_id_builder_i { term_builder_i() : m_term(nullptr) { } term_builder_i(ecs_term_t *term_ptr) { set_term(term_ptr); } Base& term(id_t id) { return this->id(id); } /* Call prior to setting values for src identifier */ Base& src() { this->assert_term(); this->m_term_id = &m_term->src; return *this; } /* Call prior to setting values for first identifier. This is either the * component identifier, or first element of a pair (in case second is * populated as well). */ Base& first() { this->assert_term(); this->m_term_id = &m_term->first; return *this; } /* Call prior to setting values for second identifier. This is the second * element of a pair. Requires that first() is populated as well. */ Base& second() { this->assert_term(); this->m_term_id = &m_term->second; return *this; } /* Select src identifier, initialize it with entity id */ Base& src(flecs::entity_t id) { this->src(); this->id(id); return *this; } /* Select src identifier, initialize it with id associated with type */ template Base& src() { this->src(_::cpp_type::id(this->world_v())); return *this; } /* Select src identifier, initialize it with name. If name starts with a $ * the name is interpreted as a variable. */ Base& src(const char *name) { ecs_assert(name != NULL, ECS_INVALID_PARAMETER, NULL); this->src(); if (name[0] == '$') { this->var(&name[1]); } else { this->name(name); } return *this; } /* Select first identifier, initialize it with entity id */ Base& first(flecs::entity_t id) { this->first(); this->id(id); return *this; } /* Select first identifier, initialize it with id associated with type */ template Base& first() { this->first(_::cpp_type::id(this->world_v())); return *this; } /* Select first identifier, initialize it with name. If name starts with a $ * the name is interpreted as a variable. */ Base& first(const char *name) { ecs_assert(name != NULL, ECS_INVALID_PARAMETER, NULL); this->first(); if (name[0] == '$') { this->var(&name[1]); } else { this->name(name); } return *this; } /* Select second identifier, initialize it with entity id */ Base& second(flecs::entity_t id) { this->second(); this->id(id); return *this; } /* Select second identifier, initialize it with id associated with type */ template Base& second() { this->second(_::cpp_type::id(this->world_v())); return *this; } /* Select second identifier, initialize it with name. If name starts with a $ * the name is interpreted as a variable. */ Base& second(const char *name) { ecs_assert(name != NULL, ECS_INVALID_PARAMETER, NULL); this->second(); if (name[0] == '$') { this->var(&name[1]); } else { this->name(name); } return *this; } /** Set role of term. */ Base& role(id_t role) { this->assert_term(); m_term->id_flags = role; return *this; } /** Set read/write access of term. */ Base& inout(flecs::inout_kind_t inout) { this->assert_term(); m_term->inout = static_cast(inout); return *this; } /** Set read/write access for stage. Use this when a system reads or writes * components other than the ones provided by the query. This information * can be used by schedulers to insert sync/merge points between systems * where deferred operations are flushed. * * Setting this is optional. If not set, the value of the accessed component * may be out of sync for at most one frame. */ Base& inout_stage(flecs::inout_kind_t inout) { this->assert_term(); m_term->inout = static_cast(inout); if (m_term->oper != EcsNot) { this->src().entity(0); } return *this; } /** Short for inout_stage(flecs::Out). * Use when system uses add, remove or set. */ Base& write() { return this->inout_stage(flecs::Out); } /** Short for inout_stage(flecs::In). * Use when system uses get. */ Base& read() { return this->inout_stage(flecs::In); } /** Short for inout_stage(flecs::InOut). * Use when system uses ensure. */ Base& read_write() { return this->inout_stage(flecs::InOut); } /** Short for inout(flecs::In) */ Base& in() { return this->inout(flecs::In); } /** Short for inout(flecs::Out) */ Base& out() { return this->inout(flecs::Out); } /** Short for inout(flecs::InOut) */ Base& inout() { return this->inout(flecs::InOut); } /** Short for inout(flecs::In) */ Base& inout_none() { return this->inout(flecs::InOutNone); } /** Set operator of term. */ Base& oper(flecs::oper_kind_t oper) { this->assert_term(); m_term->oper = static_cast(oper); return *this; } /* Short for oper(flecs::And) */ Base& and_() { return this->oper(flecs::And); } /* Short for oper(flecs::Or) */ Base& or_() { return this->oper(flecs::Or); } /* Short for oper(flecs::Or) */ Base& not_() { return this->oper(flecs::Not); } /* Short for oper(flecs::Or) */ Base& optional() { return this->oper(flecs::Optional); } /* Short for oper(flecs::AndFrom) */ Base& and_from() { return this->oper(flecs::AndFrom); } /* Short for oper(flecs::OrFrom) */ Base& or_from() { return this->oper(flecs::OrFrom); } /* Short for oper(flecs::NotFrom) */ Base& not_from() { return this->oper(flecs::NotFrom); } /** Match singleton. */ Base& singleton() { this->assert_term(); ecs_assert(m_term->id || m_term->first.id, ECS_INVALID_PARAMETER, "no component specified for singleton"); flecs::id_t sid = m_term->id; if (!sid) { sid = m_term->first.id; } ecs_assert(sid != 0, ECS_INVALID_PARAMETER, NULL); if (!ECS_IS_PAIR(sid)) { m_term->src.id = sid; } else { m_term->src.id = ecs_pair_first(world(), sid); } return *this; } /* Filter terms are not triggered on by observers */ Base& filter() { m_term->src.flags |= flecs::Filter; return *this; } ecs_term_t *m_term; protected: virtual flecs::world_t* world_v() = 0; void set_term(ecs_term_t *term) { m_term = term; if (term) { this->m_term_id = &m_term->src; // default to subject } else { this->m_term_id = nullptr; } } private: void assert_term() { ecs_assert(m_term != NULL, ECS_INVALID_PARAMETER, "no active term (call .term() first)"); } operator Base&() { return *static_cast(this); } }; } namespace flecs { /** Class that describes a term. * * @ingroup cpp_core_filters */ struct term final : term_builder_i { term() : term_builder_i(&value) , value({}) , m_world(nullptr) { value.move = true; } term(flecs::world_t *world_ptr) : term_builder_i(&value) , value({}) , m_world(world_ptr) { value.move = true; } term(flecs::world_t *world_ptr, ecs_term_t t) : term_builder_i(&value) , value({}) , m_world(world_ptr) { value = t; value.move = false; this->set_term(&value); } term(flecs::world_t *world_ptr, id_t id) : term_builder_i(&value) , value({}) , m_world(world_ptr) { if (id & ECS_ID_FLAGS_MASK) { value.id = id; } else { value.first.id = id; } value.move = false; this->set_term(&value); } term(flecs::world_t *world_ptr, entity_t r, entity_t o) : term_builder_i(&value) , value({}) , m_world(world_ptr) { value.id = ecs_pair(r, o); value.move = false; this->set_term(&value); } term(id_t id) : term_builder_i(&value) , value({}) , m_world(nullptr) { if (id & ECS_ID_FLAGS_MASK) { value.id = id; } else { value.first.id = id; } value.move = true; } term(id_t r, id_t o) : term_builder_i(&value) , value({}) , m_world(nullptr) { value.id = ecs_pair(r, o); value.move = true; } term(const term& t) : term_builder_i(&value) { m_world = t.m_world; value = ecs_term_copy(&t.value); this->set_term(&value); } term(term&& t) noexcept : term_builder_i(&value) { m_world = t.m_world; value = ecs_term_move(&t.value); t.reset(); this->set_term(&value); } term& operator=(const term& t) { ecs_assert(m_world == t.m_world, ECS_INVALID_PARAMETER, NULL); ecs_term_fini(&value); value = ecs_term_copy(&t.value); this->set_term(&value); return *this; } term& operator=(term&& t) noexcept { ecs_assert(m_world == t.m_world, ECS_INVALID_PARAMETER, NULL); ecs_term_fini(&value); value = t.value; this->set_term(&value); t.reset(); return *this; } ~term() { ecs_term_fini(&value); } void reset() { value = {}; this->set_term(nullptr); } int finalize() { return ecs_term_finalize(m_world, &value); } bool is_set() { return ecs_term_is_initialized(&value); } flecs::id id() { return flecs::id(m_world, value.id); } flecs::inout_kind_t inout() { return static_cast(value.inout); } flecs::oper_kind_t oper() { return static_cast(value.oper); } flecs::entity get_src() { return flecs::entity(m_world, value.src.id); } flecs::entity get_first() { return flecs::entity(m_world, value.first.id); } flecs::entity get_second() { return flecs::entity(m_world, value.second.id); } ecs_term_t move() { /* explicit move to ecs_term_t */ return ecs_term_move(&value); } ecs_term_t value; protected: flecs::world_t* world_v() override { return m_world; } private: flecs::world_t *m_world; }; // Term mixin implementation template inline flecs::term world::term(Args &&... args) const { return flecs::term(m_world, FLECS_FWD(args)...); } template inline flecs::term world::term() const { return flecs::term(m_world, _::cpp_type::id(m_world)); } template inline flecs::term world::term() const { return flecs::term(m_world, ecs_pair( _::cpp_type::id(m_world), _::cpp_type::id(m_world))); } } /** * @file addons/cpp/mixins/filter/impl.hpp * @brief Filter implementation. */ #pragma once /** * @file addons/cpp/mixins/filter/builder.hpp * @brief Filter builder. */ #pragma once /** * @file addons/cpp/utils/builder.hpp * @brief Builder base class. * * Generic functionality for builder classes. */ #pragma once namespace flecs { namespace _ { // Macros for template types so we don't go cross-eyed #define FLECS_TBUILDER template class #define FLECS_IBUILDER template class template struct builder : IBuilder { using IBase = IBuilder; public: builder(flecs::world_t *world) : IBase(&m_desc) , m_desc{} , m_world(world) { } builder(const builder& f) : IBase(&m_desc, f.m_term_index) { m_world = f.m_world; m_desc = f.m_desc; } builder(builder&& f) noexcept : builder(f) { } operator TDesc*() { return &m_desc; } T build() { return T(m_world, *static_cast(this)); } protected: flecs::world_t* world_v() override { return m_world; } TDesc m_desc; flecs::world_t *m_world; }; #undef FLECS_TBUILDER #undef FLECS_IBUILDER } // namespace _ } // namespace flecs /** * @file addons/cpp/mixins/filter/builder_i.hpp * @brief Filter builder interface. */ #pragma once namespace flecs { /** Filter builder interface. * * @ingroup cpp_core_filters */ template struct filter_builder_i : term_builder_i { 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 Base& with(Args&&... args) { return this->term(FLECS_FWD(args)...).inout_none(); } template Base& with(Args&&... args) { return this->term(FLECS_FWD(args)...).inout_none(); } template Base& with() { return this->term().inout_none(); } template Base& without(Args&&... args) { return this->term(FLECS_FWD(args)...).not_(); } template Base& without(Args&&... args) { return this->term(FLECS_FWD(args)...).not_(); } template Base& without() { return this->term().not_(); } /* Write/read shorthand notation */ Base& write() { term_builder_i::write(); return *this; } template Base& write(Args&&... args) { return this->term(FLECS_FWD(args)...).write(); } template Base& write(Args&&... args) { return this->term(FLECS_FWD(args)...).write(); } template Base& write() { return this->term().write(); } Base& read() { term_builder_i::read(); return *this; } template Base& read(Args&&... args) { return this->term(FLECS_FWD(args)...).read(); } template Base& read(Args&&... args) { return this->term(FLECS_FWD(args)...).read(); } template Base& read() { return this->term().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 Base& term() { this->term(); *this->m_term = flecs::term(_::cpp_type::id(this->world_v())).move(); this->m_term->inout = static_cast( _::type_to_inout()); 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 Base& term(id_t o) { return this->term(_::cpp_type::id(this->world_v()), o); } template Base& term(const char *second) { return this->term(_::cpp_type::id(this->world_v())).second(second); } template Base& term() { return this->term(_::cpp_type::id(this->world_v())); } template ::value > = 0> Base& term(E value) { flecs::entity_t r = _::cpp_type::id(this->world_v()); auto o = enum_type(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(this); } ecs_filter_desc_t *m_desc; }; } namespace flecs { namespace _ { template using filter_builder_base = builder< filter, ecs_filter_desc_t, filter_builder, filter_builder_i, Components ...>; } /** Filter builder. * * @ingroup cpp_core_filters */ template struct filter_builder final : _::filter_builder_base { filter_builder(flecs::world_t* world, const char *name = nullptr) : _::filter_builder_base(world) { _::sig(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 void each(Func&& func) { this->build().each(FLECS_FWD(func)); } }; } 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) noexcept { 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) noexcept { 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 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 struct filter : filter_base, iterable { private: using Terms = typename _::term_ptrs::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) noexcept : filter_base(FLECS_MOV(obj)) { } filter& operator=(filter&& obj) noexcept { 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 inline flecs::filter world::filter(Args &&... args) const { return flecs::filter_builder(m_world, FLECS_FWD(args)...) .build(); } template inline flecs::filter_builder world::filter_builder(Args &&... args) const { return flecs::filter_builder(m_world, FLECS_FWD(args)...); } // world::each namespace _ { // Each with entity parameter template struct filter_delegate_w_ent; template struct filter_delegate_w_ent > { filter_delegate_w_ent(const flecs::world& world, Func&& func) { auto f = world.filter(); f.each(FLECS_MOV(func)); } }; // Each without entity parameter template struct filter_delegate_no_ent; template struct filter_delegate_no_ent > { filter_delegate_no_ent(const flecs::world& world, Func&& func) { auto f = world.filter(); f.each(FLECS_MOV(func)); } }; // Switch between function with & without entity parameter template struct filter_delegate; template struct filter_delegate, flecs::entity>::value> > { filter_delegate(const flecs::world& world, Func&& func) { filter_delegate_w_ent>(world, FLECS_MOV(func)); } }; template struct filter_delegate, flecs::entity>::value> > { filter_delegate(const flecs::world& world, Func&& func) { filter_delegate_no_ent>(world, FLECS_MOV(func)); } }; } template inline void world::each(Func&& func) const { _::filter_delegate f_delegate(*this, FLECS_MOV(func)); } template inline void world::each(Func&& func) const { ecs_term_t t = {}; t.id = _::cpp_type::id(); ecs_iter_t it = ecs_term_iter(m_world, &t); while (ecs_term_next(&it)) { _::each_delegate(func).invoke(&it); } } template 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).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; } } /** * @file addons/cpp/mixins/query/impl.hpp * @brief Query implementation. */ #pragma once /** * @file addons/cpp/mixins/query/builder.hpp * @brief Query builder. */ #pragma once /** * @file addons/cpp/mixins/query/builder_i.hpp * @brief Query builder interface. */ #pragma once namespace flecs { /** Query builder interface. * * @ingroup cpp_core_queries */ template struct query_builder_i : filter_builder_i { private: using BaseClass = filter_builder_i; 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 Base& order_by(int(*compare)(flecs::entity_t, const T*, flecs::entity_t, const T*)) { ecs_order_by_action_t cmp = reinterpret_cast(compare); return this->order_by(_::cpp_type::id(this->world_v()), cmp); } /** Sort the output of a query. * Same as order_by, 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(compare); m_desc->order_by_component = component; return *this; } /** Group and sort matched tables. * Similar to 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 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(group_by_action); return this->group_by(_::cpp_type::id(this->world_v()), action); } /** Group and sort matched tables. * Same as group_by, 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(group_by_action); m_desc->group_by_id = component; return *this; } /** Group and sort matched tables. * Same as group_by, but with default group_by action. * * @tparam T The component used to determine the group rank. */ template Base& group_by() { return this->group_by(_::cpp_type::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(this); } ecs_query_desc_t *m_desc; }; } namespace flecs { namespace _ { template using query_builder_base = builder< query, ecs_query_desc_t, query_builder, query_builder_i, Components ...>; } /** Query builder. * * @ingroup cpp_core_queries */ template struct query_builder final : _::query_builder_base { query_builder(flecs::world_t* world, const char *name = nullptr) : _::query_builder_base(world) { _::sig(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); } } }; } 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 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 struct query final : query_base, iterable { public: flecs::world world() const { return flecs::world(m_world); } private: using Terms = typename _::term_ptrs::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 inline flecs::query world::query(Args &&... args) const { return flecs::query_builder(m_world, FLECS_FWD(args)...) .build(); } template inline flecs::query_builder world::query_builder(Args &&... args) const { return flecs::query_builder(m_world, FLECS_FWD(args)...); } // Builder implementation template inline Base& query_builder_i::observable(const query_base& parent) { m_desc->parent = parent; return *static_cast(this); } // query_base implementation inline query_base::operator query<>() const { return flecs::query<>(m_world, m_query); } } // namespace flecs /** * @file addons/cpp/mixins/observer/impl.hpp * @brief Observer implementation. */ #pragma once /** * @file addons/cpp/mixins/observer/builder.hpp * @brief Observer builder. */ #pragma once /** * @file addons/cpp/utils/node_builder.hpp * @brief Base builder class for node objects, like systems, observers. */ #pragma once namespace flecs { namespace _ { // Macros for template types so we don't go cross-eyed #define FLECS_IBUILDER template class template struct node_builder : IBuilder { using IBase = IBuilder; public: explicit node_builder(flecs::world_t* world, const char *name = nullptr) : IBase(&m_desc) , m_desc{} , m_world(world) , m_instanced(false) { ecs_entity_desc_t entity_desc = {}; entity_desc.name = name; entity_desc.sep = "::"; entity_desc.root_sep = "::"; m_desc.entity = ecs_entity_init(m_world, &entity_desc); } /* Iter (or each) is mandatory and always the last thing that * is added in the fluent method chain. Create system signature from both * template parameters and anything provided by the signature method. */ template T iter(Func&& func) { using Delegate = typename _::iter_delegate< typename std::decay::type, Components...>; return build(FLECS_FWD(func)); } /* Each is similar to action, but accepts a function that operates on a * single entity */ template T each(Func&& func) { using Delegate = typename _::each_delegate< typename std::decay::type, Components...>; m_instanced = true; return build(FLECS_FWD(func)); } protected: flecs::world_t* world_v() override { return m_world; } TDesc m_desc; flecs::world_t *m_world; bool m_instanced; private: template T build(Func&& func) { auto ctx = FLECS_NEW(Delegate)(FLECS_FWD(func)); m_desc.callback = Delegate::run; m_desc.binding_ctx = ctx; m_desc.binding_ctx_free = reinterpret_cast< ecs_ctx_free_t>(_::free_obj); return T(m_world, &m_desc, m_instanced); } }; #undef FLECS_IBUILDER } // namespace _ } // namespace flecs /** * @file addons/cpp/mixins/observer/builder_i.hpp * @brief Observer builder interface. */ #pragma once namespace flecs { /** Observer builder interface. * * @ingroup cpp_observers */ template struct observer_builder_i : filter_builder_i { using BaseClass = filter_builder_i; 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 Base& event() { m_desc->events[m_event_count ++] = _::cpp_type().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(this); } ecs_observer_desc_t *m_desc; int32_t m_event_count; }; } namespace flecs { namespace _ { template using observer_builder_base = node_builder< observer, ecs_observer_desc_t, observer_builder, observer_builder_i, Components ...>; } /** Observer builder. * * @ingroup cpp_observers */ template struct observer_builder final : _::observer_builder_base { observer_builder(flecs::world_t* world, const char *name = nullptr) : _::observer_builder_base(world, name) { _::sig(world).populate(this); } }; } 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::Observer); const ecs_observer_t *ob = static_cast(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 inline observer_builder world::observer(Args &&... args) const { return flecs::observer_builder(m_world, FLECS_FWD(args)...); } } // namespace flecs /** * @file addons/cpp/mixins/event/impl.hpp * @brief Event implementation. */ #pragma once namespace flecs { // Mixin implementation inline flecs::event_builder world::event(flecs::entity_t evt) const { return flecs::event_builder(m_world, evt); } template inline flecs::event_builder_typed world::event() const { return flecs::event_builder_typed(m_world, _::cpp_type().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 struct entity_observer_factory { template ::value> = 0> static void create( flecs::world_t *world, flecs::entity_t entity, Func&& f) { using Delegate = _::entity_observer_delegate; auto ctx = FLECS_NEW(Delegate)(FLECS_FWD(f)); entity_observer_create(world, _::cpp_type::id(world), entity, Delegate::run, ctx, reinterpret_cast(_::free_obj)); } template ::value> = 0> static void create( flecs::world_t *world, flecs::entity_t entity, Func&& f) { using Delegate = _::entity_payload_observer_delegate; auto ctx = FLECS_NEW(Delegate)(FLECS_FWD(f)); entity_observer_create(world, _::cpp_type::id(world), entity, Delegate::run, ctx, reinterpret_cast(_::free_obj)); } }; } template template inline Self& entity_builder::observe(flecs::entity_t evt, Func&& f) { using Delegate = _::entity_observer_delegate; auto ctx = FLECS_NEW(Delegate)(FLECS_FWD(f)); _::entity_observer_create(m_world, evt, m_id, Delegate::run, ctx, reinterpret_cast(_::free_obj)); return to_base(); } template template inline Self& entity_builder::observe(Func&& f) { _::entity_observer_factory::template create( m_world, m_id, FLECS_FWD(f)); return to_base(); } template template inline Self& entity_builder::observe(Func&& f) { return this->observe<_::event_from_func_t>(FLECS_FWD(f)); } inline void entity_view::emit(flecs::entity evt) { this->emit(evt.id()); } inline void entity_view::enqueue(flecs::entity evt) { this->enqueue(evt.id()); } } // namespace flecs /** * @file addons/cpp/mixins/enum/impl.hpp * @brief Enum implementation. */ #pragma once namespace flecs { template inline E entity_view::to_constant() const { const E* ptr = this->get(); ecs_assert(ptr != NULL, ECS_INVALID_PARAMETER, "entity is not a constant"); return ptr[0]; } template ::value >> inline flecs::entity world::to_entity(E constant) const { const auto& et = enum_type(m_world); return flecs::entity(m_world, et.entity(constant)); } } #ifdef FLECS_MODULE /** * @file addons/cpp/mixins/module/impl.hpp * @brief Module implementation. */ #pragma once namespace flecs { namespace _ { template ecs_entity_t do_import(world& world, const char *symbol) { ecs_trace("#[magenta]import#[reset] %s", _::type_name()); 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(world, nullptr, false); ecs_add_id(world, m_c, EcsModule); ecs_set_scope(world, m_c); world.emplace(world); ecs_set_scope(world, scope); // It should now be possible to lookup the module ecs_entity_t m = ecs_lookup_symbol(world, symbol, false, false); ecs_assert(m != 0, ECS_MODULE_UNDEFINED, symbol); ecs_assert(m == m_c, ECS_INTERNAL_ERROR, NULL); ecs_log_pop(); return m; } template flecs::entity import(world& world) { const char *symbol = _::symbol_name(); ecs_entity_t m = ecs_lookup_symbol(world, symbol, true, false); if (!_::cpp_type::registered(world)) { /* Module is registered with world, initialize static data */ if (m) { _::cpp_type::init(m, false); /* Module is not yet registered, register it now */ } else { m = _::do_import(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(world, symbol); } return flecs::entity(world, m); } } /** * @defgroup cpp_addons_modules Modules * @ingroup cpp_addons * Modules organize components, systems and more in reusable units of code. * * @{ */ template inline flecs::entity world::module(const char *name) const { flecs::id_t result = _::cpp_type::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 inline flecs::entity world::import() { return flecs::_::import(*this); } /** @} */ } #endif #ifdef FLECS_SYSTEM /** * @file addons/cpp/mixins/system/impl.hpp * @brief System module implementation. */ #pragma once /** * @file addons/cpp/mixins/system/builder.hpp * @brief System builder. */ #pragma once /** * @file addons/cpp/mixins/system/builder_i.hpp * @brief System builder interface. */ #pragma once namespace flecs { /** System builder interface. * * @ingroup cpp_addons_systems */ template struct system_builder_i : query_builder_i { private: using BaseClass = query_builder_i; 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; } template ::value> = 0> Base& kind(E phase) { const auto& et = enum_type(this->world_v()); flecs::entity_t target = et.entity(phase); return this->kind(target); } /** Specify in which phase the system should run. * * @tparam Phase The phase. */ template Base& kind() { return this->kind(_::cpp_type::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. * * @tparam T The type associated with the singleton tick source to use for the system. */ template Base& tick_source() { m_desc->tick_source = _::cpp_type::id(world_v()); 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(this); } ecs_system_desc_t *m_desc; }; } namespace flecs { namespace _ { template using system_builder_base = node_builder< system, ecs_system_desc_t, system_builder, system_builder_i, Components ...>; } /** System builder. * * @ingroup cpp_addons_systems */ template struct system_builder final : _::system_builder_base { system_builder(flecs::world_t* world, const char *name = nullptr) : _::system_builder_base(world, name) { _::sig(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 } }; } namespace flecs { struct system_runner_fluent { system_runner_fluent( world_t *world, entity_t id, int32_t stage_current, int32_t stage_count, ecs_ftime_t delta_time, void *param) : m_stage(world) , m_id(id) , m_delta_time(delta_time) , m_param(param) , m_offset(0) , m_limit(0) , m_stage_current(stage_current) , m_stage_count(stage_count) { } system_runner_fluent& offset(int32_t offset) { m_offset = offset; return *this; } system_runner_fluent& limit(int32_t limit) { m_limit = limit; return *this; } system_runner_fluent& stage(flecs::world& stage) { m_stage = stage.c_ptr(); return *this; } ~system_runner_fluent() { if (m_stage_count) { ecs_run_worker( m_stage, m_id, m_stage_current, m_stage_count, m_delta_time, m_param); } else { ecs_run_w_filter( m_stage, m_id, m_delta_time, m_offset, m_limit, m_param); } } private: world_t *m_stage; entity_t m_id; ecs_ftime_t m_delta_time; void *m_param; int32_t m_offset; int32_t m_limit; int32_t m_stage_current; int32_t m_stage_count; }; struct system final : entity { using entity::entity; explicit system() { m_id = 0; m_world = nullptr; } explicit system(flecs::world_t *world, ecs_system_desc_t *desc, bool instanced) { if (!desc->query.filter.instanced) { desc->query.filter.instanced = instanced; } m_world = world; m_id = ecs_system_init(world, desc); if (desc->query.filter.terms_buffer) { ecs_os_free(desc->query.filter.terms_buffer); } } void ctx(void *ctx) { ecs_system_desc_t desc = {}; desc.entity = m_id; desc.ctx = ctx; ecs_system_init(m_world, &desc); } void* ctx() const { return ecs_system_get_ctx(m_world, m_id); } flecs::query<> query() const { return flecs::query<>(m_world, ecs_system_get_query(m_world, m_id)); } system_runner_fluent run(ecs_ftime_t delta_time = 0.0f, void *param = nullptr) const { return system_runner_fluent(m_world, m_id, 0, 0, delta_time, param); } system_runner_fluent run_worker( int32_t stage_current, int32_t stage_count, ecs_ftime_t delta_time = 0.0f, void *param = nullptr) const { return system_runner_fluent( m_world, m_id, stage_current, stage_count, delta_time, param); } # ifdef FLECS_TIMER /** * @file addons/cpp/mixins/timer/system_mixin.inl * @brief Timer module system mixin. */ /** * @memberof flecs::system * @ingroup cpp_addons_timer * * @{ */ /** Set interval. * @see ecs_set_interval */ void interval(ecs_ftime_t interval); /** Get interval. * @see ecs_get_interval. */ ecs_ftime_t interval(); /** Set timeout. * @see ecs_set_timeout */ void timeout(ecs_ftime_t timeout); /** Get timeout. * @see ecs_get_timeout */ ecs_ftime_t timeout(); /** Set system rate (system is its own tick source). * @see ecs_set_rate */ void rate(int32_t rate); /** Start timer. * @see ecs_start_timer */ void start(); /** Stop timer. * @see ecs_start_timer */ void stop(); /** Set external tick source. * @see ecs_set_tick_source */ template void set_tick_source(); /** Set external tick source. * @see ecs_set_tick_source */ void set_tick_source(flecs::entity e); /** @} */ # endif }; // Mixin implementation inline system world::system(flecs::entity e) const { return flecs::system(m_world, e); } template inline system_builder world::system(Args &&... args) const { return flecs::system_builder(m_world, FLECS_FWD(args)...); } namespace _ { inline void system_init(flecs::world& world) { world.component("flecs::system::TickSource"); } } // namespace _ } // namespace flecs #endif #ifdef FLECS_PIPELINE /** * @file addons/cpp/mixins/pipeline/impl.hpp * @brief Pipeline module implementation. */ #pragma once /** * @file addons/cpp/mixins/pipeline/builder.hpp * @brief Pipeline builder. */ #pragma once /** * @file addons/cpp/mixins/pipeline/builder_i.hpp * @brief Pipeline builder interface. */ #pragma once namespace flecs { /** Pipeline builder interface. * * @ingroup cpp_pipelines */ template struct pipeline_builder_i : query_builder_i { pipeline_builder_i(ecs_pipeline_desc_t *desc, int32_t term_index = 0) : query_builder_i(&desc->query, term_index) , m_desc(desc) { } private: ecs_pipeline_desc_t *m_desc; }; } namespace flecs { namespace _ { template using pipeline_builder_base = builder< pipeline, ecs_pipeline_desc_t, pipeline_builder, pipeline_builder_i, Components ...>; } /** Pipeline builder. * * @ingroup cpp_pipelines */ template struct pipeline_builder final : _::pipeline_builder_base { pipeline_builder(flecs::world_t* world, flecs::entity_t id = 0) : _::pipeline_builder_base(world) { _::sig(world).populate(this); this->m_desc.entity = id; } }; } namespace flecs { template 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 ::value >> inline flecs::pipeline_builder<> world::pipeline() const { return flecs::pipeline_builder<>(m_world, _::cpp_type::id(m_world)); } inline void world::set_pipeline(const flecs::entity pip) const { return ecs_set_pipeline(m_world, pip); } template inline void world::set_pipeline() const { return ecs_set_pipeline(m_world, _::cpp_type::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 ::value >> inline void world::run_pipeline(ecs_ftime_t delta_time) const { return ecs_run_pipeline(m_world, _::cpp_type::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); } } #endif #ifdef FLECS_TIMER /** * @file addons/cpp/mixins/timer/impl.hpp * @brief Timer module implementation. */ #pragma once namespace flecs { // Timer class struct timer final : entity { using entity::entity; timer& interval(ecs_ftime_t interval) { ecs_set_interval(m_world, m_id, interval); return *this; } ecs_ftime_t interval() { return ecs_get_interval(m_world, m_id); } timer& timeout(ecs_ftime_t timeout) { ecs_set_timeout(m_world, m_id, timeout); return *this; } ecs_ftime_t timeout() { return ecs_get_timeout(m_world, m_id); } timer& rate(int32_t rate, flecs::entity_t tick_source = 0) { ecs_set_rate(m_world, m_id, rate, tick_source); return *this; } void start() { ecs_start_timer(m_world, m_id); } void stop() { ecs_stop_timer(m_world, m_id); } }; template inline flecs::timer world::timer() const { return flecs::timer(m_world, _::cpp_type::id(m_world)); } template inline flecs::timer world::timer(Args &&... args) const { return flecs::timer(m_world, FLECS_FWD(args)...); } inline void world::randomize_timers() const { ecs_randomize_timers(m_world); } inline void system::interval(ecs_ftime_t interval) { ecs_set_interval(m_world, m_id, interval); } inline ecs_ftime_t system::interval() { return ecs_get_interval(m_world, m_id); } inline void system::timeout(ecs_ftime_t timeout) { ecs_set_timeout(m_world, m_id, timeout); } inline ecs_ftime_t system::timeout() { return ecs_get_timeout(m_world, m_id); } inline void system::rate(int32_t rate) { ecs_set_rate(m_world, m_id, rate, 0); } inline void system::start() { ecs_start_timer(m_world, m_id); } inline void system::stop() { ecs_stop_timer(m_world, m_id); } template inline void system::set_tick_source() { ecs_set_tick_source(m_world, m_id, _::cpp_type::id(m_world)); } inline void system::set_tick_source(flecs::entity e) { ecs_set_tick_source(m_world, m_id, e); } namespace _ { inline void timer_init(flecs::world& world) { world.component("flecs::timer::RateFilter"); world.component("flecs::timer::Timer"); } } } #endif #ifdef FLECS_SNAPSHOT /** * @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) noexcept : 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) noexcept { 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 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 inline flecs::snapshot world::snapshot(Args &&... args) const { return flecs::snapshot(*this, FLECS_FWD(args)...); } } #endif #ifdef FLECS_DOC /** * @file addons/cpp/mixins/doc/impl.hpp * @brief Doc mixin implementation. */ #pragma once namespace flecs { namespace doc { /** Get human readable name for an entity. * * @see ecs_doc_get_name() * @see flecs::doc::set_name() * @see flecs::entity_view::doc_name() * * @ingroup cpp_addons_doc */ inline const char* get_name(const flecs::entity_view& e) { return ecs_doc_get_name(e.world(), e); } /** Get brief description for an entity. * * @see ecs_doc_get_brief() * @see flecs::doc::set_brief() * @see flecs::entity_view::doc_brief() * * @ingroup cpp_addons_doc */ inline const char* get_brief(const flecs::entity_view& e) { return ecs_doc_get_brief(e.world(), e); } /** Get detailed description for an entity. * * @see ecs_doc_get_detail() * @see flecs::doc::set_detail() * @see flecs::entity_view::doc_detail() * * @ingroup cpp_addons_doc */ inline const char* get_detail(const flecs::entity_view& e) { return ecs_doc_get_detail(e.world(), e); } /** Get link to external documentation for an entity. * * @see ecs_doc_get_link() * @see flecs::doc::set_link() * @see flecs::entity_view::doc_link() * * @ingroup cpp_addons_doc */ inline const char* get_link(const flecs::entity_view& e) { return ecs_doc_get_link(e.world(), e); } /** Get color for an entity. * * @see ecs_doc_get_color() * @see flecs::doc::set_color() * @see flecs::entity_view::doc_color() * * @ingroup cpp_addons_doc */ inline const char* get_color(const flecs::entity_view& e) { return ecs_doc_get_color(e.world(), e); } /** Set human readable name for an entity. * * @see ecs_doc_set_name() * @see flecs::doc::get_name() * @see flecs::entity_builder::set_doc_name() * * @ingroup cpp_addons_doc */ inline void set_name(flecs::entity& e, const char *name) { ecs_doc_set_name(e.world(), e, name); } /** Set brief description for an entity. * * @see ecs_doc_set_brief() * @see flecs::doc::get_brief() * @see flecs::entity_builder::set_doc_brief() * * @ingroup cpp_addons_doc */ inline void set_brief(flecs::entity& e, const char *description) { ecs_doc_set_brief(e.world(), e, description); } /** Set detailed description for an entity. * * @see ecs_doc_set_detail() * @see flecs::doc::get_detail() * @see flecs::entity_builder::set_doc_detail() * * @ingroup cpp_addons_doc */ inline void set_detail(flecs::entity& e, const char *description) { ecs_doc_set_detail(e.world(), e, description); } /** Set link to external documentation for an entity. * * @see ecs_doc_set_link() * @see flecs::doc::get_link() * @see flecs::entity_builder::set_doc_link() * * @ingroup cpp_addons_doc */ inline void set_link(flecs::entity& e, const char *link) { ecs_doc_set_link(e.world(), e, link); } /** Set color for an entity. * * @see ecs_doc_set_color() * @see flecs::doc::get_color() * @see flecs::entity_builder::set_doc_color() * * @ingroup cpp_addons_doc */ inline void set_color(flecs::entity& e, const char *color) { ecs_doc_set_color(e.world(), e, color); } /** @private */ namespace _ { /** @private */ inline void init(flecs::world& world) { world.component("flecs::doc::Description"); } } // namespace _ } // namespace doc } // namespace flecs #endif #ifdef FLECS_DOC #endif #ifdef FLECS_REST /** * @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("flecs::rest::Rest"); } } // namespace _ } // namespace rest } // namespace flecs #endif #ifdef FLECS_RULES /** * @file addons/cpp/mixins/rule/impl.hpp * @brief Rule implementation. */ #pragma once /** * @file addons/cpp/mixins/rule/builder.hpp * @brief Rule builder. */ #pragma once namespace flecs { namespace _ { template using rule_builder_base = builder< rule, ecs_filter_desc_t, rule_builder, filter_builder_i, Components ...>; } /** Rule builder. * * @ingroup cpp_addons_rules */ template struct rule_builder final : _::rule_builder_base { rule_builder(flecs::world_t* world, const char *name = nullptr) : _::rule_builder_base(world) { _::sig(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); } } }; } 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 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 struct rule final : rule_base, iterable { private: using Terms = typename _::term_ptrs::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 inline flecs::rule world::rule(Args &&... args) const { return flecs::rule_builder(m_world, FLECS_FWD(args)...) .build(); } template inline flecs::rule_builder world::rule_builder(Args &&... args) const { return flecs::rule_builder(m_world, FLECS_FWD(args)...); } // rule_base implementation inline rule_base::operator rule<>() const { return flecs::rule<>(m_world, m_rule); } } // namespace flecs #endif #ifdef FLECS_META /** * @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 inline flecs::opaque flecs_entity_support(flecs::world&) { return flecs::opaque() .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("flecs::meta::bool"); world.component("flecs::meta::char"); world.component("flecs::meta::u8"); world.component("flecs::meta::u16"); world.component("flecs::meta::u32"); world.component("flecs::meta::u64"); world.component("flecs::meta::i8"); world.component("flecs::meta::i16"); world.component("flecs::meta::i32"); world.component("flecs::meta::i64"); world.component("flecs::meta::f32"); world.component("flecs::meta::f64"); world.component("flecs::meta::type_kind"); world.component("flecs::meta::primitive_kind"); world.component("flecs::meta::member"); world.component("flecs::meta::enum_constant"); world.component("flecs::meta::bitmask_constant"); world.component("flecs::meta::MetaType"); world.component("flecs::meta::MetaTypeSerialized"); world.component("flecs::meta::Primitive"); world.component("flecs::meta::Enum"); world.component("flecs::meta::Bitmask"); world.component("flecs::meta::Member"); world.component("flecs::meta::MemberRanges"); world.component("flecs::meta::Struct"); world.component("flecs::meta::Array"); world.component("flecs::meta::Vector"); world.component("flecs::meta::Unit"); // To support member and member register components // (that do not have conflicting symbols with builtin ones) for platform // specific types. if (!flecs::is_same() && !flecs::is_same()) { flecs::_::cpp_type::init(flecs::Iptr, true); ecs_assert(flecs::type_id() == 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() && !flecs::is_same()) { flecs::_::cpp_type::init(flecs::Uptr, true); ecs_assert(flecs::type_id() == 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.entity("::flecs::cpp").add(flecs::Module).scope([&]{ world.component() .opaque(flecs_entity_support); world.component() .opaque(flecs_entity_support); }); } } // 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 inline flecs::entity world::array(int32_t array_count) { return this->array(_::cpp_type::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 inline flecs::entity world::vector() { return this->vector(_::cpp_type::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 inline int ecs_serializer_t::value(const T& v) const { return this->value(flecs::_::cpp_type::id( const_cast(this->world)), &v); } inline int ecs_serializer_t::member(const char *name) const { return this->member_(this, name); } #endif #ifdef FLECS_UNITS /** * @file addons/cpp/mixins/units/impl.hpp * @brief Units module implementation. */ #pragma once namespace flecs { inline units::units(flecs::world& world) { /* Import C module */ FlecsUnitsImport(world); /* Bridge between C++ types and flecs.units entities */ world.module(); // Initialize world.entity(prefixes) scope world.entity("::flecs::units::prefixes"); // Initialize prefixes world.entity("::flecs::units::prefixes::Yocto"); world.entity("::flecs::units::prefixes::Zepto"); world.entity("::flecs::units::prefixes::Atto"); world.entity("::flecs::units::prefixes::Femto"); world.entity("::flecs::units::prefixes::Pico"); world.entity("::flecs::units::prefixes::Nano"); world.entity("::flecs::units::prefixes::Micro"); world.entity("::flecs::units::prefixes::Milli"); world.entity("::flecs::units::prefixes::Centi"); world.entity("::flecs::units::prefixes::Deci"); world.entity("::flecs::units::prefixes::Deca"); world.entity("::flecs::units::prefixes::Hecto"); world.entity("::flecs::units::prefixes::Kilo"); world.entity("::flecs::units::prefixes::Mega"); world.entity("::flecs::units::prefixes::Giga"); world.entity("::flecs::units::prefixes::Tera"); world.entity("::flecs::units::prefixes::Peta"); world.entity("::flecs::units::prefixes::Exa"); world.entity("::flecs::units::prefixes::Zetta"); world.entity("::flecs::units::prefixes::Yotta"); world.entity("::flecs::units::prefixes::Kibi"); world.entity("::flecs::units::prefixes::Mebi"); world.entity("::flecs::units::prefixes::Gibi"); world.entity("::flecs::units::prefixes::Tebi"); world.entity("::flecs::units::prefixes::Pebi"); world.entity("::flecs::units::prefixes::Exbi"); world.entity("::flecs::units::prefixes::Zebi"); world.entity("::flecs::units::prefixes::Yobi"); // Initialize quantities world.entity("::flecs::units::Duration"); world.entity iter::field(int32_t index) const { ecs_assert(!(m_iter->flags & EcsIterCppEach), ECS_INVALID_OPERATION, "cannot .field from .each, use .field_at(%d, row) instead", _::type_name(), index); return get_field(index); } template ::value == false, void>::type*> inline flecs::field iter::field(int32_t index) const { ecs_assert(!(m_iter->flags & EcsIterCppEach), ECS_INVALID_OPERATION, "cannot .field from .each, use .field_at<%s>(%d, row) instead", _::type_name(), index); ecs_assert(!ecs_field_is_readonly(m_iter, index), ECS_ACCESS_VIOLATION, NULL); return get_field(index); } #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 /** * @file addons/cpp/impl/world.hpp * @brief World implementation. */ #pragma once namespace flecs { inline void world::init_builtin_components() { this->component(); this->component(); this->component("flecs::core::Iterable"); this->component(); this->component(); # 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 inline flecs::entity world::use(const char *alias) const { entity_t e = _::cpp_type::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 inline flecs::entity world::set_scope() const { return set_scope( _::cpp_type::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); } #ifndef ensure template inline T& world::ensure() const { flecs::entity e(m_world, _::cpp_type::id(m_world)); return e.ensure(); } #endif template inline void world::modified() const { flecs::entity e(m_world, _::cpp_type::id(m_world)); e.modified(); } template inline void world::set(Second second, const First& value) const { flecs::entity e(m_world, _::cpp_type::id(m_world)); e.set(second, value); } template inline void world::set(Second second, First&& value) const { flecs::entity e(m_world, _::cpp_type::id(m_world)); e.set(second, value); } template inline ref world::get_ref() const { flecs::entity e(m_world, _::cpp_type::id(m_world)); return e.get_ref(); } template inline const T* world::get() const { flecs::entity e(m_world, _::cpp_type::id(m_world)); return e.get(); } template const A* world::get() const { flecs::entity e(m_world, _::cpp_type::id(m_world)); return e.get(); } template const First* world::get(Second second) const { flecs::entity e(m_world, _::cpp_type::id(m_world)); return e.get(second); } template T* world::get_mut() const { flecs::entity e(m_world, _::cpp_type::id(m_world)); return e.get_mut(); } template A* world::get_mut() const { flecs::entity e(m_world, _::cpp_type::id(m_world)); return e.get_mut(); } template First* world::get_mut(Second second) const { flecs::entity e(m_world, _::cpp_type::id(m_world)); return e.get_mut(second); } template inline bool world::has() const { flecs::entity e(m_world, _::cpp_type::id(m_world)); return e.has(); } template inline bool world::has() const { flecs::entity e(m_world, _::cpp_type::id(m_world)); return e.has(); } template inline bool world::has(flecs::id_t second) const { flecs::entity e(m_world, _::cpp_type::id(m_world)); return e.has(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 inline void world::add() const { flecs::entity e(m_world, _::cpp_type::id(m_world)); e.add(); } template inline void world::add() const { flecs::entity e(m_world, _::cpp_type::id(m_world)); e.add(); } template inline void world::add(flecs::entity_t second) const { flecs::entity e(m_world, _::cpp_type::id(m_world)); e.add(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 inline void world::remove() const { flecs::entity e(m_world, _::cpp_type::id(m_world)); e.remove(); } template inline void world::remove() const { flecs::entity e(m_world, _::cpp_type::id(m_world)); e.remove(); } template inline void world::remove(flecs::entity_t second) const { flecs::entity e(m_world, _::cpp_type::id(m_world)); e.remove(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 inline void world::children(Func&& f) const { this->entity(0).children(FLECS_FWD(f)); } template inline flecs::entity world::singleton() const { return flecs::entity(m_world, _::cpp_type::id(m_world)); } template inline flecs::entity world::target(int32_t index) const { return flecs::entity(m_world, ecs_get_target(m_world, _::cpp_type::id(m_world), _::cpp_type::id(m_world), index)); } template 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::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 ::value > > inline void world::get(const Func& func) const { static_assert(arity::value == 1, "singleton component must be the only argument"); _::entity_with_delegate::invoke_get( this->m_world, this->singleton>(), func); } template ::value > > inline void world::set(const Func& func) const { static_assert(arity::value == 1, "singleton component must be the only argument"); _::entity_with_delegate::invoke_ensure( this->m_world, this->singleton>(), 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); } inline flecs::entity world::make_alive(flecs::entity_t e) const { ecs_make_alive(m_world, e); return flecs::entity(m_world, e); } template inline flecs::entity enum_data::entity() const { return flecs::entity(world_, impl_.id); } template inline flecs::entity enum_data::entity(underlying_type_t value) const { int index = index_by_value(value); if (index >= 0) { return flecs::entity(world_, impl_.constants[index].id); } #ifdef FLECS_META // Reflection data lookup failed. Try value lookup amongst flecs::Constant relationships flecs::world world = flecs::world(world_); return world.filter_builder() .with(flecs::ChildOf, world.id()) .with(flecs::Constant, world.id()) .build() .find([value](flecs::entity constant) { const int32_t *constant_value = constant.get_second(flecs::Constant); ecs_assert(constant_value, ECS_INTERNAL_ERROR, NULL); return value == static_cast>(*constant_value); }); #else return flecs::entity::null(world_); #endif } template inline flecs::entity enum_data::entity(E value) const { return entity(static_cast>(value)); } /** 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 inline flecs::scoped_world world::scope() const { flecs::id_t parent = _::cpp_type::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 /** * @defgroup cpp_core Core * Core ECS functionality (entities, storage, queries) * * @{ * @} */ /** * @defgroup cpp_addons Addons * C++ APIs for addons. * * @{ * @} */ /** @} */ #endif // __cplusplus #endif // FLECS_CPP #endif #endif