Init
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#include "FileSystemOperation.h"
|
||||
#include "Misc/Paths.h"
|
||||
#include "Misc/FileHelper.h"
|
||||
#include "Misc/EngineVersionComparison.h"
|
||||
#if UE_VERSION_OLDER_THAN(5, 0, 0)
|
||||
#include "HAL/PlatformFilemanager.h"
|
||||
#else
|
||||
#include "HAL/PlatformFileManager.h"
|
||||
#endif
|
||||
#include "PuertsModule.h"
|
||||
#include "Misc/SecureHash.h"
|
||||
#ifdef PUERTS_WITH_SOURCE_CONTROL
|
||||
#include "SourceControlHelpers.h"
|
||||
#endif
|
||||
|
||||
bool UFileSystemOperation::ReadFile(FString Path, FString& Data)
|
||||
{
|
||||
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
|
||||
IFileHandle* FileHandle = PlatformFile.OpenRead(*Path);
|
||||
if (FileHandle)
|
||||
{
|
||||
int len = FileHandle->Size();
|
||||
TArray<uint8> Content;
|
||||
Content.Reset(len + 2);
|
||||
Content.AddUninitialized(len);
|
||||
const bool Success = FileHandle->Read(Content.GetData(), len);
|
||||
delete FileHandle;
|
||||
|
||||
if (Success)
|
||||
{
|
||||
FFileHelper::BufferToString(Data, Content.GetData(), Content.Num());
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void UFileSystemOperation::WriteFile(FString Path, FString Data)
|
||||
{
|
||||
#ifdef PUERTS_WITH_SOURCE_CONTROL
|
||||
PuertsSourceControlUtils::CheckoutSourceControlFile(Path);
|
||||
#endif
|
||||
FFileHelper::SaveStringToFile(Data, *Path, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM);
|
||||
}
|
||||
|
||||
FString UFileSystemOperation::ResolvePath(FString Path)
|
||||
{
|
||||
return IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*Path);
|
||||
}
|
||||
|
||||
bool UFileSystemOperation::FileExists(FString Path)
|
||||
{
|
||||
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
|
||||
return PlatformFile.FileExists(*Path);
|
||||
}
|
||||
|
||||
bool UFileSystemOperation::DirectoryExists(FString Path)
|
||||
{
|
||||
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
|
||||
return PlatformFile.DirectoryExists(*Path);
|
||||
}
|
||||
|
||||
void UFileSystemOperation::CreateDirectory(FString Path)
|
||||
{
|
||||
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
|
||||
PlatformFile.CreateDirectory(*Path);
|
||||
}
|
||||
|
||||
FString UFileSystemOperation::GetCurrentDirectory()
|
||||
{
|
||||
return FPaths::ConvertRelativePathToFull(FPaths::ProjectDir());
|
||||
}
|
||||
|
||||
TArray<FString> UFileSystemOperation::GetDirectories(FString Path)
|
||||
{
|
||||
IFileManager& FileManager = IFileManager::Get();
|
||||
TArray<FString> Dirs;
|
||||
if (!Path.EndsWith(TEXT("/")))
|
||||
Path = Path + TEXT("/");
|
||||
Path = Path + "*";
|
||||
FileManager.FindFiles(Dirs, *Path, false, true);
|
||||
return Dirs;
|
||||
}
|
||||
|
||||
TArray<FString> UFileSystemOperation::GetFiles(FString Path)
|
||||
{
|
||||
IFileManager& FileManager = IFileManager::Get();
|
||||
TArray<FString> Dirs;
|
||||
if (!Path.EndsWith(TEXT("/")))
|
||||
Path = Path + TEXT("/");
|
||||
Path = Path + "*";
|
||||
FileManager.FindFiles(Dirs, *Path, true, false);
|
||||
return Dirs;
|
||||
}
|
||||
|
||||
void UFileSystemOperation::PuertsNotifyChange(FString Path, FString Source)
|
||||
{
|
||||
IPuertsModule::Get().ReloadModule(*Path, Source);
|
||||
}
|
||||
|
||||
FString UFileSystemOperation::FileMD5Hash(FString Path)
|
||||
{
|
||||
FMD5Hash Hash = FMD5Hash::HashFile(*Path);
|
||||
return LexToString(Hash);
|
||||
}
|
||||
|
||||
// TArray<FString> UFileSystemOperation::ReadDirectory(FString Path, TArray<FString> Extensions, TArray<FString> exclude, int32
|
||||
// Depth)
|
||||
//{
|
||||
//
|
||||
//}
|
||||
|
||||
#ifdef PUERTS_WITH_SOURCE_CONTROL
|
||||
namespace PuertsSourceControlUtils
|
||||
{
|
||||
bool MakeSourceControlFileWritable(const FString& InFileToMakeWritable)
|
||||
{
|
||||
if (SourceControlHelpers::IsAvailable() && FPlatformFileManager::Get().GetPlatformFile().FileExists(*InFileToMakeWritable))
|
||||
{
|
||||
return FPlatformFileManager::Get().GetPlatformFile().SetReadOnly(*InFileToMakeWritable, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CheckoutSourceControlFile(const FString& InFileToCheckout)
|
||||
{
|
||||
if (SourceControlHelpers::IsAvailable())
|
||||
{
|
||||
const FSourceControlState FileState = SourceControlHelpers::QueryFileState(InFileToCheckout);
|
||||
if (FileState.bIsValid && FileState.bIsSourceControlled && !FileState.bCanEdit)
|
||||
{
|
||||
return SourceControlHelpers::CheckOutFile(InFileToCheckout);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace PuertsSourceControlUtils
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,659 @@
|
||||
#include "PEBlueprintMetaData.h"
|
||||
|
||||
#include "Algo/AnyOf.h"
|
||||
#include "K2Node_FunctionEntry.h"
|
||||
#include "UObject/MetaData.h"
|
||||
#include "Engine/Blueprint.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "UECompatible.h"
|
||||
|
||||
const TCHAR* UPEClassMetaData::NAME_HideCategories{TEXT("HideCategories")};
|
||||
const TCHAR* UPEClassMetaData::NAME_ShowCategories{TEXT("ShowCategories")};
|
||||
const TCHAR* UPEClassMetaData::NAME_HideFunctions{TEXT("HideFunctions")};
|
||||
const TCHAR* UPEClassMetaData::NAME_AutoExpandCategories{TEXT("AutoExpandCategories")};
|
||||
const TCHAR* UPEClassMetaData::NAME_AutoCollapseCategories{TEXT("AutoCollapseCategories")};
|
||||
const TCHAR* UPEClassMetaData::NAME_ClassGroupNames{TEXT("ClassGroupNames")};
|
||||
const TCHAR* UPEClassMetaData::NAME_SparseClassDataTypes{TEXT("SparseClassDataTypes")};
|
||||
|
||||
FPEMetaDataUtils::TFormatValidator<class FFieldVariant> FPEMetaDataUtils::ValidateFormat;
|
||||
|
||||
bool FPEMetaDataUtils::AddMetaData(UField* InField, TMap<FName, FString>& InMetaData)
|
||||
{
|
||||
// check if meta data changed
|
||||
const bool bChanged = Algo::AnyOf(InMetaData, [InField](const TPair<FName, FString>& InNewData)
|
||||
{ return !InField->HasMetaData(InNewData.Key) || InField->GetMetaData(InNewData.Key) != InNewData.Value; });
|
||||
|
||||
// set the metadata for this field, since blueprint compilation will handle parent issue, we set meta data directly
|
||||
UMetaData* MetaData = InField->GetOutermost()->GetMetaData();
|
||||
MetaData->SetObjectValues(InField, MoveTemp(InMetaData));
|
||||
|
||||
return bChanged;
|
||||
}
|
||||
|
||||
void UPEClassMetaData::SetClassFlags(int32 InFlags, bool bInPlaceable)
|
||||
{
|
||||
ClassFlags = static_cast<EClassFlags>(InFlags);
|
||||
bWantsToBePlaceable = bInPlaceable;
|
||||
}
|
||||
|
||||
void UPEClassMetaData::SetMetaData(const FString& InName, const FString& InValue)
|
||||
{
|
||||
MetaData.FindOrAdd(*InName) = InValue;
|
||||
}
|
||||
|
||||
void UPEClassMetaData::SetClassWithIn(const FString& InClassName)
|
||||
{
|
||||
ClassWithIn = InClassName;
|
||||
}
|
||||
|
||||
void UPEClassMetaData::SetConfig(const FString& InConfigName)
|
||||
{
|
||||
ConfigName = InConfigName;
|
||||
}
|
||||
|
||||
void UPEClassMetaData::AddHideCategory(const FString& InCategory)
|
||||
{
|
||||
HideCategories.AddUnique(InCategory);
|
||||
}
|
||||
|
||||
void UPEClassMetaData::AddShowCategory(const FString& InCategory)
|
||||
{
|
||||
ShowCategories.AddUnique(InCategory);
|
||||
}
|
||||
|
||||
void UPEClassMetaData::AddShowSubCategory(const FString& InCategory)
|
||||
{
|
||||
ShowSubCategories.AddUnique(InCategory);
|
||||
}
|
||||
|
||||
void UPEClassMetaData::AddHideFunction(const FString& InFunctionName)
|
||||
{
|
||||
HideFunctions.AddUnique(InFunctionName);
|
||||
}
|
||||
|
||||
void UPEClassMetaData::AddShowFunction(const FString& InFunctionName)
|
||||
{
|
||||
ShowFunctions.AddUnique(InFunctionName);
|
||||
}
|
||||
|
||||
void UPEClassMetaData::AddAutoExpandCategory(const FString& InCategory)
|
||||
{
|
||||
AutoExpandCategories.AddUnique(InCategory);
|
||||
}
|
||||
|
||||
void UPEClassMetaData::AddAutoCollapseCategory(const FString& InCategory)
|
||||
{
|
||||
AutoCollapseCategories.AddUnique(InCategory);
|
||||
}
|
||||
|
||||
void UPEClassMetaData::AddDontAutoCollapseCategory(const FString& InCategory)
|
||||
{
|
||||
DontAutoCollapseCategories.AddUnique(InCategory);
|
||||
}
|
||||
|
||||
void UPEClassMetaData::AddClassGroup(const FString& InGroupName)
|
||||
{
|
||||
ClassGroupNames.AddUnique(InGroupName);
|
||||
}
|
||||
|
||||
void UPEClassMetaData::AddSparseDataType(const FString& InType)
|
||||
{
|
||||
SparseClassDataTypes.AddUnique(InType);
|
||||
}
|
||||
|
||||
bool UPEClassMetaData::Apply(UClass* InClass, UBlueprint* InBlueprint)
|
||||
{
|
||||
MergeClassCategories(InClass);
|
||||
const bool bFlagsChanged = MergeAndValidateClassFlags(InClass);
|
||||
const bool bMetaDataChanged = SetClassMetaData(InClass);
|
||||
const bool bBlueprintMetaDataChange = SyncClassToBlueprint(InClass, InBlueprint);
|
||||
return bFlagsChanged || bMetaDataChanged || bBlueprintMetaDataChange;
|
||||
}
|
||||
|
||||
void UPEClassMetaData::MergeClassCategories(UClass* InParentClass)
|
||||
{
|
||||
if (!IsValid(InParentClass))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TArray<FString> ParentShowCategories = GetClassMetaDataValues(InParentClass, NAME_ShowCategories);
|
||||
TArray<FString> ParentHideFunctions = GetClassMetaDataValues(InParentClass, NAME_HideFunctions);
|
||||
TArray<FString> ParentAutoExpandCategories = GetClassMetaDataValues(InParentClass, NAME_AutoExpandCategories);
|
||||
TArray<FString> ParentAutoCollapseCategories = GetClassMetaDataValues(InParentClass, NAME_AutoCollapseCategories);
|
||||
|
||||
// add parent categories
|
||||
ShowSubCategories.Append(MoveTemp(ParentShowCategories));
|
||||
HideFunctions.Append(MoveTemp(ParentHideFunctions));
|
||||
// If metadata is collected from ts
|
||||
FString* ExistingValue = MetaData.Find(NAME_HideCategories);
|
||||
if (ExistingValue)
|
||||
{
|
||||
ExistingValue->ParseIntoArray(HideCategories, TEXT(" "), true);
|
||||
}
|
||||
|
||||
// for show categories
|
||||
for (const FString& Value : ShowCategories)
|
||||
{
|
||||
// if we didn't find this specific category path in the HideCategories metadata
|
||||
if (HideCategories.RemoveSwap(Value) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
TArray<FString> SubCategoryList;
|
||||
Value.ParseIntoArray(SubCategoryList, TEXT("|"), true);
|
||||
|
||||
FString SubCategoryPath;
|
||||
// look to see if any of the parent paths are excluded in the HideCategories list
|
||||
for (int32 CategoryPathIndex = 0; CategoryPathIndex < SubCategoryList.Num() - 1; ++CategoryPathIndex)
|
||||
{
|
||||
SubCategoryPath += SubCategoryList[CategoryPathIndex];
|
||||
// if we're hiding a parent category, then we need to flag this sub category for show
|
||||
if (HideCategories.Contains(SubCategoryPath))
|
||||
{
|
||||
ShowSubCategories.AddUnique(Value);
|
||||
break;
|
||||
}
|
||||
SubCategoryPath += "|";
|
||||
}
|
||||
}
|
||||
// Once the categories have been merged, empty the array as we will no longer need it nor should we use it
|
||||
ShowCategories.Empty();
|
||||
|
||||
// Merge ShowFunctions and HideFunctions
|
||||
for (const FString& Value : ShowFunctions)
|
||||
{
|
||||
HideFunctions.RemoveSwap(Value);
|
||||
}
|
||||
ShowFunctions.Empty();
|
||||
|
||||
// Merge DontAutoCollapseCategories and AutoCollapseCategories
|
||||
for (const FString& Value : DontAutoCollapseCategories)
|
||||
{
|
||||
AutoCollapseCategories.RemoveSwap(Value);
|
||||
}
|
||||
DontAutoCollapseCategories.Empty();
|
||||
|
||||
// Merge ShowFunctions and HideFunctions
|
||||
for (const FString& Value : ShowFunctions)
|
||||
{
|
||||
HideFunctions.RemoveSwap(Value);
|
||||
}
|
||||
ShowFunctions.Empty();
|
||||
|
||||
// Merge AutoExpandCategories and AutoCollapseCategories (we still want to keep AutoExpandCategories though!)
|
||||
for (const FString& Value : AutoExpandCategories)
|
||||
{
|
||||
AutoCollapseCategories.RemoveSwap(Value);
|
||||
ParentAutoCollapseCategories.RemoveSwap(Value);
|
||||
}
|
||||
|
||||
// Do the same as above but the other way around
|
||||
for (const FString& Value : AutoCollapseCategories)
|
||||
{
|
||||
AutoExpandCategories.RemoveSwap(Value);
|
||||
ParentAutoExpandCategories.RemoveSwap(Value);
|
||||
}
|
||||
|
||||
// Once AutoExpandCategories and AutoCollapseCategories for THIS class have been parsed, add the parent inherited categories
|
||||
AutoCollapseCategories.Append(MoveTemp(ParentAutoCollapseCategories));
|
||||
AutoExpandCategories.Append(MoveTemp(ParentAutoExpandCategories));
|
||||
|
||||
// add the categories to the meta data
|
||||
if (ClassGroupNames.Num() > 0)
|
||||
{
|
||||
MetaData.Add(NAME_ClassGroupNames, FString::Join(ClassGroupNames, TEXT(" ")));
|
||||
}
|
||||
if (AutoExpandCategories.Num() > 0)
|
||||
{
|
||||
MetaData.Add(NAME_AutoExpandCategories, FString::Join(AutoExpandCategories, TEXT(" ")));
|
||||
}
|
||||
if (ShowSubCategories.Num() > 0)
|
||||
{
|
||||
MetaData.Add(NAME_ShowCategories, FString::Join(ShowSubCategories, TEXT(" ")));
|
||||
}
|
||||
if (SparseClassDataTypes.Num() > 0)
|
||||
{
|
||||
MetaData.Add(NAME_SparseClassDataTypes, FString::Join(SparseClassDataTypes, TEXT(" ")));
|
||||
}
|
||||
if (AutoCollapseCategories.Num() > 0)
|
||||
{
|
||||
MetaData.Add(NAME_AutoCollapseCategories, FString::Join(AutoCollapseCategories, TEXT(" ")));
|
||||
}
|
||||
}
|
||||
|
||||
bool UPEClassMetaData::MergeAndValidateClassFlags(UClass* InClass)
|
||||
{
|
||||
if (!IsValid(InClass))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const EClassFlags OldFlags = InClass->ClassFlags;
|
||||
if (bWantsToBePlaceable)
|
||||
{
|
||||
if (!(InClass->ClassFlags & CLASS_NotPlaceable))
|
||||
{
|
||||
UE_LOG(LogTemp, Error,
|
||||
TEXT("The 'placeable' specifier is only allowed on classes which have a base class that's marked as not placeable. "
|
||||
"Classes are assumed to be placeable by default."));
|
||||
return false;
|
||||
}
|
||||
InClass->ClassFlags &= ~CLASS_NotPlaceable;
|
||||
bWantsToBePlaceable = false;
|
||||
}
|
||||
|
||||
InClass->ClassFlags |= ClassFlags;
|
||||
const auto OldWithInClass = InClass->ClassWithin;
|
||||
|
||||
SetAndValidateWithinClass(InClass);
|
||||
|
||||
if (!!(InClass->ClassFlags & CLASS_EditInlineNew) && InClass->IsChildOf(AActor::StaticClass()))
|
||||
{
|
||||
UE_LOG(LogTemp, Error, TEXT("Invalid class attribute: Creating actor instances via the property window is not allowed"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (InClass->HasAllClassFlags(CLASS_MinimalAPI | CLASS_RequiredAPI))
|
||||
{
|
||||
UE_LOG(
|
||||
LogTemp, Error, TEXT("MinimalAPI cannot be specified when the class is fully exported using a MODULENAME_API macro"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return OldFlags != InClass->ClassFlags || OldWithInClass != InClass->ClassWithin;
|
||||
}
|
||||
|
||||
bool UPEClassMetaData::SetClassMetaData(UClass* InClass)
|
||||
{
|
||||
// Evaluate any key redirects on the passed in pairs
|
||||
for (TPair<FName, FString>& Pair : MetaData)
|
||||
{
|
||||
FName& CurrentKey = Pair.Key;
|
||||
FName NewKey = UMetaData::GetRemappedKeyName(CurrentKey);
|
||||
|
||||
if (NewKey != NAME_None)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("Remapping old metadata key '%s' to new key '%s', please update the declaration."),
|
||||
*CurrentKey.ToString(), *NewKey.ToString());
|
||||
CurrentKey = NewKey;
|
||||
}
|
||||
}
|
||||
|
||||
// Finish validating and associate the metadata with the field
|
||||
for (const auto& Pair : MetaData)
|
||||
{
|
||||
FString Message;
|
||||
if (!FPEMetaDataUtils::ValidateFormat(InClass, Pair.Key, Pair.Value, Message))
|
||||
{
|
||||
UE_LOG(LogTemp, Error, TEXT("failed set meta data: %s"), *Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return FPEMetaDataUtils::AddMetaData(InClass, MetaData);
|
||||
}
|
||||
|
||||
TArray<FString> UPEClassMetaData::GetClassMetaDataValues(
|
||||
UClass* InClass, const TCHAR* InMetaDataKey, const TCHAR* InDelimiter, bool bInCullEmpty)
|
||||
{
|
||||
TArray<FString> Result;
|
||||
|
||||
if (!IsValid(InClass))
|
||||
{
|
||||
return Result;
|
||||
}
|
||||
|
||||
if (!InClass->HasMetaData(InMetaDataKey))
|
||||
{
|
||||
return Result;
|
||||
}
|
||||
|
||||
InClass->GetMetaData(InMetaDataKey).ParseIntoArray(Result, InDelimiter, bInCullEmpty);
|
||||
return Result;
|
||||
}
|
||||
|
||||
bool UPEClassMetaData::SyncClassToBlueprint(UClass* InClass, UBlueprint* InBlueprint)
|
||||
{
|
||||
if (!IsValid(InClass) || !IsValid(InBlueprint))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool onChange = false;
|
||||
|
||||
if (InBlueprint->bDeprecate != (bool) (InClass->ClassFlags & CLASS_Deprecated))
|
||||
{
|
||||
InBlueprint->bDeprecate = (bool) (InClass->ClassFlags & CLASS_Deprecated);
|
||||
onChange = true;
|
||||
}
|
||||
if (InBlueprint->bGenerateAbstractClass != (bool) (InClass->ClassFlags & CLASS_Abstract))
|
||||
{
|
||||
InBlueprint->bGenerateAbstractClass = (bool) (InClass->ClassFlags & CLASS_Abstract);
|
||||
onChange = true;
|
||||
}
|
||||
FString newDescription = InClass->HasMetaData(TEXT("Tooltip")) ? InClass->GetMetaData(TEXT("Tooltip")) : FString{};
|
||||
if (InBlueprint->BlueprintDescription != newDescription)
|
||||
{
|
||||
InBlueprint->BlueprintDescription = newDescription;
|
||||
onChange = true;
|
||||
}
|
||||
FString newDisplayName = InClass->HasMetaData(TEXT("DisplayName")) ? InClass->GetMetaData(TEXT("DisplayName")) : FString{};
|
||||
if (InBlueprint->BlueprintDisplayName != newDisplayName)
|
||||
{
|
||||
InBlueprint->BlueprintDisplayName = newDisplayName;
|
||||
onChange = true;
|
||||
}
|
||||
EBlueprintType newType = (InClass->ClassFlags & CLASS_Const) ? BPTYPE_Const : BPTYPE_Normal;
|
||||
if (InBlueprint->BlueprintType != newType)
|
||||
{
|
||||
InBlueprint->BlueprintType = newType;
|
||||
onChange = true;
|
||||
}
|
||||
FString newCategory = InClass->HasMetaData(TEXT("Category")) ? InClass->GetMetaData(TEXT("Category")) : FString{};
|
||||
if (InBlueprint->BlueprintCategory != newCategory)
|
||||
{
|
||||
InBlueprint->BlueprintCategory = newCategory;
|
||||
onChange = true;
|
||||
}
|
||||
if (InBlueprint->HideCategories != HideCategories)
|
||||
{
|
||||
InBlueprint->HideCategories = HideCategories;
|
||||
onChange = true;
|
||||
}
|
||||
|
||||
return onChange;
|
||||
}
|
||||
|
||||
void UPEClassMetaData::SetAndValidateWithinClass(UClass* InClass)
|
||||
{
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION > 2
|
||||
UClass* ExpectedWithinClass = InClass->GetSuperClass() ? InClass->GetSuperClass()->ClassWithin.Get() : UObject::StaticClass();
|
||||
#else
|
||||
UClass* ExpectedWithinClass = InClass->GetSuperClass() ? InClass->GetSuperClass()->ClassWithin : UObject::StaticClass();
|
||||
#endif
|
||||
if (ClassWithIn.IsEmpty() == false)
|
||||
{
|
||||
UClass* WithinClass = PUERTS_NAMESPACE::FindAnyType<UClass>(ClassWithIn);
|
||||
if (WithinClass == nullptr)
|
||||
{
|
||||
UE_LOG(LogTemp, Error, TEXT("the with in class of %s: %s is not found"), *InClass->GetName(), *ClassWithIn);
|
||||
return;
|
||||
}
|
||||
|
||||
if (WithinClass->IsChildOf(UInterface::StaticClass()))
|
||||
{
|
||||
UE_LOG(LogTemp, Error, TEXT("the with in class of %s: %s should not be interface "), *InClass->GetName(), *ClassWithIn);
|
||||
return;
|
||||
}
|
||||
|
||||
if (InClass->ClassWithin == nullptr || InClass->ClassWithin == UObject::StaticClass() ||
|
||||
WithinClass->IsChildOf(InClass->ClassWithin))
|
||||
{
|
||||
InClass->ClassWithin = WithinClass;
|
||||
}
|
||||
|
||||
if (InClass->ClassWithin != WithinClass)
|
||||
{
|
||||
UE_LOG(LogTemp, Error, TEXT("the with in class of %s: %s is set failed"), *InClass->GetName(), *ClassWithIn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
InClass->ClassWithin = ExpectedWithinClass;
|
||||
}
|
||||
|
||||
if (!InClass->ClassWithin->IsChildOf(ExpectedWithinClass))
|
||||
{
|
||||
UE_LOG(LogTemp, Error, TEXT("the parent class with in class %s is not consist the with in class of %s: %s"),
|
||||
*ExpectedWithinClass->GetName(), *InClass->GetName(), *InClass->ClassWithin->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
void UPEClassMetaData::SetAndValidateConfigName(UClass* InClass)
|
||||
{
|
||||
if (ConfigName.IsEmpty() == false)
|
||||
{
|
||||
// if the user specified "inherit", we're just going to use the parent class's config filename
|
||||
// this is not actually necessary but it can be useful for explicitly communicating config-ness
|
||||
if (ConfigName == TEXT("inherit"))
|
||||
{
|
||||
UClass* SuperClass = InClass->GetSuperClass();
|
||||
if (!SuperClass)
|
||||
{
|
||||
UE_LOG(LogTemp, Error, TEXT("Cannot inherit config filename: %s has no super class"), *InClass->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
if (SuperClass->ClassConfigName == NAME_None)
|
||||
{
|
||||
UE_LOG(LogTemp, Error, TEXT("Cannot inherit config filename: parent class %s is not marked config."),
|
||||
*SuperClass->GetPathName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise, set the config name to the parsed identifier
|
||||
InClass->ClassConfigName = FName(*ConfigName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalidate config name if not specifically declared.
|
||||
InClass->ClassConfigName = NAME_None;
|
||||
}
|
||||
}
|
||||
|
||||
void UPEFunctionMetaData::SetFunctionFlags(int32 InHighBits, int32 InLowBits)
|
||||
{
|
||||
FunctionFlags =
|
||||
static_cast<EFunctionFlags>((static_cast<uint64>(static_cast<uint32>(InHighBits)) << 32) + static_cast<uint32>(InLowBits));
|
||||
}
|
||||
|
||||
void UPEFunctionMetaData::SetFunctionExportFlags(int32 InFlags)
|
||||
{
|
||||
FunctionExportFlags = InFlags;
|
||||
}
|
||||
|
||||
void UPEFunctionMetaData::SetMetaData(const FString& InName, const FString& InValue)
|
||||
{
|
||||
MetaData.FindOrAdd(*InName) = InValue;
|
||||
}
|
||||
|
||||
void UPEFunctionMetaData::SetCppImplName(const FString& InName)
|
||||
{
|
||||
CppImplName = InName;
|
||||
}
|
||||
|
||||
void UPEFunctionMetaData::SetCppValidationImplName(const FString& InName)
|
||||
{
|
||||
CppValidationImplName = InName;
|
||||
}
|
||||
|
||||
void UPEFunctionMetaData::SetEndpointName(const FString& InEndpointName)
|
||||
{
|
||||
EndpointName = InEndpointName;
|
||||
}
|
||||
|
||||
void UPEFunctionMetaData::SetRPCId(int32 InRPCId)
|
||||
{
|
||||
RPCId = static_cast<uint16>(InRPCId);
|
||||
}
|
||||
|
||||
void UPEFunctionMetaData::SetRPCResponseId(int32 InRPCResponseId)
|
||||
{
|
||||
RPCResponseId = InRPCResponseId;
|
||||
}
|
||||
|
||||
void UPEFunctionMetaData::SetIsSealedEvent(bool bInSealedEvent)
|
||||
{
|
||||
bSealedEvent = bInSealedEvent;
|
||||
}
|
||||
|
||||
void UPEFunctionMetaData::SetForceBlueprintImpure(bool bInForceBlueprintImpure)
|
||||
{
|
||||
bForceBlueprintImpure = bInForceBlueprintImpure;
|
||||
}
|
||||
|
||||
bool UPEFunctionMetaData::Apply(UK2Node_FunctionEntry* InFunctionEntry) const
|
||||
{
|
||||
// a helper function used to update text value, and return if the value is updated by a new value
|
||||
static const auto UpdateTextMetaData = [](FName InKey, const TMap<FName, FString>& InMetaData, FText& InOutValue) -> bool
|
||||
{
|
||||
const FText NewValue = InMetaData.Contains(InKey) ? FText::FromString(InMetaData[InKey]) : FText{};
|
||||
const bool bChanged = !NewValue.EqualTo(InOutValue);
|
||||
InOutValue = NewValue;
|
||||
return bChanged;
|
||||
};
|
||||
|
||||
// a helper function used to update boolean value, and return if the value is updated by the new value
|
||||
static const auto UpdateBooleanMetaData = [](FName InKey, const TMap<FName, FString>& InMetaData, bool& InOutValue) -> bool
|
||||
{
|
||||
const bool NewValue = InMetaData.Contains(InKey) ? true : false;
|
||||
const bool bChanged = NewValue != InOutValue;
|
||||
InOutValue = NewValue;
|
||||
return bChanged;
|
||||
};
|
||||
|
||||
// a helper function sued update string value, return return if the value is updated by the new value
|
||||
static const auto UpdateStringMetaData = [](FName InKey, const TMap<FName, FString>& InMetaData, FString& InOutValue) -> bool
|
||||
{
|
||||
const FString NewValue = InMetaData.Contains(InKey) ? InMetaData[InKey] : FString{};
|
||||
const bool bChanged = NewValue != InOutValue;
|
||||
InOutValue = NewValue;
|
||||
return bChanged;
|
||||
};
|
||||
|
||||
if (!IsValid(InFunctionEntry))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// make sure native flags is removed
|
||||
const auto OldFlags = InFunctionEntry->GetExtraFlags();
|
||||
InFunctionEntry->SetExtraFlags(InFunctionEntry->GetExtraFlags() | FunctionFlags);
|
||||
const bool bFlagsChanged = InFunctionEntry->GetExtraFlags() != OldFlags;
|
||||
|
||||
bool bMetaDataChanged = false;
|
||||
auto& MetaDataToSet = InFunctionEntry->MetaData;
|
||||
|
||||
bMetaDataChanged = UpdateBooleanMetaData(TEXT("CallInEditor"), MetaData, MetaDataToSet.bCallInEditor) || bMetaDataChanged;
|
||||
bMetaDataChanged = UpdateTextMetaData(TEXT("Category"), MetaData, MetaDataToSet.Category) || bMetaDataChanged;
|
||||
bMetaDataChanged = UpdateTextMetaData(TEXT("Keywords"), MetaData, MetaDataToSet.Keywords) || bMetaDataChanged;
|
||||
bMetaDataChanged = UpdateTextMetaData(TEXT("CompactNodeTitle"), MetaData, MetaDataToSet.CompactNodeTitle) || bMetaDataChanged;
|
||||
bMetaDataChanged = UpdateTextMetaData(TEXT("ToolTip"), MetaData, MetaDataToSet.ToolTip) || bMetaDataChanged;
|
||||
#if ENGINE_MINOR_VERSION >= 23 || ENGINE_MAJOR_VERSION > 4
|
||||
bMetaDataChanged = UpdateBooleanMetaData(TEXT("DeprecatedFunction"), MetaData, MetaDataToSet.bIsDeprecated) || bMetaDataChanged;
|
||||
bMetaDataChanged =
|
||||
UpdateStringMetaData(TEXT("DeprecationMessage"), MetaData, MetaDataToSet.DeprecationMessage) || bMetaDataChanged;
|
||||
#endif
|
||||
|
||||
return bFlagsChanged || bMetaDataChanged;
|
||||
}
|
||||
|
||||
bool UPEFunctionMetaData::Apply(UK2Node_CustomEvent* InCustomEvent) const
|
||||
{
|
||||
if (!IsValid(InCustomEvent))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// the function flags
|
||||
const auto Oldflags = InCustomEvent->FunctionFlags;
|
||||
InCustomEvent->FunctionFlags |= FunctionFlags;
|
||||
const bool bFlagsChanged = Oldflags != InCustomEvent->FunctionFlags;
|
||||
// add meta data
|
||||
bool bMetaChanged;
|
||||
ApplyCustomEventMetaData(bMetaChanged, MetaData, InCustomEvent);
|
||||
return bFlagsChanged || bMetaChanged;
|
||||
}
|
||||
|
||||
void UPEParamMetaData::SetParamFlags(int32 InHighBits, int32 InLowBits)
|
||||
{
|
||||
ParamFlags =
|
||||
static_cast<EPropertyFlags>((static_cast<uint64>(static_cast<uint32>(InHighBits)) << 32) + static_cast<uint32>(InLowBits));
|
||||
}
|
||||
|
||||
void UPEParamMetaData::SetMetaData(const FString& InName, const FString& InValue)
|
||||
{
|
||||
MetaData.FindOrAdd(*InName) = InValue;
|
||||
}
|
||||
|
||||
bool UPEParamMetaData::Apply(FEdGraphPinType& PinType) const
|
||||
{
|
||||
// most meta data could not set in blueprint, should have a way to apply on related FProperty after blueprint compilation?
|
||||
bool bChanged = false;
|
||||
bChanged = (PinType.bIsConst != !!(ParamFlags & CPF_ConstParm)) || bChanged;
|
||||
PinType.bIsConst = !!(ParamFlags & CPF_ConstParm);
|
||||
bChanged = (PinType.bIsReference != !!(ParamFlags & CPF_ReferenceParm)) || bChanged;
|
||||
PinType.bIsReference = !!(ParamFlags & CPF_ReferenceParm);
|
||||
|
||||
return bChanged;
|
||||
}
|
||||
|
||||
void UPEPropertyMetaData::SetPropertyFlags(int32 InHighBits, int32 InLowBits)
|
||||
{
|
||||
PropertyFlags =
|
||||
static_cast<EPropertyFlags>((static_cast<uint64>(static_cast<uint32>(InHighBits)) << 32) + static_cast<uint32>(InLowBits));
|
||||
}
|
||||
|
||||
void UPEPropertyMetaData::SetMetaData(const FString& InName, const FString& InValue)
|
||||
{
|
||||
MetaData.FindOrAdd(*InName) = InValue;
|
||||
}
|
||||
|
||||
void UPEPropertyMetaData::SetRepCallbackName(const FString& InName)
|
||||
{
|
||||
RepCallbackName = InName;
|
||||
}
|
||||
|
||||
bool UPEPropertyMetaData::Apply(FBPVariableDescription& Element) const
|
||||
{
|
||||
// should do more check here?
|
||||
|
||||
const auto OldFlags = Element.PropertyFlags;
|
||||
// set flags, since the default create blueprint variable could not edit instance, so modify it if needed
|
||||
Element.PropertyFlags |= PropertyFlags;
|
||||
const bool bFlagsChanged = OldFlags != Element.PropertyFlags;
|
||||
|
||||
// set meta data
|
||||
bool bMetaDataChanged = false;
|
||||
|
||||
for (int Index = Element.MetaDataArray.Num() - 1; Index >= 0; --Index)
|
||||
{
|
||||
if (!MetaData.Contains(Element.MetaDataArray[Index].DataKey))
|
||||
{
|
||||
bMetaDataChanged = true;
|
||||
Element.MetaDataArray.RemoveAt(Index);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& Pair : MetaData)
|
||||
{
|
||||
if (const auto MetaDataEntryPtr = Element.MetaDataArray.FindByPredicate(
|
||||
[Key = Pair.Key](const FBPVariableMetaDataEntry& InEntry) { return InEntry.DataKey == Key; }))
|
||||
{
|
||||
bMetaDataChanged = MetaDataEntryPtr->DataValue != Pair.Value || bMetaDataChanged;
|
||||
MetaDataEntryPtr->DataValue = Pair.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
bMetaDataChanged = true;
|
||||
Element.MetaDataArray.Emplace(Pair.Key, Pair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
// if needed set notify function, we don't check the existence of the notify function here
|
||||
bool bRepFunctionChanged = false;
|
||||
if (PropertyFlags & CPF_RepNotify)
|
||||
{
|
||||
const FName NewRepNotifyFunc =
|
||||
RepCallbackName.IsEmpty() ? *FString::Printf(TEXT("OnRep_%s"), *Element.VarName.ToString()) : *RepCallbackName;
|
||||
bRepFunctionChanged = NewRepNotifyFunc != Element.RepNotifyFunc;
|
||||
Element.RepNotifyFunc = NewRepNotifyFunc;
|
||||
}
|
||||
|
||||
return bFlagsChanged || bMetaDataChanged || bRepFunctionChanged;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#include "PEDirectoryWatcher.h"
|
||||
#include "DirectoryWatcherModule.h"
|
||||
#include "Modules/ModuleManager.h"
|
||||
#include "HAL/FileManager.h"
|
||||
#include "Misc/SecureHash.h"
|
||||
|
||||
UPEDirectoryWatcher::UPEDirectoryWatcher()
|
||||
{
|
||||
this->AddToRoot();
|
||||
}
|
||||
|
||||
bool UPEDirectoryWatcher::Watch(const FString& InDirectory)
|
||||
{
|
||||
Directory = FPaths::IsRelative(InDirectory) ? FPaths::ConvertRelativePathToFull(InDirectory) : InDirectory;
|
||||
// UE_LOG(LogTemp, Warning, TEXT("PEDirectoryWatcher::Watch: %s"), *InDirectory);
|
||||
if (IFileManager::Get().DirectoryExists(*Directory))
|
||||
{
|
||||
auto Changed = IDirectoryWatcher::FDirectoryChanged::CreateLambda(
|
||||
[&](const TArray<FFileChangeData>& FileChanges)
|
||||
{
|
||||
TArray<FString> Added;
|
||||
TArray<FString> Modified;
|
||||
TArray<FString> Removed;
|
||||
|
||||
for (auto Change : FileChanges)
|
||||
{
|
||||
//因为要算md5,所有过滤掉不关心的
|
||||
if (!Change.Filename.EndsWith(TEXT(".ts")) && !Change.Filename.EndsWith(TEXT(".mts")) &&
|
||||
!Change.Filename.EndsWith(TEXT(".tsx")) && !Change.Filename.EndsWith(TEXT(".json")) &&
|
||||
!Change.Filename.EndsWith(TEXT(".js")))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
FPaths::NormalizeFilename(Change.Filename);
|
||||
Change.Filename = FPaths::ConvertRelativePathToFull(Change.Filename);
|
||||
switch (Change.Action)
|
||||
{
|
||||
case FFileChangeData::FCA_Added:
|
||||
if (Added.Contains(Change.Filename))
|
||||
continue;
|
||||
Added.Add(Change.Filename);
|
||||
break;
|
||||
case FFileChangeData::FCA_Modified:
|
||||
if (Modified.Contains(Change.Filename))
|
||||
continue;
|
||||
Modified.Add(Change.Filename);
|
||||
break;
|
||||
case FFileChangeData::FCA_Removed:
|
||||
if (Removed.Contains(Change.Filename))
|
||||
continue;
|
||||
Removed.Add(Change.Filename);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (Added.Num() || Modified.Num() || Removed.Num())
|
||||
{
|
||||
OnChanged.Broadcast(Added, Modified, Removed);
|
||||
}
|
||||
});
|
||||
FDirectoryWatcherModule& DirectoryWatcherModule =
|
||||
FModuleManager::Get().LoadModuleChecked<FDirectoryWatcherModule>(TEXT("DirectoryWatcher"));
|
||||
IDirectoryWatcher* DirectoryWatcher = DirectoryWatcherModule.Get();
|
||||
DirectoryWatcher->RegisterDirectoryChangedCallback_Handle(
|
||||
Directory, Changed, DelegateHandle, IDirectoryWatcher::IncludeDirectoryChanges);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void UPEDirectoryWatcher::UnWatch()
|
||||
{
|
||||
if (DelegateHandle.IsValid())
|
||||
{
|
||||
FDirectoryWatcherModule& DirectoryWatcherModule =
|
||||
FModuleManager::Get().LoadModuleChecked<FDirectoryWatcherModule>(TEXT("DirectoryWatcher"));
|
||||
IDirectoryWatcher* DirectoryWatcher = DirectoryWatcherModule.Get();
|
||||
|
||||
DirectoryWatcher->UnregisterDirectoryChangedCallback_Handle(Directory, DelegateHandle);
|
||||
Directory = TEXT("");
|
||||
}
|
||||
}
|
||||
|
||||
UPEDirectoryWatcher::~UPEDirectoryWatcher()
|
||||
{
|
||||
UnWatch();
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Puerts available.
|
||||
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
|
||||
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
|
||||
* which is part of this source code package.
|
||||
*/
|
||||
|
||||
#include "PuertsEditorModule.h"
|
||||
#include "JsEnv.h"
|
||||
#include "Editor.h"
|
||||
#include "Misc/FileHelper.h"
|
||||
#include "PuertsModule.h"
|
||||
#include "TypeScriptCompilerContext.h"
|
||||
#include "TypeScriptBlueprint.h"
|
||||
#include "SourceFileWatcher.h"
|
||||
#include "JSLogger.h"
|
||||
#include "JSModuleLoader.h"
|
||||
#include "Binding.hpp"
|
||||
#include "UEDataBinding.hpp"
|
||||
#include "Object.hpp"
|
||||
|
||||
class FPuertsEditorModule : public IPuertsEditorModule
|
||||
{
|
||||
/** IModuleInterface implementation */
|
||||
void StartupModule() override;
|
||||
void ShutdownModule() override;
|
||||
|
||||
void SetCmdImpl(std::function<void(const FString&, const FString&)> Func) override
|
||||
{
|
||||
CmdImpl = Func;
|
||||
}
|
||||
|
||||
public:
|
||||
static void SetCmdCallback(std::function<void(const FString&, const FString&)> Func)
|
||||
{
|
||||
Get().SetCmdImpl(Func);
|
||||
}
|
||||
|
||||
private:
|
||||
//
|
||||
void PreBeginPIE(bool bIsSimulating);
|
||||
|
||||
void EndPIE(bool bIsSimulating);
|
||||
|
||||
void OnPostEngineInit();
|
||||
|
||||
TSharedPtr<PUERTS_NAMESPACE::FJsEnv> JsEnv;
|
||||
|
||||
TSharedPtr<PUERTS_NAMESPACE::FSourceFileWatcher> SourceFileWatcher;
|
||||
|
||||
bool Enabled = false;
|
||||
|
||||
std::function<void(const FString&, const FString&)> CmdImpl;
|
||||
|
||||
TUniquePtr<FAutoConsoleCommand> ConsoleCommand;
|
||||
};
|
||||
|
||||
UsingCppType(FPuertsEditorModule);
|
||||
|
||||
struct AutoRegisterForPEM
|
||||
{
|
||||
AutoRegisterForPEM()
|
||||
{
|
||||
PUERTS_NAMESPACE::DefineClass<FPuertsEditorModule>()
|
||||
.Function("SetCmdCallback", MakeFunction(&FPuertsEditorModule::SetCmdCallback))
|
||||
.Register();
|
||||
}
|
||||
};
|
||||
|
||||
AutoRegisterForPEM _AutoRegisterForPEM__;
|
||||
|
||||
IMPLEMENT_MODULE(FPuertsEditorModule, PuertsEditor)
|
||||
|
||||
void FPuertsEditorModule::StartupModule()
|
||||
{
|
||||
Enabled = IPuertsModule::Get().IsWatchEnabled() && !IsRunningCommandlet();
|
||||
|
||||
FEditorDelegates::PreBeginPIE.AddRaw(this, &FPuertsEditorModule::PreBeginPIE);
|
||||
FEditorDelegates::EndPIE.AddRaw(this, &FPuertsEditorModule::EndPIE);
|
||||
|
||||
ConsoleCommand = MakeUnique<FAutoConsoleCommand>(TEXT("Puerts"), TEXT("Puerts action"),
|
||||
FConsoleCommandWithArgsDelegate::CreateLambda(
|
||||
[this](const TArray<FString>& Args)
|
||||
{
|
||||
if (CmdImpl)
|
||||
{
|
||||
FString CmdForJs = TEXT("");
|
||||
FString ArgsForJs = TEXT("");
|
||||
|
||||
if (Args.Num() > 0)
|
||||
{
|
||||
CmdForJs = Args[0];
|
||||
}
|
||||
if (Args.Num() > 1)
|
||||
{
|
||||
ArgsForJs = Args[1];
|
||||
}
|
||||
CmdImpl(CmdForJs, ArgsForJs);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(Puerts, Error, TEXT("Puerts command not initialized"));
|
||||
}
|
||||
}));
|
||||
this->OnPostEngineInit();
|
||||
}
|
||||
|
||||
TSharedPtr<FKismetCompilerContext> MakeCompiler(
|
||||
UBlueprint* InBlueprint, FCompilerResultsLog& InMessageLog, const FKismetCompilerOptions& InCompileOptions)
|
||||
{
|
||||
return MakeShared<FTypeScriptCompilerContext>(CastChecked<UTypeScriptBlueprint>(InBlueprint), InMessageLog, InCompileOptions);
|
||||
}
|
||||
|
||||
void FPuertsEditorModule::OnPostEngineInit()
|
||||
{
|
||||
if (Enabled)
|
||||
{
|
||||
FKismetCompilerContext::RegisterCompilerForBP(UTypeScriptBlueprint::StaticClass(), &MakeCompiler);
|
||||
|
||||
SourceFileWatcher = MakeShared<PUERTS_NAMESPACE::FSourceFileWatcher>(
|
||||
[this](const FString& InPath)
|
||||
{
|
||||
if (JsEnv.IsValid())
|
||||
{
|
||||
TArray<uint8> Source;
|
||||
if (FFileHelper::LoadFileToArray(Source, *InPath))
|
||||
{
|
||||
JsEnv->ReloadSource(InPath, std::string((const char*) Source.GetData(), Source.Num()));
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(Puerts, Error, TEXT("read file fail for %s"), *InPath);
|
||||
}
|
||||
}
|
||||
});
|
||||
JsEnv = MakeShared<PUERTS_NAMESPACE::FJsEnv>(
|
||||
std::make_shared<PUERTS_NAMESPACE::DefaultJSModuleLoader>(TEXT("JavaScript")),
|
||||
std::make_shared<PUERTS_NAMESPACE::FDefaultLogger>(), -1,
|
||||
[this](const FString& InPath)
|
||||
{
|
||||
if (SourceFileWatcher.IsValid())
|
||||
{
|
||||
SourceFileWatcher->OnSourceLoaded(InPath);
|
||||
}
|
||||
},
|
||||
TEXT("--max-old-space-size=2048"));
|
||||
|
||||
JsEnv->Start("PuertsEditor/CodeAnalyze");
|
||||
}
|
||||
}
|
||||
|
||||
void FPuertsEditorModule::ShutdownModule()
|
||||
{
|
||||
CmdImpl = nullptr;
|
||||
if (JsEnv.IsValid())
|
||||
{
|
||||
JsEnv.Reset();
|
||||
}
|
||||
if (SourceFileWatcher.IsValid())
|
||||
{
|
||||
SourceFileWatcher.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
void FPuertsEditorModule::PreBeginPIE(bool bIsSimulating)
|
||||
{
|
||||
if (Enabled)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void FPuertsEditorModule::EndPIE(bool bIsSimulating)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "TypeScriptCompilerContext.h"
|
||||
#include "TypeScriptGeneratedClass.h"
|
||||
|
||||
#include "Kismet2/KismetReinstanceUtilities.h"
|
||||
#include "KismetCompilerMisc.h"
|
||||
|
||||
#include "Runtime/Launch/Resources/Version.h"
|
||||
|
||||
FTypeScriptCompilerContext::FTypeScriptCompilerContext(
|
||||
UBlueprint* SourceSketch, FCompilerResultsLog& MessageLog, const FKismetCompilerOptions& CompilerOptions)
|
||||
#if (ENGINE_MAJOR_VERSION <= 4) & (ENGINE_MINOR_VERSION <= 21)
|
||||
: Super(SourceSketch, MessageLog, CompilerOptions, nullptr)
|
||||
#else
|
||||
: Super(SourceSketch, MessageLog, CompilerOptions)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
void FTypeScriptCompilerContext::SpawnNewClass(const FString& NewClassName)
|
||||
{
|
||||
if (NewClassName.StartsWith(TEXT("SKEL_")))
|
||||
{
|
||||
FKismetCompilerContext::SpawnNewClass(NewClassName);
|
||||
return;
|
||||
}
|
||||
|
||||
NewClass = FindObject<UTypeScriptGeneratedClass>(Blueprint->GetOutermost(), *NewClassName);
|
||||
|
||||
if (NewClass == NULL)
|
||||
{
|
||||
// If the class hasn't been found, then spawn a new one
|
||||
NewClass =
|
||||
NewObject<UTypeScriptGeneratedClass>(Blueprint->GetOutermost(), FName(*NewClassName), RF_Public | RF_Transactional);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Already existed, but wasn't linked in the Blueprint yet due to load ordering issues
|
||||
NewClass->ClassGeneratedBy = Blueprint;
|
||||
FBlueprintCompileReinstancer::Create(NewClass);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#include "KismetCompiler.h"
|
||||
|
||||
class FTypeScriptCompilerContext final : public FKismetCompilerContext
|
||||
{
|
||||
using Super = FKismetCompilerContext;
|
||||
|
||||
public:
|
||||
FTypeScriptCompilerContext(
|
||||
UBlueprint* SourceSketch, FCompilerResultsLog& MessageLog, const FKismetCompilerOptions& CompilerOptions);
|
||||
|
||||
private:
|
||||
void SpawnNewClass(const FString& NewClassName) override;
|
||||
};
|
||||
@@ -0,0 +1,60 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||
#include "FileSystemOperation.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class PUERTSEDITOR_API UFileSystemOperation : public UBlueprintFunctionLibrary
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File")
|
||||
static bool ReadFile(FString Path, FString& Data);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File")
|
||||
static void WriteFile(FString Path, FString Data);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File")
|
||||
static FString ResolvePath(FString Path);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File")
|
||||
static bool FileExists(FString Path);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File")
|
||||
static bool DirectoryExists(FString Path);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File")
|
||||
static void CreateDirectory(FString Path);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File")
|
||||
static FString GetCurrentDirectory();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File")
|
||||
static TArray<FString> GetDirectories(FString Path);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File")
|
||||
static TArray<FString> GetFiles(FString Path);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File")
|
||||
static void PuertsNotifyChange(FString Path, FString Source);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File")
|
||||
static FString FileMD5Hash(FString Path);
|
||||
|
||||
// UFUNCTION(BlueprintCallable, Category = "File")
|
||||
// static TArray<FString> ReadDirectory(FString Path, TArray<FString> Extensions, TArray<FString> exclude, int32 Depth);
|
||||
};
|
||||
|
||||
#ifdef PUERTS_WITH_SOURCE_CONTROL
|
||||
namespace PuertsSourceControlUtils
|
||||
{
|
||||
PUERTSEDITOR_API bool MakeSourceControlFileWritable(const FString& InFileToMakeWritable);
|
||||
PUERTSEDITOR_API bool CheckoutSourceControlFile(const FString& InFileToCheckout);
|
||||
} // namespace PuertsSourceControlUtils
|
||||
#endif
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Puerts available.
|
||||
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
|
||||
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
|
||||
* which is part of this source code package.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#include "K2Node_CustomEvent.h"
|
||||
#include "PropertyMacros.h"
|
||||
#include "UObject/NoExportTypes.h"
|
||||
#include "PEBlueprintMetaData.h"
|
||||
#include "PEBlueprintAsset.generated.h"
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FPEGraphTerminalType
|
||||
{
|
||||
GENERATED_USTRUCT_BODY()
|
||||
FPEGraphTerminalType() : PinSubCategoryObject(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PEBlueprintAsset")
|
||||
FName PinCategory;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PEBlueprintAsset")
|
||||
UObject* PinSubCategoryObject;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FPEGraphPinType
|
||||
{
|
||||
GENERATED_USTRUCT_BODY()
|
||||
FPEGraphPinType() : PinSubCategoryObject(nullptr), PinContainerType(0), bIsReference(false), bIn(false)
|
||||
{
|
||||
}
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PEBlueprintAsset")
|
||||
FName PinCategory;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PEBlueprintAsset")
|
||||
UObject* PinSubCategoryObject;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PEBlueprintAsset")
|
||||
int PinContainerType;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PEBlueprintAsset")
|
||||
bool bIsReference;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PEBlueprintAsset")
|
||||
bool bIn;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class PUERTSEDITOR_API UPEBlueprintAsset : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(BlueprintReadOnly, Category = "PEBlueprintAsset")
|
||||
UClass* GeneratedClass;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "PEBlueprintAsset")
|
||||
UBlueprint* Blueprint;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "PEBlueprintAsset")
|
||||
UPackage* Package;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "PEBlueprintAsset")
|
||||
bool NeedSave;
|
||||
|
||||
UPROPERTY()
|
||||
bool HasConstructor;
|
||||
|
||||
// Record the variable's location in the .ts file.
|
||||
int32 VariableIndexInTS = 0;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "PEBlueprintAsset")
|
||||
static bool Existed(const FString& InName, const FString& InPath);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "PEBlueprintAsset")
|
||||
bool LoadOrCreate(const FString& InName, const FString& InPath, UClass* ParentClass, int32 InSetFlags, int32 InClearFlags);
|
||||
|
||||
/**
|
||||
* @brief create the class with given meta data
|
||||
* @param InName
|
||||
* @param InPath
|
||||
* @param InParentClass
|
||||
* @param InSetFlags
|
||||
* @param InClearFlags
|
||||
* @param InMetaData
|
||||
* @return
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "PEBlueprintAsset")
|
||||
bool LoadOrCreateWithMetaData(const FString& InName, const FString& InPath, UClass* InParentClass, int32 InSetFlags,
|
||||
int32 InClearFlags, UPEClassMetaData* InMetaData);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "PEBlueprintAsset")
|
||||
void AddParameter(FName InParameterName, FPEGraphPinType InGraphPinType, FPEGraphTerminalType InPinValueType);
|
||||
|
||||
/**
|
||||
* @brief add parameter with given meta data
|
||||
* @param InParameterName
|
||||
* @param InGraphPinType
|
||||
* @param InPinValueType
|
||||
* @param InMetaData
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "PEBlueprintAsset")
|
||||
void AddParameterWithMetaData(
|
||||
FName InParameterName, FPEGraphPinType InGraphPinType, FPEGraphTerminalType InPinValueType, UPEParamMetaData* InMetaData);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "PEBlueprintAsset")
|
||||
void ClearParameter();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "PEBlueprintAsset")
|
||||
void AddFunction(FName InName, bool IsVoid, FPEGraphPinType InGraphPinType, FPEGraphTerminalType InPinValueType,
|
||||
int32 InSetFlags, int32 InClearFlags);
|
||||
|
||||
/**
|
||||
* @brief create the function with given meta data
|
||||
* @param InName
|
||||
* @param IsVoid
|
||||
* @param InGraphPinType
|
||||
* @param InPinValueType
|
||||
* @param InSetFlags
|
||||
* @param InClearFlags
|
||||
* @param InMetaData
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "PEBlueprintAsset")
|
||||
void AddFunctionWithMetaData(FName InName, bool IsVoid, FPEGraphPinType InGraphPinType, FPEGraphTerminalType InPinValueType,
|
||||
int32 InSetFlags, int32 InClearFlags, UPEFunctionMetaData* InMetaData);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "PEBlueprintAsset")
|
||||
void RemoveNotExistedFunction();
|
||||
|
||||
void RemoveComponent(FName ComponentName);
|
||||
|
||||
void SetupAttachment(FName InComponentName, FName InParentComponentName);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "PEBlueprintAsset")
|
||||
void SetupAttachments(TMap<FName, FName> InAttachments);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "PEBlueprintAsset")
|
||||
void AddMemberVariable(FName NewVarName, FPEGraphPinType InGraphPinType, FPEGraphTerminalType InPinValueType, int32 InLFlags,
|
||||
int32 InHFlags, int32 InLifetimeCondition);
|
||||
|
||||
/**
|
||||
* @brief create the property with given meta data
|
||||
* @param InNewVarName
|
||||
* @param InGraphPinType
|
||||
* @param InPinValueType
|
||||
* @param InLFlags
|
||||
* @param InHFLags
|
||||
* @param InLifetimeCondition
|
||||
* @param InMetaData
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "PEBlueprintAsset")
|
||||
void AddMemberVariableWithMetaData(FName InNewVarName, FPEGraphPinType InGraphPinType, FPEGraphTerminalType InPinValueType,
|
||||
int32 InLFlags, int32 InHFLags, int32 InLifetimeCondition, UPEPropertyMetaData* InMetaData);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "PEBlueprintAsset")
|
||||
void RemoveNotExistedMemberVariable();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "PEBlueprintAsset")
|
||||
void RemoveNotExistedComponent();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "PEBlueprintAsset")
|
||||
void Save();
|
||||
|
||||
private:
|
||||
TSet<FName> ComponentsAdded;
|
||||
|
||||
TSet<FName> MemberVariableAdded;
|
||||
|
||||
TSet<FName> FunctionAdded;
|
||||
|
||||
TSet<FName> OverrideAdded;
|
||||
|
||||
TArray<FName> ParameterNames;
|
||||
|
||||
TArray<FEdGraphPinType> ParameterTypes;
|
||||
|
||||
TArray<bool> ParameterIsIn;
|
||||
};
|
||||
@@ -0,0 +1,913 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Puerts available.
|
||||
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
|
||||
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
|
||||
* which is part of this source code package.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PropertyMacros.h"
|
||||
#include "Math/UnitConversion.h"
|
||||
#include "K2Node_CustomEvent.h"
|
||||
#include "K2Node_FunctionEntry.h"
|
||||
#include "Engine/Blueprint.h"
|
||||
|
||||
#include "PEBlueprintMetaData.generated.h"
|
||||
|
||||
/**
|
||||
* @brief since the void_t defined in converter.hpp will introduce v8
|
||||
* define a temporary void_t here
|
||||
*/
|
||||
template <class...>
|
||||
using Void_t = void;
|
||||
|
||||
/**
|
||||
* @brief the utility function collection for meta data
|
||||
*/
|
||||
struct FPEMetaDataUtils
|
||||
{
|
||||
/**
|
||||
* temporary check if a type is defined
|
||||
*/
|
||||
template <typename T, typename = void>
|
||||
struct TFormatValidator
|
||||
{
|
||||
/**
|
||||
* @brief fallback
|
||||
* @param ...
|
||||
* @return
|
||||
*/
|
||||
template <typename... Args>
|
||||
bool operator()(Args&&...) const
|
||||
{
|
||||
// if the field variant is not exist, currently don't do further check
|
||||
UE_LOG(LogTemp, VeryVerbose, TEXT("FFieldVarient is not implemented in current engine"));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief if the field variant is defined, we do the check
|
||||
* @tparam T
|
||||
*/
|
||||
template <typename T>
|
||||
struct TFormatValidator<T, typename std::enable_if<(sizeof(T) > 0)>::type>
|
||||
{
|
||||
/**
|
||||
* @brief real check
|
||||
* @param InField
|
||||
* @param InKey
|
||||
* @param InValue
|
||||
* @param OutMessage
|
||||
* @return
|
||||
*/
|
||||
bool operator()(T InField, FName InKey, const FString& InValue, FString& OutMessage) const
|
||||
{
|
||||
// name pre define
|
||||
static const FName NAME_BlueprintProtected = TEXT("BlueprintProtected");
|
||||
static const FName NAME_ClampMax = TEXT("ClampMax");
|
||||
static const FName NAME_ClampMin = TEXT("ClampMin");
|
||||
static const FName NAME_CommutativeAssociativeBinaryOperator = TEXT("CommutativeAssociativeBinaryOperator");
|
||||
static const FName NAME_DevelopmentStatus = TEXT("DevelopmentStatus");
|
||||
static const FName NAME_DocumentationPolicy = TEXT("DocumentationPolicy");
|
||||
static const FName NAME_ExpandBoolAsExecs = TEXT("ExpandBoolAsExecs");
|
||||
static const FName NAME_ExpandEnumAsExecs = TEXT("ExpandEnumAsExecs");
|
||||
static const FName NAME_UIMax = TEXT("UIMax");
|
||||
static const FName NAME_UIMin = TEXT("UIMin");
|
||||
static const FName NAME_Units = TEXT("Units");
|
||||
|
||||
// a helper function used to check a function is well defined blueprint protected
|
||||
static const auto ValidateFunctionBlueprintProtected = [](UFunction* InFunction)
|
||||
{
|
||||
if (!IsValid(InFunction))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (InFunction->HasAnyFunctionFlags(FUNC_Static))
|
||||
{
|
||||
// Determine if it's a function library
|
||||
UClass* Class = InFunction->GetOuterUClass();
|
||||
while (Class != nullptr && Class->GetSuperClass() != UObject::StaticClass())
|
||||
{
|
||||
Class = Class->GetSuperClass();
|
||||
}
|
||||
|
||||
if (Class != nullptr && Class->GetName() == TEXT("BlueprintFunctionLibrary"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// a helper function used to check a function is well defined binary operator
|
||||
static const auto ValidateFunctionCommutativeAssociativeBinaryOperator = [](UFunction* InFunction)
|
||||
{
|
||||
if (!IsValid(InFunction))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bGoodParams = (InFunction->NumParms == 3);
|
||||
if (bGoodParams)
|
||||
{
|
||||
PropertyMacro* FirstParam = nullptr;
|
||||
PropertyMacro* SecondParam = nullptr;
|
||||
PropertyMacro* ReturnValue = nullptr;
|
||||
|
||||
TFieldIterator<PropertyMacro> It(InFunction);
|
||||
|
||||
auto GetNextParam = [&]()
|
||||
{
|
||||
if (It)
|
||||
{
|
||||
if (It->HasAnyPropertyFlags(CPF_ReturnParm))
|
||||
{
|
||||
ReturnValue = *It;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FirstParam == nullptr)
|
||||
{
|
||||
FirstParam = *It;
|
||||
}
|
||||
else if (SecondParam == nullptr)
|
||||
{
|
||||
SecondParam = *It;
|
||||
}
|
||||
}
|
||||
++It;
|
||||
}
|
||||
};
|
||||
|
||||
GetNextParam();
|
||||
GetNextParam();
|
||||
GetNextParam();
|
||||
ensure(!It);
|
||||
|
||||
if (ReturnValue == nullptr || SecondParam == nullptr || !SecondParam->SameType(FirstParam))
|
||||
{
|
||||
bGoodParams = false;
|
||||
}
|
||||
}
|
||||
|
||||
return bGoodParams;
|
||||
};
|
||||
|
||||
// a helper function sued to check a function is well defined as execs
|
||||
static const auto ValidateFunctionExpandAsExecs = [](UFunction* InFunction, const FString& InValue)
|
||||
{
|
||||
if (!IsValid(InFunction))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// multiple entry parsing in the same format as eg SetParam.
|
||||
TArray<FString> RawGroupings;
|
||||
InValue.ParseIntoArray(RawGroupings, TEXT(","), false);
|
||||
|
||||
PropertyMacro* FirstInput = nullptr;
|
||||
for (const FString& RawGroup : RawGroupings)
|
||||
{
|
||||
TArray<FString> IndividualEntries;
|
||||
RawGroup.ParseIntoArray(IndividualEntries, TEXT("|"));
|
||||
|
||||
for (const FString& Entry : IndividualEntries)
|
||||
{
|
||||
if (Entry.IsEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
auto FoundField = FindUFieldOrFProperty(InFunction, *Entry);
|
||||
if (!FoundField)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PropertyMacro* Prop = FoundField.Get<PropertyMacro>())
|
||||
{
|
||||
if (!Prop->HasAnyPropertyFlags(CPF_ReturnParm) &&
|
||||
|
||||
(!Prop->HasAnyPropertyFlags(CPF_OutParm) || Prop->HasAnyPropertyFlags(CPF_ReferenceParm)))
|
||||
{
|
||||
if (!FirstInput)
|
||||
{
|
||||
FirstInput = Prop;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// function body
|
||||
// check numeric keys
|
||||
if (InKey == NAME_UIMin || InKey == NAME_UIMax || InKey == NAME_ClampMin || InKey == NAME_ClampMax)
|
||||
{
|
||||
if (!InValue.IsNumeric())
|
||||
{
|
||||
OutMessage =
|
||||
FString::Printf(TEXT("Metadata value for '%s' is non-numeric : '%s'"), *InKey.ToString(), *InValue);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// check blueprint protected function
|
||||
if (InKey == NAME_BlueprintProtected)
|
||||
{
|
||||
if (!ValidateFunctionBlueprintProtected(InField.template Get<UFunction>()))
|
||||
{
|
||||
OutMessage =
|
||||
FString::Printf(TEXT("%s doesn't make sense on static method '%s' in a blueprint function library"),
|
||||
*InKey.ToString(), *InField.GetFullName());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// check binary operator function
|
||||
if (InKey == NAME_CommutativeAssociativeBinaryOperator)
|
||||
{
|
||||
if (!ValidateFunctionCommutativeAssociativeBinaryOperator(InField.template Get<UFunction>()))
|
||||
{
|
||||
OutMessage = TEXT(
|
||||
"Commutative asssociative binary operators must have exactly 2 parameters of the same type and a return "
|
||||
"value.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// check expand as execs
|
||||
if (InKey == NAME_ExpandBoolAsExecs || InKey == NAME_ExpandEnumAsExecs)
|
||||
{
|
||||
if (!ValidateFunctionExpandAsExecs(InField.template Get<UFunction>(), InValue))
|
||||
{
|
||||
OutMessage = TEXT("invalid meta data for expand as execs");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// check development status
|
||||
if (InKey == NAME_DevelopmentStatus)
|
||||
{
|
||||
const FString EarlyAccessValue(TEXT("EarlyAccess"));
|
||||
const FString ExperimentalValue(TEXT("Experimental"));
|
||||
if ((InValue != EarlyAccessValue) && (InValue != ExperimentalValue))
|
||||
{
|
||||
OutMessage = FString::Printf(TEXT("'%s' metadata was '%s' but it must be %s or %s"), *InKey.ToString(),
|
||||
*InValue, *ExperimentalValue, *EarlyAccessValue);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// check units
|
||||
if (InKey == NAME_Units)
|
||||
{
|
||||
// Check for numeric property
|
||||
auto* MaybeProperty = InField.template Get<NumericPropertyMacro>();
|
||||
if (MaybeProperty == nullptr && !MaybeProperty->template IsA<StructPropertyMacro>())
|
||||
{
|
||||
OutMessage = TEXT("'Units' meta data can only be applied to numeric and struct properties");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!FUnitConversion::UnitFromString(*InValue))
|
||||
{
|
||||
OutMessage = FString::Printf(
|
||||
TEXT("Unrecognized units (%s) specified for property '%s'"), *InValue, *InField.GetFullName());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// check documentation policy
|
||||
if (InKey == NAME_DocumentationPolicy)
|
||||
{
|
||||
const TCHAR* StrictValue = TEXT("Strict");
|
||||
if (InValue != StrictValue)
|
||||
{
|
||||
OutMessage =
|
||||
FString::Printf(TEXT("'%s' metadata was '%s' but it must be %s"), *InKey.ToString(), *InValue, StrictValue);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief the format validate
|
||||
*/
|
||||
static TFormatValidator<class FFieldVariant> ValidateFormat;
|
||||
|
||||
/**
|
||||
* @brief add specific meta data to ufield
|
||||
* @param InField
|
||||
* @param InMetaData
|
||||
* @return
|
||||
*/
|
||||
static bool AddMetaData(UField* InField, TMap<FName, FString>& InMetaData);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief a helper structure used to store the meta data of a class, @see ClassDeclarationMetaData.h/cpp
|
||||
* currently, we don't need remove methods, also the caller should ensure the internal data consistence
|
||||
* e.g. the show category added should never be added in hide categories...
|
||||
*/
|
||||
UCLASS()
|
||||
class PUERTSEDITOR_API UPEClassMetaData : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief set the class flags, ant notify if placeable specifier is set
|
||||
* @param InFlags
|
||||
* @param bInPlaceable
|
||||
*/
|
||||
UFUNCTION()
|
||||
void SetClassFlags(int32 InFlags, bool bInPlaceable);
|
||||
|
||||
/**
|
||||
* @brief set the specific meta data
|
||||
* @param InName
|
||||
* @param InValue
|
||||
*/
|
||||
UFUNCTION()
|
||||
void SetMetaData(const FString& InName, const FString& InValue);
|
||||
|
||||
/**
|
||||
* @brief set the class should be with in
|
||||
* @param InClassName
|
||||
*/
|
||||
UFUNCTION()
|
||||
void SetClassWithIn(const FString& InClassName);
|
||||
|
||||
/**
|
||||
* @brief set the configuration name
|
||||
* @param InConfigName
|
||||
*/
|
||||
UFUNCTION()
|
||||
void SetConfig(const FString& InConfigName);
|
||||
|
||||
/**
|
||||
* @brief add a category to hide in blueprint
|
||||
* @param InCategory
|
||||
*/
|
||||
UFUNCTION()
|
||||
void AddHideCategory(const FString& InCategory);
|
||||
|
||||
/**
|
||||
* @brief add a category to show in blueprint
|
||||
* @param InCategory
|
||||
*/
|
||||
UFUNCTION()
|
||||
void AddShowCategory(const FString& InCategory);
|
||||
|
||||
/**
|
||||
* @brief add a sub category to show in blueprint
|
||||
* @param InCategory
|
||||
*/
|
||||
UFUNCTION()
|
||||
void AddShowSubCategory(const FString& InCategory);
|
||||
|
||||
/**
|
||||
* @brief add a function to hide in blueprint
|
||||
* @param InFunctionName
|
||||
*/
|
||||
UFUNCTION()
|
||||
void AddHideFunction(const FString& InFunctionName);
|
||||
|
||||
/**
|
||||
* @brief add a function to show in blueprint
|
||||
* @param InFunctionName
|
||||
*/
|
||||
UFUNCTION()
|
||||
void AddShowFunction(const FString& InFunctionName);
|
||||
|
||||
/**
|
||||
* @brief add a category to auto expand in blueprint
|
||||
* @param InCategory
|
||||
*/
|
||||
UFUNCTION()
|
||||
void AddAutoExpandCategory(const FString& InCategory);
|
||||
|
||||
/**
|
||||
* @brief add a category to auto collapse in blueprint
|
||||
* @param InCategory
|
||||
*/
|
||||
UFUNCTION()
|
||||
void AddAutoCollapseCategory(const FString& InCategory);
|
||||
|
||||
/**
|
||||
* @brief forbid a category to auto collapse in blueprint
|
||||
* @param InCategory
|
||||
*/
|
||||
UFUNCTION()
|
||||
void AddDontAutoCollapseCategory(const FString& InCategory);
|
||||
|
||||
/**
|
||||
* @brief add a class group
|
||||
* @param InGroupName
|
||||
*/
|
||||
UFUNCTION()
|
||||
void AddClassGroup(const FString& InGroupName);
|
||||
|
||||
/**
|
||||
* @brief add a sparse data type
|
||||
* @param InType
|
||||
*/
|
||||
UFUNCTION()
|
||||
void AddSparseDataType(const FString& InType);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief apply the meta data to specific class, this should only call at most once
|
||||
* since this function will change the internal status of the meta data
|
||||
* @param InClass
|
||||
* @param InBlueprint
|
||||
* @return
|
||||
*/
|
||||
bool Apply(UClass* InClass, UBlueprint* InBlueprint);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief the helper function used to get the value array like meta data from the given class
|
||||
* @param InClass
|
||||
* @param InMetaDataKey
|
||||
* @param InDelimiter
|
||||
* @param bInCullEmpty
|
||||
* @return
|
||||
*/
|
||||
static TArray<FString> GetClassMetaDataValues(
|
||||
UClass* InClass, const TCHAR* InMetaDataKey, const TCHAR* InDelimiter = TEXT(" "), bool bInCullEmpty = true);
|
||||
|
||||
/**
|
||||
* @brief since blueprint compilation will reset class meta data, so make blueprint sync with class
|
||||
* @param InClass
|
||||
* @param InBlueprint
|
||||
*/
|
||||
bool SyncClassToBlueprint(UClass* InClass, UBlueprint* InBlueprint);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Merges all category properties with the class which at this point only has its parent propagated categories
|
||||
* @param InClass
|
||||
*/
|
||||
void MergeClassCategories(UClass* InClass);
|
||||
|
||||
/**
|
||||
* @brief Merge and validate the class flags, the input class is the class to set meta data
|
||||
* @param InClass
|
||||
* @return if the class flags is changed
|
||||
*/
|
||||
bool MergeAndValidateClassFlags(UClass* InClass);
|
||||
|
||||
/**
|
||||
* @brief set the class meta data
|
||||
* @param InClass
|
||||
* @return
|
||||
*/
|
||||
bool SetClassMetaData(UClass* InClass);
|
||||
|
||||
/**
|
||||
* @brief set and check with class
|
||||
* @param InClass
|
||||
*/
|
||||
void SetAndValidateWithinClass(UClass* InClass);
|
||||
|
||||
/**
|
||||
* @brief set and check the config name
|
||||
* @param InClass
|
||||
*/
|
||||
void SetAndValidateConfigName(UClass* InClass);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief the class flags
|
||||
*/
|
||||
EClassFlags ClassFlags = CLASS_None;
|
||||
|
||||
/**
|
||||
* @brief the meta data
|
||||
*/
|
||||
TMap<FName, FString> MetaData;
|
||||
|
||||
/**
|
||||
* @brief the class with in
|
||||
*/
|
||||
FString ClassWithIn;
|
||||
|
||||
/**
|
||||
* @brief the config name, from where the class to read config variables' value
|
||||
*/
|
||||
FString ConfigName;
|
||||
|
||||
/**
|
||||
* @brief the hide categories in blueprint
|
||||
*/
|
||||
TArray<FString> HideCategories;
|
||||
|
||||
/**
|
||||
* @brief the show categories in blueprint
|
||||
*/
|
||||
TArray<FString> ShowCategories;
|
||||
|
||||
/**
|
||||
* @brief the show sub categories in blueprint
|
||||
*/
|
||||
TArray<FString> ShowSubCategories;
|
||||
|
||||
/**
|
||||
* @brief the hide functions in blueprint
|
||||
*/
|
||||
TArray<FString> HideFunctions;
|
||||
|
||||
/**
|
||||
* @brief the show functions in blueprint
|
||||
*/
|
||||
TArray<FString> ShowFunctions;
|
||||
|
||||
/**
|
||||
* @brief the auto expand categories in blueprint
|
||||
*/
|
||||
TArray<FString> AutoExpandCategories;
|
||||
|
||||
/**
|
||||
* @brief the auto collapse categories in blueprint
|
||||
*/
|
||||
TArray<FString> AutoCollapseCategories;
|
||||
|
||||
/**
|
||||
* @brief the categories will not auto collapse in blueprint
|
||||
*/
|
||||
TArray<FString> DontAutoCollapseCategories;
|
||||
|
||||
/**
|
||||
* @brief the class group names
|
||||
*/
|
||||
TArray<FString> ClassGroupNames;
|
||||
|
||||
/**
|
||||
* @brief the sparse class data types
|
||||
*/
|
||||
TArray<FString> SparseClassDataTypes;
|
||||
|
||||
/**
|
||||
* @brief a boolean indicate if wants to be placeable
|
||||
*/
|
||||
bool bWantsToBePlaceable = false;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief the name of cached category in meta data
|
||||
*/
|
||||
static const TCHAR* NAME_ClassGroupNames;
|
||||
static const TCHAR* NAME_HideCategories;
|
||||
static const TCHAR* NAME_ShowCategories;
|
||||
static const TCHAR* NAME_SparseClassDataTypes;
|
||||
static const TCHAR* NAME_HideFunctions;
|
||||
static const TCHAR* NAME_AutoExpandCategories;
|
||||
static const TCHAR* NAME_AutoCollapseCategories;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief a helper structure used to store the meta data of a function, @see ParseHelper.h
|
||||
*/
|
||||
UCLASS()
|
||||
class PUERTSEDITOR_API UPEFunctionMetaData : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
private:
|
||||
friend class UPEBlueprintAsset;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief set the function flags, since this will called from js, so divide into high and low parts
|
||||
* @param InHighBits
|
||||
* @param InLowBits
|
||||
*/
|
||||
UFUNCTION()
|
||||
void SetFunctionFlags(int32 InHighBits, int32 InLowBits);
|
||||
|
||||
/**
|
||||
* @brief set the function export flags
|
||||
* @param InFlags
|
||||
*/
|
||||
UFUNCTION()
|
||||
void SetFunctionExportFlags(int32 InFlags);
|
||||
|
||||
/**
|
||||
* @brief set the specific meta data
|
||||
* @param InName
|
||||
* @param InValue
|
||||
*/
|
||||
UFUNCTION()
|
||||
void SetMetaData(const FString& InName, const FString& InValue);
|
||||
|
||||
/**
|
||||
* @brief set the cpp implementation function, is this meaningful for blueprint function?
|
||||
* @param InName
|
||||
*/
|
||||
UFUNCTION()
|
||||
void SetCppImplName(const FString& InName);
|
||||
|
||||
/**
|
||||
* @brief set the cpp implementation validation function
|
||||
* @param InName
|
||||
*/
|
||||
UFUNCTION()
|
||||
void SetCppValidationImplName(const FString& InName);
|
||||
|
||||
/**
|
||||
* @brief set the end point name,
|
||||
* @param InEndpointName
|
||||
*/
|
||||
UFUNCTION()
|
||||
void SetEndpointName(const FString& InEndpointName);
|
||||
|
||||
/**
|
||||
* @brief set the rpc id
|
||||
* @param InRPCId
|
||||
*/
|
||||
UFUNCTION()
|
||||
void SetRPCId(int32 InRPCId);
|
||||
|
||||
/**
|
||||
* @brief set the rpc response id
|
||||
* @param InRPCResponseId
|
||||
*/
|
||||
UFUNCTION()
|
||||
void SetRPCResponseId(int32 InRPCResponseId);
|
||||
|
||||
/**
|
||||
* @brief set if the function is sealed event
|
||||
* @param bInSealedEvent
|
||||
*/
|
||||
UFUNCTION()
|
||||
void SetIsSealedEvent(bool bInSealedEvent);
|
||||
|
||||
/**
|
||||
* @brief set if the function is force blueprint impure
|
||||
* @param bInForceBlueprintImpure
|
||||
*/
|
||||
UFUNCTION()
|
||||
void SetForceBlueprintImpure(bool bInForceBlueprintImpure);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief apply to a custom event
|
||||
* @param InCustomEvent
|
||||
*/
|
||||
bool Apply(UK2Node_CustomEvent* InCustomEvent) const;
|
||||
|
||||
/**
|
||||
* @brief apply to a normal function
|
||||
* @param InFunctionEntry
|
||||
*/
|
||||
bool Apply(UK2Node_FunctionEntry* InFunctionEntry) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief
|
||||
* fallback if the custom event not support the user defined meta data
|
||||
* @param bOutChanged
|
||||
* @param ...
|
||||
*/
|
||||
template <typename... Args>
|
||||
static void ApplyCustomEventMetaData(bool& bOutChanged, Args&&...)
|
||||
{
|
||||
bOutChanged = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief add user defined meta data for custom event
|
||||
* @tparam CustomEvent
|
||||
* @param bOutChanged
|
||||
* @param InMetaData
|
||||
* @param InCustomEvent
|
||||
* @return
|
||||
*/
|
||||
template <typename CustomEvent>
|
||||
static auto ApplyCustomEventMetaData(bool& bOutChanged, const TMap<FName, FString>& InMetaData, CustomEvent* InCustomEvent) ->
|
||||
typename std::enable_if<true, Void_t<decltype(std::declval<CustomEvent>().GetUserDefinedMetaData())>>::type
|
||||
{
|
||||
check(IsValid(InCustomEvent));
|
||||
|
||||
// a helper function used to update text value, and return if the value is updated by a new value
|
||||
static const auto UpdateTextMetaData = [](FName InKey, const TMap<FName, FString>& InMetaData, FText& InOutValue) -> bool
|
||||
{
|
||||
const FText NewValue = InMetaData.Contains(InKey) ? FText::FromString(InMetaData[InKey]) : FText{};
|
||||
const bool bChanged = !NewValue.EqualTo(InOutValue);
|
||||
InOutValue = NewValue;
|
||||
return bChanged;
|
||||
};
|
||||
// a helper function used to update boolean value, and return if the value is updated by the new value
|
||||
static const auto UpdateBooleanMetaData = [](FName InKey, const TMap<FName, FString>& InMetaData, bool& InOutValue) -> bool
|
||||
{
|
||||
const bool NewValue = InMetaData.Contains(InKey) ? true : false;
|
||||
const bool bChanged = NewValue != InOutValue;
|
||||
InOutValue = NewValue;
|
||||
return bChanged;
|
||||
};
|
||||
// a helper function sued update string value, return return if the value is updated by the new value
|
||||
static const auto UpdateStringMetaData = [](FName InKey, const TMap<FName, FString>& InMetaData,
|
||||
FString& InOutValue) -> bool
|
||||
{
|
||||
const FString NewValue = InMetaData.Contains(InKey) ? InMetaData[InKey] : FString{};
|
||||
const bool bChanged = NewValue != InOutValue;
|
||||
InOutValue = NewValue;
|
||||
return bChanged;
|
||||
};
|
||||
|
||||
bool bMetaDataChanged = false;
|
||||
auto& MetaDataToSet = InCustomEvent->GetUserDefinedMetaData();
|
||||
|
||||
bMetaDataChanged = UpdateBooleanMetaData(TEXT("CallInEditor"), InMetaData, MetaDataToSet.bCallInEditor) || bMetaDataChanged;
|
||||
bMetaDataChanged = UpdateTextMetaData(TEXT("Category"), InMetaData, MetaDataToSet.Category) || bMetaDataChanged;
|
||||
bMetaDataChanged = UpdateTextMetaData(TEXT("Keywords"), InMetaData, MetaDataToSet.Keywords) || bMetaDataChanged;
|
||||
bMetaDataChanged =
|
||||
UpdateTextMetaData(TEXT("CompactNodeTitle"), InMetaData, MetaDataToSet.CompactNodeTitle) || bMetaDataChanged;
|
||||
bMetaDataChanged = UpdateTextMetaData(TEXT("ToolTip"), InMetaData, MetaDataToSet.ToolTip) || bMetaDataChanged;
|
||||
bMetaDataChanged =
|
||||
UpdateBooleanMetaData(TEXT("DeprecatedFunction"), InMetaData, MetaDataToSet.bIsDeprecated) || bMetaDataChanged;
|
||||
bMetaDataChanged =
|
||||
UpdateStringMetaData(TEXT("DeprecationMessage"), InMetaData, MetaDataToSet.DeprecationMessage) || bMetaDataChanged;
|
||||
|
||||
bOutChanged = bMetaDataChanged;
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief the function flags
|
||||
*/
|
||||
EFunctionFlags FunctionFlags = FUNC_None;
|
||||
|
||||
/**
|
||||
* @brief the function export flags
|
||||
*/
|
||||
int32 FunctionExportFlags = 0;
|
||||
|
||||
/**
|
||||
* @brief the meta data of the function
|
||||
*/
|
||||
TMap<FName, FString> MetaData;
|
||||
|
||||
/**
|
||||
* @brief the cpp implementation name, is this ok for blueprint function? or generated function could be a no-blueprint function
|
||||
* ?
|
||||
*/
|
||||
FString CppImplName;
|
||||
|
||||
/**
|
||||
* @brief the cpp validation implementation name,
|
||||
*/
|
||||
FString CppValidationImplName;
|
||||
|
||||
/**
|
||||
* @brief endpoint name
|
||||
*/
|
||||
FString EndpointName;
|
||||
|
||||
/**
|
||||
* @brief identifier for an RPC call to a platform service
|
||||
*/
|
||||
uint16 RPCId = 0;
|
||||
|
||||
/**
|
||||
* @brief identifier for an RPC call expect a response
|
||||
*/
|
||||
uint16 RPCResponseId = 0;
|
||||
|
||||
/**
|
||||
* @brief whether this function represents a sealed event
|
||||
*/
|
||||
bool bSealedEvent = false;
|
||||
|
||||
/**
|
||||
* @brief true if the function is being forced to be considered as impure by the user
|
||||
*/
|
||||
bool bForceBlueprintImpure = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief a helper structure used to store the meta data of a function parameter
|
||||
*/
|
||||
UCLASS()
|
||||
class PUERTSEDITOR_API UPEParamMetaData : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
private:
|
||||
friend class UPEBlueprintAsset;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief set the parameter's property flags
|
||||
* @param InHighBits
|
||||
* @param InLowBits
|
||||
*/
|
||||
UFUNCTION()
|
||||
void SetParamFlags(int32 InHighBits, int32 InLowBits);
|
||||
|
||||
/**
|
||||
* @brief set specific meta data
|
||||
* @param InName
|
||||
* @param InValue
|
||||
*/
|
||||
UFUNCTION()
|
||||
void SetMetaData(const FString& InName, const FString& InValue);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief apply to pin type
|
||||
* @param PinType
|
||||
* @return
|
||||
*/
|
||||
bool Apply(FEdGraphPinType& PinType) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief the parameter's flags
|
||||
*/
|
||||
EPropertyFlags ParamFlags;
|
||||
|
||||
/**
|
||||
* @brief the meta data
|
||||
*/
|
||||
TMap<FName, FString> MetaData;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief a helper function used to store the meta data of a class's member variable
|
||||
*/
|
||||
UCLASS()
|
||||
class PUERTSEDITOR_API UPEPropertyMetaData : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
private:
|
||||
friend class UPEBlueprintAsset;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief set the property flags
|
||||
* @param InHighBits
|
||||
* @param InLowBits
|
||||
*/
|
||||
UFUNCTION()
|
||||
void SetPropertyFlags(int32 InHighBits, int32 InLowBits);
|
||||
|
||||
/**
|
||||
* @brief set the meta data of the property
|
||||
* @param InName
|
||||
* @param InValue
|
||||
*/
|
||||
UFUNCTION()
|
||||
void SetMetaData(const FString& InName, const FString& InValue);
|
||||
|
||||
/**
|
||||
* @brief set the rep callback name
|
||||
* @param InName
|
||||
*/
|
||||
UFUNCTION()
|
||||
void SetRepCallbackName(const FString& InName);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief apply the meta data to the property
|
||||
* @param Element
|
||||
*/
|
||||
bool Apply(FBPVariableDescription& Element) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief the property's flags
|
||||
*/
|
||||
EPropertyFlags PropertyFlags;
|
||||
|
||||
/**
|
||||
* @brief the function name for a replicated function
|
||||
*/
|
||||
FString RepCallbackName;
|
||||
|
||||
/**
|
||||
* @brief the meta data for the property
|
||||
*/
|
||||
TMap<FName, FString> MetaData;
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "IDirectoryWatcher.h"
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/NoExportTypes.h"
|
||||
#include "PEDirectoryWatcher.generated.h"
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(
|
||||
FDirectoryWatcherCallback, const TArray<FString>&, Added, const TArray<FString>&, Modified, const TArray<FString>&, Removed);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class PUERTSEDITOR_API UPEDirectoryWatcher : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
FDelegateHandle DelegateHandle;
|
||||
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FDirectoryWatcherCallback OnChanged;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File")
|
||||
bool Watch(const FString& InDirectory);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File")
|
||||
void UnWatch();
|
||||
|
||||
UPEDirectoryWatcher();
|
||||
|
||||
~UPEDirectoryWatcher();
|
||||
|
||||
private:
|
||||
FString Directory;
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Puerts available.
|
||||
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
|
||||
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
|
||||
* which is part of this source code package.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <functional>
|
||||
|
||||
#include "Modules/ModuleManager.h"
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
class IPuertsEditorModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
static inline IPuertsEditorModule& Get()
|
||||
{
|
||||
return FModuleManager::LoadModuleChecked<IPuertsEditorModule>("PuertsEditor");
|
||||
}
|
||||
|
||||
static inline bool IsAvailable()
|
||||
{
|
||||
return FModuleManager::Get().IsModuleLoaded("PuertsEditor");
|
||||
}
|
||||
|
||||
virtual void SetCmdImpl(std::function<void(const FString&, const FString&)> Func) = 0;
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making Puerts available.
|
||||
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may be subject to their corresponding license terms.
|
||||
* This file is subject to the terms and conditions defined in file 'LICENSE', which is part of this source code package.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class PuertsEditor : ModuleRules
|
||||
{
|
||||
public PuertsEditor(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PublicDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"Core",
|
||||
"CoreUObject",
|
||||
"UMG",
|
||||
"UnrealEd",
|
||||
"LevelEditor",
|
||||
"Engine",
|
||||
"Slate",
|
||||
"SlateCore",
|
||||
"EditorStyle",
|
||||
"InputCore",
|
||||
"Projects",
|
||||
"JsEnv",
|
||||
"Puerts",
|
||||
"DirectoryWatcher",
|
||||
"AssetRegistry",
|
||||
"KismetCompiler",
|
||||
"BlueprintGraph",
|
||||
"AssetTools"
|
||||
}
|
||||
);
|
||||
|
||||
if (JsEnv.WithSourceControl)
|
||||
{
|
||||
PrivateDependencyModuleNames.Add("SourceControl");
|
||||
PublicDefinitions.Add("PUERTS_WITH_SOURCE_CONTROL");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user