Hello, I ran into a frustrating interaction, I’m not sure if it’s intended but it seems pretty unintuitive to me. If you create an entity query in your system via GetEntityQuery
with a single component and add a ChangeFilter to it, then any call to GetSingleton
or GetSingletonEntity
will inherit that filter - meaning GetSingleton will throw an exception if that singleton wasn’t written to that frame. A simplified example:
using Unity.Entities;
using UnityEngine;
struct Comp : IComponentData
{
public int value;
}
public class GetSingletonTest : SystemBase
{
EntityQuery _unrelatedQuery;
protected override void OnCreate()
{
EntityManager.CreateEntity(typeof(Comp));
_unrelatedQuery = GetEntityQuery(ComponentType.ReadOnly<Comp>());
// If you comment this out then we get no exception
_unrelatedQuery.AddChangedVersionFilter(ComponentType.ReadOnly<Comp>());
}
protected override void OnUpdate()
{
// Throws an exception after the first frame since our singleton is never written to.
GetSingletonEntity<Comp>();
// Gets called once on the first frame since creation counts as write access
Debug.Log("OnUpdate");
}
}
Given how “GetEntityQuery” works I understand why this would happen, but I personally think GetSingleton/GetSingletonEntity should ignore filtering on what I expected to be an unrelated query, it’s very unintuitive.
2 Likes
So I noticed another strange thing when messing with this. It’s a bit complicated for me to explain so bear with me. If you RequireSingletonForUpdate
on the component with the changefilter (added via an entity query with the same archetype) - it actually RESPECTS the changefilter. Your system will NOT update unless that singleton gets written to. This is actually a good thing in the case of RequireForUpdate, or it would be if we had the option to enable or disable that behaviour (passing in an IgnoreFiltering bool or something would be good).
BUT - I was not expecting that at all. The reason being, if you RequireForUpdate
on an EntityQuery it ignores filtering. I’ve tried this in the past and was disappointed by it, since it’s an ideal setup for a reactive system. For example - this system runs all the time no matter what:
public class EQTest : SystemBase
{
EntityQuery _eq;
protected override void OnCreate()
{
_eq = GetEntityQuery(typeof(Comp));
_eq.AddChangedVersionFilter(typeof(Comp));
RequireForUpdate(_eq);
}
protected override void OnUpdate()
{
Debug.Log("Test");
}
}
So for me the ideal API would be something like:
System.GetSingleton/GetSingletonEntity - Always ignores any filtering. If filtering behaviour is needed, we would use entityQuery.GetSingleton which would obviously respect any filtering on that query.
RequireSingletonForUpdate/RequireForUpdate - Give us the option to pass in a bool specifying whether these should or should not ignore filtering. I would really love this change as it would make it easier to write intuitive reactive systems.
2 Likes