Skip to content

Commit

Permalink
#33 change ecs_delete_w_type to ecs_delete_w_filter
Browse files Browse the repository at this point in the history
  • Loading branch information
Sander Mertens committed Sep 4, 2019
1 parent 9f2c2ab commit e3fc831
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 28 deletions.
46 changes: 40 additions & 6 deletions include/flecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,44 @@ void ecs_delete(
ecs_world_t *world,
ecs_entity_t entity);

/** Types that describes a type filter.
* A type filter is used to match against zero or more types. For example,
* a type filter that includes component "Position" will match types
* [Position], [Position, Velocity], [Position, Mass] etc. When no include
* filter is specified, all types will be matched.
*
* A filter can be narrowed down by specifying an exclude filter. For example,
* a filter which includes "Position" but excludes "Mass" will match types
* [Position] and [Position, Velocity], but not [Position, Mass].
*
* A type filter may contain multiple components. The filter kind determines
* how the filter is interpreted. When the kind is EcsMatchAll, all the
* components in the filter must be either included or excluded from the type
* being matched. If the kind is EcsMatchAny, any of the components should
* match with the type being matched.
*
* For example, a filter that includes {[Position, Velocity], EcsMatchAny} will
* match types [Position], [Position, Velocity] and [Velocity], but not [Mass].
* A filter that excludes {[Position, Velocity], EcsMatchAll} will not match
* [Position, Velocity] or [Position, Velocity, Mass], but will match
* [Position].
*
* When the kind is left to EcsMatchDefault, the include_kind will be set to
* EcsMatchAll, while the exclude_kind will be set to EcsMatchAny.
*/
typedef enum ecs_type_filter_kind_t {
EcsMatchDefault = 0,
EcsMatchAll,
EcsMatchAny
} ecs_type_filter_kind_t;

typedef struct ecs_type_filter_t {
ecs_type_t include;
ecs_type_t exclude;
ecs_type_filter_kind_t include_kind;
ecs_type_filter_kind_t exclude_kind;
} ecs_type_filter_t;

/** Delete all entities containing a (set of) component(s).
* This operation provides a more efficient alternative to deleting entities one
* by one by deleting an entire table or set of tables in a single operation.
Expand All @@ -847,13 +885,9 @@ void ecs_delete(
* @param except Tables with any of these components will not be cleared.
*/
FLECS_EXPORT
void _ecs_delete_w_type(
void ecs_delete_w_filter(
ecs_world_t *world,
ecs_type_t to_delete,
ecs_type_t except);

#define ecs_delete_w_type(world, to_delete, except)\
_ecs_delete_w_type(world, T##to_delete, T##except)
ecs_type_filter_t *filter);

/** Add a type to an entity.
* This operation will add one or more components (as per the specified type) to
Expand Down
29 changes: 22 additions & 7 deletions src/entity.c
Original file line number Diff line number Diff line change
Expand Up @@ -1483,10 +1483,9 @@ void ecs_delete(
}
}

void _ecs_delete_w_type(
void ecs_delete_w_filter(
ecs_world_t *world,
ecs_type_t to_delete,
ecs_type_t except)
ecs_type_filter_t *filter)
{
ecs_assert(world != NULL, ECS_INVALID_PARAMETER, NULL);
ecs_stage_t *stage = ecs_get_stage(&world);
Expand All @@ -1500,14 +1499,30 @@ void _ecs_delete_w_type(
ecs_table_t *table = ecs_chunked_get(stage->tables, ecs_table_t, i);
ecs_type_t type = table->type;

if (to_delete) {
if (!ecs_type_contains(world, type, to_delete, true, false)) {
if (filter->include) {
/* Default for include_kind is MatchAll */
if (!ecs_type_contains(world, type, filter->include,
filter->include_kind != EcsMatchAny, false))
{
continue;
}

/* If no include filter is specified, make sure that builtin components
* aren't matched by default. */
} else {
if (ecs_type_contains(
world, type, world->t_builtins, false, false))
{
/* Continue if table contains any of the builtin components */
continue;
}
}

if (except) {
if (ecs_type_contains(world, type, except, false, false)) {
if (filter->exclude) {
/* Default for exclude_kind is MatchAny */
if (ecs_type_contains(world, type, filter->exclude,
filter->exclude_kind == EcsMatchAll, false))
{
continue;
}
}
Expand Down
1 change: 1 addition & 0 deletions src/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ struct ecs_world {
ecs_type_t t_prefab;
ecs_type_t t_row_system;
ecs_type_t t_col_system;
ecs_type_t t_builtins;


/* -- Time management -- */
Expand Down
6 changes: 6 additions & 0 deletions src/world.c
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,12 @@ ecs_world_t *ecs_init(void) {
ecs_new_system(world, "EcsInitPrefab", EcsOnAdd, "EcsPrefab", EcsInitPrefab);
ecs_new_system(world, "EcsSetPrefab", EcsOnSet, "EcsPrefab", EcsSetPrefab);

/* Create type that allows for quickly checking if a type contains builtin
* components. */
world->t_builtins = ecs_expr_to_type(world,
"EcsComponent, EcsTypeComponent, EcsPrefab, EcsPrefabParent"
", EcsPrefabBuilder, EcsRowSystem, EcsColSystem");

return world;
}

Expand Down
6 changes: 4 additions & 2 deletions test/api/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,16 @@
"delete_w_on_remove"
]
}, {
"id": "Delete_w_type",
"id": "Delete_w_filter",
"testcases": [
"delete_1",
"delete_2",
"delete_1_2_types",
"delete_2_2_types",
"delete_except_1",
"delete_except_2"
"delete_except_2",
"delete_with_any_of_2",
"delete_except_all_of_2"
]
}, {
"id": "Set",
Expand Down
137 changes: 125 additions & 12 deletions test/api/src/Delete_w_type.c → test/api/src/Delete_w_filter.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include <api.h>

void Delete_w_type_delete_1() {
void Delete_w_filter_delete_1() {
ecs_world_t *world = ecs_init();

ECS_COMPONENT(world, Position);
Expand All @@ -12,7 +12,9 @@ void Delete_w_type_delete_1() {
test_int( ecs_count(world, Position), 3);
test_int( ecs_count(world, Mass), 3);

ecs_delete_w_type(world, Position, 0);
ecs_delete_w_filter(world, &(ecs_type_filter_t){
ecs_type(Position)
});

test_int( ecs_count(world, Position), 0);
test_int( ecs_count(world, Mass), 3);
Expand All @@ -24,7 +26,7 @@ void Delete_w_type_delete_1() {
ecs_fini(world);
}

void Delete_w_type_delete_2() {
void Delete_w_filter_delete_2() {
ecs_world_t *world = ecs_init();

ECS_COMPONENT(world, Position);
Expand All @@ -39,7 +41,9 @@ void Delete_w_type_delete_2() {
test_int( ecs_count(world, Type), 3);
test_int( ecs_count(world, Mass), 3);

ecs_delete_w_type(world, Type, 0);
ecs_delete_w_filter(world, &(ecs_type_filter_t){
ecs_type(Type)
});

test_int( ecs_count(world, Type), 0);
test_int( ecs_count(world, Mass), 3);
Expand All @@ -51,7 +55,7 @@ void Delete_w_type_delete_2() {
ecs_fini(world);
}

void Delete_w_type_delete_1_2_types() {
void Delete_w_filter_delete_1_2_types() {
ecs_world_t *world = ecs_init();

ECS_COMPONENT(world, Position);
Expand All @@ -71,7 +75,9 @@ void Delete_w_type_delete_1_2_types() {
test_int( ecs_count(world, Mass), 3);

/* Delete both entities of Type_1 and Type_2 */
ecs_delete_w_type(world, Type_1, 0);
ecs_delete_w_filter(world, &(ecs_type_filter_t){
ecs_type(Type_1)
});

test_int( ecs_count(world, Type_1), 0);
test_int( ecs_count(world, Type_2), 0);
Expand All @@ -86,7 +92,7 @@ void Delete_w_type_delete_1_2_types() {
ecs_fini(world);
}

void Delete_w_type_delete_2_2_types() {
void Delete_w_filter_delete_2_2_types() {
ecs_world_t *world = ecs_init();

ECS_COMPONENT(world, Position);
Expand All @@ -108,7 +114,9 @@ void Delete_w_type_delete_2_2_types() {
test_int( ecs_count(world, Mass), 6);

/* Delete both entities of Type_1 and Type_2 */
ecs_delete_w_type(world, Type_1, 0);
ecs_delete_w_filter(world, &(ecs_type_filter_t){
ecs_type(Type_1)
});

test_int( ecs_count(world, Type_1), 0);
test_int( ecs_count(world, Type_2), 0);
Expand All @@ -123,7 +131,7 @@ void Delete_w_type_delete_2_2_types() {
ecs_fini(world);
}

void Delete_w_type_delete_except_1() {
void Delete_w_filter_delete_except_1() {
ecs_world_t *world = ecs_init();

ECS_COMPONENT(world, Position);
Expand All @@ -149,7 +157,10 @@ void Delete_w_type_delete_except_1() {
test_int( ecs_count(world, Mass), 6);

/* Delete both entities of Type_1 and Type_3 but not Type_3 */
ecs_delete_w_type(world, Type_1, Mass);
ecs_delete_w_filter(world, &(ecs_type_filter_t){
.include = ecs_type(Type_1),
.exclude = ecs_type(Mass)
});

test_int( ecs_count(world, Type_1), 3); /* Type_1 is superset of Type_2 */
test_int( ecs_count(world, Type_2), 3); /* Type_2 has Mass so not deleted */
Expand All @@ -166,7 +177,7 @@ void Delete_w_type_delete_except_1() {
ecs_fini(world);
}

void Delete_w_type_delete_except_2() {
void Delete_w_filter_delete_except_2() {
ecs_world_t *world = ecs_init();

ECS_COMPONENT(world, Position);
Expand All @@ -193,7 +204,10 @@ void Delete_w_type_delete_except_2() {
test_int( ecs_count(world, Mass), 6);

/* Delete both entities of Type_1 and Type_3 but not Type_3 */
ecs_delete_w_type(world, Type_1, Except);
ecs_delete_w_filter(world, &(ecs_type_filter_t){
.include = ecs_type(Type_1),
.exclude = ecs_type(Except)
});

test_int( ecs_count(world, Type_1), 6); /* Type_1 is superset of Type_2 */
test_int( ecs_count(world, Type_2), 3); /* Type_2 has Mass so not deleted */
Expand All @@ -208,3 +222,102 @@ void Delete_w_type_delete_except_2() {

ecs_fini(world);
}

void Delete_w_filter_delete_with_any_of_2() {
ecs_world_t *world = ecs_init();

ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Mass);
ECS_COMPONENT(world, Rotation);

ECS_TYPE(world, Type_1, Position, Velocity);
ECS_TYPE(world, Type_2, Position, Velocity, Mass);
ECS_TYPE(world, Type_3, Position, Velocity, Rotation);
ECS_TYPE(world, Include, Mass, Rotation);

ecs_new_w_count(world, Type_1, 3);
ecs_new_w_count(world, Type_2, 3);
ecs_new_w_count(world, Type_3, 3);
ecs_new_w_count(world, Mass, 3);

/* Type_1 is superset of Type_2 and Type_3 */
test_int( ecs_count(world, Type_1), 9);
test_int( ecs_count(world, Type_2), 3);
test_int( ecs_count(world, Type_3), 3);

/* Mass is also in Type_2 */
test_int( ecs_count(world, Mass), 6);

/* Delete both entities of Type_1 and Type_3 but not Type_3 */
ecs_delete_w_filter(world, &(ecs_type_filter_t){
.include = ecs_type(Include),
.include_kind = EcsMatchAny
});

test_int( ecs_count(world, Type_1), 3); /* Type_1 is superset of Type_2 */
test_int( ecs_count(world, Type_2), 0); /* Type_2 has Mass so not deleted */
test_int( ecs_count(world, Type_3), 0);
test_int( ecs_count(world, Mass), 0);

/* Test if table is left in a state that can be repopulated */
ecs_new(world, Type_2);
ecs_new(world, Type_3);
ecs_new(world, Mass);
test_int( ecs_count(world, Type_1), 5);
test_int( ecs_count(world, Type_2), 1);
test_int( ecs_count(world, Type_3), 1);
test_int( ecs_count(world, Mass), 2);

ecs_fini(world);
}

void Delete_w_filter_delete_except_all_of_2() {
ecs_world_t *world = ecs_init();

ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Mass);
ECS_COMPONENT(world, Rotation);

ECS_TYPE(world, Type_1, Position, Velocity);
ECS_TYPE(world, Type_2, Position, Velocity, Mass);
ECS_TYPE(world, Type_3, Position, Velocity, Mass, Rotation);
ECS_TYPE(world, Exclude, Mass, Rotation);

ecs_new_w_count(world, Type_1, 3);
ecs_new_w_count(world, Type_2, 3);
ecs_new_w_count(world, Type_3, 3);
ecs_new_w_count(world, Mass, 3);

/* Type_1 is superset of Type_2 and Type_3 */
test_int( ecs_count(world, Type_1), 9);
test_int( ecs_count(world, Type_2), 6);
test_int( ecs_count(world, Type_3), 3);

/* Mass is also in Type_2 and Type_3 */
test_int( ecs_count(world, Mass), 9);

/* Delete everything but Type_3 */
ecs_delete_w_filter(world, &(ecs_type_filter_t){
.exclude = ecs_type(Exclude),
.exclude_kind = EcsMatchAll
});

test_int( ecs_count(world, Type_1), 3); /* Type_1 is superset of Type_2 */
test_int( ecs_count(world, Type_2), 3); /* Type_2 is superset of Type_3 */
test_int( ecs_count(world, Type_3), 3);
test_int( ecs_count(world, Mass), 3);

/* Test if table is left in a state that can be repopulated */
ecs_new(world, Type_1);
ecs_new(world, Type_2);
ecs_new(world, Mass);

test_int( ecs_count(world, Type_1), 5);
test_int( ecs_count(world, Type_2), 4);
test_int( ecs_count(world, Type_3), 3);
test_int( ecs_count(world, Mass), 5);

ecs_fini(world);
}
Loading

0 comments on commit e3fc831

Please sign in to comment.