Add AssetLookup module to find assets by name.
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
117
Source/Integration/AssetLookup.cpp
Normal file
117
Source/Integration/AssetLookup.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
|
||||
#include "AssetLookup.h"
|
||||
#include "AssetRegistry/IAssetRegistry.h"
|
||||
#include "AssetRegistry/AssetData.h"
|
||||
#include "AssetRegistry/AssetRegistryState.h"
|
||||
#include "LuprexGameModeBase.h"
|
||||
|
||||
void UlxAssetLookup::RebuildIndex()
|
||||
{
|
||||
CachedTangibles.Empty();
|
||||
CachedStaticMeshes.Empty();
|
||||
IAssetRegistry::GetChecked().WaitForCompletion();
|
||||
ScanTangibles();
|
||||
ScanStaticMeshes();
|
||||
}
|
||||
|
||||
void UlxAssetLookup::ScanTangibles()
|
||||
{
|
||||
TArray<FAssetData> FoundData;
|
||||
FARFilter AssetFilter;
|
||||
AssetFilter.PackagePaths.Add(FName(TEXT("/Game/Tangibles")));
|
||||
AssetFilter.ClassPaths.Add(UBlueprint::StaticClass()->GetClassPathName());
|
||||
AssetFilter.bIncludeOnlyOnDiskAssets = true;
|
||||
AssetFilter.bRecursivePaths = true;
|
||||
IAssetRegistry::GetChecked().GetAssets(AssetFilter, FoundData);
|
||||
|
||||
UE_LOG(LogLuprexIntegration, Display, TEXT("Found %d assets in /Game/Tangibles"), FoundData.Num());
|
||||
for (const FAssetData &Data : FoundData)
|
||||
{
|
||||
FString Path = Data.GetObjectPathString();
|
||||
CachedTangibles.Add(Data.AssetName, Path);
|
||||
}
|
||||
}
|
||||
|
||||
void UlxAssetLookup::ScanStaticMeshes()
|
||||
{
|
||||
TArray<FAssetData> FoundData;
|
||||
FARFilter AssetFilter;
|
||||
AssetFilter.PackagePaths.Add(FName(TEXT("/Game/StarterContent/Shapes")));
|
||||
AssetFilter.PackagePaths.Add(FName(TEXT("/Game/StaticMeshes")));
|
||||
AssetFilter.ClassPaths.Add(UStaticMesh::StaticClass()->GetClassPathName());
|
||||
AssetFilter.bIncludeOnlyOnDiskAssets = true;
|
||||
AssetFilter.bRecursivePaths = true;
|
||||
IAssetRegistry::GetChecked().GetAssets(AssetFilter, FoundData);
|
||||
|
||||
UE_LOG(LogLuprexIntegration, Display, TEXT("Found %d static mesh assets"), FoundData.Num());
|
||||
for (const FAssetData &Data : FoundData)
|
||||
{
|
||||
FString Path = Data.GetObjectPathString();
|
||||
CachedStaticMeshes.Add(Data.AssetName, Path);
|
||||
}
|
||||
}
|
||||
|
||||
FString UlxAssetLookup::TangibleLoadPath(const FName &AssetName) const
|
||||
{
|
||||
FScopeLock lock(&Mutex);
|
||||
|
||||
const FString *Result = CachedTangibles.Find(AssetName);
|
||||
if (Result == nullptr) return TEXT("");
|
||||
return *Result;
|
||||
}
|
||||
|
||||
FString UlxAssetLookup::StaticMeshLoadPath(const FName &AssetName) const
|
||||
{
|
||||
FScopeLock lock(&Mutex);
|
||||
|
||||
const FString *Result = CachedStaticMeshes.Find(AssetName);
|
||||
if (Result == nullptr) return TEXT("");
|
||||
return *Result;
|
||||
}
|
||||
|
||||
UStaticMesh *UlxAssetLookup::GetStaticMeshByName(const UObject *Context, const FString &Name)
|
||||
{
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(Context);
|
||||
FString Path = mode->GetAssetLookup()->StaticMeshLoadPath(FName(Name));
|
||||
if (Path.IsEmpty())
|
||||
{
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Static mesh not on search path: %s"), *Name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FString FullPath = Path;
|
||||
UStaticMesh *Result = LoadObject<UStaticMesh>(nullptr, *FullPath);
|
||||
if (Result == nullptr) {
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Cannot load static mesh: %s"), *FullPath);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
UClass *UlxAssetLookup::GetTangibleClassByName(const UObject *Context, const FString &Name) {
|
||||
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(Context);
|
||||
FString Path = mode->GetAssetLookup()->TangibleLoadPath(FName(FString("Tan") + Name));
|
||||
if (Path.IsEmpty())
|
||||
{
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Tangible not on search path: %s"), *Name);
|
||||
return nullptr;
|
||||
}
|
||||
FString FullPath = Path + TEXT("_C");
|
||||
UClass *Result = LoadObject<UClass>(nullptr, *FullPath);
|
||||
if (Result == nullptr) {
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Cannot load tangible class: %s"), *FullPath);
|
||||
return nullptr;
|
||||
}
|
||||
if (!Result->IsChildOf(AActor::StaticClass())) {
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Tangible class is not an actor: %s"), *FullPath);
|
||||
return nullptr;
|
||||
}
|
||||
UFunction *aqchanged = Result->FindFunctionByName(FName(TEXT("Animation Queue Changed")));
|
||||
if ((aqchanged == nullptr)||(aqchanged->ParmsSize != 0))
|
||||
{
|
||||
UE_LOG(LogLuprexIntegration, Error, TEXT("Tangible does not have 'Animation Queue Changed' function: %s"), *FullPath);
|
||||
return nullptr;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
43
Source/Integration/AssetLookup.h
Normal file
43
Source/Integration/AssetLookup.h
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/NoExportTypes.h"
|
||||
#include "CommonTypes.h"
|
||||
#include "AssetLookup.generated.h"
|
||||
|
||||
UCLASS(MinimalAPI)
|
||||
class UlxAssetLookup : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
private:
|
||||
mutable FCriticalSection Mutex;
|
||||
|
||||
// Map from asset name to full loadable path.
|
||||
UPROPERTY()
|
||||
TMap<FName, FString> CachedTangibles;
|
||||
|
||||
// Map from asset name to to full loadable path.
|
||||
UPROPERTY()
|
||||
TMap<FName, FString> CachedStaticMeshes;
|
||||
|
||||
public:
|
||||
void RebuildIndex();
|
||||
void ScanTangibles();
|
||||
void ScanStaticMeshes();
|
||||
|
||||
// Get the full path name of a
|
||||
FString TangibleLoadPath(const FName &AssetName) const;
|
||||
|
||||
// Get a static mesh by its asset name.
|
||||
FString StaticMeshLoadPath(const FName &AssetName) const;
|
||||
|
||||
// Get a static mesh by name
|
||||
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"), Category = "Luprex|Miscellaneous")
|
||||
static UStaticMesh *GetStaticMeshByName(const UObject *Context, const FString &Name);
|
||||
|
||||
// Get a static mesh by name
|
||||
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"), Category = "Luprex|Miscellaneous")
|
||||
static UClass *GetTangibleClassByName(const UObject *Context, const FString &Name);
|
||||
};
|
||||
52
Source/Integration/DebugPrint.h
Normal file
52
Source/Integration/DebugPrint.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ConsoleOutput
|
||||
//
|
||||
// This class stores the text that's in the unreal console.
|
||||
// It stores it as one great big string, which contains
|
||||
// newlines to denote line breaks.
|
||||
//
|
||||
// This class also contains a 'dirty' bit. Each time somebody
|
||||
// appends a line of text to the console, the dirty bit is
|
||||
// automatically set. The bit can be checked using 'IsDirty'
|
||||
// and cleared using 'ClearDirty'. This makes it so that
|
||||
// you don't have to update the unreal widget unless the
|
||||
// text has actually changed.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
class FlxConsoleOutput {
|
||||
private:
|
||||
FString Content;
|
||||
bool Dirty;
|
||||
|
||||
// Truncate the console to a reasonable number of
|
||||
// lines. The length is hardwired.
|
||||
void Truncate();
|
||||
|
||||
// Add a newline if there isn't one. Returns true if it changed anything.
|
||||
bool MaybeAppendNewline();
|
||||
|
||||
// Append text. Returns true if it changed anything.
|
||||
bool MaybeAppendText(const FString& text);
|
||||
|
||||
public:
|
||||
// Append a line of text to the console.
|
||||
void Append(const FString& text);
|
||||
|
||||
// Append a line of text to the console on a line by itself.
|
||||
void AppendLine(const FString& text);
|
||||
|
||||
// Get the console text as a string.
|
||||
const FString& Get() const { return Content; }
|
||||
|
||||
// Return if the dirty flag is set.
|
||||
bool IsDirty() const { return Dirty; }
|
||||
|
||||
// Clear the dirty flag.
|
||||
void ClearDirty() { Dirty = false; }
|
||||
};
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@ DEFINE_LOG_CATEGORY(LogLuprexIntegration);
|
||||
|
||||
ALuprexGameModeBase::ALuprexGameModeBase()
|
||||
{
|
||||
TangibleManager = NewObject<UlxTangibleManager>();
|
||||
TangibleManager = nullptr;
|
||||
AssetLookup = nullptr;
|
||||
PlayerId = 0;
|
||||
EngineSeconds = 0.0;
|
||||
//PrimaryActorTick.bCanEverTick = true; // Probably wrong
|
||||
@@ -58,6 +59,11 @@ void ALuprexGameModeBase::ResetToInitialState()
|
||||
TangibleManager = nullptr;
|
||||
}
|
||||
|
||||
if (AssetLookup != nullptr) {
|
||||
AssetLookup->ConditionalBeginDestroy();
|
||||
AssetLookup = nullptr;
|
||||
}
|
||||
|
||||
// Shut down the thread
|
||||
LuprexUpdateTask.Shutdown();
|
||||
|
||||
@@ -301,9 +307,13 @@ void ALuprexGameModeBase::InitializeGlobalState()
|
||||
LuprexUpdateTask.Startup(this);
|
||||
}
|
||||
|
||||
// Initialize the asset lookup table.
|
||||
AssetLookup = NewObject<UlxAssetLookup>(this);
|
||||
AssetLookup->RebuildIndex();
|
||||
|
||||
// Initialize the tangible manager.
|
||||
TangibleManager = NewObject<UlxTangibleManager>();
|
||||
TangibleManager->Init(GetWorld(), this);
|
||||
TangibleManager = NewObject<UlxTangibleManager>(this);
|
||||
TangibleManager->Init(this);
|
||||
|
||||
// If somebody generates a log message that's severe enough, break to debugger.
|
||||
BreakToDebuggerLogVerbosityDevice.Reset(
|
||||
@@ -319,7 +329,7 @@ int64 ALuprexGameModeBase::GetPlayerId() {
|
||||
return PlayerId;
|
||||
}
|
||||
|
||||
ALuprexGameModeBase *ALuprexGameModeBase::FromContext(UObject *context) {
|
||||
ALuprexGameModeBase *ALuprexGameModeBase::FromContext(const UObject *context) {
|
||||
ALuprexGameModeBase *result = context->GetWorld()->GetAuthGameMode<ALuprexGameModeBase>();
|
||||
if (result == nullptr) {
|
||||
UE_LOG(LogBlueprint, Fatal, TEXT("Not currently using a Luprex Game Mode."));
|
||||
|
||||
@@ -8,16 +8,17 @@
|
||||
#include "ConsoleOutput.h"
|
||||
#include "StringDecoder.h"
|
||||
#include "TangibleManager.h"
|
||||
#include "AssetLookup.h"
|
||||
#include "LuprexSockets.h"
|
||||
#include "TriggeredTask.h"
|
||||
#include "BlueprintErrors.h"
|
||||
#include "LuprexGameModeBase.generated.h"
|
||||
|
||||
// Messages that come from inside the Luprex Core.
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogLuprex, Warning, All);
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogLuprex, Display, All);
|
||||
|
||||
// Messages that pertain to our Luprex integration with Unreal.
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogLuprexIntegration, Warning, All);
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogLuprexIntegration, Display, All);
|
||||
|
||||
class LookAtDetector;
|
||||
|
||||
@@ -100,6 +101,9 @@ public:
|
||||
// Execute a debugging command, typed on the GUI.
|
||||
void ExecuteDebuggingCommand(FlxLockedWrapper &w, const FString &fs);
|
||||
|
||||
// Get the Asset Lookup table.
|
||||
const UlxAssetLookup *GetAssetLookup() const { return AssetLookup; }
|
||||
|
||||
// Transfer console output from the Luprex engine to unreal.
|
||||
void UpdateConsoleOutput();
|
||||
|
||||
@@ -124,8 +128,11 @@ public:
|
||||
virtual uint32 Run() override;
|
||||
|
||||
// Get the current Luprex Game Mode Base, given a context object.
|
||||
static ALuprexGameModeBase *FromContext(UObject *context);
|
||||
static ALuprexGameModeBase *FromContext(const UObject *context);
|
||||
|
||||
// Asset Lookup by Name.
|
||||
UPROPERTY()
|
||||
UlxAssetLookup *AssetLookup;
|
||||
|
||||
UPROPERTY()
|
||||
UlxTangibleManager *TangibleManager;
|
||||
|
||||
@@ -33,10 +33,10 @@ void UlxTangible::SetActorBlueprint(const FString &XName) {
|
||||
}
|
||||
|
||||
// Get the blueprint.
|
||||
UClass *blueprint = Manager->GetTangibleClass(Name);
|
||||
UClass *blueprint = UlxAssetLookup::GetTangibleClassByName(this, Name);
|
||||
if (blueprint == nullptr)
|
||||
{
|
||||
blueprint = Manager->GetTangibleClass(DEFAULT_BLUEPRINT);
|
||||
blueprint = UlxAssetLookup::GetTangibleClassByName(this, DEFAULT_BLUEPRINT);
|
||||
check(blueprint != nullptr);
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ void UlxTangible::MaybeExecuteAnimStateChanged() {
|
||||
if (blueprint.IsEmpty()) blueprint = DEFAULT_BLUEPRINT;
|
||||
SetActorBlueprint(blueprint);
|
||||
AActor *actor = GetActor();
|
||||
UFunction *aqchanged = UlxTangibleManager::GetAnimationQueueChanged(actor->GetClass());
|
||||
UFunction *aqchanged = actor->GetClass()->FindFunctionByName(FName(TEXT("Animation Queue Changed")));
|
||||
if (aqchanged != nullptr) {
|
||||
actor->ProcessEvent(aqchanged, nullptr);
|
||||
}
|
||||
|
||||
@@ -4,56 +4,15 @@
|
||||
#include "TangibleManager.h"
|
||||
#include "Tangible.h"
|
||||
#include "LuprexGameModeBase.h"
|
||||
#include "AssetRegistry/AssetRegistryModule.h"
|
||||
#include "AssetRegistry/ARFilter.h"
|
||||
|
||||
UFunction *UlxTangibleManager::GetAnimationQueueChanged(UClass *uclass) {
|
||||
UFunction *result = uclass->FindFunctionByName(FName(TEXT("Animation Queue Changed")));
|
||||
if (result == nullptr) return nullptr;
|
||||
if (result->ParmsSize != 0) return nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
UClass *UlxTangibleManager::GetTangibleClass(const FString &name) {
|
||||
UPackage *Pack = LoadObject<UPackage>(nullptr, TEXT("/Game/Tangibles"));
|
||||
UE_LOG(LogBlueprint, Verbose, TEXT("Pack=%ld"), int64(Pack));
|
||||
if (name.IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (name == TEXT("unknown")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FString path(TEXT("/Game/Tangibles/"));
|
||||
path += TEXT("Tan");
|
||||
path += name;
|
||||
path += TCHAR('.');
|
||||
path += TEXT("Tan");
|
||||
path += name;
|
||||
path += TCHAR('_');
|
||||
path += TCHAR('C');
|
||||
UClass *result = LoadObject<UClass>(nullptr, *path);
|
||||
if (result == nullptr) {
|
||||
UE_LOG(LogBlueprint, Error, TEXT("No such UClass: %s"), *path);
|
||||
return nullptr;
|
||||
}
|
||||
if (!result->IsChildOf(AActor::StaticClass())) {
|
||||
UE_LOG(LogBlueprint, Error, TEXT("UClass is not an actor: %s"), *path);
|
||||
return nullptr;
|
||||
}
|
||||
UFunction *aqchanged = GetAnimationQueueChanged(result);
|
||||
if (aqchanged == nullptr) {
|
||||
UE_LOG(LogBlueprint, Error, TEXT("UClass does not have 'Animation Queue Changed' function: %s"), *path);
|
||||
return nullptr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
UlxTangibleManager::UlxTangibleManager() {
|
||||
World = nullptr;
|
||||
PossessedTangible = nullptr;
|
||||
}
|
||||
|
||||
void UlxTangibleManager::Init(UWorld* world, ALuprexGameModeBase *gamemode) {
|
||||
World = world;
|
||||
void UlxTangibleManager::Init(ALuprexGameModeBase *gamemode) {
|
||||
GameMode = gamemode;
|
||||
}
|
||||
|
||||
@@ -71,7 +30,7 @@ UlxTangible* UlxTangibleManager::MakeTangible(int64 id) {
|
||||
check(id > 0);
|
||||
UlxTangible*& t = IdToTangible.FindOrAdd(id);
|
||||
if (t == nullptr) {
|
||||
t = NewObject<UlxTangible>();
|
||||
t = NewObject<UlxTangible>(this);
|
||||
t->Init(this, id);
|
||||
}
|
||||
return t;
|
||||
|
||||
@@ -21,10 +21,6 @@ public:
|
||||
using IdArray = CommonTypes::IdArray;
|
||||
using TanArray = TArray<UlxTangible*>;
|
||||
|
||||
// A pointer to our world.
|
||||
UPROPERTY()
|
||||
TWeakObjectPtr<UWorld> World;
|
||||
|
||||
// A pointer to our game mode.
|
||||
UPROPERTY()
|
||||
TWeakObjectPtr<ALuprexGameModeBase> GameMode;
|
||||
@@ -41,11 +37,7 @@ public:
|
||||
|
||||
// Initialize the tangible manager.
|
||||
//
|
||||
void Init(UWorld *world, ALuprexGameModeBase *gamemode);
|
||||
|
||||
// Get a pointer to our world.
|
||||
//
|
||||
UWorld* GetWorld() const override { return World.Get(); }
|
||||
void Init(ALuprexGameModeBase *gamemode);
|
||||
|
||||
// Get a pointer to our game mode.
|
||||
ALuprexGameModeBase *GetGameMode() { return GameMode.Get(); }
|
||||
@@ -97,13 +89,5 @@ public:
|
||||
// Given an array of tangibles, return an array of tangible Ids.
|
||||
//
|
||||
static IdArray GetIds(const TanArray &tans);
|
||||
|
||||
// Convert a blueprint name to a blueprint class.
|
||||
//
|
||||
UClass *GetTangibleClass(const FString &name);
|
||||
|
||||
// Get the Animation Queue Changed function from a UClass.
|
||||
//
|
||||
static UFunction *GetAnimationQueueChanged(UClass *uclass);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user