#Attempted to access ComponentLookup which has been invalidated by a structural change

1 messages · Page 1 of 1 (latest)

daring stump
#

The following foreach loop gives me the above error

        foreach (var (monsterSpawner, timerAspect) in SystemAPI.Query<MonsterSpawner, TimerAspect>())
        {
            if (timerAspect.isNextNow(ref random, dt))
            {
                Debug.Log(monsterSpawner.SpawnCenter);
                var instance = ecb.Instantiate(monsterSpawner.MonsterPrefab);
                var positionNoise = new float3(random.NextFloat(), 0, random.NextFloat()) * 5;
                var spawnAt = WorldTransformLookup[monsterSpawner.SpawnCenter];
                var spawnAtPosition = positionNoise;
                //Debug.Log(spawnAtPosition);
                var transform = LocalTransform.FromPosition(spawnAtPosition);
                Debug.Log(transform);
                ecb.SetComponent(instance, transform);
            }   
        }

Is anyone able to help?

#

The full error is ObjectDisposedException: Attempted to access ComponentLookup<Unity.Collections.NativeText.ReadOnly> which has been invalidated by a structural change.

gaunt ibex
#

OK this is a huge gotcha in entities

#

any structural change will invalidate all dynamic buffers and lookups

#

except hmm you seem to be using a command buffer

#

so now i'm confused

hollow bloom
#

what isNextNow does?

gaunt ibex
#

i.e. is there entitymanager usaged somewhere

daring stump
#

I can post the full code if you guys want it, just didn't want to overwhelm

#

One second

#

Full system:

using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Rendering;
using Unity.Transforms;
using UnityEngine;
using Random = Unity.Mathematics.Random;

[BurstCompile]
partial struct MonsterSpawningSystem : ISystem
{
    [ReadOnly] ComponentLookup<WorldTransform> WorldTransformLookup;
    public Entity player;
    public float timeUntilNextMonster;
    public EntityQuery monsterSpawnerQuery;
    public Random random;
    
    [BurstCompile]
    public void OnCreate(ref SystemState state)
    {
        WorldTransformLookup = state.GetComponentLookup<WorldTransform>(true);
        monsterSpawnerQuery = SystemAPI.QueryBuilder().WithAll<MonsterSpawner>().WithAspect<TimerAspect>().Build();
        random = new Random(8328732);
    }

    //[BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        var dt = SystemAPI.Time.DeltaTime;
        //var config = SystemAPI.GetSingleton<Config>();

        var ecbSingleton = SystemAPI.GetSingleton<BeginSimulationEntityCommandBufferSystem.Singleton>();
        var ecb = ecbSingleton.CreateCommandBuffer(state.WorldUnmanaged);
        foreach (var (monsterSpawner, timerAspect) in SystemAPI.Query<MonsterSpawner, TimerAspect>())
        {
            if (timerAspect.isNextNow(ref random, dt))
            {
                Debug.Log(monsterSpawner.SpawnCenter);
                var instance = ecb.Instantiate(monsterSpawner.MonsterPrefab);
                var positionNoise = new float3(random.NextFloat(), 0, random.NextFloat()) * 5;
                var spawnAt = WorldTransformLookup[monsterSpawner.SpawnCenter];
                var spawnAtPosition = positionNoise;
                //Debug.Log(spawnAtPosition);
                var transform = LocalTransform.FromPosition(spawnAtPosition);
                Debug.Log(transform);
                ecb.SetComponent(instance, transform);
            }   
        }
    }
}
#

and the timer aspect (allthough that part works, everything here works perfectly as long as I do not use the WorldTransformLookup)

hollow bloom
#

ok

daring stump
#
readonly partial struct TimerAspect : IAspect
{
    private readonly RefRW<Timer> Timer;

    public bool isNextNow(ref Random rng, float dt)
    {
        Timer.ValueRW.timeUntilNext = Timer.ValueRW.timeUntilNext - dt;
        if (Timer.ValueRW.timeUntilNext <= 0)
        {
            float rate = Timer.ValueRO.rate;
            Timer.ValueRW.timeUntilNext = rng.NextFloat(rate * 0.5f, rate * 1.5f);
            return true;
        }

        return false;
    }
}
hollow bloom
#

SpawnCenter

gaunt ibex
#

WorldTransformLookup.Update(ref state);

hollow bloom
#

ooh

#

right

gaunt ibex
#

you need to update your lookup each frame

daring stump
#

Ah ok, thank you so much again!

hollow bloom
#

(use SystemAPI)

daring stump
#

Love ECS but reading the tutorials from to many sources at once I guess, since not everything works yet

hollow bloom
#

setComponent, getComponent methods will do it for you

daring stump
#

Because I am not in a Job?

gaunt ibex
daring stump
#

I should use getComponent and setComponent?

hollow bloom
daring stump
#

Do you think the above stuff should rather go into a Job?

hollow bloom
#

if you expect lots of entities - job

#

if it's very few

#

query would probably be fine

daring stump
#

It seems that Entitites.Foreach does not work in ISystem right, so I have to use foreach() (which is single threaded) or a Job, do I understand that right?

#

And ISystem is the future, right?

hollow bloom
#

ISystem is present

#

😅

gaunt ibex
#

if you are just starting out

#

dont even think about entities foreach

#

ignore any tutorial you see with it

#

they're out of date

daring stump
#

I used ECS like one or two years ago and have some loose memories

#

haha the main tutorial still uses it

#

on github

gaunt ibex
#

ignore it, ideally it'd be deleted

daring stump
#

They firstuse ISystem with foreach(...) and then later say now we use the SystemBase again until foreach has reached feature-parity

gaunt ibex
#

IJobEntity and SystemAPI.Query (and IJob) are your primary tools

daring stump
#

but is there any up to date tutorial?

#

I'm talking about the github entities tutorial in ECSSamples

#

I thought thats as new as it gets

#

but yeah from forum threads I understood that SystemBase is meant to be gone at some point and ISystem is where you want to be, right?

#

One more question maybe, how much code should I put in aspects?

hollow bloom
#

SystemBase is for managed systems

daring stump
#

and how much in the system?

hollow bloom
#

where you want to run code non-bursted

daring stump
#

but what code might that be?

hollow bloom
#

UI bridge for example

daring stump
#

stuff where I have to still interact with the classic engine since features are not there yet?

#

ok ok

hollow bloom
#

or some other managed world integration

daring stump
#

How much code do you put in aspects vs in systems?

hollow bloom
#

ugh, don't think there are rules on that

#

just follow DRY pattern with this one I guess

daring stump
#

ok, thanks again for the quick and good help!

#

Hey, It actually is not fully resolved, I now get

InvalidOperationException: The previously scheduled job LocalToWorldSystem:ComputeRootLocalToWorldJob writes to the ComponentLookup<Unity.Collections.NativeText.ReadOnly> ComputeRootLocalToWorldJob.JobData.WorldTransformTypeHandleRW. You must call JobHandle.Complete() on the job LocalToWorldSystem:ComputeRootLocalToWorldJob, before you can read from the ComponentLookup<Unity.Collections.NativeText.ReadOnly> safely.

How do I tell this job to run after the unity scheduled job ComputeRootLocalToWorldJob ?

gaunt ibex
#

well you're not using a job is kind of the issue

#

SystemAPI.Query
is running on main thread

#

and i guess you're using transform aspect so you need to finish any job that's using it i guess

#

you probably just need to call state.Dependency.Complete()

#

or move your work to a job