Skip to content

Commit ac53f03

Browse files
#1549 Fix issue with command queue that contains both recycld and old id
1 parent 7ddc71d commit ac53f03

File tree

5 files changed

+89
-16
lines changed

5 files changed

+89
-16
lines changed

distr/flecs.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16201,6 +16201,7 @@ ecs_cmd_t* flecs_cmd_new_batched(
1620116201

1620216202
int32_t cur = ecs_vec_count(cmds);
1620316203
ecs_cmd_t *cmd = flecs_cmd_new(stage);
16204+
bool is_new = false;
1620416205
if (entry) {
1620516206
if (entry->first == -1) {
1620616207
/* Existing but invalidated entry */
@@ -16209,16 +16210,25 @@ ecs_cmd_t* flecs_cmd_new_batched(
1620916210
} else {
1621016211
int32_t last = entry->last;
1621116212
ecs_cmd_t *arr = ecs_vec_first_t(cmds, ecs_cmd_t);
16212-
ecs_assert(arr[last].entity == e, ECS_INTERNAL_ERROR, NULL);
16213-
ecs_cmd_t *last_op = &arr[last];
16214-
last_op->next_for_entity = cur;
16215-
if (last == entry->first) {
16216-
/* Flip sign bit so flush logic can tell which command
16217-
* is the first for an entity */
16218-
last_op->next_for_entity *= -1;
16213+
if (arr[last].entity == e) {
16214+
ecs_cmd_t *last_op = &arr[last];
16215+
last_op->next_for_entity = cur;
16216+
if (last == entry->first) {
16217+
/* Flip sign bit so flush logic can tell which command
16218+
* is the first for an entity */
16219+
last_op->next_for_entity *= -1;
16220+
}
16221+
} else {
16222+
/* Entity with different version was in the same queue. Discard
16223+
* the old entry and create a new one. */
16224+
is_new = true;
1621916225
}
1622016226
}
1622116227
} else {
16228+
is_new = true;
16229+
}
16230+
16231+
if (is_new) {
1622216232
cmd->entry = entry = flecs_sparse_ensure_fast_t(
1622316233
&stage->cmd->entries, ecs_cmd_entry_t, e);
1622416234
entry->first = cur;

src/stage.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ ecs_cmd_t* flecs_cmd_new_batched(
4242

4343
int32_t cur = ecs_vec_count(cmds);
4444
ecs_cmd_t *cmd = flecs_cmd_new(stage);
45+
bool is_new = false;
4546
if (entry) {
4647
if (entry->first == -1) {
4748
/* Existing but invalidated entry */
@@ -50,16 +51,25 @@ ecs_cmd_t* flecs_cmd_new_batched(
5051
} else {
5152
int32_t last = entry->last;
5253
ecs_cmd_t *arr = ecs_vec_first_t(cmds, ecs_cmd_t);
53-
ecs_assert(arr[last].entity == e, ECS_INTERNAL_ERROR, NULL);
54-
ecs_cmd_t *last_op = &arr[last];
55-
last_op->next_for_entity = cur;
56-
if (last == entry->first) {
57-
/* Flip sign bit so flush logic can tell which command
58-
* is the first for an entity */
59-
last_op->next_for_entity *= -1;
54+
if (arr[last].entity == e) {
55+
ecs_cmd_t *last_op = &arr[last];
56+
last_op->next_for_entity = cur;
57+
if (last == entry->first) {
58+
/* Flip sign bit so flush logic can tell which command
59+
* is the first for an entity */
60+
last_op->next_for_entity *= -1;
61+
}
62+
} else {
63+
/* Entity with different version was in the same queue. Discard
64+
* the old entry and create a new one. */
65+
is_new = true;
6066
}
6167
}
6268
} else {
69+
is_new = true;
70+
}
71+
72+
if (is_new) {
6373
cmd->entry = entry = flecs_sparse_ensure_fast_t(
6474
&stage->cmd->entries, ecs_cmd_entry_t, e);
6575
entry->first = cur;

test/core/project.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2284,7 +2284,8 @@
22842284
"redefine_named_in_threaded_app",
22852285
"batched_cmd_w_component_init",
22862286
"deep_command_nesting",
2287-
"ensure_from_2_stages"
2287+
"ensure_from_2_stages",
2288+
"batch_w_old_and_recycled_id"
22882289
]
22892290
}, {
22902291
"id": "SingleThreadStaging",

test/core/src/Commands.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4749,3 +4749,50 @@ void Commands_ensure_from_2_stages(void) {
47494749

47504750
ecs_fini(world);
47514751
}
4752+
4753+
static ECS_COMPONENT_DECLARE(Velocity);
4754+
4755+
static void remove_velocity(ecs_iter_t *it) {
4756+
ecs_remove(it->world, it->entities[0], Velocity);
4757+
}
4758+
4759+
void Commands_batch_w_old_and_recycled_id(void) {
4760+
ecs_world_t *world = ecs_mini();
4761+
4762+
ECS_COMPONENT(world, Position);
4763+
ECS_COMPONENT_DEFINE(world, Velocity);
4764+
4765+
ecs_observer(world, {
4766+
.query.terms = {{ ecs_id(Position) }},
4767+
.events = { EcsOnRemove },
4768+
.callback = remove_velocity
4769+
});
4770+
4771+
ecs_entity_t parent = ecs_new(world);
4772+
ecs_entity_t child = ecs_new_w_pair(world, EcsChildOf, parent);
4773+
4774+
ecs_entity_t grandchild = ecs_new(world);
4775+
ecs_add_pair(world, grandchild, EcsChildOf, child);
4776+
ecs_add(world, grandchild, Position);
4777+
4778+
ecs_defer_begin(world);
4779+
ecs_defer_suspend(world);
4780+
ecs_delete(world, child);
4781+
ecs_entity_t child_2 = ecs_new_w_pair(world, EcsChildOf, parent);
4782+
ecs_defer_resume(world);
4783+
ecs_entity_t e = ecs_new(world);
4784+
ecs_add(world, e, Position);
4785+
4786+
test_assert(!ecs_has(world, e, Position));
4787+
ecs_defer_end(world);
4788+
4789+
test_assert(ecs_is_alive(world, parent));
4790+
test_assert(!ecs_is_alive(world, child));
4791+
test_assert(ecs_is_alive(world, child_2));
4792+
test_assert(!ecs_is_alive(world, grandchild));
4793+
test_assert(ecs_is_alive(world, e));
4794+
test_assert(ecs_has_pair(world, child_2, EcsChildOf, parent));
4795+
test_assert(ecs_has(world, e, Position));
4796+
4797+
ecs_fini(world);
4798+
}

test/core/src/main.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2204,6 +2204,7 @@ void Commands_redefine_named_in_threaded_app(void);
22042204
void Commands_batched_cmd_w_component_init(void);
22052205
void Commands_deep_command_nesting(void);
22062206
void Commands_ensure_from_2_stages(void);
2207+
void Commands_batch_w_old_and_recycled_id(void);
22072208

22082209
// Testsuite 'SingleThreadStaging'
22092210
void SingleThreadStaging_setup(void);
@@ -10915,6 +10916,10 @@ bake_test_case Commands_testcases[] = {
1091510916
{
1091610917
"ensure_from_2_stages",
1091710918
Commands_ensure_from_2_stages
10919+
},
10920+
{
10921+
"batch_w_old_and_recycled_id",
10922+
Commands_batch_w_old_and_recycled_id
1091810923
}
1091910924
};
1092010925

@@ -11795,7 +11800,7 @@ static bake_test_suite suites[] = {
1179511800
"Commands",
1179611801
NULL,
1179711802
NULL,
11798-
155,
11803+
156,
1179911804
Commands_testcases
1180011805
},
1180111806
{

0 commit comments

Comments
 (0)