Files
UnrealEngine/Engine/Source/Runtime/UniversalObjectLocator/Public/IUniversalObjectLocatorModule.h
2025-05-18 13:04:45 +08:00

137 lines
5.5 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Modules/ModuleInterface.h"
#include "UniversalObjectLocatorFwd.h"
#include "UniversalObjectLocatorFragmentTypeHandle.h"
#include "UniversalObjectLocatorFragmentType.h"
#include "UniversalObjectLocatorStringParams.h"
#include "UniversalObjectLocatorInitializeResult.h"
#include "UniversalObjectLocatorFragment.h"
#include "UniversalObjectLocatorFragmentType.h"
#include "Concepts/GetTypeHashable.h"
#include "Templates/UnrealTypeTraits.h"
#include "Misc/GeneratedTypeName.h"
struct FSubObjectLocator;
namespace UE::UniversalObjectLocator
{
struct FFragmentTypeParameters
{
FFragmentTypeParameters(FName InFragmentTypeID, FText InDisplayText)
: DisplayText(InDisplayText)
, FragmentTypeID(InFragmentTypeID)
, Flags(EFragmentTypeFlags::None)
{
}
FText DisplayText;
FName FragmentTypeID;
FName PrimaryEditorType;
EFragmentTypeFlags Flags;
};
class IUniversalObjectLocatorModule
: public IModuleInterface
{
public:
/**
* Register a new fragment type that can be used to locate objects from a Universal Object Locator
*
* Fragment types must be serializable USTRUCTS, must be equality comparable, and must be GetTypeHashable.
* Additionally, the following member functions must be defined:
*
* // Initialize the fragment to point at an object within a context
* FInitializeResult Initialize(const FInitializeParams& InParams) const;
* // Resolve the fragment to the resulting object, potentially loading or unloading it
* FResolveResult Resolve(const FResolveParams& Params) const;
*
* // Convert this fragment to its string representation
* void ToString(FStringBuilderBase& OutStringBuilder) const;
* // Try and parse this fragment from its string representation
* FParseStringResult TryParseString(FStringView InString, const FParseStringParams& Params) const;
*
* // Compute a priority for this fragment based on an object and context in order to decide which fragment type should be used if multiple can address the same object
* static uint32 ComputePriority(const UObject* Object, const UObject* Context) const;
*/
template<typename PayloadStructType
UE_REQUIRES(
// Payloads must be equality-comparable (we don't use the CEqualityComparable concept here because we need to make sure the ICppStructOps are set up correctly)
(TStructOpsTypeTraits<PayloadStructType>::WithIdenticalViaEquality || TStructOpsTypeTraits<PayloadStructType>::WithIdentical) &&
// Payloads must be type-hashable
TModels_V<CGetTypeHashable, PayloadStructType>
)
>
TFragmentTypeHandle<PayloadStructType> RegisterFragmentType(FFragmentTypeParameters& FragmentTypeParameters)
{
checkf(FragmentTypeParameters.FragmentTypeID != NAME_None, TEXT("'None' is not a valid Fragment Type ID for type %s"), GetGeneratedTypeName<PayloadStructType>());
checkf(!FAsciiSet::HasAny(*FragmentTypeParameters.FragmentTypeID.ToString(), ~FUniversalObjectLocatorFragment::ValidFragmentTypeCharacters), TEXT("Fragment Type ID '%s' contains invalid characters"), *FragmentTypeParameters.FragmentTypeID.ToString());
FFragmentType NewFragmentType;
NewFragmentType.FragmentTypeID = FragmentTypeParameters.FragmentTypeID;
NewFragmentType.PrimaryEditorType = FragmentTypeParameters.PrimaryEditorType;
NewFragmentType.Flags = FragmentTypeParameters.Flags;
NewFragmentType.PayloadType = PayloadStructType::StaticStruct();
// Static bindings
NewFragmentType.StaticBindings.Priority = PayloadStructType::ComputePriority;
// Member function bindings
NewFragmentType.InstanceBindings.Resolve = [](const void* Payload, const FResolveParams& Params) -> FResolveResult
{
return static_cast<const PayloadStructType*>(Payload)->Resolve(Params);
};
NewFragmentType.InstanceBindings.Initialize = [](void* Payload, const FInitializeParams& InParams) -> FInitializeResult
{
return static_cast<PayloadStructType*>(Payload)->Initialize(InParams);
};
NewFragmentType.InstanceBindings.ToString = [](const void* Payload, FStringBuilderBase& OutStringBuilder)
{
return static_cast<const PayloadStructType*>(Payload)->ToString(OutStringBuilder);
};
NewFragmentType.InstanceBindings.TryParseString = [](void* Payload, FStringView InString, const FParseStringParams& Params) -> FParseStringResult
{
return static_cast<PayloadStructType*>(Payload)->TryParseString(InString, Params);
};
#if UE_UNIVERSALOBJECTLOCATOR_DEBUG
NewFragmentType.StaticBindings.FragmentDebugInitializer = [](void* Payload)
{
new (Payload) TFragmentPayload<PayloadStructType>;
};
#endif
return TFragmentTypeHandle<PayloadStructType>(RegisterFragmentTypeImpl(NewFragmentType));
}
template<typename ParameterType>
TParameterTypeHandle<ParameterType> RegisterParameterType()
{
return TParameterTypeHandle<ParameterType>(RegisterParameterTypeImpl(ParameterType::StaticStruct()));
}
void UnregisterParameterType(FParameterTypeHandle InHandle)
{
UnregisterParameterTypeImpl(InHandle);
}
template<typename PayloadStructType>
void UnregisterFragmentType(TFragmentTypeHandle<PayloadStructType> FragmentType)
{
UnregisterFragmentTypeImpl(FragmentType);
}
private:
virtual FFragmentTypeHandle RegisterFragmentTypeImpl(const FFragmentType& FragmentType) = 0;
virtual void UnregisterFragmentTypeImpl(FFragmentTypeHandle FragmentType) = 0;
virtual FParameterTypeHandle RegisterParameterTypeImpl(UScriptStruct* Struct) = 0;
virtual void UnregisterParameterTypeImpl(FParameterTypeHandle ParameterType) = 0;
};
} // namespace UE::UniversalObjectLocator