vault backup: 2024-10-12 17:19:45
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
# HasDedicatedAsyncNode
|
||||
|
||||
- **使用位置:** UCLASS
|
||||
- **元数据类型:** bool
|
||||
- **关联项:** [ExposedAsyncProxy](../ExposedAsyncProxy/ExposedAsyncProxy.md)
|
||||
|
||||
隐藏UBlueprintAsyncActionBase子类里工厂方法自动生成的蓝图异步节点,以便自己可以手动自定义创建一个相应的UK2Node_XXX。
|
||||
|
||||
```cpp
|
||||
/**
|
||||
* BlueprintCallable factory functions for classes which inherit from UBlueprintAsyncActionBase will have a special blueprint node created for it: UK2Node_AsyncAction
|
||||
* You can stop this node spawning and create a more specific one by adding the UCLASS metadata "HasDedicatedAsyncNode"
|
||||
*/
|
||||
|
||||
UCLASS(MinimalAPI)
|
||||
class UBlueprintAsyncActionBase : public UObject
|
||||
{}
|
||||
```
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
UCLASS(Blueprintable, BlueprintType,meta = (ExposedAsyncProxy = MyAsyncObject,HasDedicatedAsyncNode))
|
||||
class INSIDER_API UMyFunction_Async :public UCancellableAsyncAction
|
||||
{}
|
||||
|
||||
//可以自定义一个K2Node
|
||||
UCLASS()
|
||||
class INSIDER_API UK2Node_MyFunctionAsyncAction : public UK2Node_AsyncAction
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
// UK2Node interface
|
||||
virtual void GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const override;
|
||||
virtual void AllocateDefaultPins() override;
|
||||
// End of UK2Node interface
|
||||
|
||||
protected:
|
||||
virtual bool HandleDelegates(
|
||||
const TArray<FBaseAsyncTaskHelper::FOutputPinAndLocalVariable>& VariableOutputs, UEdGraphPin* ProxyObjectPin,
|
||||
UEdGraphPin*& InOutLastThenPin, UEdGraph* SourceGraph, FKismetCompilerContext& CompilerContext) override;
|
||||
};
|
||||
|
||||
void UK2Node_MyFunctionAsyncAction::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
|
||||
{
|
||||
struct GetMenuActions_Utils
|
||||
{
|
||||
static void SetNodeFunc(UEdGraphNode* NewNode, bool /*bIsTemplateNode*/, TWeakObjectPtr<UFunction> FunctionPtr)
|
||||
{
|
||||
UK2Node_MyFunctionAsyncAction* AsyncTaskNode = CastChecked<UK2Node_MyFunctionAsyncAction>(NewNode);
|
||||
if (FunctionPtr.IsValid())
|
||||
{
|
||||
UFunction* Func = FunctionPtr.Get();
|
||||
FObjectProperty* ReturnProp = CastFieldChecked<FObjectProperty>(Func->GetReturnProperty());
|
||||
|
||||
AsyncTaskNode->ProxyFactoryFunctionName = Func->GetFName();
|
||||
AsyncTaskNode->ProxyFactoryClass = Func->GetOuterUClass();
|
||||
AsyncTaskNode->ProxyClass = ReturnProp->PropertyClass;
|
||||
AsyncTaskNode->NodeComment = TEXT("This is MyCustomK2Node");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
UClass* NodeClass = GetClass();
|
||||
ActionRegistrar.RegisterClassFactoryActions<UMyFunction_Async>(FBlueprintActionDatabaseRegistrar::FMakeFuncSpawnerDelegate::CreateLambda([NodeClass](const UFunction* FactoryFunc)->UBlueprintNodeSpawner*
|
||||
{
|
||||
UBlueprintNodeSpawner* NodeSpawner = UBlueprintFunctionNodeSpawner::Create(FactoryFunc);
|
||||
check(NodeSpawner != nullptr);
|
||||
NodeSpawner->NodeClass = NodeClass;
|
||||
|
||||
TWeakObjectPtr<UFunction> FunctionPtr = MakeWeakObjectPtr(const_cast<UFunction*>(FactoryFunc));
|
||||
NodeSpawner->CustomizeNodeDelegate = UBlueprintNodeSpawner::FCustomizeNodeDelegate::CreateStatic(GetMenuActions_Utils::SetNodeFunc, FunctionPtr);
|
||||
|
||||
return NodeSpawner;
|
||||
}));
|
||||
}
|
||||
|
||||
void UK2Node_MyFunctionAsyncAction::AllocateDefaultPins()
|
||||
{
|
||||
Super::AllocateDefaultPins();
|
||||
}
|
||||
|
||||
bool UK2Node_MyFunctionAsyncAction::HandleDelegates(const TArray<FBaseAsyncTaskHelper::FOutputPinAndLocalVariable>& VariableOutputs, UEdGraphPin* ProxyObjectPin, UEdGraphPin*& InOutLastThenPin, UEdGraph* SourceGraph, FKismetCompilerContext& CompilerContext)
|
||||
{
|
||||
bool bIsErrorFree = true;
|
||||
|
||||
for (TFieldIterator<FMulticastDelegateProperty> PropertyIt(ProxyClass); PropertyIt && bIsErrorFree; ++PropertyIt)
|
||||
{
|
||||
UEdGraphPin* LastActivatedThenPin = nullptr;
|
||||
bIsErrorFree &= FBaseAsyncTaskHelper::HandleDelegateImplementation(*PropertyIt, VariableOutputs, ProxyObjectPin, InOutLastThenPin, LastActivatedThenPin, this, SourceGraph, CompilerContext);
|
||||
}
|
||||
|
||||
return bIsErrorFree;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 蓝图效果:
|
||||
|
||||
左侧是引擎自带的UK2Node_AsyncAction生成节点,右边是自定义的UK2Node_MyFunctionAsyncAction生成的蓝图节点,虽然功能一致,但是右边额外加了个注释以便区分。有了这个基础,你也可以在其中继续重载方法进一步自定义。
|
||||
|
||||

|
||||
|
||||
## 当前在源码里有两处地方使用:
|
||||
|
||||
```cpp
|
||||
UCLASS(BlueprintType, meta = (ExposedAsyncProxy = "AsyncTask", HasDedicatedAsyncNode))
|
||||
class GAMEPLAYMESSAGES_API UAsyncAction_RegisterGameplayMessageReceiver : public UBlueprintAsyncActionBase
|
||||
{
|
||||
UFUNCTION(BlueprintCallable, Category = Messaging, meta=(WorldContext="WorldContextObject", BlueprintInternalUseOnly="true"))
|
||||
static UAsyncAction_RegisterGameplayMessageReceiver* RegisterGameplayMessageReceiver(UObject* WorldContextObject, FEventMessageTag Channel, UScriptStruct* PayloadType, EGameplayMessageMatchType MatchType = EGameplayMessageMatchType::ExactMatch, AActor* ActorContext = nullptr);
|
||||
|
||||
}
|
||||
//由UK2Node_GameplayMessageAsyncAction来负责创建
|
||||
void UK2Node_GameplayMessageAsyncAction::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
|
||||
{
|
||||
//...
|
||||
UClass* NodeClass = GetClass();
|
||||
ActionRegistrar.RegisterClassFactoryActions<UAsyncAction_RegisterGameplayMessageReceiver>(FBlueprintActionDatabaseRegistrar::FMakeFuncSpawnerDelegate::CreateLambda([NodeClass](const UFunction* FactoryFunc)->UBlueprintNodeSpawner*
|
||||
{
|
||||
UBlueprintNodeSpawner* NodeSpawner = UBlueprintFunctionNodeSpawner::Create(FactoryFunc);
|
||||
check(NodeSpawner != nullptr);
|
||||
NodeSpawner->NodeClass = NodeClass;
|
||||
|
||||
TWeakObjectPtr<UFunction> FunctionPtr = MakeWeakObjectPtr(const_cast<UFunction*>(FactoryFunc));
|
||||
NodeSpawner->CustomizeNodeDelegate = UBlueprintNodeSpawner::FCustomizeNodeDelegate::CreateStatic(GetMenuActions_Utils::SetNodeFunc, FunctionPtr);
|
||||
|
||||
return NodeSpawner;
|
||||
}) );
|
||||
}
|
||||
|
||||
UCLASS(BlueprintType, meta=(ExposedAsyncProxy = "AsyncTask", HasDedicatedAsyncNode))
|
||||
class UMovieSceneAsyncAction_SequencePrediction : public UBlueprintAsyncActionBase
|
||||
{
|
||||
UFUNCTION(BlueprintCallable, Category=Cinematics)
|
||||
static UMovieSceneAsyncAction_SequencePrediction* PredictWorldTransformAtTime(UMovieSceneSequencePlayer* Player, USceneComponent* TargetComponent, float TimeInSeconds);
|
||||
}
|
||||
```
|
||||
|
||||
## 生成的蓝图:
|
||||
|
||||
UAsyncAction_RegisterGameplayMessageReceiver由自定义的UK2Node_GameplayMessageAsyncAction来创建蓝图节点,从而提供了一个泛型的Payload输出引脚。而UMovieSceneAsyncAction_SequencePrediction 里的工厂方法PredictWorldTransformAtTime,由于隐藏了自动生成的版本,又没有加上BlueprintInternalUseOnly来抑制UHT生成的版本,因此最终呈现的是普通版本的静态函数蓝图节点。
|
||||
|
||||

|
||||
|
||||
## 源码里的作用机制:
|
||||
|
||||
可以看到,如果在类上有找到HasDedicatedAsyncNode,直接就返回nullptr,不再生成NodeSpawner,因此就阻止了蓝图节点的生成。
|
||||
|
||||
```cpp
|
||||
void UK2Node_AsyncAction::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
|
||||
{
|
||||
ActionRegistrar.RegisterClassFactoryActions<UBlueprintAsyncActionBase>(FBlueprintActionDatabaseRegistrar::FMakeFuncSpawnerDelegate::CreateLambda([NodeClass](const UFunction* FactoryFunc)->UBlueprintNodeSpawner*
|
||||
{
|
||||
UClass* FactoryClass = FactoryFunc ? FactoryFunc->GetOwnerClass() : nullptr;
|
||||
if (FactoryClass && FactoryClass->HasMetaData(TEXT("HasDedicatedAsyncNode")))
|
||||
{
|
||||
// Wants to use a more specific blueprint node to handle the async action
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UBlueprintNodeSpawner* NodeSpawner = UBlueprintFunctionNodeSpawner::Create(FactoryFunc);
|
||||
check(NodeSpawner != nullptr);
|
||||
NodeSpawner->NodeClass = NodeClass;
|
||||
|
||||
TWeakObjectPtr<UFunction> FunctionPtr = MakeWeakObjectPtr(const_cast<UFunction*>(FactoryFunc));
|
||||
NodeSpawner->CustomizeNodeDelegate = UBlueprintNodeSpawner::FCustomizeNodeDelegate::CreateStatic(GetMenuActions_Utils::SetNodeFunc, FunctionPtr);
|
||||
|
||||
return NodeSpawner;
|
||||
}) );
|
||||
}
|
||||
```
|
Binary file not shown.
After Width: | Height: | Size: 74 KiB |
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
Reference in New Issue
Block a user