#[1.3.5] Update System Group multiple times manually only trigger ChangeFilter once

1 messages · Page 1 of 1 (latest)

tawdry jasper
#

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.

night pumice
#

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?

tawdry jasper
#

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().

night pumice
#

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

tawdry jasper
#

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

proud breach
#

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

tawdry jasper
night pumice
#

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

jaunty yarrow
#

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
}
night pumice
#

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?

jaunty yarrow
#

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

night pumice
#

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?

jaunty yarrow
#

no?

#

it doesn't matter how many times it increases

#

those may as well just be 100 unique systems

#

it's the same thing

night pumice
#

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?

jaunty yarrow
#

system B updates and has change filter 101

#

it's LastUpdateVersion is 0

night pumice
#

System version is same across all systems?

jaunty yarrow
#

yes

#

though i've just realized the system isn't caching it

night pumice
#

Ok, makes sense

jaunty yarrow
#

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

proud breach
#

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)?

tawdry jasper
proud breach
#

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(
}
tawdry jasper
#

[1.3.5] Update System Group multiple times manually only trigger ChangeFilter once