Files
integration/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h

212 lines
6.8 KiB
C++

#pragma once
#include "CoreMinimal.h"
#include "WingServer.h"
#include "WingTypes.h"
#include "WingHandler.h"
#include "WingFetcher.h"
#include "WingUtils.h"
#include "Engine/Blueprint.h"
#include "Animation/AnimBlueprint.h"
#include "Animation/Skeleton.h"
#include "WingActorComponent.h"
#include "WingFunctionArgs.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "AnimationGraph.h"
#include "AnimationGraphSchema.h"
#include "AnimationStateMachineSchema.h"
#include "Blueprint_Dump.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS()
class UWing_Blueprint_Dump : public UObject, public IWingHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="Blueprint path"))
FString Blueprint;
virtual FString GetDescription() const override
{
return TEXT("Dump a Blueprint's structure: variables, interfaces, components, "
"and graph names. Does not include graph contents (use Graph_Dump for that).");
}
virtual void Handle() override
{
WingFetcher F;
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
if (!BP) return;
// Header
UWingServer::Printf(TEXT("Blueprint: %s\n"), *WingUtils::FormatName(BP));
UWingServer::Printf(TEXT("Parent: %s\n"), BP->ParentClass ? *WingUtils::FormatName(BP->ParentClass) : TEXT("None"));
UWingServer::Printf(TEXT("Type: %s\n"), *WingUtils::EnumToString(BP->BlueprintType));
// Animation Blueprint
if (UAnimBlueprint* AnimBP = Cast<UAnimBlueprint>(BP))
{
if (AnimBP->TargetSkeleton)
UWingServer::Printf(TEXT("TargetSkeleton: %s\n"), *AnimBP->TargetSkeleton->GetPathName());
}
// Interfaces
for (const FBPInterfaceDescription& I : BP->ImplementedInterfaces)
{
if (I.Interface) UWingServer::Printf(TEXT("Interface: %s\n"), *WingUtils::FormatName(I));
}
// Variables
if (!BP->NewVariables.IsEmpty())
{
UWingServer::Print(TEXT("\nVariables:\n"));
for (const FBPVariableDescription& V : BP->NewVariables)
{
UWingServer::Printf(TEXT(" %s %s"),
*UWingTypes::TypeToText(V.VarType),
*WingUtils::FormatName(V));
if (!V.DefaultValue.IsEmpty())
UWingServer::Printf(TEXT(" = %s"), *V.DefaultValue);
if (!V.Category.IsEmpty() && V.Category.ToString() != TEXT("Default"))
UWingServer::Printf(TEXT(" [%s]"), *V.Category.ToString());
UWingServer::Print(TEXT("\n"));
}
}
// Components
TArray<FWingActorComponent> Components = FWingActorComponent::GetAll(BP);
if (!Components.IsEmpty())
{
UWingServer::Print(TEXT("\nComponents:\n"));
for (const FWingActorComponent& Comp : Components)
{
UWingServer::Printf(TEXT(" %s %s"), *Comp.GetClassName(), *Comp.GetName());
FString ParentName = Comp.GetParentName();
if (!ParentName.IsEmpty())
UWingServer::Printf(TEXT(" [parent: %s]"), *ParentName);
if (!Comp.IsOwnedBy(BP))
UWingServer::Print(TEXT(" [inherited]"));
UWingServer::Print(TEXT("\n"));
}
}
// Event Dispatchers
if (!BP->DelegateSignatureGraphs.IsEmpty())
{
UWingServer::Print(TEXT("\nEvent Dispatchers:\n"));
for (UEdGraph* Graph : BP->DelegateSignatureGraphs)
PrintEventDispatcher(Graph);
}
// Graphs
TSet<UEdGraph*> Printed;
UWingServer::Print(TEXT("\nGraphs:\n"));
for (UEdGraph* Graph : BP->UbergraphPages)
{
UWingServer::Printf(TEXT(" EventGraph %s\n"), *WingUtils::FormatName(Graph));
Printed.Add(Graph);
}
for (UEdGraph* Graph : BP->FunctionGraphs)
{
if (Graph->IsA<UAnimationGraph>()) continue;
PrintGraph(Graph, TEXT("Function"));
Printed.Add(Graph);
}
for (UEdGraph* Graph : BP->MacroGraphs)
{
PrintGraph(Graph, TEXT("Macro"));
Printed.Add(Graph);
}
for (const FBPInterfaceDescription& I : BP->ImplementedInterfaces)
for (UEdGraph* Graph : I.Graphs)
{
PrintGraph(Graph, TEXT("Interface"), I.Interface);
Printed.Add(Graph);
}
// Delegate signature graphs are not real graphs, but mark them as printed.
for (UEdGraph* Graph : BP->DelegateSignatureGraphs)
Printed.Add(Graph);
// Animation graphs and state machines.
TArray<UEdGraph*> AllGraphs = WingUtils::AllGraphs(BP);
FString AnimGraphNames;
for (UEdGraph* Graph : AllGraphs)
{
if (Printed.Contains(Graph)) continue;
if (!Graph->Schema || !Graph->Schema->IsChildOf(UAnimationGraphSchema::StaticClass())) continue;
if (!AnimGraphNames.IsEmpty()) AnimGraphNames += TEXT(", ");
AnimGraphNames += WingUtils::FormatName(Graph);
Printed.Add(Graph);
}
if (!AnimGraphNames.IsEmpty())
UWingServer::Printf(TEXT("\nAnimation Graphs: %s\n"), *AnimGraphNames);
FString StateMachineNames;
for (UEdGraph* Graph : AllGraphs)
{
if (Printed.Contains(Graph)) continue;
if (!Graph->Schema || !Graph->Schema->IsChildOf(UAnimationStateMachineSchema::StaticClass())) continue;
if (!StateMachineNames.IsEmpty()) StateMachineNames += TEXT(", ");
StateMachineNames += WingUtils::FormatName(Graph);
Printed.Add(Graph);
}
if (!StateMachineNames.IsEmpty())
UWingServer::Printf(TEXT("\nAnimation State Machines: %s\n"), *StateMachineNames);
// Catch any graphs we missed.
for (UEdGraph* Graph : AllGraphs)
{
if (Printed.Contains(Graph)) continue;
UWingServer::Printf(TEXT("WARNING: unlisted graph: %s (%s)\n"),
*WingUtils::FormatName(Graph),
*WingUtils::FormatName(Graph->GetSchema()->GetClass()));
}
}
private:
void PrintEventDispatcher(UEdGraph* Graph)
{
TWeakObjectPtr<UK2Node_EditablePinBase> EntryNode;
TWeakObjectPtr<UK2Node_EditablePinBase> ResultNode;
FBlueprintEditorUtils::GetEntryAndResultNodes(Graph, EntryNode, ResultNode);
FString Args;
if (EntryNode.IsValid() && WingFunctionArgs::HasArgs(EntryNode.Get()))
Args = WingFunctionArgs::GetArgs(EntryNode.Get());
UWingServer::Printf(TEXT(" %s(%s)\n"), *WingUtils::FormatName(Graph), *Args);
}
void PrintGraph(UEdGraph* Graph, const TCHAR* Type, UClass* Interface = nullptr)
{
TWeakObjectPtr<UK2Node_EditablePinBase> EntryNode;
TWeakObjectPtr<UK2Node_EditablePinBase> ResultNode;
FBlueprintEditorUtils::GetEntryAndResultNodes(Graph, EntryNode, ResultNode);
FString InputArgs;
FString OutputArgs;
if (EntryNode.IsValid() && WingFunctionArgs::HasArgs(EntryNode.Get()))
InputArgs = WingFunctionArgs::GetArgs(EntryNode.Get());
if (ResultNode.IsValid() && WingFunctionArgs::HasArgs(ResultNode.Get()))
OutputArgs = WingFunctionArgs::GetArgs(ResultNode.Get());
UWingServer::Printf(TEXT(" %s %s"), Type, *WingUtils::FormatName(Graph));
if (!InputArgs.IsEmpty())
UWingServer::Printf(TEXT("(%s)"), *InputArgs);
if (!OutputArgs.IsEmpty())
UWingServer::Printf(TEXT(" -> (%s)"), *OutputArgs);
if (Interface)
UWingServer::Printf(TEXT(" [%s]"), *WingUtils::FormatName(Interface));
UWingServer::Print(TEXT("\n"));
}
};