State Tree Property binding value promotion

Similar to the engines FStateTreeRunEnvQueryTask, I have a similar state tree property reference declared identically

UPROPERTY(EditAnywhere, Category = Input, meta = (RefType = "/Script/CoreUObject.Vector, /Script/Engine.Actor", CanRefToArray))
FStateTreePropertyRef ContextItems;


But I noticed, that in the state tree, it’s not giving me the option to bind it to derived actor types.

To verify this, I changed it as such

UPROPERTY(EditAnywhere, Category = Input, meta = (RefType = "/Script/CoreUObject.Vector, /Script/Engine.Actor, /Script/TestProject.GameTeleportTargetActor", CanRefToArray))
FStateTreePropertyRef ContextItems;

By declaring the actor type explicitly, then property binding shows options to bind to that type, but I would expect that /Script/Engine.Actor would encompass any derived actor type, and that there is probably a missing IsChildOf somewhere in the code that

Perhaps in IsNativePropertyRefCompatibleWithProperty

[Image Removed]

[Image Removed]

Clearly this code needs an IsChildOf allowance, right?

The comment doesn’t make much sense, as it’s possible to allow implicit upcasting without allowing downcasting.

Seems like an easy fix, but I’m not sure if any downstream bugs could come out of this

[Image Removed]

[Attachment Removed]

Hi there,

I’ve had a bit of a deep dive into this. To me this is likely a deliberate implementation in order to enforce exact type usage. On the surface level, It seems clear from the documentation/comments that the RefType specifier requires a full path for it’s types & must be the exact class. Additionally this area of the code has not changed in the 2 years since it has been implemented.

It does look like the specifier could benefit from this change. For example allowing the specifier to align with the behavior of AllowedClasses & optionally use the ExactClass Specifier. However Since the property reference is mutable at runtime and the property ref can be accessed outside of the “normal” execution context such as with async tasks. It could potentially break some assumptions made by the state tree framework. Therefore casting the value of the reference before/after is the safest option. I can’t speak to the state tree team’s true intent however.

- Louis

[Attachment Removed]

Hey Jeremy,

I do get the confusion on this. Originally, we had the ability to use ChildOf classes for object property refs. It was changed after finding that a TStateTreePropertyRef<AActor> could be bound to an ACharacter, but since the property ref was an underlying AActor, it meant that there was a possibility of someone writing back an AActor to the ACharacter. The change was made to prevent that from ever happening by having a strict type enforcement. In researching this and talking with the team, the ability to use derived structs is actually the bug solely from a safety perspective.

That being said, we certainly see the need for a read-only style property ref that would allow binding with child classes, but prevent being able to write back into the bound property. I am creating a feature request for us to explore this kind of “ConstPropertyRef” in StateTree. We are looking at the larger engine and user base, so we err on the side of preventing the possibility of someone writing bad data. This certain case seems like a bug that would be quite difficult to track and diagnose in the wild.

If you are willing to assume the risk and responsibility of using these property refs as read-only, then your change would work but lack a hard guarantee of read-only. I would not advise using them in this way for writing data back as I imagine it would be difficult to audit all places property refs may have data written back over the life of your project.

If I missed a key point or misunderstood part of your request, please let me know. And as a complete asides, has it really been years already for us?! Lol I should be at UFest Chicago this year, and if you are attending, I would love a chance to talk about all you have been making.

-James

[Attachment Removed]

We found it thanks to a QA engineer when we were working on the property ref system early on, but it does appear we overlooked the struct usage in property refs which is likely due to still having the StateTreeStructRef in use. I do have a task that is in our JIRA to look into a const/read-only style property ref because the whole team agrees it would be a great addition for issues precisely like what you described. It also aligns with our vision of using property refs explicitly for performance or other concrete reasons rather than only writing data back to other parameters. The only issue with it being a task in our JIRA is that I do not have a public issue tracker link to share. You can always ping me on here to check if any progress has been made with it.

That sounds great! I look forward to seeing you there!

-James

[Attachment Removed]

The ‘RefType’ looks like it explicitly supports ‘base types’ for struct types, to allow derived types to be referenced with a similar declaration referencing the base type. And I’m pretty sure that actually works for structs. Even in the commented examples above TStateTreePropertyRef and FStateTreePropertyRef, there are examples utilizing a base struct type.

I would expect to be able to do the same with Object references as well. The state machine has no casting support, and it doesn’t make sense to make custom tasks just to satisfy strict object type exactness.

And nowhere else does the binding system enforce exact class. It’s permissible all over the place for a derived input property to bind to a base output property. I would not expect this situation to be any different.

[Image Removed]

[Attachment Removed]

Hi again,

Despite the documentation referencing base types I have confirmed through testing both UStateTreeTaskBlueprintBase & FStateTreeTaskCommonBase that RefType does not allow derived types in this situation:

[Image Removed]Additionally I think the root cause here is not on the binding system but specifically caused by the property ref.

I agree that it would be beneficial to have this feature. However I can’t be sure if this is a deliberate design decision or a feature that was overlooked. I am going to escalate this case so that we can get some information from the epic team.

Cheers,

Louis

[Attachment Removed]

Thanks for your time

I have the following

[Image Removed]

Bound to

[Image Removed]

Where

[Image Removed]

It’s possible we have made a local engine change that allows this. I suppose if it’s not a bug then consider it a feature request.

If possible, can you ask [mention removed]​ about the intent here? He and I have a multi year history of UDN posts documenting state tree binding bugs, edge cases, etc, and given how the rest of the engine supports ‘base’ fields being able to reference child objects everywhere else, including the struct utils library, I would be surprised if being this rigid with the type binding in state tree were intentional. But maybe there’s a technical reason unknown to me that our own fix has not encountered(yet).

Thanks

[Attachment Removed]

Hey [mention removed]​

Thanks for your explanation. That would not have occurred to me. I haven’t really used property refs to stomp the entire property with an assignment that might need to account for write based type safety. A const version would definitely be very useful, with more relaxed bindings. Most of my usages I think would fall under const.

Yes! I am planning on attending Unreal Fest in Chicago. Would love to meet up and talk shop.

[Attachment Removed]