How to register a system that doesn't query for any components?
miguno opened this issue · 7 comments
Let's say I want to create a system that prints delta_time on every tick. How can I do this with Flecs.NET?
Here's how to do it in C:
void S_PrintDeltaTime(ecs_iter_t *it) {
printf("delta_time %f\n", (double)it->delta_time);
}
// This is the relevant line for this GH question.
ECS_SYSTEM(world, PrintDeltaTime, EcsOnUpdate, 0);
The system above doesn't query for any components which means it won't match any entities, but will still be run once for each call to ecs_progress()
.
The following attempts didn't work with Flecs.NET:
// Attempt 1: fails at runtime with "fatal: flecs.c: 44682: assert: table != NULL INTERNAL_ERROR"
_world.Routine(
filter: _world.FilterBuilder(),
/* ... */);
// Attempt 2: routine is never called
_world.Routine(
filter: _world.FilterBuilder().With(0),
/* ... */);
// Attempt 3: routine is never called
_world.Routine(
filter: _world.FilterBuilder().Term(0),
/* ... */);
That's strange, this code is working for me without crashing. What Nuget version are you using?
using System;
using Flecs.NET.Core;
using World world = World.Create();
world.Routine(
filter: world.FilterBuilder(), // You can omit this
callback: (Iter it) =>
{
Console.WriteLine(it.DeltaTime());
}
);
world.App().Run();
I am using 3.2.7-build.12
.
<PackageReference Include="Flecs.NET.Debug" Version="3.2.7-build.12" />
<PackageReference Include="Flecs.NET.Release" Version="3.2.7-build.12" />
Regarding your code snippet: When I remove the filter: ...
line, then the app crashes with:
fatal: flecs.c: 44682: assert: table != NULL INTERNAL_ERROR
1 libflecs.dylib 0x000000010e8c86cc flecs_log_msg + 3696
2 libflecs.dylib 0x000000010e934590 ecs_printv_ + 328
3 libflecs.dylib 0x000000010e833990 ecs_log_ + 156
4 libflecs.dylib 0x000000010e8173c8 ecs_assert_ + 388
5 libflecs.dylib 0x000000010e84f8c4 ecs_table_count + 92
6 ??? 0x000000028173b5a4 0x0 + 10761778596
7 ??? 0x000000028173b4e0 0x0 + 10761778400
8 ??? 0x000000028173b3fc 0x0 + 10761778172
9 ??? 0x000000028173f3b8 0x0 + 10761794488
10 ??? 0x0000000281739c34 0x0 + 10761772084
11 ??? 0x0000000281739714 0x0 + 10761770772
12 libflecs.dylib 0x000000010ea02b18 ecs_run_intern + 3420
13 libflecs.dylib 0x000000010ea01c24 flecs_run_pipeline_ops + 2472
14 libflecs.dylib 0x000000010ea03b14 flecs_run_pipeline + 3580
15 libflecs.dylib 0x000000010ea00778 flecs_workers_progress + 320
16 libflecs.dylib 0x000000010ea04d84 ecs_progress + 808
17 ??? 0x00000002817390ec 0x0 + 10761769196
18 ??? 0x0000000281739014 0x0 + 10761768980
19 ??? 0x0000000281737330 0x0 + 10761761584
20 ??? 0x00000002817368d4 0x0 + 10761758932
21 ??? 0x0000000281158040 0x0 + 10755604544
22 ??? 0x00000002810e1830 0x0 + 10755119152
23 libcoreclr.dylib 0x00000001056f2a48 CallDescrWorkerInternal + 132
24 libcoreclr.dylib 0x00000001055bd24c _Z26CallDescrWorkerWithHandlerP13CallDescrDatai + 108
25 libcoreclr.dylib 0x00000001055bd704 _ZN18MethodDescCallSite16CallTargetWorkerEPKmPmi + 640
26 libcoreclr.dylib 0x00000001054e8890 _Z7RunMainP10MethodDescsPiPP8PtrArray + 548
27 libcoreclr.dylib 0x00000001054e8b04 _ZN8Assembly17ExecuteMainMethodEPP8PtrArrayi + 268
28 libcoreclr.dylib 0x000000010550f854 _ZN8CorHost215ExecuteAssemblyEjPKDsiPS1_Pj + 476
29 libcoreclr.dylib 0x00000001054d71bc coreclr_execute_assembly + 224
30 libhostpolicy.dylib 0x0000000104b38520 _Z19run_app_for_contextRK20hostpolicy_context_tiPPKc + 904
31 libhostpolicy.dylib 0x0000000104b387a4 _Z7run_appiPPKc + 56
32 libhostpolicy.dylib 0x0000000104b39028 corehost_main + 160
33 libhostfxr.dylib 0x0000000104acb040 _ZN10fx_muxer_t24handle_exec_host_commandERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEERK19host_startup_info_tS8_RKNS0_13unordered_mapI13known_optionsNS0_6vectorIS6_NS4_IS6_EEEE18known_options_hashNS0_8equal_toISD_EENS4_INS0_4pairIKSD_SG_EEEEEEiPPKci11host_mode_tbPciPi + 1092
34 libhostfxr.dylib 0x0000000104aca4c0 _ZN10fx_muxer_t7executeENSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEiPPKcRK19host_startup_info_tPciPi + 852
35 libhostfxr.dylib 0x0000000104ac77c0 hostfxr_main_startupinfo + 152
36 monotone 0x0000000104a3d4d0 _Z9exe_startiPPKc + 1436
37 monotone 0x0000000104a3d6c4 main + 160
38 dyld 0x0000000188f31058 start + 2224
at System.Environment.get_StackTrace()
at Flecs.NET.Core.BindingContext.OsApiAbort()
at Flecs.NET.Bindings.Native.ecs_table_count(ecs_table_t* table)
at Flecs.NET.Bindings.Native.ecs_table_count(ecs_table_t* table)
at Flecs.NET.Core.Table..ctor(ecs_world_t* world, ecs_table_t* table)
at Flecs.NET.Core.Iter.Table()
at monotone.Game1.<CreateSystems>b__11_2(Iter it) in Game1.cs:line 183
at Flecs.NET.Core.Invoker.Iter(ecs_iter_t* iter, IterCallback callback)
at Flecs.NET.Core.BindingContext.RoutineIter(ecs_iter_t* iter)
at Flecs.NET.Bindings.Native.ecs_progress(ecs_world_t* world, Single delta_time)
at Flecs.NET.Bindings.Native.ecs_progress(ecs_world_t* world, Single delta_time)
at Flecs.NET.Core.World.Progress(Single deltaTime)
at monotone.Game1.Update(GameTime gameTime) in Game1.cs:line 236
at Microsoft.Xna.Framework.Game.DoUpdate(GameTime gameTime)
at Microsoft.Xna.Framework.Game.Run(GameRunBehavior runBehavior)
at Program.<Main>$(String[] args) in Program.cs:line 3
What I am currently doing is using a sentinel tag that the system queries, which is a workaround so that I can add a working query to the system and still know that the query is reasonably cheap (as, in my setup, there's only a single entity in the system with that sentinel tag).
I tested the code snippet you provided in a new project—it works. So the error lies elsewhere, will take a look.
Are you by any chance calling Iter.Table()
anywhere in your callback function? When running a system that uses 0 terms, it looks like the table pointer is always null. In the C# API, I make a call to ecs_table_count
in the table constructors which is what I think is causing the crash. I am working on updating to flecs version 3.2.8 right now and will add a null check before calling ecs_table_count
but you should avoid using the table struct inside of a system if you can. This C++ sample produces the same assertion.
int main(void) {
flecs::world ecs;
ecs.system().iter([](flecs::iter it) {
it.table().count();
});
ecs.app().run();
}
Yes, I do call Iter.Table()
in the callback. Nice find!
That call is not necessary for the callback's functionality, so I can simply remove that call for the time being. FWIW, I used Iter.Table()
to inspect what kind of entities the callback was iterating on, copying from the Hello World example from flecs.
you should avoid using the table struct inside of a system if you can.
Interesting, I was not aware of this being an anti-pattern (again, because it was shown in literally flecs' own first code example). Thanks for letting me know!
you should avoid using the table struct inside of a system if you can.
Sorry that was a typo, I mean't you shouldn't use it in an empty table system. It's fine to use tables otherwise. Closing this issue now!