More MCP work
This commit is contained in:
@@ -1,248 +1,12 @@
|
||||
#include "MCPAssetFinder.h"
|
||||
#include "Engine/Engine.h"
|
||||
#include "Engine/Blueprint.h"
|
||||
#include "Engine/World.h"
|
||||
#include "Engine/Level.h"
|
||||
#include "Engine/LevelScriptBlueprint.h"
|
||||
#include "Materials/Material.h"
|
||||
#include "Materials/MaterialInstanceConstant.h"
|
||||
#include "Materials/MaterialFunction.h"
|
||||
#include "Animation/Skeleton.h"
|
||||
#include "Animation/AnimSequence.h"
|
||||
#include "Animation/BlendSpace.h"
|
||||
#include "Animation/AnimBlueprint.h"
|
||||
#include "AnimationStateMachineGraph.h"
|
||||
#include "MCPUtils.h"
|
||||
#include "AssetRegistry/AssetRegistryModule.h"
|
||||
#include "AssetRegistry/IAssetRegistry.h"
|
||||
|
||||
const TArray<FAssetData> UMCPAssetFinder::EmptyAssetArray;
|
||||
|
||||
// ============================================================
|
||||
// Initialize / Deinitialize — subscribe to asset registry events
|
||||
// ============================================================
|
||||
|
||||
void UMCPAssetFinder::Initialize(FSubsystemCollectionBase& Collection)
|
||||
{
|
||||
Super::Initialize(Collection);
|
||||
|
||||
IAssetRegistry& AR = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry").Get();
|
||||
AR.OnAssetAdded().AddUObject(this, &UMCPAssetFinder::OnAssetEvent);
|
||||
AR.OnAssetRemoved().AddUObject(this, &UMCPAssetFinder::OnAssetEvent);
|
||||
AR.OnAssetUpdated().AddUObject(this, &UMCPAssetFinder::OnAssetEvent);
|
||||
AR.OnAssetRenamed().AddUObject(this, &UMCPAssetFinder::OnAssetRenamed);
|
||||
}
|
||||
|
||||
void UMCPAssetFinder::Deinitialize()
|
||||
{
|
||||
IAssetRegistry* AR = IAssetRegistry::Get();
|
||||
if (AR)
|
||||
{
|
||||
AR->OnAssetAdded().RemoveAll(this);
|
||||
AR->OnAssetRemoved().RemoveAll(this);
|
||||
AR->OnAssetUpdated().RemoveAll(this);
|
||||
AR->OnAssetRenamed().RemoveAll(this);
|
||||
}
|
||||
Super::Deinitialize();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Get / Refresh
|
||||
// ============================================================
|
||||
|
||||
UMCPAssetFinder* UMCPAssetFinder::Get()
|
||||
{
|
||||
UMCPAssetFinder* Self = GEngine ? GEngine->GetEngineSubsystem<UMCPAssetFinder>() : nullptr;
|
||||
checkf(Self, TEXT("MCPAssetFinder::Get() called before engine initialization"));
|
||||
return Self;
|
||||
}
|
||||
|
||||
void UMCPAssetFinder::CacheAssets(IAssetRegistry &Registry, UClass *Class, bool IncludeSubclasses)
|
||||
{
|
||||
FName Key = Class->GetFName();
|
||||
TArray<FAssetData>& List = AssetCache.Add(Key);
|
||||
Registry.GetAssetsByClass(Class->GetClassPathName(), List, IncludeSubclasses);
|
||||
}
|
||||
|
||||
void UMCPAssetFinder::Refresh()
|
||||
{
|
||||
checkf(IsInGameThread(), TEXT("MCPAssetFinder must only be accessed from the game thread"));
|
||||
UMCPAssetFinder* Self = Get();
|
||||
|
||||
IAssetRegistry& AR = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry").Get();
|
||||
|
||||
while (AR.IsLoadingAssets()) FPlatformProcess::Sleep(0.1f);
|
||||
|
||||
if (!Self->bDirty) return;
|
||||
|
||||
Self->AssetCache.Empty();
|
||||
|
||||
// Cache all asset classes.
|
||||
Self->CacheAssets(AR, UBlueprint::StaticClass(), true);
|
||||
Self->CacheAssets(AR, UWorld::StaticClass(), false);
|
||||
Self->CacheAssets(AR, UMaterial::StaticClass(), false);
|
||||
Self->CacheAssets(AR, UMaterialInstanceConstant::StaticClass(), false);
|
||||
Self->CacheAssets(AR, UMaterialFunction::StaticClass(), false);
|
||||
Self->CacheAssets(AR, UUserDefinedStruct::StaticClass(), false);
|
||||
Self->CacheAssets(AR, UUserDefinedEnum::StaticClass(), false);
|
||||
Self->CacheAssets(AR, USkeleton::StaticClass(), false);
|
||||
Self->CacheAssets(AR, UAnimSequence::StaticClass(), false);
|
||||
Self->CacheAssets(AR, UBlendSpace::StaticClass(), false);
|
||||
Self->CacheAssets(AR, UAnimBlueprint::StaticClass(), false);
|
||||
|
||||
// Combined list: blueprints + maps
|
||||
TArray<FAssetData>& Combined = Self->AssetCache.Add(BlueprintsAndMaps);
|
||||
Combined = Self->AssetCache[UBlueprint::StaticClass()->GetFName()];
|
||||
Combined.Append(Self->AssetCache[UWorld::StaticClass()->GetFName()]);
|
||||
|
||||
Self->bDirty = false;
|
||||
|
||||
UE_LOG(LogTemp, Display, TEXT("MCPAssetFinder: Refreshed — %d asset types cached"),
|
||||
Self->AssetCache.Num());
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Static asset list accessors
|
||||
// ============================================================
|
||||
|
||||
const TArray<FAssetData>& UMCPAssetFinder::GetAssets(FName Key)
|
||||
{
|
||||
TArray<FAssetData>* Found = Get()->AssetCache.Find(Key);
|
||||
return Found ? *Found : EmptyAssetArray;
|
||||
}
|
||||
|
||||
const TArray<FAssetData>& UMCPAssetFinder::GetAssets(UClass* Class)
|
||||
{
|
||||
return GetAssets(Class->GetFName());
|
||||
}
|
||||
|
||||
FName UMCPAssetFinder::BlueprintsAndMaps = FName(TEXT("BlueprintsAndMaps"));
|
||||
|
||||
// ============================================================
|
||||
// Find / Search helpers
|
||||
// ============================================================
|
||||
|
||||
FAssetData* UMCPAssetFinder::FindAsset(FName Class, const FString& NameOrPath, FString* OutError)
|
||||
{
|
||||
const TArray<FAssetData>& List = GetAssets(Class);
|
||||
bool IsPath = NameOrPath.Contains(TEXT("/"));
|
||||
|
||||
FAssetData* Found = nullptr;
|
||||
for (const FAssetData& Asset : List)
|
||||
{
|
||||
FName Name = IsPath ? Asset.PackageName : Asset.AssetName;
|
||||
if (!Name.ToString().Equals(NameOrPath, ESearchCase::IgnoreCase)) continue;
|
||||
if (!Found)
|
||||
{
|
||||
Found = const_cast<FAssetData*>(&Asset);
|
||||
continue;
|
||||
}
|
||||
if (OutError)
|
||||
{
|
||||
*OutError = FString::Printf(
|
||||
TEXT("Ambiguous asset name '%s' — matches both '%s' and '%s'. Use the full package path to disambiguate."),
|
||||
*NameOrPath, *Found->PackageName.ToString(), *Asset.PackageName.ToString());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
return Found;
|
||||
}
|
||||
|
||||
FAssetData* UMCPAssetFinder::FindAsset(UClass* Class, const FString& NameOrPath, FString* OutError)
|
||||
{
|
||||
return FindAsset(Class->GetFName(), NameOrPath, OutError);
|
||||
}
|
||||
|
||||
TArray<FAssetData*> UMCPAssetFinder::SearchAssets(FName Class, const FString& Filter, FString* OutError)
|
||||
{
|
||||
const TArray<FAssetData>& List = GetAssets(Class);
|
||||
TArray<FAssetData*> Results;
|
||||
for (const FAssetData& Asset : List)
|
||||
{
|
||||
FString AssetName = Asset.AssetName.ToString();
|
||||
FString PackagePath = Asset.PackageName.ToString();
|
||||
if (AssetName.Contains(Filter, ESearchCase::IgnoreCase) ||
|
||||
PackagePath.Contains(Filter, ESearchCase::IgnoreCase))
|
||||
{
|
||||
Results.Add(const_cast<FAssetData*>(&Asset));
|
||||
}
|
||||
}
|
||||
return Results;
|
||||
}
|
||||
|
||||
TArray<FAssetData*> UMCPAssetFinder::SearchAssets(UClass* Class, const FString& Filter, FString* OutError)
|
||||
{
|
||||
return SearchAssets(Class->GetFName(), Filter, OutError);
|
||||
}
|
||||
|
||||
FAssetData* UMCPAssetFinder::FindAnyAsset(const FString& NameOrPath, FString* OutError)
|
||||
{
|
||||
FAssetData* Found = nullptr;
|
||||
|
||||
for (auto& Pair : Get()->AssetCache)
|
||||
{
|
||||
if (Pair.Key == BlueprintsAndMaps) continue;
|
||||
|
||||
FString LocalError;
|
||||
FAssetData* Asset = FindAsset(Pair.Key, NameOrPath, &LocalError);
|
||||
if (!LocalError.IsEmpty())
|
||||
{
|
||||
if (OutError) *OutError = LocalError;
|
||||
return nullptr;
|
||||
}
|
||||
if (!Asset) continue;
|
||||
if (Found)
|
||||
{
|
||||
if (OutError)
|
||||
{
|
||||
*OutError = FString::Printf(
|
||||
TEXT("Ambiguous asset name '%s' — matches '%s' and '%s'. Use the full package path to disambiguate."),
|
||||
*NameOrPath, *Found->PackageName.ToString(), *Asset->PackageName.ToString());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
Found = Asset;
|
||||
}
|
||||
return Found;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Load helpers
|
||||
// ============================================================
|
||||
|
||||
UBlueprint* UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(FAssetData& Asset, MCPErrorCallback Error)
|
||||
{
|
||||
// Regular blueprint asset
|
||||
UBlueprint* BP = Cast<UBlueprint>(Asset.GetAsset());
|
||||
if (BP) return BP;
|
||||
|
||||
// Map asset — extract the level blueprint
|
||||
UWorld* World = Cast<UWorld>(Asset.GetAsset());
|
||||
if (World && World->PersistentLevel)
|
||||
{
|
||||
ULevelScriptBlueprint* LevelBP = World->PersistentLevel->GetLevelScriptBlueprint(true);
|
||||
if (LevelBP) return LevelBP;
|
||||
}
|
||||
|
||||
Error.SetError(FString::Printf(TEXT("Asset '%s' loaded but its level blueprint could not be retrieved."),
|
||||
*Asset.AssetName.ToString()));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UBlueprint* UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(const FString& NameOrPath, MCPErrorCallback Error)
|
||||
{
|
||||
FString FindError;
|
||||
FAssetData* Asset = FindAsset(BlueprintsAndMaps, NameOrPath, &FindError);
|
||||
if (!Asset)
|
||||
{
|
||||
if (FindError.IsEmpty())
|
||||
FindError = FString::Printf(TEXT("Blueprint '%s' not found."), *NameOrPath);
|
||||
Error.SetError(FindError);
|
||||
return nullptr;
|
||||
}
|
||||
return LoadBlueprintOrLevelBlueprint(*Asset, Error);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// MCPAssetsBase
|
||||
// ============================================================
|
||||
@@ -263,7 +27,7 @@ MCPAssetsBase& MCPAssetsBase::Exact(const FString& InName)
|
||||
MCPAssetsBase& MCPAssetsBase::Substring(const FString& InFilter)
|
||||
{
|
||||
MatchName = InFilter;
|
||||
bExactMatch = false;
|
||||
bExactMatch = false;
|
||||
bPatternHasSlash = MatchName.Contains(TEXT("/"));
|
||||
return *this;
|
||||
}
|
||||
@@ -411,20 +175,3 @@ void MCPAssetsBase::SetError(const FString &Msg)
|
||||
UObjectResults.Empty();
|
||||
ErrorCB.SetError(Msg);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Load helpers
|
||||
// ============================================================
|
||||
|
||||
UAnimationStateMachineGraph* UMCPAssetFinder::LoadAnimStateMachineGraph(
|
||||
const FString& BlueprintName, const FString& GraphName, MCPErrorCallback Error)
|
||||
{
|
||||
UAnimBlueprint* AnimBP = LoadAsset<UAnimBlueprint>(BlueprintName, Error);
|
||||
if (!AnimBP) return nullptr;
|
||||
|
||||
UAnimationStateMachineGraph* SMGraph = MCPUtils::FindStateMachineGraph(AnimBP, GraphName);
|
||||
if (!SMGraph)
|
||||
Error.SetError(FString::Printf(TEXT("State machine graph '%s' not found in '%s'"), *GraphName, *BlueprintName));
|
||||
return SMGraph;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user