Commit Graph

22 Commits

Author SHA1 Message Date
Julien StJean
0ebac3a7ff Changed the TypedElementInterface to use UInterfaces instead of an object base api.
#jira UETOOL-4054
#preflight 6132413c1a52e20001dce90d
#rb Jamie.Dale

[CL 17424653 by Julien StJean in ue5-main branch]
2021-09-03 14:17:38 -04:00
Jamie Dale
dd96f734b2 Converted UTypedElementList to no longer be a UObject
Storing typed elements in UObjects can easily lead to reference leaks if the elements aren't cleared prior to the UObject being left pending GC. This actually made UTypedElementList tricky to use, as you had to remember to manually empty it when you'd finished with it to avoid reference leaks, and we've had several cases now where that was done incorrectly.

To address this issue, we've moved element lists back to being a normal C++ class, FTypedElementList. However, unlike the original version of FTypedElementList (which was itself a UStruct), this version is always heap-allocated and referenced via a TSharedPtr/TSharedRef.

This gives us a nice middle-ground of a well defined lifetime (ie, no lingering references prior to GC) while still being efficient to pass around, including for scripting APIs via FTypedElementListProxy (which just wraps the TSharedPtr in a UStruct).

The downside of this approach is that we need to wrap the FTypedElementList functions that we want to expose to the scripting API (see UTypedElementListLibrary), however that is a far more reasonable burden than requring every user of the typed element framework to know and understand that UTypedElementList had to be manually cleared to avoid potentially hard to find reference leaks (especially if via leaked via scripting APIs).

The core of this change is to TypedElementList.h/.cpp, with TypedElementListFwd.h existing to forward declare the pointer types, and TypedElementListProxy.h and TypedElementListLibrary.h existing to declare the proxy type and wrapped functions used for scripting APIs. TypedElementSelectionInterface.h (and its implementations) provide an example of using FTypedElementListProxy within a scripting API, and the rest of the change is mostly just fallout to transform const UTypedElementList* to FTypedElementListConstRef and UTypedElementList* to FTypedElementListRef.

#rb Brooke.Hubert
#preflight 60d2720c634cd100016c804b

[CL 16776547 by Jamie Dale in ue5-main branch]
2021-06-24 14:29:38 -04:00
Jamie Dale
2c21b4c695 Provided an interface to query element parent<->child hierarchy information and used it to unify selection normalization
Previously we relied on element implementations to know what their parent or child elements might be, and to deal with them correctly in the following cases:
 1) When "normalising" a selection to be safe for operations like a move or delete, eg) removing elements that are children of other selected elements.
 2) When deleting an element, also ensuring that any implicitly destroyed child elements were deselected, eg) deleting an ISM component that has selected static mesh instances.

This approach hurts the modularity of the elements themselves, as it requires that the element implementations have intrinsic knowledge of any other child (or parent) element types that may exist, and to deal with them accordingly when needed. As a concrete example, an ISM component may have child elements in the form of static mesh instance elements, however the generic component element type does not (and should not) directly know that static mesh instance elements exist.

To address this issue, we've added a new interface, UTypedElementHierarchyInterface, which can be used to provide information about the logical parent<->child hierarchy information of elements. This is implemented as follows for our current element types:
 - Actor:
   - GetParentElement returns an invalid element handle.
   - GetChildElements returns the element handles of any components on the actor.
 - Component:
   - GetParentElement returns its owner actor element handle.
   - GetChildElements returns nothing by default, but UActorComponent::GetComponentChildElements may be overridden to control this behavior.
     - eg) UInstancedStaticMeshComponent overrides it to return its static mesh instance element handles.
 - SMInstance:
   - GetParentElement returns its owner ISM component element handle.
   - GetChildElements returns nothing.

Now the problems listed above can be solved by using this interface instead of relying on the element implementations:
 1) Selection normalization is now handled by UTypedElementSelectionSet, replacing the previous duplicate implementations of UTypedElementCommonActions and UTypedElementViewportInteraction.
 2) UTypedElementSelectionSet will now walk and also update the selection state of child elements, when asked to via the FTypedElementSelectionOptions.

Breaking Changes:
 - UTypedElementCommonActions::GetElementsForAction and UTypedElementViewportInteraction::GetSelectedElementsToMove have been removed, in favor of using the selection normalization functions of UTypedElementSelectionSet.
   - Note: You may still favor using FLevelEditorViewportClient::GetElementsToManipulate, as it will have removed normalized elements that also cannot be moved by a gizmo.
 - UTypedElementCommonActions::DeleteElements and UTypedElementCommonActions::DuplicateElements have been removed, as these functions operated on an unnormalized selection and could be unsafe. UTypedElementCommonActions::DeleteNormalizedElements and UTypedElementCommonActions::DuplicateNormalizedElements should be used instead.
 - AGroupActor::ForEachActorInGroup and AGroupActor::ForEachMovableActorInGroup now take a second AGroupActor* argument in their callback.

#rb Brooke.Hubert
#preflight 60ca33a678c3b00001e8f5df

[CL 16705229 by Jamie Dale in ue5-main branch]
2021-06-17 11:19:23 -04:00
Jamie Dale
2b4fd7e927 Ensure GizmoManipulationStarted and GizmoManipulationStopped are called in pairs
The editor viewport would previously skip the GizmoManipulationStopped call if nothing had actually moved, but this causes an imbalance in the APIs which call NotifyMovementStarted and NotifyMovementEnded.

GizmoManipulationStopped is now always called, but with an extra argument saying if anything actually moved.

#rb Brooke.Hubert
#preflight 60aeb2de1db8a70001cbe077

[CL 16537833 by Jamie Dale in ue5-main branch]
2021-06-02 15:11:28 -04:00
Jamie Dale
1e8124423f Removed redundant element selection helpers
#fyi Brooke.Hubert
#preflight 609ebf6ccbf9a4000127a842
#rnx

[CL 16333920 by Jamie Dale in ue5-main branch]
2021-05-14 15:47:41 -04:00
Andrew Davidson
3ddc3a4da3 Merge up from //UE5/Dev-LargeWorldCoordinates
#rb none

[CL 16211417 by Andrew Davidson in ue5-main branch]
2021-05-05 15:07:25 -04:00
Jamie Dale
00c1da79ba Removed selection annotations
These existed as an optimization for USelection to quickly know if an object was selected, without having to test its array. UTypedElementList has that optimization embedded, so at this point the selection annotations are just extra state to keep in-sync, and failure to do so has already lead to bugs.

This change removes them in the simplest way possible, by using a function pointer to callback into editor code from core/engine code (as core/engine cannot directly access the global selection state), though longer-term we probably want to remove IsSelected/IsSelectedInEditor from UObject and let specific systems provide that functionality if they need it (eg, AActor/UActorComponent could provide it by getting the selection set from the owner world, rather than the global state).

#rb Brooke.Hubert
#preflight 607de942e7a5ac0001a6b7d6

[CL 16075785 by Jamie Dale in ue5-main branch]
2021-04-21 12:38:24 -04:00
jamie dale
ef31a91045 Removed finalizer from FTypedElementViewportInteractionCustomization::GetElementsToMove
This was to optimize selecting groups, but we've handled this case elsewhere by just skipping the group logic if the group is already in the list of things that we've processed. This applies that approach to getting the elements to move.

#rb Brooke.Hubert

#ROBOMERGE-SOURCE: CL 15890607 in //UE5/Release-5.0-EarlyAccess/...
#ROBOMERGE-BOT: STARSHIP (Release-5.0-EarlyAccess -> Main) (v786-15839533)

[CL 15890762 by jamie dale in ue5-main branch]
2021-04-01 12:41:54 -04:00
brooke hubert
04c41e993f Components which are not moveable should not allow viewport interactions with gizmos.
#Jira UE-109811
#preflight 60591b7cb558c40001f80f4c
#rb jamie.dale

#ROBOMERGE-SOURCE: CL 15775510 in //UE5/Release-5.0-EarlyAccess/...
#ROBOMERGE-BOT: STARSHIP (Release-5.0-EarlyAccess -> Main) (v783-15756269)

[CL 15785982 by brooke hubert in ue5-main branch]
2021-03-23 17:59:02 -04:00
jamie dale
bdb2748f10 Implemented common "Duplicate" operation using typed elements
- Moved the logic for managing the offset when pasting/duplicating out of the internal Paste/DuplicateActors implementation, and instead pass the desired offset into the duplicate functions.
 - Made the function for getting the list of elements to operate on for a common action more generic, and added helper functions to delete and duplicate the current selection set.
 - Added a CanDuplicateElements function to UTypedElementWorldInterface.
 - Implemented duplication offset for static mesh instances.

#rb Brooke.Hubert

#ROBOMERGE-SOURCE: CL 15750144 in //UE5/Release-5.0-EarlyAccess/...
#ROBOMERGE-BOT: STARSHIP (Release-5.0-EarlyAccess -> Main) (v781-15675533)

[CL 15753927 by jamie dale in ue5-main branch]
2021-03-20 04:30:12 -04:00
jamie dale
c922ceb04e Optimized GetElementsToMove for large group actors
Each group actor is now only enumerated once at the end, rather than once for each selected actor within a group

#jira UE-108343
#rb Brooke.Hubert

#ROBOMERGE-SOURCE: CL 15475127 in //UE5/Release-5.0-EarlyAccess/...
#ROBOMERGE-BOT: STARSHIP (Release-5.0-EarlyAccess -> Main) (v771-15082668)

[CL 15475131 by jamie dale in ue5-main branch]
2021-02-19 15:51:43 -04:00
Jamie Dale
38a52472be Added support for deleting typed elements from a world
#rb Brooke.Hubert

[CL 15265153 by Jamie Dale in ue5-main branch]
2021-01-31 11:46:45 -04:00
Jamie Dale
228c42a04d Updated the level editor pivot to use typed elements
#rb Brooke.Hubert

[CL 15265102 by Jamie Dale in ue5-main branch]
2021-01-31 10:58:38 -04:00
Jamie Dale
3e06018cf5 Renamed TypedElementInterfaces to TypedElementRuntime and moved UTypedElementSelectionSet to it
This lets UTypedElementSelectionSet (which has minimal dependencies) to be used by the Engine and InteractiveToolsFramework modules

#rb Brooke.Hubert

[CL 15219316 by Jamie Dale in ue5-main branch]
2021-01-27 14:25:08 -04:00
Jamie Dale
ca08dfb897 Removed GLevelEditorModeTools use from typed element interface implementations
#rb Brooke.Hubert
#rnx

[CL 14828542 by Jamie Dale in ue5-main branch]
2020-12-01 12:05:35 -04:00
Jamie Dale
2c17ac1408 Cleaned-up internal element data access
This avoids interfaces needing to know the direct structure of the element data, in case it were to change in the future. It also provides utils for accessing data from arrays of element handles.

#rb none
#rnx

[CL 14818377 by Jamie Dale in ue5-main branch]
2020-11-28 14:16:25 -04:00
Jamie Dale
cf9fcc3e71 Implemented initial support for element based viewport interaction
There are two parts to this:
 - UTypedElementWorldInterface, which provides the lower-level access to things like element transforms.
 - UTypedElementViewportInteraction, which provides the higher-level access for things like gizmo manipulation.
   - The default implementation is implemented purely in terms of get/set transform via UTypedElementWorldInterface.
   - The level editor overrides this to continue to go through the current code path for gizmo manipulation.

#rb Brooke.Hubert

[CL 14813510 by Jamie Dale in ue5-main branch]
2020-11-25 14:31:59 -04:00
Jamie Dale
6dc9d4f940 Formalized the process for creating higher-level element interfaces that can be customized by specific asset editors
This takes the framework used for UTypedElementSelectionSet and moves to it a utility base class that other higher-level interfaces can also make use of.

This also changes the interface implementations for these systems to be non-UObject types, as the script exposure is handled by the owner object, and this can solve some cyclic parsing issues with UHT (eg, between UnrealEd and LevelEditor).

#rb Chris.Gagnon, Brooke.Hubert
#rnx

[CL 14704895 by Jamie Dale in ue5-main branch]
2020-11-10 14:12:52 -04:00
Jamie Dale
ff7d47fbf4 Made typed element includes more consistent
- Moved all the "framework" code under "Elements/Framework".
 - Moved all the "interface" code under "Elements/Interfaces".

This lets the code be split over multiple modules (including the Engine and Editor) while retaining consistent include paths with things like "Elements/Actor", "Elements/Component", etc, as well as letting new interfaces and frameworky things be added outside of the core typed element modules while still maintaining a coherent include scheme.

#fyi Brooke.Hubert
#rb Chris.Gagnon

[CL 14585700 by Jamie Dale in ue5-main branch]
2020-10-27 07:00:04 -04:00
Jamie Dale
e3ac0f1b0f Updated USelection to be a legacy shim around a UTypedElementSelectionSet
This change removes the original UObject-array based USelection implementation that was still being used for generic UObject selection, in favor of always using a UTypedElementSelectionSet to back the USelection.

 - Added an "Object" element type, so that generic objects can be stored in a UTypedElementSelectionSet.
 - Added UEngineElementsLibrary to manage the creation and destruction of "Object" elements, as CoreUObject cannot directly use the TypedElementFramework.
   - Also migrated "Actor" and "Component" element creation and destruction to UEngineElementsLibrary for consistency.
 - Fixed a race condition in the AcquireEditorXElementHandle functions due to the TTypedElementOwnerStore lock being released between the find and the add (see TTypedElementOwnerStore::FindOrRegisterElementOwner).
 - Moved the GetObject function onto a new UTypedElementObjectInterface, as that function will likely be needed by legacy code outside of selection.
 - Removed UTypedElementSelectionSet::GetMutableElementList in favor of selectively exposing certain functions from the underlying UTypedElementList, which should avoid potential abuse or misuse of the underlying list.

#rb Brooke.Hubert
#rnx

[CL 14535062 by Jamie Dale in ue5-main branch]
2020-10-21 12:09:05 -04:00
Jamie Dale
1c6685f78d Added missing null check when walking parent component tree
#jira UE-101022
#rb none
#rnx

[CL 14481516 by Jamie Dale in ue5-main branch]
2020-10-13 13:31:53 -04:00
Jamie Dale
64b075c319 First phase of converting Level Editor viewport selection to use typed elements
This phase focuses on the minimum set of changes needed to port the UnrealEd logic for handling the selection of actors and components within the Level Editor viewport to use typed element interfaces. There is still future work to be done to clean this up further.

This change adds a new framework type, UTypedElementSelectionSet, which manages the concept of "selection" for typed elements. Internally this owns its own UTypedElementList, and ensures that mutation of that list goes via the UTypedElementSelectionInterface implementations.

To allow specific asset editors to customize their selection behavior, UTypedElementSelectionSet may have "selection proxies" that implement UTypedElementAssetEditorSelectionProxy registered to it. This is what's used to allow the level editor to implement its type specific rules.

The core Level Editor selection implementation for actors and components now lives inside UActorElementLevelEditorSelectionProxy and UComponentElementLevelEditorSelectionProxy, and the existing UUnrealEdEngine functions that used to deal with this logic now proxy through to those implementations via UTypedElementSelectionSet. This means that the implementation has moved into the LevelEditor module without UnrealEd even knowing.

Future work will focus on:
 - Cleaning up the legacy USelection bridge, so that all USelection instances are just a proxy around a UTypedElementSelectionSet.
   - This will involve making a basic "Object" element type to handle the generic UObject based selection (for assets) that USelection also handles.
   - This should allow GetMutableElementList to be removed from UTypedElementSelectionSet, to avoid potential abuse or misuse.
 - Investigating the best way to integrate element based selection into the editor modes.

#rb Chris.Gagnon, Brooke.Hubert
#rnx

[CL 14470181 by Jamie Dale in ue5-main branch]
2020-10-11 12:40:44 -04:00