diff --git a/distr/flecs.c b/distr/flecs.c index e5d488ada..3755b6bb7 100644 --- a/distr/flecs.c +++ b/distr/flecs.c @@ -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); @@ -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"); @@ -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; @@ -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 ++; @@ -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; } diff --git a/distr/flecs.h b/distr/flecs.h index 2ca9ce4bd..ed26d92ce 100644 --- a/distr/flecs.h +++ b/distr/flecs.h @@ -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 diff --git a/include/flecs/private/api_flags.h b/include/flecs/private/api_flags.h index a5e5de628..b89ea1b8e 100644 --- a/include/flecs/private/api_flags.h +++ b/include/flecs/private/api_flags.h @@ -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 diff --git a/src/world.c b/src/world.c index 3224fbe7f..bf2afe36a 100644 --- a/src/world.c +++ b/src/world.c @@ -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); @@ -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"); @@ -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; @@ -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 ++; @@ -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; } diff --git a/test/core/project.json b/test/core/project.json index 69bd2a0aa..ad8c43832 100644 --- a/test/core/project.json +++ b/test/core/project.json @@ -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", @@ -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", diff --git a/test/core/src/World.c b/test/core/src/World.c index c4e845030..25119f609 100644 --- a/test/core/src/World.c +++ b/test/core/src/World.c @@ -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); +} diff --git a/test/core/src/main.c b/test/core/src/main.c index 856bbfde4..dab90263e 100644 --- a/test/core/src/main.c +++ b/test/core/src/main.c @@ -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); @@ -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 } }; @@ -11084,7 +11094,7 @@ static bake_test_suite suites[] = { "World", World_setup, NULL, - 60, + 62, World_testcases }, {