State Tree: If you Promote to Parameter a bitfield, it loses its bitfield functionality

Promoting a bitfield breaks the variable type

Steps to Reproduce
Expose a property from a state tree node/task, as a bitfield, such as

[Image Removed]

In the state tree editor, observe that if you attempt to Promote to Parameter, the property in the global parameters will(I guess) lose the metadata responsible for having it function as a bit field

[Image Removed]

Hey Jeremy,

I have put this suggestion forward with the team. We are working on a article to highlight various items in StateTree with a special emphasis on things that are only documented in code but not in any official docs. This seems like a prime candidate to be included in that article, but having some warning or tooltip to explain that is possible seems like a reasonable item.

-James

Hey Jeremy,

We have changed the behavior for the latest on StateTree to include metadata when promoting to a parameter. It should be in 5.7, but if you would like to cherrypick it into 5.6, it is CL 44785962 in UE5/Main P4.

-James

Hi Jeremy,

Thank you for reporting this issue and providing repro steps. I was able to repro this behavior on my end here.

My first impression is that the Global Parameters of a State Tree do not currently support Bitmasks or any other Metadata-based property customizations, since there is no UI in the Editor where the relevant flags could be viewed and changed. On the Blueprint Editor, for example, you can manually create an Integer variable for an Actor, select it, and enable “Bitmask” on its Details Panel. On the State Tree Editor, on the other hand, Global Parameters cannot be selected and do not offer settings in the Details Panel.

I am going to investigate this a little to see if there is an easy workaround to at least propagate these metadata flags when the promotion takes place, and I’ll get back to you soon. I’ll also pass this on to the engine devs, but I believe they will prefer to handle it as a missing feature instead of a bug.

Best regards,

Vitor

Thanks for your response. FPropertyBagPropertyDesc looks like it has code to copy metadata, but I’m not sure if that gets invoked by the promote to variable code path, but that whole parameter system is based off of FInstancedPropertyBag, so it seems like it’s most of the way there.

Hi Jeremy,

I have investigated this further, and you are correct that FPropertyBagPropertyDesc’s constructor has code to copy property metadata. However, it later gets explicitly wiped out with the goal of keeping a consistent behavior with properties added from the UI, where there is currently no support for setting up metadata. The flow is as follows:

- On file [PropertyBindingExtension.cpp], function FCachedBindingData::PromoteToParameter() creates and populates “PropertyCreationDescs”, which is a “TArray<FPropertyCreationDescriptor>”.

- Each “FPropertyCreationDescriptor” has a field “PropertyDesc” with type “FPropertyBagPropertyDesc”. It is constructed from the source property and initially includes all metadata as you noted.

- Right afterwards, BindingsOwner->OnPromotingToParameter() is called on an instance of “UStateTreeEditorData”. This is a virtual function.

- UStateTreeEditorData inherits from IStateTreeEditorPropertyBindingsOwner, which inherits from base IPropertyBindingBindingCollectionOwner, where OnPromotingToParameter() is defined as:

[PropertyBindingBindingCollectionOwner.h]
class IPropertyBindingBindingCollectionOwner
{
  // (...)
  
	/**
	 * Called when a property is being promoted to a parameter.
	 * @param PropertyDesc The newly created property descriptor
	 */
	virtual void OnPromotingToParameter(FPropertyBagPropertyDesc& PropertyDesc)
	{
		// By default, we create a descriptor based on the Target Property, but without the meta-data.
		// This functionality mirrors the user action of adding a new property from the UI, where meta-data is not available.
		// Additionally, meta-data like EditCondition is not desirable here.
		// Derived classes can override this behavior.
		PropertyDesc.MetaClass = nullptr;
		PropertyDesc.MetaData.Reset();
	}
  
  // (...)
};

We can see in the code above that “PropertyDesc.MetaData.Reset()” is explicitly called, and the rationality is given in the preceding comment. This behavior is therefore by design, but if you are able to make changes to the engine source code, it is quite easy to avoid clearing the “Bitmask” and “BitmaskEnum” metadata. Just edit “IPropertyBindingBindingCollectionOwner::OnPromotingToParameter()”, or better yet, create a new override “IStateTreeEditorPropertyBindingsOwner::OnPromotingToParameter()” along the lines of the following snippet:

[StateTreeEditorPropertyBindings.h]
class IStateTreeEditorPropertyBindingsOwner
{
  // (...)
  
#if WITH_EDITOR
  /**
   * Called when a property is being promoted to a parameter.
   * @param PropertyDesc The newly created property descriptor
   */
  void OnPromotingToParameter(FPropertyBagPropertyDesc& PropertyDesc) override
  {
    PropertyDesc.MetaClass = nullptr;
    PropertyDesc.MetaData.RemoveAll(
      [](const FPropertyBagPropertyDescMetaData& MetaData)
      {
        if (MetaData.Key == TEXT("Bitmask") || MetaData.Key == TEXT("BitmaskEnum"))
          return false;
        return true;
      });
  }
#endif // WITH_EDITOR
 
  // (...)
};

I tested the engine change above and it seems to work correctly (remember the “#if WITH_EDITOR” if implementing an override inside IStateTreeEditorPropertyBindingsOwner). If you cannot make changes to the engine source code, I would suggest replacing the bitmask variable with a set of independent enum and/or boolean variables.

Please let me know if the solution above works for you or if you have any further questions.

Best regards,

Vitor

Hi [mention removed]​ I appreciate your time in looking into this. What I have decided to do is just wrap my bitfield property in a struct and use that in the state tree. This has the added benefit of being represented as a concrete type, rather than a plain integer that could be anything without the metadata.

[Image Removed]

From a user perspective, it would appear less like a bug if you got a warning popup when you promoted a property like this where clearing the metadata completely breaks the details customization for the property. Maybe just a general “If it has metadata, present a modal confirmation during the promotion”. Not a big deal though. Thanks for your time.

Wrapping the bitfield property in a struct is also a great workaround, thank you for sharing!

I have reached out to the engine devs, and I was told that the devs that own this system will discuss this issue internally, so I will forward this ticket to them now. Note that Epic does not provide a public progress tracker for feature requests, in case they choose to handle this as such. But feel free to follow up here (or on a new ticket if this one gets closed) if you want to share any extra information or ask for any further assistance.

All the best,

Vitor