Working on Asset_Create
This commit is contained in:
BIN
Content/Testing/BP1.uasset
LFS
BIN
Content/Testing/BP1.uasset
LFS
Binary file not shown.
BIN
Content/Testing/BP_T1.uasset
LFS
Normal file
BIN
Content/Testing/BP_T1.uasset
LFS
Normal file
Binary file not shown.
BIN
Content/Testing/BP_Test1.uasset
LFS
BIN
Content/Testing/BP_Test1.uasset
LFS
Binary file not shown.
39
Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Create.h
Normal file
39
Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Create.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "WingServer.h"
|
||||||
|
#include "WingHandler.h"
|
||||||
|
#include "WingFactories.h"
|
||||||
|
#include "Asset_Create.generated.h"
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
UCLASS()
|
||||||
|
class UWing_Asset_Create : public UObject, public IWingHandler
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(meta=(Description="Full asset path for the new asset (e.g. '/Game/MyFolder/MyAsset')"))
|
||||||
|
FString AssetPath;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Description="Factory type name from Asset_SearchTypes (e.g. 'Material', 'Blueprint')"))
|
||||||
|
FString Factory;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Optional, Description="Factory configuration properties as key-value pairs"))
|
||||||
|
FWingJsonObject Config;
|
||||||
|
|
||||||
|
virtual FString GetDescription() const override
|
||||||
|
{
|
||||||
|
return TEXT("Create a new asset using a factory. Use Asset_SearchTypes to find "
|
||||||
|
"available factory types and their configurable properties.");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Handle() override
|
||||||
|
{
|
||||||
|
UWingFactories::CreateAsset(AssetPath, Factory, Config);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "WingServer.h"
|
||||||
|
#include "WingHandler.h"
|
||||||
|
#include "WingFactories.h"
|
||||||
|
#include "Asset_SearchTypes.generated.h"
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
UCLASS()
|
||||||
|
class UWing_Asset_SearchTypes : public UObject, public IWingHandler
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(meta=(Description="Query string, can contain *"))
|
||||||
|
FString Query;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Optional, Description="Maximum number of results (default 50)"))
|
||||||
|
int32 MaxResults = 50;
|
||||||
|
|
||||||
|
virtual FString GetDescription() const override
|
||||||
|
{
|
||||||
|
return TEXT("Search for asset factory types that can be used with Asset_Create. "
|
||||||
|
"Returns factory names and their configurable properties.");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Handle() override
|
||||||
|
{
|
||||||
|
FString ExtQuery = TEXT("*") + Query + TEXT("*");
|
||||||
|
const TArray<UWingFactories::Info>& All = UWingFactories::AllFactories();
|
||||||
|
|
||||||
|
int32 Count = 0;
|
||||||
|
for (const UWingFactories::Info& Entry : All)
|
||||||
|
{
|
||||||
|
if (Count >= MaxResults) break;
|
||||||
|
if (!Entry.CanCreateNew()) continue;
|
||||||
|
if (!Entry.Name.MatchesWildcard(ExtQuery, ESearchCase::IgnoreCase)) continue;
|
||||||
|
|
||||||
|
UWingServer::Printf(TEXT("%s\n"), *Entry.Name);
|
||||||
|
|
||||||
|
for (const FName& Prop : Entry.Config)
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT(" %s\n"), *Prop.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
Count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Count == 0)
|
||||||
|
{
|
||||||
|
UWingServer::Print(TEXT("No matching factory types found.\n"));
|
||||||
|
}
|
||||||
|
else if (Count >= MaxResults)
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("WARNING: Reached limit of %d results. You may specify MaxResults.\n"), MaxResults);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -75,7 +75,7 @@ public:
|
|||||||
UBlueprint* NewBP = FKismetEditorUtilities::CreateBlueprint(
|
UBlueprint* NewBP = FKismetEditorUtilities::CreateBlueprint(
|
||||||
ParentClassObj,
|
ParentClassObj,
|
||||||
Maker.Package(),
|
Maker.Package(),
|
||||||
FName(*Maker.Name()),
|
Maker.GetFName(),
|
||||||
BlueprintType,
|
BlueprintType,
|
||||||
UBlueprint::StaticClass(),
|
UBlueprint::StaticClass(),
|
||||||
UBlueprintGeneratedClass::StaticClass()
|
UBlueprintGeneratedClass::StaticClass()
|
||||||
|
|||||||
181
Plugins/UEWingman/Source/UEWingman/Private/WingFactories.cpp
Normal file
181
Plugins/UEWingman/Source/UEWingman/Private/WingFactories.cpp
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
#include "WingFactories.h"
|
||||||
|
#include "WingServer.h"
|
||||||
|
#include "Editor.h"
|
||||||
|
#include "WingUtils.h"
|
||||||
|
#include "WingProperty.h"
|
||||||
|
#include "WingPackageMaker.h"
|
||||||
|
#include "Kismet2/KismetEditorUtilities.h"
|
||||||
|
#include "Kismet2/EnumEditorUtils.h"
|
||||||
|
#include "Factories/BlueprintFactory.h"
|
||||||
|
#include "Factories/EnumFactory.h"
|
||||||
|
#include "Algo/BinarySearch.h"
|
||||||
|
|
||||||
|
void UWingFactories::Initialize(FSubsystemCollectionBase& Collection)
|
||||||
|
{
|
||||||
|
Super::Initialize(Collection);
|
||||||
|
PopulateRegistry();
|
||||||
|
}
|
||||||
|
|
||||||
|
const TArray<UWingFactories::Info>& UWingFactories::AllFactories()
|
||||||
|
{
|
||||||
|
return GEditor->GetEditorSubsystem<UWingFactories>()->Registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UWingFactories::Info::CanCreateNew() const
|
||||||
|
{
|
||||||
|
return FactoryClass->GetDefaultObject<UFactory>()->CanCreateNew();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UWingFactories::PopulateRegistry()
|
||||||
|
{
|
||||||
|
TArray<UClass*> FactoryClasses;
|
||||||
|
GetDerivedClasses(UFactory::StaticClass(), FactoryClasses);
|
||||||
|
|
||||||
|
// Populate it with initial data.
|
||||||
|
for (UClass* Class : FactoryClasses)
|
||||||
|
{
|
||||||
|
if (Class->HasAnyClassFlags(CLASS_Abstract)) continue;
|
||||||
|
|
||||||
|
Info Entry;
|
||||||
|
Entry.Name = DeriveFactoryName(Class);
|
||||||
|
Entry.FactoryClass = Class;
|
||||||
|
Entry.Config = FWingProperty::GetNames(Class, CPF_Edit);
|
||||||
|
Registry.Add(MoveTemp(Entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort the registry.
|
||||||
|
Registry.Sort([](const Info& A, const Info& B) { return A.Name < B.Name; });
|
||||||
|
|
||||||
|
// Blacklist certain bad factories.
|
||||||
|
DisableFactory(TEXT("PhysicsAsset")); // PhysicsAsset factory pops a modal dialog
|
||||||
|
}
|
||||||
|
|
||||||
|
void UWingFactories::DisableFactory(const TCHAR* Name)
|
||||||
|
{
|
||||||
|
Info* Entry = Find(Name);
|
||||||
|
if (!Entry)
|
||||||
|
{
|
||||||
|
UE_LOG(LogTemp, Fatal, TEXT("UWingFactories::DisableFactory: factory '%s' not found"), Name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Entry->Disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
UObject* UWingFactories::CreateAsset(const FString& Path, const FString& FactoryName, FWingJsonObject& Config)
|
||||||
|
{
|
||||||
|
UWingFactories* Self = GEditor->GetEditorSubsystem<UWingFactories>();
|
||||||
|
|
||||||
|
// Look up the factory info.
|
||||||
|
const Info* FactoryInfo = Self->Find(FactoryName);
|
||||||
|
if (!FactoryInfo)
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: Unknown factory '%s'\n"), *FactoryName);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure this is the a creation factory, as opposed to an import factory.
|
||||||
|
if (!FactoryInfo->CanCreateNew())
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: Factory '%s' cannot create objects from scratch\n"), *FactoryName);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the path, and that there's not already something there.
|
||||||
|
WingPackageMaker Maker(Path);
|
||||||
|
if (!Maker.Ok()) return nullptr;
|
||||||
|
FName Name = Maker.GetFName();
|
||||||
|
|
||||||
|
// Create the factory instance.
|
||||||
|
UFactory* Factory = NewObject<UFactory>(GetTransientPackage(), FactoryInfo->FactoryClass);
|
||||||
|
|
||||||
|
// Get the editable properties
|
||||||
|
TArray<FWingProperty> Props =
|
||||||
|
FWingProperty::GetNamed(Factory->GetClass(), Factory, FactoryInfo->Config);
|
||||||
|
|
||||||
|
// if there is no config table, make a blank config table.
|
||||||
|
TSharedPtr<FJsonObject> ConfigJson = Config.Json;
|
||||||
|
if (ConfigJson == nullptr) ConfigJson = MakeShared<FJsonObject>();
|
||||||
|
|
||||||
|
// Populate the configuration properties from the json.
|
||||||
|
if (!FWingProperty::PopulateFromJson(Props, ConfigJson.Get(), false))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Pre-check: block factories that would cause problems.
|
||||||
|
// In particular, this blocks those that would pop a dialog.
|
||||||
|
if (!PreCheck(Factory, Name, Path)) return nullptr;
|
||||||
|
|
||||||
|
// Create the asset.
|
||||||
|
if (!Maker.Make()) return nullptr;
|
||||||
|
UObject* NewAsset = Factory->FactoryCreateNew(
|
||||||
|
FactoryInfo->FactoryClass->GetDefaultObject<UFactory>()->GetSupportedClass(),
|
||||||
|
Maker.Package(),
|
||||||
|
Name,
|
||||||
|
RF_Public | RF_Standalone | RF_Transactional,
|
||||||
|
nullptr,
|
||||||
|
GWarn
|
||||||
|
);
|
||||||
|
if (!NewAsset)
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: Factory '%s' returned null\n"), *FactoryName);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UWingServer::Printf(TEXT("Created: %s\n"), *WingUtils::ExternalizeID(Name));
|
||||||
|
return NewAsset;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UWingFactories::PreCheck(UFactory* Factory, FName Name, const FString &Path)
|
||||||
|
{
|
||||||
|
// Blueprint factories: FactoryCreateNew pops FMessageDialog if ParentClass is invalid.
|
||||||
|
if (UBlueprintFactory* BPFactory = Cast<UBlueprintFactory>(Factory))
|
||||||
|
{
|
||||||
|
if (!BPFactory->ParentClass)
|
||||||
|
{
|
||||||
|
UWingServer::Print(TEXT("ERROR: ParentClass must be set\n"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!FKismetEditorUtilities::CanCreateBlueprintOfClass(BPFactory->ParentClass))
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: Cannot create a blueprint based on class '%s'\n"), *BPFactory->ParentClass->GetName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enum factory: FactoryCreateNew pops FMessageDialog if the name already exists.
|
||||||
|
if (UEnumFactory* EFactory = Cast<UEnumFactory>(Factory))
|
||||||
|
{
|
||||||
|
if(!FEnumEditorUtils::IsNameAvailebleForUserDefinedEnum(Name))
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("Enum name is already taken: %s"),
|
||||||
|
*WingUtils::ExternalizeID(Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
UWingFactories::Info* UWingFactories::Find(const FString& Name)
|
||||||
|
{
|
||||||
|
int32 Index = Algo::LowerBound(Registry, Name, [](Info& Entry, const FString& N) {
|
||||||
|
return Entry.Name < N;
|
||||||
|
});
|
||||||
|
if (Index < Registry.Num() && Registry[Index].Name == Name)
|
||||||
|
{
|
||||||
|
return &Registry[Index];
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
FString UWingFactories::DeriveFactoryName(UClass* FactoryClass)
|
||||||
|
{
|
||||||
|
FString Name = FactoryClass->GetName();
|
||||||
|
if (Name.EndsWith(TEXT("FactoryNew")))
|
||||||
|
{
|
||||||
|
Name.LeftChopInline(10);
|
||||||
|
}
|
||||||
|
else if (Name.EndsWith(TEXT("Factory")))
|
||||||
|
{
|
||||||
|
Name.LeftChopInline(7);
|
||||||
|
}
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
@@ -60,11 +60,6 @@ void WingManual::PrintHandlerHelp(UClass* HandlerClass)
|
|||||||
|
|
||||||
void WingManual::PrintManual(TSet<Section> Sections, UClass *Handler, bool Abridged)
|
void WingManual::PrintManual(TSet<Section> Sections, UClass *Handler, bool Abridged)
|
||||||
{
|
{
|
||||||
if (Handler == nullptr)
|
|
||||||
{
|
|
||||||
Sections.Remove(Section::HandlerHelp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Sections.IsEmpty()) return;
|
if (Sections.IsEmpty()) return;
|
||||||
|
|
||||||
const bool bPrintAll = Sections.Contains(Section::All);
|
const bool bPrintAll = Sections.Contains(Section::All);
|
||||||
@@ -74,7 +69,7 @@ void WingManual::PrintManual(TSet<Section> Sections, UClass *Handler, bool Abrid
|
|||||||
UWingServer::Printf(TEXT("\n--- AUTOMATIC DOCUMENTATION ---\n"));
|
UWingServer::Printf(TEXT("\n--- AUTOMATIC DOCUMENTATION ---\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Sections.Contains(Section::HandlerHelp) || bPrintAll)
|
if (Handler && (Sections.Contains(Section::HandlerHelp) || bPrintAll))
|
||||||
{
|
{
|
||||||
PrintHandlerHelp(Handler);
|
PrintHandlerHelp(Handler);
|
||||||
}
|
}
|
||||||
@@ -286,6 +281,9 @@ void WingManual::PrintManual(TSet<Section> Sections, UClass *Handler, bool Abrid
|
|||||||
"\n Graph_Dump: a fairly detailed listing of any Graph"
|
"\n Graph_Dump: a fairly detailed listing of any Graph"
|
||||||
"\n Property_Dump: show information on many objects"
|
"\n Property_Dump: show information on many objects"
|
||||||
"\n"
|
"\n"
|
||||||
|
"\n You can use ShowCommands(Query=SomeCommand,Verbose=true)"
|
||||||
|
"\n to get detailed help for a specific command."
|
||||||
|
"\n"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#include "WingPackageMaker.h"
|
||||||
|
#include "AssetRegistry/AssetRegistryModule.h"
|
||||||
|
|
||||||
|
WingPackageMaker::WingPackageMaker(const FString& InFullPath)
|
||||||
|
: FullPath(InFullPath)
|
||||||
|
{
|
||||||
|
if (!CheckNewAssetPath(InFullPath))
|
||||||
|
{
|
||||||
|
bError = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WingPackageMaker::CheckNewAssetPath(const FString& Path)
|
||||||
|
{
|
||||||
|
if (!FPackageName::IsValidTextForLongPackageName(Path))
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: Package path '%s' is not a valid package name\n"), *Path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Path.StartsWith(TEXT("/Game")))
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: Package path '%s' must start with '/Game'\n"), *Path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (FindObject<UPackage>(nullptr, *Path))
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: An asset already exists at '%s'\n"), *Path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool WingPackageMaker::Make()
|
||||||
|
{
|
||||||
|
if (bError) return false;
|
||||||
|
Pkg = CreatePackage(*FullPath);
|
||||||
|
if (!Pkg)
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: Failed to create package at '%s'\n"), *FullPath);
|
||||||
|
bError = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pkg->ClearFlags(RF_Transient);
|
||||||
|
Pkg->SetIsExternallyReferenceable(true);
|
||||||
|
Pkg->MarkPackageDirty();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -107,9 +107,27 @@ bool FWingProperty::SetText(FString Value)
|
|||||||
*Value, *WingUtils::FormatName(Prop), *Prop->GetCPPType());
|
*Value, *WingUtils::FormatName(Prop), *Prop->GetCPPType());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!CheckImportTextResult(Value)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FWingProperty::CheckImportTextResult(const FString &Value)
|
||||||
|
{
|
||||||
|
uint8 *VP = Prop->ContainerPtrToValuePtr<uint8>(Container);
|
||||||
|
if (FObjectPropertyBase *OProp = CastField<FObjectPropertyBase>(Prop))
|
||||||
|
{
|
||||||
|
UObject *Obj = OProp->GetObjectPropertyValue(VP);
|
||||||
|
if (Obj == nullptr && Value.TrimStartAndEnd().Compare(TEXT("None"), ESearchCase::IgnoreCase) != 0)
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: Failed to parse '%s' for property '%s'\n"),
|
||||||
|
*Value, *WingUtils::FormatName(Prop));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool FWingProperty::SetJson(const TSharedPtr<FJsonValue> &JsonValue)
|
bool FWingProperty::SetJson(const TSharedPtr<FJsonValue> &JsonValue)
|
||||||
{
|
{
|
||||||
if (JsonValue->Type == EJson::String)
|
if (JsonValue->Type == EJson::String)
|
||||||
@@ -235,6 +253,41 @@ void FWingProperty::Collect(UStruct* StructType, void* Container, TArray<FWingPr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TArray<FWingProperty> FWingProperty::GetAll(UObject* Object, EPropertyFlags Flags)
|
||||||
|
{
|
||||||
|
return GetAll(Object->GetClass(), Object, Flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
TArray<FWingProperty> FWingProperty::GetAll(UStruct* StructType, void* Container, EPropertyFlags Flags)
|
||||||
|
{
|
||||||
|
TArray<FWingProperty> Result;
|
||||||
|
Collect(StructType, Container, Result, Flags);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TArray<FWingProperty> FWingProperty::GetNamed(UStruct* StructType, void* Container, const TArray<FName> &Names)
|
||||||
|
{
|
||||||
|
TArray<FWingProperty> Result;
|
||||||
|
for (FName Name : Names)
|
||||||
|
{
|
||||||
|
FProperty *Prop = StructType->FindPropertyByName(Name);
|
||||||
|
if (Prop != nullptr) Result.Emplace(Prop, Container);
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TArray<FName> FWingProperty::GetNames(UStruct *StructType, EPropertyFlags Flags)
|
||||||
|
{
|
||||||
|
TArray<FName> Result;
|
||||||
|
for (TFieldIterator<FProperty> It(StructType); It; ++It)
|
||||||
|
{
|
||||||
|
if (Flags != 0 && !It->HasAnyPropertyFlags(Flags)) continue;
|
||||||
|
Result.Add(It->GetFName());
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
void FWingProperty::Remove(TArray<FWingProperty>& Props, const FString& Name)
|
void FWingProperty::Remove(TArray<FWingProperty>& Props, const FString& Name)
|
||||||
{
|
{
|
||||||
Props.RemoveAll([&](const FWingProperty& P) { return P.Prop->GetName() == Name; });
|
Props.RemoveAll([&](const FWingProperty& P) { return P.Prop->GetName() == Name; });
|
||||||
@@ -312,17 +365,6 @@ TArray<FWingProperty> FWingProperty::GetDetailsGeneral(UObject* Obj, EPropertyFl
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TArray<FWingProperty> FWingProperty::GetAll(UObject* Object, EPropertyFlags Flags)
|
|
||||||
{
|
|
||||||
return GetAll(Object->GetClass(), Object, Flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
TArray<FWingProperty> FWingProperty::GetAll(UStruct* StructType, void* Container, EPropertyFlags Flags)
|
|
||||||
{
|
|
||||||
TArray<FWingProperty> Result;
|
|
||||||
Collect(StructType, Container, Result, Flags);
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
TArray<FWingProperty> FWingProperty::FindAllSubstring(const TArray<FWingProperty>& Props, const FString& Substring)
|
TArray<FWingProperty> FWingProperty::FindAllSubstring(const TArray<FWingProperty>& Props, const FString& Substring)
|
||||||
{
|
{
|
||||||
|
|||||||
42
Plugins/UEWingman/Source/UEWingman/Public/WingFactories.h
Normal file
42
Plugins/UEWingman/Source/UEWingman/Public/WingFactories.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "EditorSubsystem.h"
|
||||||
|
#include "Factories/Factory.h"
|
||||||
|
#include "WingHandler.h"
|
||||||
|
#include "WingFactories.generated.h"
|
||||||
|
|
||||||
|
UCLASS()
|
||||||
|
class UWingFactories : public UEditorSubsystem
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct Info
|
||||||
|
{
|
||||||
|
FString Name;
|
||||||
|
UClass* FactoryClass = nullptr;
|
||||||
|
TArray<FName> Config;
|
||||||
|
bool Disabled = false;
|
||||||
|
bool CanCreateNew() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
|
||||||
|
virtual void Deinitialize() override {}
|
||||||
|
|
||||||
|
static const TArray<Info>& AllFactories();
|
||||||
|
|
||||||
|
// Create an asset on disk, using a factory. Returns the main object.
|
||||||
|
// If there are problems, prints error messages and returns nullptr.
|
||||||
|
static UObject *CreateAsset(const FString &Path, const FString &Factory, FWingJsonObject &Config);
|
||||||
|
|
||||||
|
private:
|
||||||
|
TArray<Info> Registry;
|
||||||
|
|
||||||
|
Info* Find(const FString& Name);
|
||||||
|
|
||||||
|
void PopulateRegistry();
|
||||||
|
void DisableFactory(const TCHAR* Name);
|
||||||
|
static bool PreCheck(UFactory *Factory, FName Name, const FString &Path);
|
||||||
|
static FString DeriveFactoryName(UClass* FactoryClass);
|
||||||
|
};
|
||||||
@@ -12,43 +12,13 @@
|
|||||||
class WingPackageMaker
|
class WingPackageMaker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WingPackageMaker(const FString& InFullPath)
|
WingPackageMaker(const FString& InFullPath);
|
||||||
: FullPath(InFullPath)
|
|
||||||
{
|
|
||||||
// Path must start with /Game.
|
|
||||||
if (!FullPath.StartsWith(TEXT("/Game")))
|
|
||||||
{
|
|
||||||
UWingServer::Printf(TEXT("ERROR: Package path '%s' must start with '/Game'\n"), *FullPath);
|
|
||||||
bError = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for an existing asset at this path.
|
|
||||||
if (FindObject<UPackage>(nullptr, *FullPath))
|
|
||||||
{
|
|
||||||
UWingServer::Printf(TEXT("ERROR: An asset already exists at '%s'\n"), *FullPath);
|
|
||||||
bError = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Ok() const { return !bError; }
|
bool Ok() const { return !bError; }
|
||||||
|
bool Make();
|
||||||
bool Make()
|
|
||||||
{
|
|
||||||
if (bError) return false;
|
|
||||||
Pkg = CreatePackage(*FullPath);
|
|
||||||
if (!Pkg)
|
|
||||||
{
|
|
||||||
UWingServer::Printf(TEXT("ERROR: Failed to create package at '%s'\n"), *FullPath);
|
|
||||||
bError = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
UPackage* Package() const { return Pkg; }
|
UPackage* Package() const { return Pkg; }
|
||||||
FString Name() const { return FPackageName::GetShortName(FullPath); }
|
FString GetName() const { return FPackageName::GetShortName(FullPath); }
|
||||||
|
FName GetFName() const { return FName(GetName()); }
|
||||||
|
|
||||||
template<typename AssetClass, typename FactoryClass>
|
template<typename AssetClass, typename FactoryClass>
|
||||||
AssetClass* CreateAsset()
|
AssetClass* CreateAsset()
|
||||||
@@ -72,4 +42,6 @@ private:
|
|||||||
FString FullPath;
|
FString FullPath;
|
||||||
UPackage* Pkg = nullptr;
|
UPackage* Pkg = nullptr;
|
||||||
bool bError = false;
|
bool bError = false;
|
||||||
|
|
||||||
|
static bool CheckNewAssetPath(const FString& Path);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -59,6 +59,14 @@ struct FWingProperty
|
|||||||
static TArray<FWingProperty> GetAll(UObject* Object, EPropertyFlags Flags);
|
static TArray<FWingProperty> GetAll(UObject* Object, EPropertyFlags Flags);
|
||||||
static TArray<FWingProperty> GetAll(UStruct* StructType, void* Container, EPropertyFlags Flags);
|
static TArray<FWingProperty> GetAll(UStruct* StructType, void* Container, EPropertyFlags Flags);
|
||||||
|
|
||||||
|
// Get the names of the properties in the specified class.
|
||||||
|
//
|
||||||
|
static TArray<FName> GetNames(UStruct *StructType, EPropertyFlags Flags);
|
||||||
|
|
||||||
|
// Get the named properties.
|
||||||
|
//
|
||||||
|
static TArray<FWingProperty> GetNamed(UStruct* StructType, void* Container, const TArray<FName> &Names);
|
||||||
|
|
||||||
// Functions to find items by name in an array of properties.
|
// Functions to find items by name in an array of properties.
|
||||||
//
|
//
|
||||||
static TArray<FWingProperty> FindAllSubstring(const TArray<FWingProperty>& Props, const FString& Substring);
|
static TArray<FWingProperty> FindAllSubstring(const TArray<FWingProperty>& Props, const FString& Substring);
|
||||||
@@ -76,4 +84,5 @@ private:
|
|||||||
static TArray<FWingProperty> GetDetailsGeneral(UObject* Obj, EPropertyFlags Flags, bool Mutable);
|
static TArray<FWingProperty> GetDetailsGeneral(UObject* Obj, EPropertyFlags Flags, bool Mutable);
|
||||||
void PrintExpectsReceived(const TCHAR *Type);
|
void PrintExpectsReceived(const TCHAR *Type);
|
||||||
static void Collect(UStruct* Struct, void* Container, TArray<FWingProperty> &Props, EPropertyFlags Flags);
|
static void Collect(UStruct* Struct, void* Container, TArray<FWingProperty> &Props, EPropertyFlags Flags);
|
||||||
|
bool CheckImportTextResult(const FString &Value);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user