EditInlineNew + Instanced Components

Sep 17, 2020.Knowledge

[Bug] Editor Created Subobjects Used as Archetypes Do Not Work as Expected | Dan O’Connor

Editor created subobjects used as archetypes, do not function usefully as currently implemented. Archetype lookup for Objects is based on name, and the editor (details panel and other controls) does nothing to maintain a coherent name across hierarchies. Even if it did reliably name user created subobjects, there are open questions about how to handle changes to individual pieces of an archetype graph. The Actor/Component system, UMG, and animation system, all reinvent the wheel here and none of them address the shortcomings around using EditInlineNew and the Instanced keyword.

Here is a rough list of the work we’ve discovered that needs to be done in order to make the EditInlineNew and Instanced keyword function correctly. The list is roughly ranked from easiest to most difficult:

  • FPropertyValueImpl::ImportText will do a shallow copy of a UObject resulting in ‘instanced’ objects being shared - they will not render as shared*
  • FPropertyNode::PropagatePropertyChange will do a shallow comparison of a UObject that is instanced, it also calls UProperty::ImportText directly which shallow copies UObject*s.*
  • UEngine::CopyPropertiesForUnrelatedObjects handling of instanced, editinlineonly references is inconsistent. This effects reinstancing flows
  • FObjectInstancingGraph::GetInstancedSubobject will often think it does not need to instance Instanced, EditinlineNew subobjects
  • UArrayProperty/USetProperty/UMapProperty::SerializeItem do not provide default values to its inner Serialize call, breaking delta serialization for objects nested in arrays
  • FComponentPropertyWriter does not do deep comparison of nested objects
  • FComponentPropertyReader has no way to map subobjects that have been recreated in the new instance
  • UActorComponent::DetermineUCSModifiedProperties does not do a deep comparison of nested objects
  • FActorComponentInstanceData does not properly instance subobjects
  • The blueprint compilation manager does not detect archetypes that are dependent on other archetypes - it may need to do so in order to get archetype reinstancing order correct.
  • The details panel does not deterministically name subobjects and so looking up their archetype via name is unreliable The details panel either needs to name them deterministically (very hard in the case of dynamic containers), or archetype data needs to be stored at archetype edit time (boot time, blueprint load time, blueprint compile time, etc), or the details panel needs to allow users to name subobjects - giving users control over archetype. Design must account for data that is based on an archetype but not currently loaded.
  • There are also serious performance problems when instancing subobjects that are deeply nested and are also based on a deeply nested subobject.

Unfortunately, we can’t confirm that this list is exhaustive. We welcome feedback on what the community thinks should happen here. We try to be very responsive to pull requests in this area, but the shortcomings are somewhat systemic.

Also, to clarify how UMG and the Actor/Component system work around this is they both redirect the property editor to special template instances and handle the edit time creation of new widgets/components themselves (see SCSEditor.cpp). Then at runtime instead of relying on vanilla NewObject they use StaticDuplicateObject as their baseline implementation (with optimized paths to handle common cases). Understanding those systems offers one way of implementing your own object based DSL.