I have a BarSystem that write data to FooComponent and then update FoobarSystemGroup multiple times to get the output data I want. In FoobarSystemGroup, there's a bunch of systems group together and one of the FooSystem has ChangeFilter FooComponent to detect FooComponent write access to update the system. I expect FooSystem to update 10 times when BarSystem updates 10 times but in reality FooSystem only update once. I would like official to improve this so I can achieve my goal. My expectations is for each time access FooComponent as write access then call FoobarSystemGroup.Update() should update the system once.
#[1.3.5] Update System Group multiple times manually only trigger ChangeFilter once
1 messages · Page 1 of 1 (latest)
Change filters don't work in RequireForUpdate because it would call IsEmptyIgnoreFilter. Are you sure you expecting the correct behaviour here?
Or by system update you mean job going over chunk?
I didn't have OnCreate() at system so no RequireForUpdate. System update I mean call state.World.GetExistingSystem<FoobarSystemGroup>().Update() to force all the relevant systems run OnUpdate().
does it have a rate manager?
I don't think change filters are relevant here, because unless you explicitly sync for them and check on main thread, they wouldn't prevent system update in any way
Hi @proud breach I would like official to fix this issue. I try to explain it much clearer here. So I have a system running for loop 100 times doing FooComponent.ValueRW.value += 1 then call state.World.GetExistingSystem<FoobarSystemGroup>().Update(). Inside FoobarSystemGroup, there's a couple systems has ChangeFilter<FooComponent> should trigger the change filter and run the system logic 100 times but in reality all the corresponding systems inside FoobarSystemGroup only trigger change filter 1 time instead of 100 times. What I expect is each time when access FooComponent as RW then get the system group or the system that has ChangeFilter<FooComponent> to call Update() should trigger one time
Let me confirm understanding; is this accurate?
for i=1,100 do:
FooSystem.Update():
FooComponent.ValueRW.value += 1
FoobarSystemGroup.Update():
ChangeDetectionSystem.Update():
if DidChange<FooComponent>():
Log "FooComponent changed"!
Expected results: "FooComponent changed!" logged 100 times
Actual result: "FooComponent changed!" logged only once
Yes something like that but for I just want the all the systems inside system group able to go into idiomatic for each that has FooComponent change filter update the systems 100 times . Do u want repro project? I can pm u later
Change filtering works of world version, which makes your actual result an expected one. So basically you need to trigger whole world update, not just that system group
Or in other words: all your systems last version is same through all those 100 updates, thus no change can be detected
That's not really true? It works on GlobalSystemVersion
Which is incremented every BeforeOnUpdate in a system
So I would expect it to work for manaully updating systems
But a system won't trigger its own change filter
I think the issue here is he's trying to Update systems from inside a system?
System1
BumpVersion to 1
for 0..100
i = 0
FooComponent.ValueRW.value += 1 // writes changefilter 1
FoobarSystemGroup.Update()
{
BumpVersion to 2
SystemUpdate
{
BumpVersion to 3
LastUpdateVersion = 0
0 < 1, change filter triggers
LastUpdateVersion = 3
}
}
i = 1
FooComponent.ValueRW.value += 1 // writes changefilter 3 because it still state.m_GlobalSystemVersion wasn't bumped as OnBeforeUpdate wasn't run
FoobarSystemGroup.Update()
{
BumpVersion to 4
SystemUpdate
{
BumpVersion to 5
LastUpdateVersion = 3
3 == 3, no change filter trigger
LastUpdateVersion = 5
}
}
etc
}
Hold up, if it works like this, then any sysyem trigerring more than once will result fully breaking any other loops, no?
Some loop jumped 100 more. What happens to the rest of systems?
every system update just bumps version 1
and stores last update version in AfterUpdate
it uses lastupdate to compare to change filter to see if it's been updated since system last ran
Yeah, so assuming 100 times it bumped version. What happens now, is that those systems will never trigger of other system changes, as all those other systems versions are 100 versions behind. No?
no?
it doesn't matter how many times it increases
those may as well just be 100 unique systems
it's the same thing
System A updated 100 times and has version 100. It writes this to change version of chunk. Next system B updates once and has change version of 1. What happens to change version when it writes to same chunk?
System version is same across all systems?
Ok, makes sense
its only caching the lastversion
so now i'm not sure why it's not actually writing a new version
oh except that it matches the system
yeah same problem, just wrong number in example - updated
if you fixed this by doing equality as changed, it would break entities by causing systems to trigger their own change filters
Ah, okay -- this is reminding me of some long, long-ago conversations with a long-since-departed colleague who implemented a lot of the early EntityQuery and SystemGroup interactions. They raised a concern at the time that the exact behavior of change versions & change version filtering within the scope of system would be very error-prone. Our conclusion at the time was that the best way to solve these errors was to avoid them completely, by not mixing component-modification logic and recursive system updates within the same system.
So @tawdry jasper, do you get the expected behavior if you move the write to FooComponent out of BarSystem (if BarSystem is the one that's recursively updating the FoobarSystemGroup)?
Nope. At usual game update, BarSystem still needs to update the system as usual when FooComponent detect change filter changes. And then when force update FooComponent and FoobarSystemGroup 100 times inside for loop, BarSystem and other relevant systems that has change filter FooComponent will update 100 times.
I fear I'm still not wrapping my head around this. Can I get a ~40-50 line concrete, self-contained, compileable-and-runnable example of the systems/components/loops you're describing, what you expect to happen, and what actually happens? Ideally something I can drop into the ComponentSystemGroupTests.cs file in the Entities package. Something like this, adapted as necessary:
struct FooComponent : IComponentData
{
public int Value;
}
partial class WriteComponentValueSystem : SystemBase
{
protected override void OnUpdate()
{
}
}
partial class ChangeFilterLoopSystem : SystemBase
{
protected override void OnUpdate()
{
for (int i = 0; i < 100; ++i)
{
foreach (var f in SystemAPI.Query<FooComponent>().WithChangeFilter<FooComponent>())
{
}
}
}
}
partial class FoobarSystemGroup : ComponentSystemGroup
{
}
[Test]
public void ChangeVersionFilterLoopTest()
{
using World w = new World("Test World");
var writeSys = w.CreateSystemManaged<WriteComponentValueSystem>();
var loopSys = w.CreateSystemManaged<ChangeFilterLoopSystem>();
var foobarSysGroup = w.CreateSystemManaged<FoobarSystemGroup>();
foobarSysGroup.AddSystemToUpdateList(
}
[1.3.5] Update System Group multiple times manually only trigger ChangeFilter once