Files
UnrealEngineUWP/Engine/Source/Runtime/UniversalObjectLocator/Public/UniversalObjectLocator.h
david bromberg 71e3da8dc8 Sequencer: Major integration of Universal Object Locators into Sequencer. This includes:
* Adding some first pass UI for editing the Universal Object Locators that are used to bind objects to tracks in Sequencer. This is currently in the form of:
   * An 'Add Empty Binding' item in the + Actor to Sequencer menu
   * A 'Binding Properties' sub-menu in the object binding track properties that allows you to modify the array of UOL's that bind objects to the track. This allows you to specifically select certain UOL types and then fill in the data that makes up that UOL. This is necessary for example for the FortAIPlayerPawn    binding we plan on adding for UEFN.
* Major refactor of MovieScene binding code to more seamlessly allow for the use of the Locator resolution, especially in the case of supporting locators that spawn actors, either in the case of editor preview actors or future runtime 'spawnables'. This was necessary to consolidate the cases where locator resolve params were being created to as few places as possible for simplicity.
* Add the concept of 'default' editor and runtime flags to locators to make it easier for Sequencer to know how to interact with bindings of different types. These flags are then stored with the binding in Sequencer and editable by users as necessary. Sequencer treats 'load'/'unload' in this case similar to 'spawn'/'despawn' and generally speaking resolving a locator with editor flags of 'load' will expect the locator to spawn an actor for preview, while resolving a locator with runtime flags of 'load' will expect the locator to create a 'spawnable' character.
* To manage lifetime of these preview/spawnable characters, created an interface for a 'LocatorSpawnedCache' which the locators interact with when creating or destroying an actor. This allows the resolver of locators to differentiate between cases where they expect multiple resolves of the same locator to create duplicate actors vs. resolve to the same actor and track the lifetimes of these spawned actors.
* Sequencer implements the above cache within its own object cache in evaluation state.
* Expand the role of the previously created Binding Lifetime track to trigger loading/unloading via locators in the cache. The Binding Lifetime track will now automatically be added to a binding if its locator type contains 'Load' as a default editor or runtime flag.
* Some other editor updates to support the above.

Future issues to be resolved:
* We want to more easily expose the editing of binding properties when necessary rather than having it buried in a sub-menu. Ideas for this include some kind of UI on the track itself, for example a combo box with binding types on it, as well as potentially the properties menu appearing on hovering over the possessable icon on the object binding track. We also want to expose properties based on selection, for example object binding properties, track properties, and section properties, in another external window.
* We want to eventually replace the 'Actor to Sequencer' and 'Assign Actor' menu with this once the UX is better.

The above was all tested with a Fortnite NPC Locator type which will be added in a separate changelist.

[REVIEW] [at]ue-sequencer
#jira UE-199299

[CL 30596833 by david bromberg in ue5-main branch]
2024-01-12 12:41:00 -05:00

266 lines
11 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreTypes.h"
#include "UniversalObjectLocatorFwd.h"
#include "UniversalObjectLocatorFragment.h"
#include "UniversalObjectLocatorResolveParams.h"
#include "UniversalObjectLocatorFragmentType.h"
#include "UniversalObjectLocator.generated.h"
/**
* Universal Object Locators (UOLs) define an address to an object.
*
* The address is implemented as a chain of FUniversalObjectLocatorFragments, allowing addressing of objects
* that may be nested deeply within levels of externally defined spawn or ownership logic.
*
* For example, a Universal Object Locator may reference an Anim Instance within a Skeletal Mesh Actor
* is spawned by a Child Actor Component that is spawned by Sequencer. This is impossible with a
* regular soft object path, but is perfectly feasible for a UOL.
*
* This type is 16 bytes.
*/
USTRUCT(BlueprintType, Category=GameFramework, meta=(HasNativeMake="/Script/Engine.UniversalObjectLocatorScriptingExtensions.MakeUniversalObjectLocator"))
struct FUniversalObjectLocator
{
GENERATED_BODY()
using FResolveParams = UE::UniversalObjectLocator::FResolveParams;
using FResolveResult = UE::UniversalObjectLocator::FResolveResult;
using FResolveResultData = UE::UniversalObjectLocator::FResolveResultData;
using FParseStringParams = UE::UniversalObjectLocator::FParseStringParams;
using FParseStringResult = UE::UniversalObjectLocator::FParseStringResult;
/**
* Default constructor
*/
UNIVERSALOBJECTLOCATOR_API FUniversalObjectLocator();
/**
* Attempt to construct this locator from a given object.
* May result in an empty locator if no suitable address could be created.
*
* @param Object The object that this locator should represent
* @param Context (Optional) Constrain this universal reference based on the specified context. This context should be passed to Resolve otherwise the resolution may fail.
* @param StopAtContext (Optional) Stop constructing this universal reference when we reach the following context (can be used if that context is always passed to Resolve to keep this type smaller)
*/
UNIVERSALOBJECTLOCATOR_API FUniversalObjectLocator(UObject* Object, UObject* Context = nullptr, UObject* StopAtContext = nullptr);
/**
* Check if this locator is 'empty'. An empty locator contains no fragments and will never resolve.
*/
bool IsEmpty() const
{
return Fragments.Num() == 0;
}
/**
* Attempt to resolve this locator by invoking the payload's 'Resolve' function
*
* @param Params Resolution parameters defining the type of resolution to perform
* @return A result structure defining the resolved object pointer, and associated flags
*/
UNIVERSALOBJECTLOCATOR_API FResolveResult Resolve(const FResolveParams& Params) const;
/**
* Attempt to find the object this locator points to.
* Shorthand for Resolve(FResolveParams::AsyncFind(Context)).AsObject().ReleaseFuture().
*
* @param Context (Optional) An optional context to use for finding the object - should match what was specified in Reset() or in construction
* @return A result structure that may or may not already have a result populated
*/
UNIVERSALOBJECTLOCATOR_API FResolveResult AsyncFind(UObject* Context = nullptr) const;
/**
* Attempt to find the object this locator points to, loading it if necessary (and possible).
* Shorthand for Resolve(FResolveParams::AsyncLoad(Context)).AsObject().ReleaseFuture().
*
* @param Context (Optional) An optional context to use for finding/loading the object - should match what was specified in Reset()
* @return A result structure that may or may not already have a result populated
*/
UNIVERSALOBJECTLOCATOR_API FResolveResult AsyncLoad(UObject* Context = nullptr) const;
/**
* Attempt to unload the object this locator points to if possible.
* Shorthand for Resolve(FResolveParams::AsyncUnload(Context)).AsVoid().ReleaseFuture().
*
* @param Context (Optional) An optional context to use for finding/loading the object - should match what was specified in Reset()
* @return A result structure that may or may not already have a result populated
*/
UNIVERSALOBJECTLOCATOR_API FResolveResult AsyncUnload(UObject* Context = nullptr) const;
/**
* Attempt to find the object this locator points to.
* Shorthand for Resolve(FResolveParams::SyncFind(Context)).AsObject().SyncGet().Object.
*
* @param Context (Optional) An optional context to use for finding the object - should match what was specified in Reset() or in construction
* @return The located object, or nullptr on failure
*/
UNIVERSALOBJECTLOCATOR_API UObject* SyncFind(UObject* Context = nullptr) const;
/**
* Attempt to find the object this locator points to, loading it if necessary (and possible), and blocking until it is loaded.
* Shorthand for Resolve(FResolveParams::SyncLoad(Context)).AsObject().SyncGet().Object.
*
* @param Context (Optional) An optional context to use for finding/loading the object - should match what was specified in Reset()
* @return The located object, or nullptr on failure
*/
UNIVERSALOBJECTLOCATOR_API UObject* SyncLoad(UObject* Context = nullptr) const;
/**
* Attempt to unload the object this locator points to if possible.
* Shorthand for Resolve(FResolveParams::SyncUnload(Context)).AsVoid().SyncGet().
*
* @param Context (Optional) An optional context to use for finding/loading the object - should match what was specified in Reset()
* @return The located object, or nullptr on failure
*/
UNIVERSALOBJECTLOCATOR_API void SyncUnload(UObject* Context = nullptr) const;
/**
* Retrieve the fragment type relating to the last locator in this address
*/
UNIVERSALOBJECTLOCATOR_API const UE::UniversalObjectLocator::FFragmentType* GetLastFragmentType() const;
/**
* Retrieve the fragment type handle relating to the last locator in this address
*/
UNIVERSALOBJECTLOCATOR_API UE::UniversalObjectLocator::FFragmentTypeHandle GetLastFragmentTypeHandle() const;
/**
* Convert this locator to its string representation
*
* @param OutString String builder to populate
*/
UNIVERSALOBJECTLOCATOR_API void ToString(FStringBuilderBase& OutString) const;
/**
* Attempt to deserialize this locator from a string
*
* @param InString The string to parse
* @param InParams Additional string parameters
* @return Parse result, specifying success or failure, and number of characters that were parsed
*/
UNIVERSALOBJECTLOCATOR_API FParseStringResult TryParseString(FStringView InString, const FParseStringParams& InParams);
/**
* Attempt to deserialize a new locator from a string.
* Shorthand for FUniversalObjectLocator L; L.TryParseString(InString, InParams);.
*
* @param InString The string to parse
* @param InParams Additional string parameters
* @return A (perhaps empty) object locator
*/
static UNIVERSALOBJECTLOCATOR_API FUniversalObjectLocator FromString(FStringView InString, const FParseStringParams& InParams);
public:
/**
* Reset this locator back to its default-constructed, empty state
*/
UNIVERSALOBJECTLOCATOR_API void Reset();
/**
* Attempt to reset this locator to point at a different object.
* May result in an empty locator if no suitable address could be created.
*
* @param Object The object that this locator should represent
* @param Context (Optional) Constrain this universal reference based on the specified context. This context should be passed to Resolve otherwise the resolution may fail.
* @param StopAtContext (Optional) Stop constructing this universal reference when we reach the following context (can be used if that context is always passed to Resolve to keep this type smaller)
*/
UNIVERSALOBJECTLOCATOR_API void Reset(UObject* Object, UObject* Context = nullptr, UObject* StopAtContext = nullptr);
/**
* Add a fragment to the end of this locator
*
* @param InFragment The fragment to add
*/
UNIVERSALOBJECTLOCATOR_API void AddFragment(FUniversalObjectLocatorFragment&& InFragment);
/**
* Templated helper for AddFragment
*
* @param InFragment The fragment to add
*/
template<typename FragmentType, typename ...ArgTypes>
void AddFragment(ArgTypes&&... FragmentArgs);
/**
* Retrieve the last fragment in this address
*/
UNIVERSALOBJECTLOCATOR_API FUniversalObjectLocatorFragment* GetLastFragment();
/**
* Retrieve the last fragment in this address
*/
UNIVERSALOBJECTLOCATOR_API const FUniversalObjectLocatorFragment* GetLastFragment() const;
/*
* Iterates over all fragments and combines their types' default editor flags.
*/
UNIVERSALOBJECTLOCATOR_API UE::UniversalObjectLocator::EFragmentTypeFlags GetDefaultEditorFlags() const;
/*
* Iterates over all fragments and combines their types' default runtime flags.
*/
UNIVERSALOBJECTLOCATOR_API UE::UniversalObjectLocator::EFragmentTypeFlags GetDefaultRuntimeFlags() const;
/**
* Equality comparison.
* @note: This tests for exact equality of its piecewise fragments. Equivalent but not equal locators will always return false.
*/
UNIVERSALOBJECTLOCATOR_API friend bool operator==(const FUniversalObjectLocator& A, const FUniversalObjectLocator& B);
/**
* Inequality comparison.
* @note: This tests for exact inequality of its piecewise fragments. Equivalent but not equal locators will always return true.
*/
UNIVERSALOBJECTLOCATOR_API friend bool operator!=(const FUniversalObjectLocator& A, const FUniversalObjectLocator& B);
/**
* Type hashable
*/
UNIVERSALOBJECTLOCATOR_API friend uint32 GetTypeHash(const FUniversalObjectLocator& Locator);
/*~ Begin TStructOpsTypeTraits implementation */
UNIVERSALOBJECTLOCATOR_API bool ExportTextItem(FString& ValueStr, const FUniversalObjectLocator& DefaultValue, UObject* Parent, int32 PortFlags, UObject* ExportRootScope) const;
UNIVERSALOBJECTLOCATOR_API bool ImportTextItem(const TCHAR*& Buffer, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText, FArchive* InSerializingArchive = nullptr);
UNIVERSALOBJECTLOCATOR_API bool SerializeFromMismatchedTag(const FPropertyTag& Tag, FStructuredArchive::FSlot Slot);
/*~ End TStructOpsTypeTraits implementation */
private:
/** */
bool AddFragment(const UObject* Object, UObject* Context, UObject* StopAtContext);
FResolveResult ResolveSyncImpl(const FResolveParams& Params) const;
FResolveResult ResolveAsyncImpl(const FResolveParams& Params) const;
private:
/** Array of relative locators ordered sequentially from outer to inner. The first locator is probably 'absolute' and is resolved with no context, although that is not a hard restriction */
UPROPERTY()
TArray<FUniversalObjectLocatorFragment> Fragments;
};
template<typename FragmentType, typename ...ArgTypes>
void FUniversalObjectLocator::AddFragment(ArgTypes&&... FragmentArgs)
{
TUniversalObjectLocatorFragment<FragmentType> NewFragment(Forward<ArgTypes>(FragmentArgs)...);
AddFragment(MoveTemp(NewFragment));
}
template<>
struct TStructOpsTypeTraits<FUniversalObjectLocator> : public TStructOpsTypeTraitsBase2<FUniversalObjectLocator>
{
enum
{
WithIdenticalViaEquality = true,
WithExportTextItem = true,
WithImportTextItem = true,
WithStructuredSerializeFromMismatchedTag = true,
};
};