From 148ddcd2c0613bb96050b8a72e9f6f83513ca9ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Madar=C3=A1sz?= Date: Sun, 15 Aug 2021 18:32:11 +0200 Subject: [PATCH] code: updated flecs to 2.4.1 --- code/game/src/debug_replay.c | 5 + code/game/src/debug_ui.c | 1 + code/game/src/debug_ui_actions.c | 24 ++ code/vendors/flecs/flecs.c | 123 ++++-- code/vendors/flecs/flecs.h | 670 +++++++++++++++++++------------ 5 files changed, 523 insertions(+), 300 deletions(-) diff --git a/code/game/src/debug_replay.c b/code/game/src/debug_replay.c index 7c612f4..d2a8390 100644 --- a/code/game/src/debug_replay.c +++ b/code/game/src/debug_replay.c @@ -10,6 +10,7 @@ typedef enum { // NOTE(zaklaus): Special actions RPKIND_SPAWN_CAR, RPKIND_PLACE_ICE_RINK, + RPKIND_SPAWN_CIRCLING_DRIVER, } replay_kind; typedef struct { @@ -150,6 +151,7 @@ void debug_replay_run(void) { } void ActPlaceIceRink(); +void ActSpawnCirclingDriver(void); void debug_replay_update(void) { if (!is_playing) return; @@ -178,6 +180,9 @@ void debug_replay_update(void) { case RPKIND_PLACE_ICE_RINK: { ActPlaceIceRink(); }break; + case RPKIND_SPAWN_CIRCLING_DRIVER: { + ActSpawnCirclingDriver(); + }break; default: { ZPL_PANIC("unreachable"); }break; diff --git a/code/game/src/debug_ui.c b/code/game/src/debug_ui.c index 1c75893..61c3108 100644 --- a/code/game/src/debug_ui.c +++ b/code/game/src/debug_ui.c @@ -112,6 +112,7 @@ static debug_item items[] = { .items = (debug_item[]) { { .kind = DITEM_BUTTON, .name = "spawn car", .on_click = ActSpawnCar }, { .kind = DITEM_BUTTON, .name = "place ice rink", .on_click = ActPlaceIceRink }, + { .kind = DITEM_BUTTON, .name = "spawn circling driver", .on_click = ActSpawnCirclingDriver }, { .kind = DITEM_LIST, .name = "demo npcs", diff --git a/code/game/src/debug_ui_actions.c b/code/game/src/debug_ui_actions.c index cd9f841..013cfef 100644 --- a/code/game/src/debug_ui_actions.c +++ b/code/game/src/debug_ui_actions.c @@ -18,6 +18,30 @@ ActSpawnCar(void) { debug_replay_special_action(RPKIND_SPAWN_CAR); } +void +ActSpawnCirclingDriver(void) { + ecs_entity_t plr = camera_get().ent_id; + ecs_entity_t ve = vehicle_spawn(); + ecs_entity_t e = entity_spawn(EKIND_DEMO_NPC); + + Position const *origin = ecs_get(world_ecs(), plr, Position); + Position *veh_dest = ecs_get_mut(world_ecs(), ve, Position, NULL); + Position *dest = ecs_get_mut(world_ecs(), e, Position, NULL); + *veh_dest = *origin; + *dest = *origin; + + Input *input = ecs_get_mut(world_ecs(), e, Input, NULL); + input->x = input->y = 1.0f; + input->use = false; + + Vehicle *veh = ecs_get_mut(world_ecs(), ve, Vehicle, NULL); + veh->seats[0] = e; + + ecs_set(world_ecs(), e, IsInVehicle, { .veh = ve }); + + debug_replay_special_action(RPKIND_SPAWN_CIRCLING_DRIVER); +} + void ActPlaceIceRink(void) { ecs_entity_t plr = camera_get().ent_id; diff --git a/code/vendors/flecs/flecs.c b/code/vendors/flecs/flecs.c index f5fc0cc..a926d6c 100644 --- a/code/vendors/flecs/flecs.c +++ b/code/vendors/flecs/flecs.c @@ -2948,8 +2948,9 @@ void dtor_component( if (cdata && (dtor = cdata->lifecycle.dtor)) { void *ctx = cdata->lifecycle.ctx; int16_t size = column->size; - int16_t alignment = column->alignment; + int16_t alignment = column->alignment; + ecs_assert(column->data != NULL, ECS_INTERNAL_ERROR, NULL); void *ptr = ecs_vector_get_t(column->data, size, alignment, row); ecs_assert(ptr != NULL, ECS_INTERNAL_ERROR, NULL); @@ -4549,6 +4550,9 @@ bool flecs_table_match_filter( const ecs_table_t *table, const ecs_filter_t * filter) { + ecs_assert(world != NULL, ECS_INTERNAL_ERROR, NULL); + ecs_assert(table != NULL, ECS_INTERNAL_ERROR, NULL); + if (!filter) { return true; } @@ -4767,13 +4771,13 @@ void* get_base_component( ecs_type_t type = table->type; ecs_id_t *ids = ecs_vector_first(type, ecs_id_t); - int32_t i = tr_isa->column, count = tr_isa->count; + int32_t i = tr_isa->column, end = tr_isa->count + tr_isa->column; void *ptr = NULL; do { - ecs_id_t pair = ids[i]; - + ecs_id_t pair = ids[i ++]; ecs_entity_t base = ecs_pair_object(world, pair); + ecs_record_t *r = ecs_eis_get(world, base); if (!r) { continue; @@ -4794,8 +4798,7 @@ void* get_base_component( int32_t row = flecs_record_to_row(r->row, &is_monitored); ptr = get_component_w_index(table, tr->column, row); } - i ++; - } while (!ptr && (i < count)); + } while (!ptr && (i < end)); return ptr; } @@ -6275,7 +6278,7 @@ ecs_entity_t ecs_new_id( } ecs_assert(!unsafe_world->stats.max_id || - entity <= unsafe_world->stats.max_id, + ecs_entity_t_lo(entity) <= unsafe_world->stats.max_id, ECS_OUT_OF_RANGE, NULL); return entity; @@ -6444,7 +6447,7 @@ ecs_table_t *traverse_from_expr( if (ptr) { ecs_term_t term = {0}; while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term))){ - if (!ecs_term_is_set(&term)) { + if (!ecs_term_is_initialized(&term)) { break; } @@ -6530,7 +6533,7 @@ void defer_from_expr( if (ptr) { ecs_term_t term = {0}; while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term))) { - if (!ecs_term_is_set(&term)) { + if (!ecs_term_is_initialized(&term)) { break; } @@ -7891,6 +7894,8 @@ ecs_entity_t ecs_get_case( ecs_assert(ecs_is_valid(world, entity), ECS_INVALID_PARAMETER, NULL); ecs_assert(ecs_is_valid(world, sw_id), ECS_INVALID_PARAMETER, NULL); + world = ecs_get_world(world); + ecs_entity_info_t info; ecs_table_t *table; if (!flecs_get_info(world, entity, &info) || !(table = info.table)) { @@ -11270,7 +11275,7 @@ int ecs_plecs_from_str( } while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term))) { - if (!ecs_term_is_set(&term)) { + if (!ecs_term_is_initialized(&term)) { break; } @@ -12203,10 +12208,7 @@ ecs_data_t* duplicate_data( ecs_entity_t component = components[i]; ecs_column_t *column = &result->columns[i]; - if (component > ECS_HI_COMPONENT_ID) { - column->data = NULL; - continue; - } + component = ecs_get_typeid(world, component); const ecs_type_info_t *cdata = flecs_get_c_info(world, component); int16_t size = column->size; @@ -12287,7 +12289,6 @@ ecs_snapshot_t* snapshot_create( } ecs_table_leaf_t *l = ecs_vector_add(&result->tables, ecs_table_leaf_t); - l->table = t; l->type = t->type; l->data = duplicate_data(world, t, data); @@ -16601,6 +16602,12 @@ bool ecs_id_match( return false; } +bool ecs_id_is_pair( + ecs_id_t id) +{ + return ECS_HAS_ROLE(id, PAIR); +} + bool ecs_id_is_wildcard( ecs_id_t id) { @@ -16620,7 +16627,7 @@ bool ecs_term_id_is_set( return id->entity != 0 || id->name != NULL; } -bool ecs_term_is_set( +bool ecs_term_is_initialized( const ecs_term_t *term) { return term->id != 0 || ecs_term_id_is_set(&term->pred); @@ -16819,7 +16826,7 @@ int ecs_filter_init( } else { terms = (ecs_term_t*)desc->terms; for (i = 0; i < ECS_TERM_CACHE_SIZE; i ++) { - if (!ecs_term_is_set(&terms[i])) { + if (!ecs_term_is_initialized(&terms[i])) { break; } @@ -16848,7 +16855,7 @@ int ecs_filter_init( const char *ptr = desc->expr; ecs_term_t term = {0}; while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term))){ - if (!ecs_term_is_set(&term)) { + if (!ecs_term_is_initialized(&term)) { break; } @@ -16925,6 +16932,42 @@ error: return -1; } +void ecs_filter_copy( + ecs_filter_t *dst, + const ecs_filter_t *src) +{ + if (src) { + *dst = *src; + + if (src->terms == src->term_cache) { + dst->terms = dst->term_cache; + } else { + /* Copying allocated term arrays is unsupported at this moment */ + ecs_abort(ECS_UNSUPPORTED, NULL); + } + } else { + ecs_os_memset_t(dst, 0, ecs_filter_t); + } +} + +void ecs_filter_move( + ecs_filter_t *dst, + ecs_filter_t *src) +{ + if (src) { + *dst = *src; + + if (src->terms == src->term_cache) { + dst->terms = dst->term_cache; + } + + src->terms = NULL; + src->term_count = 0; + } else { + ecs_os_memset_t(dst, 0, ecs_filter_t); + } +} + void ecs_filter_fini( ecs_filter_t *filter) { @@ -17195,6 +17238,10 @@ bool flecs_filter_match_table( result = !result; } + if (oper == EcsOptional) { + result = true; + } + if (is_or) { or_result |= result; } else if (!result) { @@ -17215,16 +17262,14 @@ bool flecs_filter_match_table( int32_t t_i = term->index; void **ptr = ptrs ? &ptrs[t_i] : NULL; - bool has_data = populate_from_column(world, table, term->id, column, + populate_from_column(world, table, term->id, column, source, &ids[t_i], &types[t_i], &subjects[t_i], &sizes[t_i], ptr); - if (!source) { - if (has_data) { - columns[t_i] = column + 1; - } else { - columns[t_i] = 0; - } + if (column != -1) { + columns[t_i] = column + 1; + } else { + columns[t_i] = 0; } } } @@ -17427,7 +17472,7 @@ ecs_iter_t ecs_filter_iter( const ecs_filter_t *filter) { ecs_assert(world != NULL, ECS_INVALID_PARAMETER, NULL); - + ecs_iter_t it = { .world = world }; @@ -19717,8 +19762,6 @@ add_pair: references = add_ref(world, query, references, term, component, entity); table_data.columns[c] = -ecs_vector_count(references); - } else { - table_data.columns[c] = 0; } table_data.subjects[c] = entity; @@ -19729,9 +19772,7 @@ add_pair: const EcsComponent *cptr = ecs_get(world, type_id, EcsComponent); if (!cptr || !cptr->size) { int32_t column = table_data.columns[c]; - if (column > 0) { - table_data.columns[c] = 0; - } else if (column) { + if (column < 0) { ecs_ref_t *r = ecs_vector_get( references, ecs_ref_t, -column - 1); r->component = 0; @@ -21877,11 +21918,12 @@ void mark_columns_dirty( for (i = 0; i < count; i ++) { ecs_term_t *term = &terms[i]; ecs_term_id_t *subj = &term->args[0]; + if (term->inout != EcsIn && (term->inout != EcsInOutDefault || (subj->entity == EcsThis && subj->set.mask == EcsSelf))) { int32_t table_column = table_data->columns[c]; - if (table_column > 0) { + if (table_column > 0 && table_column <= table->column_count) { table->dirty_state[table_column] ++; } } @@ -23708,6 +23750,7 @@ bool ecs_term_is_owned( int32_t term) { ecs_assert(it->is_valid, ECS_INVALID_PARAMETER, NULL); + ecs_assert(term > 0, ECS_INVALID_PARAMETER, NULL); return it->subjects == NULL || it->subjects[term - 1] == 0; } @@ -23716,6 +23759,7 @@ bool ecs_term_is_readonly( int32_t term_index) { ecs_assert(it->is_valid, ECS_INVALID_PARAMETER, NULL); + ecs_assert(term_index > 0, ECS_INVALID_PARAMETER, NULL); ecs_query_t *query = it->query; @@ -23743,10 +23787,21 @@ bool ecs_term_is_readonly( } } } - + return false; } +bool ecs_term_is_set( + const ecs_iter_t *it, + int32_t term) +{ + ecs_assert(it->is_valid, ECS_INVALID_PARAMETER, NULL); + ecs_assert(it->columns != NULL, ECS_INTERNAL_ERROR, NULL); + ecs_assert(term > 0, ECS_INVALID_PARAMETER, NULL); + + return it->columns[term - 1] != 0; +} + ecs_entity_t ecs_term_source( const ecs_iter_t *it, int32_t term) @@ -24179,7 +24234,7 @@ ecs_entity_t ecs_trigger_init( goto error; } - if (!ecs_term_is_set(&term)) { + if (!ecs_term_is_initialized(&term)) { ecs_parser_error( name, expr, 0, "invalid empty trigger expression"); goto error; diff --git a/code/vendors/flecs/flecs.h b/code/vendors/flecs/flecs.h index a007cf8..3694dc7 100644 --- a/code/vendors/flecs/flecs.h +++ b/code/vendors/flecs/flecs.h @@ -1109,6 +1109,8 @@ private: int m_index; }; +/* C++ class mainly used as wrapper around internal ecs_vector_t. Do not use + * this class as a replacement for STL datastructures! */ template class vector { public: @@ -1150,6 +1152,10 @@ public: ecs_vector_clear(m_vector); } + void destruct() { + ecs_vector_free(m_vector); + } + void add(T& value) { T* elem = static_cast(_ecs_vector_add(&m_vector, ECS_VECTOR_T(T))); *elem = value; @@ -1402,6 +1408,8 @@ void ecs_map_memory( namespace flecs { +/* C++ class mainly used as wrapper around internal ecs_map_t. Do not use + * this class as a replacement for STL datastructures! */ template class map { public: @@ -1437,6 +1445,10 @@ public: reinterpret_cast(key))); } + void destruct() { + ecs_map_free(m_map); + } + private: void init(size_t count) { m_map = ecs_map_new(T, static_cast(count)); @@ -2549,6 +2561,7 @@ struct ecs_iter_t { ecs_table_t *table; /**< Current table */ ecs_data_t *data; + ecs_id_t *ids; ecs_type_t *types; int32_t *columns; @@ -6061,7 +6074,7 @@ bool ecs_term_id_is_set( * @return True when set, false when not set. */ FLECS_API -bool ecs_term_is_set( +bool ecs_term_is_initialized( const ecs_term_t *term); /** Test whether a term is a trivial term. @@ -6166,6 +6179,15 @@ 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. @@ -6272,6 +6294,18 @@ FLECS_API bool ecs_filter_next( ecs_iter_t *iter); +/** Move resources of one filter to another. */ +FLECS_API +void ecs_filter_move( + ecs_filter_t *dst, + ecs_filter_t *src); + +/** Copy resources of one filter to another. */ +FLECS_API +void ecs_filter_copy( + ecs_filter_t *dst, + const ecs_filter_t *src); + /** @} */ /** @@ -6673,6 +6707,20 @@ bool ecs_term_is_readonly( const ecs_iter_t *it, int32_t index); +/** Test whether term is set. + * This function returns false for terms with the Not operator and for terms + * with the Optional operator if the matched entities (table) do not have the + * (component) id of the term. + * + * @param it The iterator. + * @param term The term. + * @return True if term is set, false if it is not set. + */ +FLECS_API +bool ecs_term_is_set( + const ecs_iter_t *it, + int32_t term); + /** Test whether the term is owned * This operation returns whether the term is owned by the currently iterated * entity. This function will return false when the term is owned by another @@ -9248,13 +9296,15 @@ class type; class pipeline; class iter; class term; -class filter; class filter_iterator; class child_iterator; class world_filter; class snapshot_filter; class query_base; +template +class filter; + template class query; @@ -9264,6 +9314,9 @@ class system; template class observer; +template +class filter_builder; + template class query_builder; @@ -9448,6 +9501,7 @@ using std::is_const; using std::is_pointer; using std::is_reference; using std::is_volatile; +using std::is_same; // Apply cv modifiers from source type to destination type @@ -9966,6 +10020,7 @@ struct function_traits } // _ + template struct is_callable { static constexpr bool value = _::function_traits::is_callable; @@ -9982,6 +10037,23 @@ using return_type_t = typename _::function_traits::return_type; template using arg_list_t = typename _::function_traits::args; + +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; + } // flecs namespace flecs { @@ -10826,14 +10898,14 @@ public: */ bool is_owned(int32_t index) const { return ecs_term_is_owned(m_iter, index); - } + } /** Returns whether term is set. * * @param index The term index. */ bool is_set(int32_t index) const { - return ecs_term_w_size(m_iter, 0, index) != NULL; + return ecs_term_is_set(m_iter, index); } /** Returns whether term is readonly. @@ -11744,89 +11816,6 @@ public: */ void use(flecs::entity entity, const char *alias = nullptr); - /** Delete all entities matching a filter. - * - * @param filter The filter to use for matching. - */ - void delete_entities(flecs::filter filter) const; - - /** Add component to all entities matching a filter. - * - * @tparam T The component to add. - * @param filter The filter to use for matching. - */ - template - void add(flecs::filter filter) const; - - /** Add type to all entities. - * - * @param type The type to add. - */ - void add(flecs::type type) const; - - /** Add type to all entities matching a filter. - * - * @param type The type to add. - * @param filter The filter to use for matching. - */ - void add(flecs::type type, flecs::filter filter) const; - - /** Add entity to all entities. - * - * @param entity The entity to add. - */ - void add(flecs::entity entity) const; - - /** Add entity to all entities matching a filter. - * - * @param entity The entity to add. - * @param filter The filter to use for matching. - */ - void add(flecs::entity entity, flecs::filter filter) const; - - /** Remove component from all entities matching a filter. - * - * @tparam T The component to remove. - * @param filter The filter to use for matching. - */ - template - void remove(flecs::filter filter) const; - - /** Remove type from all entities. - * - * @param type The component to remove. - */ - void remove(flecs::type type) const; - - /** Remove type from all entities matching a filter. - * - * @tparam T The component to remove. - * @param filter The filter to use for matching. - */ - void remove(flecs::type type, flecs::filter filter) const; - - /** Remove entity from all entities. - * - * @param entity The entity to remove. - */ - void remove(flecs::entity entity) const; - - /** Remove entity from all entities matching a filter. - * - * @param entity The entity to remove. - * @param filter The filter to use for matching. - */ - void remove(flecs::entity entity, flecs::filter filter) const; - - /** Create iterable filter for entities in world. - * - * @param filter The filter to create. - */ - world_filter filter(const flecs::filter& filter) const; - - flecs::filter_iterator begin() const; - flecs::filter_iterator end() const; - /** Count entities matching a component. * * @tparam T The component to use for matching. @@ -11836,11 +11825,8 @@ public: return ecs_count_id(m_world, _::cpp_type::id(m_world)); } - /** Count entities matching a filter. - * - * @param filter The filter to use for matching. - */ - int count(flecs::filter filter) const; + flecs::filter_iterator begin() const; + flecs::filter_iterator end() const; /** Enable locking. * @@ -11920,6 +11906,9 @@ public: } /** Iterate over all entities with provided component. + * The function parameter must match the following signature: + * void(*)(T&) or + * void(*)(flecs::entity, T&) */ template void each(Func&& func) const; @@ -11929,6 +11918,14 @@ public: template void each(flecs::id_t term_id, Func&& func) const; + /** Iterate over all entities with components in argument list of function. + * The function parameter must match the following signature: + * void(*)(T&, U&, ...) or + * void(*)(flecs::entity, T&, U&, ...) + */ + template + void each(Func&& func) const; + /** Create a prefab. */ template @@ -11973,6 +11970,16 @@ public: template flecs::observer_builder observer(Args &&... args) const; + /** Create a filter. + */ + template + flecs::filter filter(Args &&... args) const; + + /** Create a filter builder. + */ + template + flecs::filter_builder filter_builder(Args &&... args) const; + /** Create a query. */ template @@ -15472,7 +15479,7 @@ public: } bool is_set() { - return ecs_term_is_set(&value); + return ecs_term_is_initialized(&value); } bool is_trivial() { @@ -15522,7 +15529,7 @@ public: ecs_assert(term_index > 0, ECS_INVALID_PARAMETER, NULL); m_term_index = term_index - 1; this->term(); - ecs_assert(ecs_term_is_set(this->m_term), ECS_INVALID_PARAMETER, NULL); + ecs_assert(ecs_term_is_initialized(this->m_term), ECS_INVALID_PARAMETER, NULL); return *this; } @@ -15916,6 +15923,66 @@ private: int32_t m_event_count; }; +// Filter builder +template +class filter_builder_base + : public filter_builder_i, Components ...> +{ +public: + filter_builder_base(flecs::world_t *world) + : filter_builder_i, Components ...>(&m_desc) + , m_desc({}) + , m_world(world) + { + this->populate_filter_from_pack(); + } + + filter_builder_base(const filter_builder_base& obj) + : filter_builder_i, Components ...>(&m_desc, obj.m_term_index) + { + m_world = obj.m_world; + m_desc = obj.m_desc; + } + + filter_builder_base(filter_builder_base&& obj) + : filter_builder_i, Components ...>(&m_desc, obj.m_term_index) + { + m_world = obj.m_world; + m_desc = obj.m_desc; + } + + operator filter() const; + + operator ecs_filter_t() const { + ecs_filter_t f; + + int res = ecs_filter_init(this->m_world, &f, &this->m_desc); + if (res != 0) { + ecs_abort(ECS_INVALID_PARAMETER, NULL); + } + + return f; + } + + filter build() const; + + ecs_filter_desc_t m_desc; + + flecs::world_t* world() override { return m_world; } + +protected: + flecs::world_t *m_world; +}; + +template +class filter_builder final : public filter_builder_base { +public: + filter_builder(flecs::world_t *world) + : filter_builder_base(world) { } + + operator filter<>() const; +}; + // Query builder template class query_builder_base @@ -16025,7 +16092,7 @@ private: if (is_trigger) { ecs_trigger_desc_t desc = {}; ecs_term_t term = m_desc.query.filter.terms[0]; - if (ecs_term_is_set(&term)) { + if (ecs_term_is_initialized(&term)) { desc.term = term; } else { desc.expr = m_desc.query.filter.expr; @@ -16458,94 +16525,157 @@ flecs::entity import(world& world) { } } // namespace flecs - namespace flecs { //////////////////////////////////////////////////////////////////////////////// -//// A filter is used to match subsets of tables +//// Ad hoc queries (filters) //////////////////////////////////////////////////////////////////////////////// - -enum match_kind { - MatchAll = EcsMatchAll, - MatchAny = EcsMatchAny, - MatchExact = EcsMatchExact -}; -class filter { +class filter_base { public: - filter() - : m_world( nullptr ) - , m_filter{ } {} - - explicit filter(const world& world) - : m_world( world.c_ptr() ) - , m_filter{ } { } - - filter& include(type type) { - m_filter.include = ecs_type_merge(m_world, m_filter.include, type.c_ptr(), nullptr); - return *this; - } - - filter& include(entity entity) { - m_filter.include = ecs_type_add(m_world, m_filter.include, entity.id()); - return *this; - } - - template - filter& include() { - m_filter.include = ecs_type_add(m_world, m_filter.include, _::cpp_type::id(m_world)); - return *this; - } - - filter& include_kind(match_kind kind) { - m_filter.include_kind = static_cast(kind); - return *this; - } - - type include() { - return type(m_world, m_filter.include); - } - - filter& exclude(type type) { - m_filter.exclude = ecs_type_merge(m_world, m_filter.exclude, type.c_ptr(), nullptr); - return *this; - } - - filter& exclude(entity entity) { - m_filter.exclude = ecs_type_add(m_world, m_filter.exclude, entity.id()); - return *this; - } - - template - filter& exclude() { - m_filter.exclude = ecs_type_add(m_world, m_filter.exclude, _::cpp_type::id(m_world)); - return *this; - } - - filter& exclude_kind(match_kind kind) { - m_filter.exclude_kind = static_cast(kind); - return *this; - } - - type exclude() { - return type(m_world, m_filter.exclude); - } + filter_base() + : m_world(nullptr) + , m_filter({}) { } + + filter_base(world_t *world, ecs_filter_t *filter = NULL) + : m_world(world) { + ecs_filter_move(&m_filter, filter); + } + /** Get pointer to C filter object. + */ const filter_t* c_ptr() const { - if (m_world) { + if (m_filter.term_count) { return &m_filter; } else { - return nullptr; + return NULL; } } -private: + filter_base(const filter_base& obj) { + this->m_world = obj.m_world; + ecs_filter_copy(&m_filter, &obj.m_filter); + } + + filter_base& operator=(const filter_base& obj) { + this->m_world = obj.m_world; + ecs_filter_copy(&m_filter, &obj.m_filter); + return *this; + } + + filter_base(filter_base&& obj) { + this->m_world = obj.m_world; + ecs_filter_move(&m_filter, &obj.m_filter); + } + + filter_base& operator=(filter_base&& obj) { + this->m_world = obj.m_world; + ecs_filter_move(&m_filter, &obj.m_filter); + return *this; + } + + + /** Free the filter. + */ + ~filter_base() { + ecs_filter_fini(&m_filter); + } + + template + void iter(Func&& func) const { + ecs_iter_t it = ecs_filter_iter(m_world, &m_filter); + while (ecs_filter_next(&it)) { + _::iter_invoker(func).invoke(&it); + } + } + + template + void each_term(const Func& func) { + for (int i = 0; i < m_filter.term_count; i ++) { + flecs::term t(m_world, m_filter.terms[i]); + func(t); + } + } + + flecs::term term(int32_t index) { + return flecs::term(m_world, m_filter.terms[index]); + } + + int32_t term_count() { + return m_filter.term_count; + } + + flecs::string str() { + char *result = ecs_filter_str(m_world, &m_filter); + return flecs::string(result); + } + +protected: world_t *m_world; filter_t m_filter; }; -} // namespace flecs + +template +class filter : public filter_base { + using Terms = typename _::term_ptrs::array; + +public: + filter() { } + + filter(world_t *world, filter_t *f) + : filter_base(world, f) { } + + explicit filter(const world& world, const char *expr = nullptr) + : filter_base(world.c_ptr()) + { + auto qb = world.filter_builder() + .expr(expr); + + if (!expr) { + qb.substitute_default(); + } + + flecs::filter_t f = qb; + ecs_filter_move(&m_filter, &f); + } + + filter(const filter& obj) : filter_base(obj) { } + + filter& operator=(const filter& obj) { + *this = obj; + return *this; + } + + filter(filter&& obj) : filter_base(std::move(obj)) { } + + filter& operator=(filter&& obj) { + filter_base(std::move(obj)); + return *this; + } + + template + void each(Func&& func) const { + iterate<_::each_invoker>(std::forward(func), ecs_filter_next); + } + + template + void iter(Func&& func) const { + iterate<_::iter_invoker>(std::forward(func), ecs_filter_next); + } + +private: + template < template class Invoker, typename Func, typename NextFunc, typename ... Args> + void iterate(Func&& func, NextFunc next, Args &&... args) const { + ecs_iter_t it = ecs_filter_iter(m_world, &m_filter); + while (next(&it, std::forward(args)...)) { + Invoker(std::move(func)).invoke(&it); + } + } +}; + +} namespace flecs { @@ -16596,15 +16726,17 @@ public: m_snapshot = ecs_snapshot_take(m_world.c_ptr()); } - void take(flecs::filter filter) { + template + void take(const F& f) { if (m_snapshot) { ecs_snapshot_free(m_snapshot); } - ecs_iter_t it = ecs_filter_iter(m_world.c_ptr(), filter.c_ptr()); - m_snapshot = ecs_snapshot_take_w_iter( - &it, ecs_filter_next); - } + ecs_iter_t it = ecs_filter_iter(m_world, f.c_ptr()); + + printf("filter = %s\n", ecs_filter_str(m_world, f.c_ptr())); + m_snapshot = ecs_snapshot_take_w_iter(&it, ecs_filter_next); + } void restore() { if (m_snapshot) { @@ -16623,8 +16755,6 @@ public: return m_snapshot; } - snapshot_filter filter(const filter& filter); - filter_iterator begin(); filter_iterator end(); @@ -16651,17 +16781,17 @@ public: , m_iter{ } , m_action(action) { } - filter_iterator(const world& world, const filter& filter, ecs_iter_next_action_t action) + filter_iterator(const world& world, ecs_iter_next_action_t action) : m_world( world.c_ptr() ) - , m_iter( ecs_filter_iter(m_world, filter.c_ptr()) ) + , m_iter( ecs_filter_iter(m_world, NULL) ) , m_action(action) { m_has_next = m_action(&m_iter); } - filter_iterator(const world& world, const snapshot& snapshot, const filter& filter, ecs_iter_next_action_t action) + filter_iterator(const world& world, const snapshot& snapshot, ecs_iter_next_action_t action) : m_world( world.c_ptr() ) - , m_iter( ecs_snapshot_iter(snapshot.c_ptr(), filter.c_ptr()) ) + , m_iter( ecs_snapshot_iter(snapshot.c_ptr(), NULL) ) , m_action(action) { m_has_next = m_action(&m_iter); @@ -16723,18 +16853,18 @@ private: ecs_iter_t m_iter; }; + //////////////////////////////////////////////////////////////////////////////// //// Utility for creating a world-based filter iterator //////////////////////////////////////////////////////////////////////////////// class world_filter { public: - world_filter(const world& world, const filter& filter) - : m_world( world ) - , m_filter( filter ) { } + world_filter(const world& world) + : m_world( world ) { } inline filter_iterator begin() const { - return filter_iterator(m_world, m_filter, ecs_filter_next); + return filter_iterator(m_world, ecs_filter_next); } inline filter_iterator end() const { @@ -16743,7 +16873,6 @@ public: private: const world& m_world; - const filter& m_filter; }; @@ -16753,13 +16882,12 @@ private: class snapshot_filter { public: - snapshot_filter(const world& world, const snapshot& snapshot, const filter& filter) + snapshot_filter(const world& world, const snapshot& snapshot) : m_world( world ) - , m_snapshot( snapshot ) - , m_filter( filter ) { } + , m_snapshot( snapshot ) { } inline filter_iterator begin() const { - return filter_iterator(m_world, m_snapshot, m_filter, ecs_snapshot_next); + return filter_iterator(m_world, m_snapshot, ecs_snapshot_next); } inline filter_iterator end() const { @@ -16769,7 +16897,6 @@ public: private: const world& m_world; const snapshot& m_snapshot; - const filter& m_filter; }; @@ -16801,12 +16928,8 @@ private: //// Filter fwd declared functions //////////////////////////////////////////////////////////////////////////////// -inline snapshot_filter snapshot::filter(const flecs::filter& filter) { - return snapshot_filter(m_world, *this, filter); -} - inline filter_iterator snapshot::begin() { - return filter_iterator(m_world, *this, flecs::filter(m_world), ecs_snapshot_next); + return filter_iterator(m_world, *this, ecs_snapshot_next); } inline filter_iterator snapshot::end() { @@ -17022,13 +17145,6 @@ public: iterate<_::each_invoker>(std::forward(func), ecs_query_next); } - template - void each(const flecs::filter& filter, Func&& func) const { - const filter_t* filter_ptr = filter.c_ptr(); - iterate<_::each_invoker>(std::forward(func), - ecs_query_next_w_filter, filter_ptr); - } - template void each_worker(int32_t stage_current, int32_t stage_count, Func&& func) const { iterate<_::each_invoker>(std::forward(func), @@ -17040,13 +17156,6 @@ public: iterate<_::iter_invoker>(std::forward(func), ecs_query_next); } - template - void iter(const flecs::filter& filter, Func&& func) const { - const filter_t* filter_ptr = filter.c_ptr(); - iterate<_::iter_invoker>(std::forward(func), - ecs_query_next_w_filter, filter_ptr); - } - template void iter_worker(int32_t stage_current, int32_t stage_count, Func&& func) const { iterate<_::iter_invoker>(std::forward(func), @@ -17097,8 +17206,9 @@ public: , m_stage_current(stage_current) , m_stage_count(stage_count) { } - system_runner_fluent& filter(filter filter) { - m_filter = filter; + template + system_runner_fluent& filter(const F& f) { + m_filter = f; return *this; } @@ -17128,12 +17238,13 @@ public: m_filter.c_ptr(), m_param); } } + private: world_t *m_stage; entity_t m_id; FLECS_FLOAT m_delta_time; void *m_param; - flecs::filter m_filter; + flecs::filter<> m_filter; int32_t m_offset; int32_t m_limit; int32_t m_stage_current; @@ -17746,70 +17857,14 @@ inline flecs::id world::pair(entity_t r, entity_t o) const { ecs_pair(r, o)); } -inline void world::delete_entities(flecs::filter filter) const { - ecs_bulk_delete(m_world, filter.c_ptr()); -} - -template -inline void world::add(flecs::filter filter) const { - ecs_bulk_add_remove_type( - m_world, _::cpp_type::type(m_world), nullptr, filter.c_ptr()); -} - -inline void world::add(flecs::type t) const { - ecs_bulk_add_remove_type(m_world, t.c_ptr(), nullptr, nullptr); -} - -inline void world::add(flecs::type t, flecs::filter filter) const { - ecs_bulk_add_remove_type(m_world, t.c_ptr(), nullptr, filter.c_ptr()); -} - -inline void world::add(class flecs::entity e) const { - ecs_bulk_add_remove_type(m_world, e.to_type().c_ptr(), nullptr, nullptr); -} - -inline void world::add(class flecs::entity e, flecs::filter filter) const { - ecs_bulk_add_remove_type(m_world, e.to_type().c_ptr(), nullptr, filter.c_ptr()); -} - -template -inline void world::remove(flecs::filter filter) const { - ecs_bulk_add_remove_type( - m_world, nullptr, _::cpp_type::type(m_world), filter.c_ptr()); -} - -inline void world::remove(flecs::type t) const { - ecs_bulk_add_remove_type(m_world, nullptr, t.c_ptr(), nullptr); -} - -inline void world::remove(flecs::type t, flecs::filter filter) const { - ecs_bulk_add_remove_type(m_world, nullptr, t.c_ptr(), filter.c_ptr()); -} - -inline void world::remove(class entity e) const { - ecs_bulk_add_remove_type(m_world, nullptr, e.to_type().c_ptr(), nullptr); -} - -inline void world::remove(class entity e, flecs::filter filter) const { - ecs_bulk_add_remove_type(m_world, nullptr, e.to_type().c_ptr(), filter.c_ptr()); -} - -inline flecs::world_filter world::filter(const flecs::filter& filter) const { - return flecs::world_filter(*this, filter); -} - inline filter_iterator world::begin() const { - return filter_iterator(*this, flecs::filter(*this), ecs_filter_next); + return filter_iterator(*this, ecs_filter_next); } inline filter_iterator world::end() const { return filter_iterator(ecs_filter_next); } -inline int world::count(flecs::filter filter) const { - return ecs_count_w_filter(m_world, filter.c_ptr()); -} - /** All entities created in function are created in scope. All operations * called in function (such as lookup) are relative to scope. */ @@ -17957,6 +18012,16 @@ inline flecs::observer_builder world::observer(Args &&... args) const return flecs::observer_builder(*this, std::forward(args)...); } +template +inline flecs::filter world::filter(Args &&... args) const { + return flecs::filter(*this, std::forward(args)...); +} + +template +inline flecs::filter_builder world::filter_builder(Args &&... args) const { + return flecs::filter_builder(*this, std::forward(args)...); +} + template inline flecs::query world::query(Args &&... args) const { return flecs::query(*this, std::forward(args)...); @@ -18020,7 +18085,7 @@ inline void world::each(Func&& func) const { while (ecs_term_next(&it)) { _::each_invoker(func).invoke(&it); - } + } } template @@ -18034,6 +18099,61 @@ inline void world::each(flecs::id_t term_id, Func&& func) const { } } +namespace _ { + +// Each with entity parameter +template +struct filter_invoker_w_ent; + +template +struct filter_invoker_w_ent > +{ + filter_invoker_w_ent(const flecs::world& world, Func&& func) { + flecs::filter f(world); + f.each(std::move(func)); + } +}; + +// Each without entity parameter +template +struct filter_invoker_no_ent; + +template +struct filter_invoker_no_ent > +{ + filter_invoker_no_ent(const flecs::world& world, Func&& func) { + flecs::filter f(world); + f.each(std::move(func)); + } +}; + +// Switch between function with & without entity parameter +template +class filter_invoker; + +template +class filter_invoker, flecs::entity>::value> > { +public: + filter_invoker(const flecs::world& world, Func&& func) { + filter_invoker_w_ent>(world, std::move(func)); + } +}; + +template +class filter_invoker, flecs::entity>::value> > { +public: + filter_invoker(const flecs::world& world, Func&& func) { + filter_invoker_no_ent>(world, std::move(func)); + } +}; + +} + +template +inline void world::each(Func&& func) const { + _::filter_invoker f_invoker(*this, std::move(func)); +} + } // namespace flecs namespace flecs @@ -18046,6 +18166,24 @@ inline Base& term_builder_i::id(const flecs::type& type) { return *this; } +template +inline filter_builder_base::operator filter() const { + ecs_filter_t filter = *this; + return flecs::filter(m_world, &filter); +} + +template +inline filter_builder::operator filter<>() const { + ecs_filter_t filter = *this; + return flecs::filter<>(this->m_world, &filter); +} + +template +inline filter filter_builder_base::build() const { + ecs_filter_t filter = *this; + return flecs::filter(m_world, &filter); +} + template inline query_builder_base::operator query() const { ecs_query_t *query = *this;