Skip to content

Commit

Permalink
#1347 Prevent calling run_post_frame outside of frame
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderMertens committed Sep 18, 2024
1 parent 8871d57 commit 0cd6d23
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 5 deletions.
12 changes: 12 additions & 0 deletions distr/flecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -18822,6 +18822,9 @@ void ecs_run_post_frame(
ecs_check(action != NULL, ECS_INVALID_PARAMETER, NULL);

ecs_stage_t *stage = flecs_stage_from_world(&world);
ecs_check((world->flags & EcsWorldFrameInProgress), ECS_INVALID_OPERATION,
"cannot register post frame action while frame is not in progress");

ecs_action_elem_t *elem = ecs_vec_append_t(&stage->allocator,
&stage->post_frame_actions, ecs_action_elem_t);
ecs_assert(elem != NULL, ECS_INTERNAL_ERROR, NULL);
Expand Down Expand Up @@ -19396,6 +19399,8 @@ ecs_ftime_t ecs_frame_begin(
flecs_poly_assert(world, ecs_world_t);
ecs_check(!(world->flags & EcsWorldReadonly), ECS_INVALID_OPERATION,
"cannot begin frame while world is in readonly mode");
ecs_check(!(world->flags & EcsWorldFrameInProgress), ECS_INVALID_OPERATION,
"cannot begin frame while frame is already in progress");
ecs_check(ECS_NEQZERO(user_delta_time) || ecs_os_has_time(),
ECS_MISSING_OS_API, "get_time");

Expand All @@ -19420,6 +19425,8 @@ ecs_ftime_t ecs_frame_begin(

ecs_run_aperiodic(world, 0);

world->flags |= EcsWorldFrameInProgress;

return world->info.delta_time;
error:
return (ecs_ftime_t)0;
Expand All @@ -19431,6 +19438,8 @@ void ecs_frame_end(
flecs_poly_assert(world, ecs_world_t);
ecs_check(!(world->flags & EcsWorldReadonly), ECS_INVALID_OPERATION,
"cannot end frame while world is in readonly mode");
ecs_check((world->flags & EcsWorldFrameInProgress), ECS_INVALID_OPERATION,
"cannot end frame while frame is not in progress");

world->info.frame_count_total ++;

Expand All @@ -19444,6 +19453,9 @@ void ecs_frame_end(
/* Reset command handler each frame */
world->on_commands_active = NULL;
world->on_commands_ctx_active = NULL;

world->flags &= ~EcsWorldFrameInProgress;

error:
return;
}
Expand Down
2 changes: 1 addition & 1 deletion distr/flecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ extern "C" {
#define EcsWorldMeasureFrameTime (1u << 5)
#define EcsWorldMeasureSystemTime (1u << 6)
#define EcsWorldMultiThreaded (1u << 7)

#define EcsWorldFrameInProgress (1u << 8)

////////////////////////////////////////////////////////////////////////////////
//// OS API flags
Expand Down
2 changes: 1 addition & 1 deletion include/flecs/private/api_flags.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ extern "C" {
#define EcsWorldMeasureFrameTime (1u << 5)
#define EcsWorldMeasureSystemTime (1u << 6)
#define EcsWorldMultiThreaded (1u << 7)

#define EcsWorldFrameInProgress (1u << 8)

////////////////////////////////////////////////////////////////////////////////
//// OS API flags
Expand Down
12 changes: 12 additions & 0 deletions src/world.c
Original file line number Diff line number Diff line change
Expand Up @@ -1320,6 +1320,9 @@ void ecs_run_post_frame(
ecs_check(action != NULL, ECS_INVALID_PARAMETER, NULL);

ecs_stage_t *stage = flecs_stage_from_world(&world);
ecs_check((world->flags & EcsWorldFrameInProgress), ECS_INVALID_OPERATION,
"cannot register post frame action while frame is not in progress");

ecs_action_elem_t *elem = ecs_vec_append_t(&stage->allocator,
&stage->post_frame_actions, ecs_action_elem_t);
ecs_assert(elem != NULL, ECS_INTERNAL_ERROR, NULL);
Expand Down Expand Up @@ -1894,6 +1897,8 @@ ecs_ftime_t ecs_frame_begin(
flecs_poly_assert(world, ecs_world_t);
ecs_check(!(world->flags & EcsWorldReadonly), ECS_INVALID_OPERATION,
"cannot begin frame while world is in readonly mode");
ecs_check(!(world->flags & EcsWorldFrameInProgress), ECS_INVALID_OPERATION,
"cannot begin frame while frame is already in progress");
ecs_check(ECS_NEQZERO(user_delta_time) || ecs_os_has_time(),
ECS_MISSING_OS_API, "get_time");

Expand All @@ -1918,6 +1923,8 @@ ecs_ftime_t ecs_frame_begin(

ecs_run_aperiodic(world, 0);

world->flags |= EcsWorldFrameInProgress;

return world->info.delta_time;
error:
return (ecs_ftime_t)0;
Expand All @@ -1929,6 +1936,8 @@ void ecs_frame_end(
flecs_poly_assert(world, ecs_world_t);
ecs_check(!(world->flags & EcsWorldReadonly), ECS_INVALID_OPERATION,
"cannot end frame while world is in readonly mode");
ecs_check((world->flags & EcsWorldFrameInProgress), ECS_INVALID_OPERATION,
"cannot end frame while frame is not in progress");

world->info.frame_count_total ++;

Expand All @@ -1942,6 +1951,9 @@ void ecs_frame_end(
/* Reset command handler each frame */
world->on_commands_active = NULL;
world->on_commands_ctx_active = NULL;

world->flags &= ~EcsWorldFrameInProgress;

error:
return;
}
Expand Down
6 changes: 4 additions & 2 deletions test/core/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@
"emplace_inherited",
"override_component",
"delete_w_override_component",
"delete_w_override_on_remove_isa",
"delete_w_override_on_remove_isa",
"ctor_after_emplace",
"ctor_dtor_after_remove",
"ctor_dtor_after_clear",
Expand Down Expand Up @@ -1970,7 +1970,9 @@
"set_get_binding_context",
"set_get_context_w_free",
"set_get_binding_context_w_free",
"get_entities"
"get_entities",
"run_post_frame",
"run_post_frame_outside_of_frame"
]
}, {
"id": "WorldInfo",
Expand Down
37 changes: 37 additions & 0 deletions test/core/src/World.c
Original file line number Diff line number Diff line change
Expand Up @@ -1639,3 +1639,40 @@ void World_get_entities(void) {

ecs_fini(world);
}

static
int post_frame_action_invoked = 0;

static
void post_frame_action(
ecs_world_t *world,
void *ctx)
{
test_int(*(int*)ctx, 10);
post_frame_action_invoked ++;
}

void World_run_post_frame(void) {
ecs_world_t *world = ecs_mini();

ecs_frame_begin(world, 0);

int ctx = 10;
ecs_run_post_frame(world, post_frame_action, &ctx);

test_int(post_frame_action_invoked, 0);
ecs_frame_end(world);
test_int(post_frame_action_invoked, 1);

ecs_fini(world);
}

void World_run_post_frame_outside_of_frame(void) {
install_test_abort();

ecs_world_t *world = ecs_mini();

test_expect_abort();
int ctx = 10;
ecs_run_post_frame(world, post_frame_action, &ctx);
}
12 changes: 11 additions & 1 deletion test/core/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1896,6 +1896,8 @@ void World_set_get_binding_context(void);
void World_set_get_context_w_free(void);
void World_set_get_binding_context_w_free(void);
void World_get_entities(void);
void World_run_post_frame(void);
void World_run_post_frame_outside_of_frame(void);

// Testsuite 'WorldInfo'
void WorldInfo_get_tick(void);
Expand Down Expand Up @@ -9564,6 +9566,14 @@ bake_test_case World_testcases[] = {
{
"get_entities",
World_get_entities
},
{
"run_post_frame",
World_run_post_frame
},
{
"run_post_frame_outside_of_frame",
World_run_post_frame_outside_of_frame
}
};

Expand Down Expand Up @@ -11084,7 +11094,7 @@ static bake_test_suite suites[] = {
"World",
World_setup,
NULL,
60,
62,
World_testcases
},
{
Expand Down

0 comments on commit 0cd6d23

Please sign in to comment.