178 lines
4.6 KiB
C++
178 lines
4.6 KiB
C++
|
|
// Voir LPDumpFunctionCommandlet.h
|
||
|
|
|
||
|
|
#include "LPDumpFunctionCommandlet.h"
|
||
|
|
|
||
|
|
#include "AssetRegistry/AssetRegistryModule.h"
|
||
|
|
#include "EdGraph/EdGraph.h"
|
||
|
|
#include "EdGraph/EdGraphPin.h"
|
||
|
|
#include "EdGraphSchema_K2.h"
|
||
|
|
#include "Engine/Blueprint.h"
|
||
|
|
#include "K2Node_CallFunction.h"
|
||
|
|
#include "K2Node_Variable.h"
|
||
|
|
#include "UObject/UObjectGlobals.h"
|
||
|
|
|
||
|
|
DEFINE_LOG_CATEGORY_STATIC(LogLPDump, Log, All);
|
||
|
|
|
||
|
|
namespace
|
||
|
|
{
|
||
|
|
/** Ce que fait le noeud, en une ligne : appel de fonction, acces variable, ou sa classe. */
|
||
|
|
FString DescribeNode(const UEdGraphNode* Node)
|
||
|
|
{
|
||
|
|
if (const UK2Node_CallFunction* Call = Cast<UK2Node_CallFunction>(Node))
|
||
|
|
{
|
||
|
|
const UClass* Owner = Call->FunctionReference.GetMemberParentClass();
|
||
|
|
return FString::Printf(TEXT("appel %s::%s()"),
|
||
|
|
Owner ? *Owner->GetName() : TEXT("?"),
|
||
|
|
*Call->FunctionReference.GetMemberName().ToString());
|
||
|
|
}
|
||
|
|
if (const UK2Node_Variable* Var = Cast<UK2Node_Variable>(Node))
|
||
|
|
{
|
||
|
|
return FString::Printf(TEXT("variable '%s'"), *Var->VariableReference.GetMemberName().ToString());
|
||
|
|
}
|
||
|
|
return Node->GetClass()->GetName();
|
||
|
|
}
|
||
|
|
|
||
|
|
FString DescribePin(const UEdGraphPin* Pin)
|
||
|
|
{
|
||
|
|
if (Pin->LinkedTo.Num() == 0)
|
||
|
|
{
|
||
|
|
return Pin->DefaultValue.IsEmpty()
|
||
|
|
? FString(TEXT("(vide)"))
|
||
|
|
: FString::Printf(TEXT("= '%s'"), *Pin->DefaultValue);
|
||
|
|
}
|
||
|
|
|
||
|
|
TArray<FString> Ends;
|
||
|
|
for (const UEdGraphPin* L : Pin->LinkedTo)
|
||
|
|
{
|
||
|
|
Ends.Add(FString::Printf(TEXT("%s.%s"),
|
||
|
|
L->GetOwningNode() ? *L->GetOwningNode()->GetName() : TEXT("?"),
|
||
|
|
*L->PinName.ToString()));
|
||
|
|
}
|
||
|
|
return FString::Printf(TEXT("-> %s"), *FString::Join(Ends, TEXT(", ")));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
ULPDumpFunctionCommandlet::ULPDumpFunctionCommandlet()
|
||
|
|
{
|
||
|
|
IsClient = false;
|
||
|
|
IsServer = false;
|
||
|
|
IsEditor = true;
|
||
|
|
LogToConsole = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32 ULPDumpFunctionCommandlet::Main(const FString& Params)
|
||
|
|
{
|
||
|
|
TArray<FString> Tokens, Switches;
|
||
|
|
TMap<FString, FString> ParamsMap;
|
||
|
|
ParseCommandLine(*Params, Tokens, Switches, ParamsMap);
|
||
|
|
|
||
|
|
const FString WantedBP = ParamsMap.FindRef(TEXT("BP"));
|
||
|
|
const FString WantedFn = ParamsMap.FindRef(TEXT("Fn"));
|
||
|
|
const bool bShowPins = Switches.Contains(TEXT("Pins"));
|
||
|
|
|
||
|
|
if (WantedBP.IsEmpty())
|
||
|
|
{
|
||
|
|
UE_LOG(LogLPDump, Error, TEXT("Usage : -BP=<Blueprint> [-Fn=<Fonction>] [-Pins]"));
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
FAssetRegistryModule& AssetRegistryModule =
|
||
|
|
FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
|
||
|
|
AssetRegistryModule.Get().SearchAllAssets(true);
|
||
|
|
|
||
|
|
TArray<FAssetData> BlueprintAssets;
|
||
|
|
#if ENGINE_MAJOR_VERSION >= 5
|
||
|
|
AssetRegistryModule.Get().GetAssetsByClass(UBlueprint::StaticClass()->GetClassPathName(), BlueprintAssets, true);
|
||
|
|
#else
|
||
|
|
AssetRegistryModule.Get().GetAssetsByClass(UBlueprint::StaticClass()->GetFName(), BlueprintAssets, true);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
UBlueprint* Target = nullptr;
|
||
|
|
for (const FAssetData& AssetData : BlueprintAssets)
|
||
|
|
{
|
||
|
|
if (!AssetData.PackageName.ToString().StartsWith(TEXT("/Game/")))
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if (AssetData.AssetName.ToString() == WantedBP)
|
||
|
|
{
|
||
|
|
Target = Cast<UBlueprint>(AssetData.GetAsset());
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!Target)
|
||
|
|
{
|
||
|
|
UE_LOG(LogLPDump, Error, TEXT("Blueprint '%s' introuvable sous /Game."), *WantedBP);
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
TArray<UEdGraph*> Graphs;
|
||
|
|
Target->GetAllGraphs(Graphs);
|
||
|
|
|
||
|
|
// Sans -Fn : on se contente de lister les graphes disponibles.
|
||
|
|
if (WantedFn.IsEmpty())
|
||
|
|
{
|
||
|
|
UE_LOG(LogLPDump, Warning, TEXT("=== %s : %d graphe(s) ==="), *WantedBP, Graphs.Num());
|
||
|
|
for (const UEdGraph* Graph : Graphs)
|
||
|
|
{
|
||
|
|
if (Graph)
|
||
|
|
{
|
||
|
|
UE_LOG(LogLPDump, Warning, TEXT(" %s (%d noeuds)"), *Graph->GetName(), Graph->Nodes.Num());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// -Fn=* : balayage complet, pour diffuser deux versions du meme Blueprint et
|
||
|
|
// laisser un diff textuel pointer les ecarts.
|
||
|
|
const bool bAll = (WantedFn == TEXT("*"));
|
||
|
|
|
||
|
|
int32 Dumped = 0;
|
||
|
|
for (UEdGraph* Graph : Graphs)
|
||
|
|
{
|
||
|
|
if (!Graph || (!bAll && Graph->GetName() != WantedFn))
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
++Dumped;
|
||
|
|
UE_LOG(LogLPDump, Warning, TEXT("=== %s :: %s (%d noeuds) ==="),
|
||
|
|
*WantedBP, *Graph->GetName(), Graph->Nodes.Num());
|
||
|
|
|
||
|
|
for (UEdGraphNode* Node : Graph->Nodes)
|
||
|
|
{
|
||
|
|
if (!Node)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
UE_LOG(LogLPDump, Warning, TEXT(" %-34s %s"), *Node->GetName(), *DescribeNode(Node));
|
||
|
|
|
||
|
|
if (!bShowPins)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (const UEdGraphPin* Pin : Node->Pins)
|
||
|
|
{
|
||
|
|
if (!Pin || Pin->PinType.PinCategory == UEdGraphSchema_K2::PC_Exec)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
UE_LOG(LogLPDump, Warning, TEXT(" %s%-22s %s"),
|
||
|
|
Pin->bOrphanedPin ? TEXT("[X] ") : TEXT(" "),
|
||
|
|
*Pin->PinName.ToString(), *DescribePin(Pin));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (Dumped == 0)
|
||
|
|
{
|
||
|
|
UE_LOG(LogLPDump, Error, TEXT("Fonction '%s' introuvable dans %s. Relancer sans -Fn pour lister."),
|
||
|
|
*WantedFn, *WantedBP);
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|