You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
ControlRig / RigVM: Offer user workflows per unit / node
#rb sara.schvartzman jack.cai #jira UE-144670 #preflight https://horde.devtools.epicgames.com/job/624c14e1e434babd8a41478d [CL 19622287 by Helge Mathee in ue5-main branch]
This commit is contained in:
@@ -221,6 +221,15 @@ float FRigVMStruct::GetRatioFromIndex(int32 InIndex, int32 InCount)
|
||||
return ((float)FMath::Clamp<int32>(InIndex, 0, InCount - 1)) / ((float)(InCount - 1));
|
||||
}
|
||||
|
||||
TArray<FRigVMUserWorkflow> FRigVMStruct::GetWorkflows(ERigVMUserWorkflowType InType) const
|
||||
{
|
||||
return GetSupportedWorkflows().FilterByPredicate([InType](const FRigVMUserWorkflow& InWorkflow) -> bool
|
||||
{
|
||||
return uint32(InWorkflow.GetType()) & uint32(InType) &&
|
||||
InWorkflow.IsValid();
|
||||
});
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
|
||||
bool FRigVMStruct::ValidateStruct(UScriptStruct* InStruct, FString* OutErrorMessage)
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "RigVMCore/RigVMUserWorkflow.h"
|
||||
#include "RigVMCore/RigVMMemoryStorage.h"
|
||||
#include "RigVMModule.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool URigVMUserWorkflowOptions::RequiresDialog() const
|
||||
{
|
||||
for (TFieldIterator<FProperty> It(GetClass()); It; ++It)
|
||||
{
|
||||
if(const FProperty* Property = CastField<FProperty>(*It))
|
||||
{
|
||||
if(RequiresDialog(Property))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool URigVMUserWorkflowOptions::RequiresDialog(const FProperty* InProperty) const
|
||||
{
|
||||
if(!InProperty->HasAnyPropertyFlags(CPF_Edit))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static const FName SubjectName = TEXT("Subject");
|
||||
static const FName WorkflowName = TEXT("Workflow");
|
||||
return InProperty->GetFName() != SubjectName && InProperty->GetFName() != WorkflowName;
|
||||
}
|
||||
|
||||
void URigVMUserWorkflowOptions::Report(EMessageSeverity::Type InSeverity, const FString& InMessage) const
|
||||
{
|
||||
if (ReportDelegate.IsBound())
|
||||
{
|
||||
ReportDelegate.Execute(InSeverity, GetSubject(), InMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (InSeverity == EMessageSeverity::Error)
|
||||
{
|
||||
FScriptExceptionHandler::Get().HandleException(ELogVerbosity::Error, *InMessage, *FString());
|
||||
}
|
||||
else if (InSeverity == EMessageSeverity::Warning)
|
||||
{
|
||||
FScriptExceptionHandler::Get().HandleException(ELogVerbosity::Warning, *InMessage, *FString());
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogRigVM, Display, TEXT("%s"), *InMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TArray<FRigVMUserWorkflowAction> FRigVMUserWorkflow::GetActions(const URigVMUserWorkflowOptions* InOptions) const
|
||||
{
|
||||
TArray<FRigVMUserWorkflowAction> Actions;
|
||||
if(!IsValid() || !ValidateOptions(InOptions))
|
||||
{
|
||||
return Actions;
|
||||
}
|
||||
|
||||
if(OnGetActionsDelegate.IsBound())
|
||||
{
|
||||
Actions = OnGetActionsDelegate.Execute(InOptions);
|
||||
}
|
||||
else if(OnGetActionsDynamicDelegate.IsBound())
|
||||
{
|
||||
Actions = OnGetActionsDynamicDelegate.Execute(InOptions);
|
||||
}
|
||||
|
||||
Actions = Actions.FilterByPredicate([](const FRigVMUserWorkflowAction& Action) -> bool
|
||||
{
|
||||
return Action.IsValid();
|
||||
});
|
||||
|
||||
return Actions;
|
||||
}
|
||||
|
||||
bool FRigVMUserWorkflow::ValidateOptions(const URigVMUserWorkflowOptions* InOptions) const
|
||||
{
|
||||
UClass* ExpectedOptionsClass = GetOptionsClass();
|
||||
if(!ensure(ExpectedOptionsClass != nullptr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!ensure(ExpectedOptionsClass->IsChildOf(URigVMUserWorkflowOptions::StaticClass())))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!ensure(InOptions != nullptr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!ensure(InOptions->IsValid()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!ensure(InOptions->GetClass()->IsChildOf(ExpectedOptionsClass)))
|
||||
{
|
||||
InOptions->Reportf(
|
||||
EMessageSeverity::Error,
|
||||
TEXT("Workflow '%s' cannot execute: Options are of type '%s' - expected was type '%s'."),
|
||||
*GetTitle(),
|
||||
*InOptions->GetClass()->GetName(),
|
||||
*ExpectedOptionsClass->GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "RigVMCore/RigVMRegistry.h"
|
||||
#include "RigVMCore/RigVMExternalVariable.h"
|
||||
#include "RigVMCore/RigVMTraits.h"
|
||||
#include "RigVMCore/RigVMUserWorkflow.h"
|
||||
#include "RigVMStruct.generated.h"
|
||||
|
||||
// delegates used for variable introspection / creation
|
||||
@@ -221,6 +222,9 @@ public:
|
||||
// node creation
|
||||
FORCEINLINE virtual void OnUnitNodeCreated(FRigVMUnitNodeCreatedContext& InContext) const {}
|
||||
|
||||
// user workflow
|
||||
TArray<FRigVMUserWorkflow> GetWorkflows(ERigVMUserWorkflowType InType = ERigVMUserWorkflowType::All) const;
|
||||
|
||||
#if WITH_EDITOR
|
||||
static bool ValidateStruct(UScriptStruct* InStruct, FString* OutErrorMessage);
|
||||
static bool CheckPinType(UScriptStruct* InStruct, const FName& PinName, const FString& ExpectedType, FString* OutErrorMessage = nullptr);
|
||||
@@ -232,7 +236,27 @@ public:
|
||||
#endif
|
||||
static FString ExportToFullyQualifiedText(const FProperty* InMemberProperty, const uint8* InMemberMemoryPtr, bool bUseQuotes = true);
|
||||
static FString ExportToFullyQualifiedText(const UScriptStruct* InStruct, const uint8* InStructMemoryPtr);
|
||||
|
||||
template <
|
||||
typename T,
|
||||
typename TEnableIf<TRigVMIsBaseStructure<T>::Value>::Type * = nullptr
|
||||
>
|
||||
FORCEINLINE static FString ExportToFullyQualifiedText(const T& InStructValue)
|
||||
{
|
||||
return ExportToFullyQualifiedText(TBaseStructure<T>::Get(), (const uint8*)&InStructValue);
|
||||
}
|
||||
|
||||
template <
|
||||
typename T,
|
||||
typename TEnableIf<TModels<CRigVMUStruct, T>::Value>::Type * = nullptr
|
||||
>
|
||||
FORCEINLINE static FString ExportToFullyQualifiedText(const T& InStructValue)
|
||||
{
|
||||
return ExportToFullyQualifiedText(T::StaticStruct(), (const uint8*)&InStructValue);
|
||||
}
|
||||
|
||||
FString ExportToFullyQualifiedText(const UScriptStruct* InScriptStruct, const FName& InPropertyName, const uint8* InStructMemoryPointer = nullptr) const;
|
||||
|
||||
virtual FName GetNextAggregateName(const FName& InLastAggregatePinName) const { return FName(); }
|
||||
virtual FRigVMStructUpgradeInfo GetUpgradeInfo() const { return FRigVMStructUpgradeInfo(); }
|
||||
|
||||
@@ -276,6 +300,7 @@ protected:
|
||||
static float GetRatioFromIndex(int32 InIndex, int32 InCount);
|
||||
TMap<FName, FString> GetDefaultValues(UScriptStruct* InScriptStruct) const;
|
||||
bool ApplyUpgradeInfo(const FRigVMStructUpgradeInfo& InUpgradeInfo);
|
||||
FORCEINLINE virtual TArray<FRigVMUserWorkflow> GetSupportedWorkflows() const { return TArray<FRigVMUserWorkflow>(); }
|
||||
|
||||
friend struct FRigVMStructUpgradeInfo;
|
||||
friend class FRigVMGraphStructUpgradeInfoTest;
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Logging/TokenizedMessage.h"
|
||||
#include "RigVMCore/RigVMTraits.h"
|
||||
#include "RigVMUserWorkflow.generated.h"
|
||||
|
||||
class URigVMUserWorkflowOptions;
|
||||
|
||||
DECLARE_DELEGATE_ThreeParams(FRigVMReportDelegate, EMessageSeverity::Type, UObject*, const FString&);
|
||||
|
||||
// Types of actions within a workflow
|
||||
UENUM(BlueprintType)
|
||||
enum class ERigVMUserWorkflowActionType : uint8
|
||||
{
|
||||
Invalid = 0 UMETA(Hidden),
|
||||
SetPinDefaultValue = 1
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct RIGVM_API FRigVMUserWorkflowAction
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
FORCEINLINE FRigVMUserWorkflowAction()
|
||||
: Type(ERigVMUserWorkflowActionType::Invalid)
|
||||
, Subject()
|
||||
, Data()
|
||||
{}
|
||||
|
||||
FORCEINLINE FRigVMUserWorkflowAction(
|
||||
ERigVMUserWorkflowActionType InType,
|
||||
UObject* InSubject,
|
||||
const FString& InData)
|
||||
: Type(InType)
|
||||
, Subject(InSubject)
|
||||
, Data(InData)
|
||||
{}
|
||||
|
||||
FORCEINLINE bool IsValid() const { return Type != ERigVMUserWorkflowActionType::Invalid && Subject != nullptr; }
|
||||
FORCEINLINE ERigVMUserWorkflowActionType GetType() const { return Type; }
|
||||
FORCEINLINE UObject* GetSubject() const { return Subject; }
|
||||
FORCEINLINE const FString& GetData() const { return Data; }
|
||||
|
||||
template<typename T>
|
||||
FORCEINLINE T* GetSubject() const { return Cast<T>(Subject.Get()); }
|
||||
|
||||
protected:
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Action, meta = (AllowPrivateAccess = true))
|
||||
ERigVMUserWorkflowActionType Type;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Action, meta = (AllowPrivateAccess = true))
|
||||
TObjectPtr<UObject> Subject;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Action, meta = (AllowPrivateAccess = true))
|
||||
FString Data;
|
||||
};
|
||||
|
||||
// Types of workflows offered by a rigvm struct node
|
||||
UENUM(BlueprintType)
|
||||
enum class ERigVMUserWorkflowType : uint8
|
||||
{
|
||||
Invalid = 0 UMETA(Hidden),
|
||||
NodeContext = 0x001,
|
||||
PinContext = 0x002,
|
||||
OnPinDefaultChanged = 0x004,
|
||||
All = NodeContext | PinContext | OnPinDefaultChanged
|
||||
};
|
||||
|
||||
DECLARE_DELEGATE_RetVal_OneParam(TArray<FRigVMUserWorkflowAction>, FRigVMWorkflowGetActionsDelegate, const URigVMUserWorkflowOptions*);
|
||||
DECLARE_DYNAMIC_DELEGATE_RetVal_OneParam(TArray<FRigVMUserWorkflowAction>, FRigVMWorkflowGetActionsDynamicDelegate, const URigVMUserWorkflowOptions*, InOptions);
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct RIGVM_API FRigVMUserWorkflow
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
FORCEINLINE FRigVMUserWorkflow()
|
||||
: Title()
|
||||
, Tooltip()
|
||||
, Type(ERigVMUserWorkflowType::Invalid)
|
||||
, OnGetActionsDelegate()
|
||||
, OnGetActionsDynamicDelegate()
|
||||
, OptionsClass(nullptr)
|
||||
{}
|
||||
|
||||
FORCEINLINE FRigVMUserWorkflow(
|
||||
const FString& InTitle,
|
||||
const FString& InTooltip,
|
||||
ERigVMUserWorkflowType InType,
|
||||
FRigVMWorkflowGetActionsDelegate InGetActionsDelegate,
|
||||
UClass* InOptionsClass)
|
||||
: Title(InTitle)
|
||||
, Tooltip(InTooltip)
|
||||
, Type(InType)
|
||||
, OnGetActionsDelegate(InGetActionsDelegate)
|
||||
, OnGetActionsDynamicDelegate()
|
||||
, OptionsClass(InOptionsClass)
|
||||
{}
|
||||
|
||||
FORCEINLINE virtual ~FRigVMUserWorkflow() {}
|
||||
|
||||
FORCEINLINE bool IsValid() const
|
||||
{
|
||||
return Type != ERigVMUserWorkflowType::Invalid &&
|
||||
GetOptionsClass() != nullptr &&
|
||||
(OnGetActionsDelegate.IsBound() || OnGetActionsDynamicDelegate.IsBound());
|
||||
}
|
||||
|
||||
FORCEINLINE const FString& GetTitle() const { return Title; }
|
||||
FORCEINLINE const FString& GetTooltip() const { return Tooltip; }
|
||||
FORCEINLINE ERigVMUserWorkflowType GetType() const { return Type; }
|
||||
FORCEINLINE UClass* GetOptionsClass() const { return OptionsClass; }
|
||||
|
||||
TArray<FRigVMUserWorkflowAction> GetActions(const URigVMUserWorkflowOptions* InOptions) const;
|
||||
|
||||
protected:
|
||||
|
||||
bool ValidateOptions(const URigVMUserWorkflowOptions* InOptions) const;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Workflow, meta = (AllowPrivateAccess = true))
|
||||
FString Title;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Workflow, meta = (AllowPrivateAccess = true))
|
||||
FString Tooltip;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Workflow, meta = (AllowPrivateAccess = true))
|
||||
ERigVMUserWorkflowType Type;
|
||||
|
||||
FRigVMWorkflowGetActionsDelegate OnGetActionsDelegate;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Workflow, meta = (ScriptName = "OnGetActions", AllowPrivateAccess = true))
|
||||
FRigVMWorkflowGetActionsDynamicDelegate OnGetActionsDynamicDelegate;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Workflow, meta = (AllowPrivateAccess = true))
|
||||
TObjectPtr<UClass> OptionsClass;
|
||||
};
|
||||
|
||||
UCLASS(BlueprintType)
|
||||
class RIGVM_API URigVMUserWorkflowOptions : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
FORCEINLINE bool IsValid() const { return Subject != nullptr; }
|
||||
bool RequiresDialog() const;
|
||||
FORCEINLINE UObject* GetSubject() const { return Subject.Get(); }
|
||||
|
||||
template<typename T>
|
||||
FORCEINLINE T* GetSubject() const { return Cast<T>(Subject.Get()); }
|
||||
|
||||
FORCEINLINE UObject* GetSubjectChecked() const
|
||||
{
|
||||
UObject* Object = Subject.Get();
|
||||
check(Object);
|
||||
return Object;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
FORCEINLINE T* GetSubjectChecked() const { return CastChecked<T>(Subject.Get()); }
|
||||
|
||||
const FRigVMUserWorkflow& GetWorkflow() const { return Workflow; }
|
||||
|
||||
void Report(EMessageSeverity::Type InSeverity, const FString& InMessage) const;
|
||||
|
||||
template <typename FmtType, typename... Types>
|
||||
void Reportf(EMessageSeverity::Type InSeverity, const FmtType& Fmt, Types... Args) const
|
||||
{
|
||||
Report(InSeverity, FString::Printf(Fmt, Args...));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool RequiresDialog(const FProperty* InProperty) const;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = Options, meta = (AllowPrivateAccess = true))
|
||||
TObjectPtr<UObject> Subject;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = Options, meta = (AllowPrivateAccess = true))
|
||||
FRigVMUserWorkflow Workflow;
|
||||
|
||||
FRigVMReportDelegate ReportDelegate;
|
||||
|
||||
friend class URigVMController;
|
||||
};
|
||||
Reference in New Issue
Block a user