#Friction with enablable components

1 messages · Page 1 of 1 (latest)

worldly yarrow
#

It feels difficult to manage enablable components under moderately complicated scenarios.

  • You have to make aspects or work manually to avoid errors regarding multiple identical types in queries if you want to have both a EnabledRef and Ref in the same one.
  • If you wanted to ignore enabled state it seems WithNone will disregard it too, which means if you need WithNone you can't also include disabled components in your query.
  • I encounter many places where I want to disable one tag and enable another in the same foreach, but you can't achieve it sensibly afaik without these ignore/include contradictions.

I'm sure the list goes on, but it's late and I'm just looking to get the question up before I sleep!

It feels like EntityQueryOptions.IgnoreComponentEnabledState is not granular enough, and you should be able to specify it per-component, or in some specific parts of the query.

It actually feels like there's a whole bunch of work that needs to be done to make it painless in general... I've only had a tough time, having to constantly refactor due to unexpected interactions or errors, none of which I feel are intuitive, though I understand the limitations when I encounter them.

Is this being felt internally, and are there things coming soon to improve the situation?

heady wharf
#

Hello! There's a lot of points to address here.

Errors from EnabledRef<T> + Ref<T> (and variations thereof) have already been fixed in our main branch, and should appear in a forthcoming DOTS release. This should no longer require aspects to work.

#

WithNone<T> with an enableable T is definitely a known issue. The initial design of enableable components tried to preserve the original semantics of WithNone, and in retrospect we probably shouldnot have bundled "component isn't present" and "component is present but disabled" under the same query constraint; they're very different use cases.

In my own experience (ymmv), it's rare to see a case of WithNone<T> that can't safely be replaced with either WithAbsent<T> (if the intent is to use the query to add missing components) or WithDisabled<T> (if the intent is to use the query to re-enable disabled components). That's my recommended guidance in the short term. A longer-term fix will probably require breaking API changes, and are thus a bit further away.

#

Enabling/disabling multiple tags in the same foreach should work afaik; can you give a specific example of something you've tried that doesn't work, and I can try to figure out what's going wrong?

#

You are 100% correct about EntityQueryOptions.IgnoreComponentEnabledState being too granular; it was originally intended as a stopgap measure, as the original query syntax didn't expose ANY way to match a disabled component. With the addition of WithDisabled<T> and the hot-of-the-presses addition of WithPresent<T> (meaning "match entities with component T whether it is enabled or not), the vast majority of use cases of IgnoreComponentEnabledState can be replaced with more explicit per-type constraints.

sand jasper
heady wharf
#

Specific release plans aren't my department; I'll have to summon a PM for that.

#

@worldly yarrow If you have further pain points with enableable components, keep 'em coming!

sand jasper
heady wharf
#

I mean that various combinations of EnabledRef<T> and Ref<T> and ref T WithAll<T> in the same IJobEntity or idiomatic foreach should no longer complain about multiple instances of T in the query.

#

I looked into just teaching Ref<T> how to enable/disable the component to simplify the API a bit, but it turned into a larger/more invasive change than we can make in the short term.

clever vortex
heady wharf
#

😬 WithAny<T> is the one thing we haven't touched yet, and it surely has some inexpressible combinations we should sort out. But "read/write some enabled state without attachment to its [current] enabled/disabled state" sounds like a use case for the brand-new-coming-soon WithPresent<T> constraint, if I understand correctly.

clever vortex
heady wharf
#

It should work anywhere a query can be declared, explicitly or implicitly!

clever vortex
heady wharf
#

That is indeed the intent. I'm on vacation at the moment and unable to verify directly, but will check when I get back. If this doesn't work, it's a bug and we'll fix it!

#

WithAny<T1,T2,Tn> still requires at least one of the Ts to be present and enabled; there's no way to combine Any semantics and more complex enabled-ness constraints. The query syntax is getting pretty gnarly as-is, and this feels like it's getting pretty niche, so we'd probably wait until a concrete use case arises before we tackle that one.

heady wharf
rotund wraith
#

Very excited to hear about the newly added WithPresent! That will solve a lot of the issues I've had with enableable components.

#

But I would like to add another thing. Can we get support for [Optional] for EnabledRefRW/RO fields in aspects?

worldly yarrow
#

All the stated improvements sound great and I'm really looking forward to having them 😄

rotund wraith
# rotund wraith But I would like to add another thing. Can we get support for [Optional] for Ena...

I should clarify this use case a bit. The current [Optional] attribute means the component can either be present or not. What I want is some way to say that the enableable component can either be disabled or enabled, but still present. Basically, the equivalent of WithPresent, but for aspects. And although I haven't needed it yet, I assume I'll eventually want the equivalent of WithDisabled on an EnabledRefRW field in an aspect.

I assume the new WithPresent can be used on queries in conjunction with an aspect to get the behavior I want, but this requires that each job using the aspect also has the WithPresent attribute. It is similar to how we can use EntityQueryOptions.IgnoreComponentEnabledState in conjunction with aspects today. Personally, I always forget to do this when defining a new job that uses an aspect. Then I spend an hour debugging why my job isn't matching anything.

So I think the bigger ask is allowing us to specify all of these query filters (WithPresent, WithDisabled, WithAll, etc.) inside of an aspect rather than requiring the caller to do. The current [Optional] attribute basically accomplishes this for regular components, but we don't have the same tools for enableable components

rotund wraith
worldly yarrow
# heady wharf Enabling/disabling multiple tags in the same foreach _should_ work afaik; can yo...

Ah it is still a problem afaik:

// EntityQueryDescValidationException: EntityQuery contains a filter with duplicate component type name EnableMe.  Queries can only contain a single component of a given type in a filter.
foreach (var example in SystemAPI.Query<EnabledRefRW<EnableMe>, EnabledRefRW<DisableMe>>().WithDisabled<EnableMe>())

If I wanted to make a query that took in a disabled component I want to enable, and an enabled component I want to disable, what setup am I meant to have?
If I use EntityQueryOptions.IgnoreComponentEnabledState then the DisableMe component's enabled state will be ignored, and I need it enabled.
I might just be mistaken and this is easy to do, but I run into it a lot

rotund wraith
worldly yarrow
rotund wraith
#

Does it work if you remove the EnabledRefRW<DisableMe> from the query? So just an EnabledRefRW<T> and WithDisabled<T>. Because that works fine in IJE. Here is an example:

    [WithDisabled(typeof(Destroy))]
    [BurstCompile]
    private partial struct DestroyAtTickJob : IJobEntity
    {
        public double ElapsedTicks;

        [BurstCompile]
        private void Execute(Entity entity, in DestroyAtTick destroyAt, EnabledRefRW<Destroy> destroy)
        {
            if (ElapsedTicks > destroyAt.ElapsedTicks)
            {
                destroy.ValueRW = true;
            }
        }
    }
#

Regardless, this sounds like a bug

rotund wraith
#

Yup, I'm seeing the same error with this example:

foreach (EnabledRefRW<Destroy> example in SystemAPI.Query<EnabledRefRW<Destroy>>().WithDisabled<Destroy>())

But the exact same thing works fine with IJE.

worldly yarrow
#

90% of my complaints with Entities is this kind of thing tbh, shuffling code around until something likes the structure. It's not a compiler error, it's a runtime exception, so you can get so far thinking something like that works when really it doesn't. And I have no idea if it's a bug, or if it's just not intended or will be supported later. Hopefully someone can lmk whether this one is meant to work 👀

Though perhaps it's related to the whole:

Errors from EnabledRef<T> + Ref<T> (and variations thereof) have already been fixed in our main branch, and should appear in a forthcoming DOTS release. This should no longer require aspects to work.

heady wharf