vault backup: 2024-10-12 17:19:45
@@ -0,0 +1,79 @@
|
||||
# Abstract
|
||||
|
||||
- **功能描述:** 指定此类为抽象基类。可被继承,但不可生成对象。
|
||||
- **引擎模块:** Blueprint
|
||||
- **元数据类型:** bool
|
||||
- **作用机制:** 在ClassFlags中添加[CLASS_Abstract](../../../../Flags/EClassFlags/CLASS_Abstract.md)
|
||||
- **常用程度:** ★★★★★
|
||||
|
||||
指定此类为抽象基类。可被继承,但不可生成对象。
|
||||
|
||||
一般是用在XXXBase基类。
|
||||
|
||||
## 示例代码:
|
||||
|
||||
```cpp
|
||||
/*
|
||||
ClassFlags: CLASS_Abstract | CLASS_MatchedSerializers | CLASS_Native | CLASS_RequiredAPI | CLASS_TokenStreamAssembled | CLASS_Intrinsic | CLASS_Constructed
|
||||
*/
|
||||
UCLASS(Blueprintable, abstract)
|
||||
class INSIDER_API UMyClass_Abstract :public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
};
|
||||
|
||||
//测试语句:
|
||||
UMyClass_Abstract* obj=NewObject<UMyClass_Abstract>();
|
||||
```
|
||||
|
||||
## 示例效果:
|
||||
|
||||
在蓝图中的ConstructObject不会出现该类。同时在C++中NewObject也会报错。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
在NewObject的时候会进行Abstract的判断。
|
||||
|
||||
```cpp
|
||||
bool StaticAllocateObjectErrorTests( const UClass* InClass, UObject* InOuter, FName InName, EObjectFlags InFlags)
|
||||
{
|
||||
// Validation checks.
|
||||
if( !InClass )
|
||||
{
|
||||
UE_LOG(LogUObjectGlobals, Fatal, TEXT("Empty class for object %s"), *InName.ToString() );
|
||||
return true;
|
||||
}
|
||||
|
||||
// for abstract classes that are being loaded NOT in the editor we want to error. If they are in the editor we do not want to have an error
|
||||
if (FScopedAllowAbstractClassAllocation::IsDisallowedAbstractClass(InClass, InFlags))
|
||||
{
|
||||
if ( GIsEditor )
|
||||
{
|
||||
const FString ErrorMsg = FString::Printf(TEXT("Class which was marked abstract was trying to be loaded in Outer %s. It will be nulled out on save. %s %s"), *GetPathNameSafe(InOuter), *InName.ToString(), *InClass->GetName());
|
||||
// if we are trying instantiate an abstract class in the editor we'll warn the user that it will be nulled out on save
|
||||
UE_LOG(LogUObjectGlobals, Warning, TEXT("%s"), *ErrorMsg);
|
||||
ensureMsgf(false, TEXT("%s"), *ErrorMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogUObjectGlobals, Fatal, TEXT("%s"), *FString::Printf( TEXT("Can't create object %s in Outer %s: class %s is abstract"), *InName.ToString(), *GetPathNameSafe(InOuter), *InClass->GetName()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FScopedAllowAbstractClassAllocation::IsDisallowedAbstractClass(const UClass* InClass, EObjectFlags InFlags)
|
||||
{
|
||||
if (((InFlags& RF_ClassDefaultObject) == 0) && InClass->HasAnyClassFlags(CLASS_Abstract))
|
||||
{
|
||||
if (AllowAbstractCount == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
```
|
After Width: | Height: | Size: 82 KiB |
@@ -0,0 +1,93 @@
|
||||
# BlueprintType
|
||||
|
||||
- **功能描述:** 可当做变量类型
|
||||
- **引擎模块:** Blueprint
|
||||
- **元数据类型:** bool
|
||||
- **作用机制:** Meta增加[BlueprintType](../../../../Meta/Blueprint/BlueprintType.md)
|
||||
- **关联项:** [NotBlueprintType ](../NotBlueprintType.md)
|
||||
- **常用程度:** ★★★★★
|
||||
|
||||
可当做变量类型。
|
||||
|
||||
关键是设置BlueprintType和NotBlueprintType这两个metadata.
|
||||
|
||||
## 示例代码:
|
||||
|
||||
```cpp
|
||||
|
||||
/*
|
||||
(BlueprintType = true, IncludePath = Class/MyClass_BlueprintType.h, ModuleRelativePath = Class/MyClass_BlueprintType.h)
|
||||
*/
|
||||
UCLASS(BlueprintType)
|
||||
class INSIDER_API UMyClass_BlueprintType :public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
};
|
||||
|
||||
/*
|
||||
(IncludePath = Class/MyClass_BlueprintType.h, ModuleRelativePath = Class/MyClass_BlueprintType.h)
|
||||
*/
|
||||
UCLASS()
|
||||
class INSIDER_API UMyClass_BlueprintType_Child :public UMyClass_BlueprintType
|
||||
{
|
||||
GENERATED_BODY()
|
||||
};
|
||||
|
||||
/*
|
||||
(IncludePath = Class/MyClass_BlueprintType.h, ModuleRelativePath = Class/MyClass_BlueprintType.h, NotBlueprintType = true)
|
||||
*/
|
||||
UCLASS(NotBlueprintType)
|
||||
class INSIDER_API UMyClass_NotBlueprintType :public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
};
|
||||
|
||||
/*
|
||||
(BlueprintType = true, IncludePath = Class/MyClass_BlueprintType.h, ModuleRelativePath = Class/MyClass_BlueprintType.h)
|
||||
*/
|
||||
UCLASS(BlueprintType)
|
||||
class INSIDER_API UMyClass_NotBlueprintType_To_BlueprintType:public UMyClass_NotBlueprintType
|
||||
{
|
||||
GENERATED_BODY()
|
||||
};
|
||||
|
||||
/*
|
||||
(IncludePath = Class/MyClass_BlueprintType.h, ModuleRelativePath = Class/MyClass_BlueprintType.h, NotBlueprintType = true)
|
||||
*/
|
||||
UCLASS(NotBlueprintType)
|
||||
class INSIDER_API UMyClass_BlueprintType_To_NotBlueprintType:public UMyClass_BlueprintType
|
||||
{
|
||||
GENERATED_BODY()
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## 示例结果:
|
||||
|
||||
带有BlueprintType =true的才可以当作变量
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
在UEdGraphSchema_K2::IsAllowableBlueprintVariableType的3个重载函数分别判断UEnum,UClass,UScriptStruct能否当作变量。
|
||||
|
||||
```cpp
|
||||
用UEdGraphSchema_K2::IsAllowableBlueprintVariableType来判断
|
||||
|
||||
const UClass* ParentClass = InClass;
|
||||
while(ParentClass)
|
||||
{
|
||||
// Climb up the class hierarchy and look for "BlueprintType" and "NotBlueprintType" to see if this class is allowed.
|
||||
if(ParentClass->GetBoolMetaData(FBlueprintMetadata::MD_AllowableBlueprintVariableType)
|
||||
|| ParentClass->HasMetaData(FBlueprintMetadata::MD_BlueprintSpawnableComponent))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if(ParentClass->GetBoolMetaData(FBlueprintMetadata::MD_NotAllowableBlueprintVariableType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ParentClass = ParentClass->GetSuperClass();
|
||||
}
|
||||
```
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,96 @@
|
||||
# Blueprintable
|
||||
|
||||
- **功能描述:** 可以在蓝图里被继承,隐含的作用也可当变量类型
|
||||
- **引擎模块:** Blueprint
|
||||
- **元数据类型:** bool
|
||||
- **作用机制:** 在Meta添加[IsBlueprintBase](../../../../Meta/Blueprint/IsBlueprintBase.md)和[BlueprintType](../../../../Meta/Blueprint/BlueprintType.md)
|
||||
- **关联项:** [NotBlueprintable](../NotBlueprintable.md)
|
||||
- **常用程度:** ★★★★★
|
||||
|
||||
可以在蓝图里被继承,隐含的作用也可当变量类型。
|
||||
|
||||
当设置Blueprintable标记的时候,会隐含的设置上BlueprintType = true的metadata。去除的时候,也会相应的去除掉BlueprintType = true。
|
||||
|
||||
## 示例代码:
|
||||
|
||||
```cpp
|
||||
/*
|
||||
(BlueprintType = true, IncludePath = Class/MyClass_Blueprintable.h, IsBlueprintBase = true, ModuleRelativePath = Class/MyClass_Blueprintable.h)
|
||||
*/
|
||||
UCLASS(Blueprintable)
|
||||
class INSIDER_API UMyClass_Blueprintable :public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
};
|
||||
|
||||
/*
|
||||
(IncludePath = Class/MyClass_Blueprintable.h, IsBlueprintBase = false, ModuleRelativePath = Class/MyClass_Blueprintable.h)
|
||||
*/
|
||||
UCLASS(NotBlueprintable)
|
||||
class INSIDER_API UMyClass_NotBlueprintable :public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
};
|
||||
|
||||
/*
|
||||
(BlueprintType = true, IncludePath = Class/MyClass_Blueprintable.h, IsBlueprintBase = true, ModuleRelativePath = Class/MyClass_Blueprintable.h)
|
||||
*/
|
||||
UCLASS(Blueprintable)
|
||||
class INSIDER_API UMyClass_NotBlueprintable_To_Blueprintable :public UMyClass_NotBlueprintable
|
||||
{
|
||||
GENERATED_BODY()
|
||||
};
|
||||
|
||||
/*
|
||||
(IncludePath = Class/MyClass_Blueprintable.h, IsBlueprintBase = false, ModuleRelativePath = Class/MyClass_Blueprintable.h)
|
||||
*/
|
||||
UCLASS(NotBlueprintable)
|
||||
class INSIDER_API UMyClass_Blueprintable_To_NotBlueprintable :public UMyClass_Blueprintable
|
||||
{
|
||||
GENERATED_BODY()
|
||||
};
|
||||
```
|
||||
|
||||
## 示例效果:
|
||||
|
||||
只有带有Blueprintable才可以被选做基类。
|
||||
|
||||

|
||||
|
||||
不过是否能够当做变量的规则,还是会依赖父类的Blueprint标记。因此以下这3个都是可以当做变量的。
|
||||
|
||||
其中UMyClass_Blueprintable_To_NotBlueprintable可以当做变量是因为父类UMyClass_Blueprintable可以当做变量,因此就继承了下来。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
可见MD_IsBlueprintBase的判断用来决定是否能创建子类
|
||||
|
||||
```cpp
|
||||
bool FKismetEditorUtilities::CanCreateBlueprintOfClass(const UClass* Class)
|
||||
{
|
||||
bool bCanCreateBlueprint = false;
|
||||
|
||||
if (Class)
|
||||
{
|
||||
bool bAllowDerivedBlueprints = false;
|
||||
GConfig->GetBool(TEXT("Kismet"), TEXT("AllowDerivedBlueprints"), /*out*/ bAllowDerivedBlueprints, GEngineIni);
|
||||
|
||||
bCanCreateBlueprint = !Class->HasAnyClassFlags(CLASS_Deprecated)
|
||||
&& !Class->HasAnyClassFlags(CLASS_NewerVersionExists)
|
||||
&& (!Class->ClassGeneratedBy || (bAllowDerivedBlueprints && !IsClassABlueprintSkeleton(Class)));
|
||||
|
||||
const bool bIsBPGC = (Cast<UBlueprintGeneratedClass>(Class) != nullptr);
|
||||
|
||||
const bool bIsValidClass = Class->GetBoolMetaDataHierarchical(FBlueprintMetadata::MD_IsBlueprintBase)
|
||||
|| (Class == UObject::StaticClass())
|
||||
|| (Class == USceneComponent::StaticClass() || Class == UActorComponent::StaticClass())
|
||||
|| bIsBPGC; // BPs are always considered inheritable
|
||||
|
||||
bCanCreateBlueprint &= bIsValidClass;
|
||||
}
|
||||
|
||||
return bCanCreateBlueprint;
|
||||
}
|
||||
```
|
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,60 @@
|
||||
# Const
|
||||
|
||||
- **功能描述:** 表示本类的内部属性不可在蓝图中被修改,只读不可写。
|
||||
- **引擎模块:** Blueprint
|
||||
- **元数据类型:** bool
|
||||
- **作用机制:** 在ClassFlags中添加[CLASS_Abstract](../../../../Flags/EClassFlags/CLASS_Const.md)
|
||||
- **常用程度:** ★★★
|
||||
|
||||
表示本类的内部属性不可在蓝图中被修改,只读不可写。
|
||||
|
||||
继承的蓝图类也是如此。其实就是自动的给本类和子类上添加const的标志。注意只是在蓝图里检查,C++依然可以随意改变,遵循C++的规则。所以这个const是只给蓝图用的,在蓝图里检查。函数依然可以随便调用,只是没有属性的Set方法了,也不能改变了。
|
||||
|
||||
## 示例代码:
|
||||
|
||||
```cpp
|
||||
/*
|
||||
ClassFlags: CLASS_MatchedSerializers | CLASS_Native | CLASS_Const | CLASS_RequiredAPI | CLASS_TokenStreamAssembled | CLASS_Intrinsic | CLASS_Constructed
|
||||
*/
|
||||
UCLASS(Blueprintable, Const)
|
||||
class INSIDER_API UMyClass_Const :public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
int32 MyProperty = 123;
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void MyFunc() { ++MyProperty; }
|
||||
};
|
||||
```
|
||||
|
||||
## 示例效果:
|
||||
|
||||
在蓝图子类中尝试修改属性会报错。
|
||||
|
||||

|
||||
|
||||
跟蓝图Class Settings里打开这个开关设定的一样
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
Const类生成的实例属性对带有const的标记,从而阻止修改自身的属性。
|
||||
|
||||
```cpp
|
||||
void FKCHandler_VariableSet::InnerAssignment(FKismetFunctionContext& Context, UEdGraphNode* Node, UEdGraphPin* VariablePin, UEdGraphPin* ValuePin)
|
||||
{
|
||||
if (!(*VariableTerm)->IsTermWritable())
|
||||
{
|
||||
CompilerContext.MessageLog.Error(*LOCTEXT("WriteConst_Error", "Cannot write to const @@").ToString(), VariablePin);
|
||||
}
|
||||
}
|
||||
|
||||
bool FBPTerminal::IsTermWritable() const
|
||||
{
|
||||
return !bIsLiteral && !bIsConst;
|
||||
}
|
||||
```
|
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 28 KiB |
@@ -0,0 +1,108 @@
|
||||
# HideFunctions
|
||||
|
||||
- **功能描述:** 在子类的函数覆盖列表里隐藏掉某些函数。
|
||||
- **引擎模块:** Blueprint
|
||||
- **元数据类型:** strings=(abc,"d|e","x|y|z")
|
||||
- **作用机制:** 在Meta中增加[HideFunctions](../../../../Meta/Blueprint/HideFunctions.md)
|
||||
- **关联项:** [ShowFunctions](../ShowFunctions.md)
|
||||
- **常用程度:** ★★
|
||||
|
||||
在子类的函数覆盖列表里隐藏掉某些函数。
|
||||
|
||||
- 在蓝图中鼠标右键依然可以查看到该类下BlueprintCallable的函数,依然可以调用,本标记只是用在类的函数覆盖列表上。
|
||||
- HideFunctions其实只能填函数名字,想要隐藏一个目录下的函数,是需要HideCategories再额外定义的。
|
||||
|
||||
源码中只有一个地方用到,一个很好的示例是UCameraComponent中定义的SetFieldOfView和SetAspectRatio,对UCineCameraComponent 来说是无意义的,因此隐藏掉会更好。
|
||||
|
||||
```cpp
|
||||
class ENGINE_API UCameraComponent : public USceneComponent
|
||||
{
|
||||
UFUNCTION(BlueprintCallable, Category = Camera)
|
||||
virtual void SetFieldOfView(float InFieldOfView) { FieldOfView = InFieldOfView; }
|
||||
UFUNCTION(BlueprintCallable, Category = Camera)
|
||||
void SetAspectRatio(float InAspectRatio) { AspectRatio = InAspectRatio; }
|
||||
}
|
||||
|
||||
UCLASS(HideCategories = (CameraSettings), HideFunctions = (SetFieldOfView, SetAspectRatio), Blueprintable, ClassGroup = Camera, meta = (BlueprintSpawnableComponent), Config = Engine)
|
||||
class CINEMATICCAMERA_API UCineCameraComponent : public UCameraComponent
|
||||
```
|
||||
|
||||
## 示例代码:
|
||||
|
||||
```cpp
|
||||
UCLASS(Blueprintable, HideFunctions = (MyFunc1, MyEvent2),hideCategories= EventCategory2)
|
||||
class INSIDER_API AMyClass_HideFunctions :public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void MyFunc1() {}
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void MyFunc2() {}
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "FuncCategory1")
|
||||
void MyFuncInCategory1() {}
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "FuncCategory2")
|
||||
void MyFuncInCategory2() {}
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintImplementableEvent)
|
||||
void MyEvent1();
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent)
|
||||
void MyEvent2();
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "EventCategory1")
|
||||
void MyEventInCategory1();
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "EventCategory2")
|
||||
void MyEventInCategory2();
|
||||
};
|
||||
|
||||
UCLASS(Blueprintable, ShowFunctions = (MyEvent2),showCategories= EventCategory2)
|
||||
class INSIDER_API AMyClass_ShowFunctions :public AMyClass_HideFunctions
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
|
||||
};
|
||||
```
|
||||
|
||||
## 示例效果:
|
||||
|
||||
发现Callable的函数是依然可以调用的。
|
||||
|
||||

|
||||
|
||||
在HideFunction子类里,函数重载会发现少两个
|
||||
|
||||

|
||||
|
||||
在ShowFunction的子类里可以重新打开Event2和EventCategory2
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
原理显示,HideFunctions其实只能填函数名字,想要隐藏一个目录下的函数,是需要HideCategories再额外定义的。
|
||||
|
||||
```cpp
|
||||
bool IsFunctionHiddenFromClass( const UFunction* InFunction,const UClass* Class )
|
||||
{
|
||||
bool bResult = false;
|
||||
if( InFunction )
|
||||
{
|
||||
bResult = Class->IsFunctionHidden( *InFunction->GetName() );
|
||||
|
||||
static const FName FunctionCategory(TEXT("Category")); // FBlueprintMetadata::MD_FunctionCategory
|
||||
if( !bResult && InFunction->HasMetaData( FunctionCategory ) )
|
||||
{
|
||||
FString const& FuncCategory = InFunction->GetMetaData(FunctionCategory);
|
||||
bResult = FEditorCategoryUtils::IsCategoryHiddenFromClass(Class, FuncCategory);
|
||||
}
|
||||
}
|
||||
return bResult;
|
||||
}
|
||||
```
|
After Width: | Height: | Size: 104 KiB |
After Width: | Height: | Size: 116 KiB |
After Width: | Height: | Size: 59 KiB |
@@ -0,0 +1,24 @@
|
||||
# NeedsDeferredDependencyLoading
|
||||
|
||||
- **引擎模块:** Blueprint
|
||||
- **元数据类型:** bool
|
||||
- **作用机制:** 在ClassFlags增加[CLASS_NeedsDeferredDependencyLoading](../../../Flags/EClassFlags/CLASS_NeedsDeferredDependencyLoading.md)
|
||||
|
||||
## 源码例子:
|
||||
|
||||
```cpp
|
||||
UCLASS(NeedsDeferredDependencyLoading, MinimalAPI)
|
||||
class UBlueprintGeneratedClass : public UClass, public IBlueprintPropertyGuidProvider
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
## 原理:
|
||||
|
||||
```cpp
|
||||
if (ClassFlags.HasAnyFlags(EClassFlags.NeedsDeferredDependencyLoading) && !IsChildOf(Session.UClass))
|
||||
{
|
||||
// CLASS_NeedsDeferredDependencyLoading can only be set on classes derived from UClass
|
||||
this.LogError($"'NeedsDeferredDependencyLoading' is set on '{SourceName}' but the flag can only be used with classes derived from UClass.");
|
||||
}
|
||||
```
|
@@ -0,0 +1,8 @@
|
||||
# NotBlueprintType
|
||||
|
||||
- **功能描述:** 不可当做变量类型
|
||||
- **引擎模块:** Blueprint
|
||||
- **元数据类型:** bool
|
||||
- **作用机制:** Meta移除[BlueprintType](../../../Meta/Blueprint/BlueprintType.md)
|
||||
- **关联项:** [BlueprintType](BlueprintType/BlueprintType.md)
|
||||
- **常用程度:★★★★**
|
@@ -0,0 +1,9 @@
|
||||
# NotBlueprintable
|
||||
|
||||
- **功能描述:** 不可在蓝图里继承,隐含作用也不可当作变量
|
||||
- **引擎模块:** Blueprint
|
||||
- **元数据类型:** bool
|
||||
- **作用机制:** 在Meta去除[IsBlueprintBase](../../../Meta/Blueprint/IsBlueprintBase.md)和[BlueprintType](../../../Meta/Blueprint/BlueprintType.md)
|
||||
- **关联项:** [Blueprintable](Blueprintable/Blueprintable.md)
|
||||
- **常用程度:★★★★**
|
||||
|
@@ -0,0 +1,31 @@
|
||||
# ShowFunctions
|
||||
|
||||
- **功能描述:** 在子类的函数覆盖列表里重新打开某些函数。
|
||||
- **引擎模块:** Blueprint
|
||||
- **元数据类型:** strings=(abc,"d|e","x|y|z")
|
||||
- **作用机制:** 在Meta中去除[HideFunctions](../../../Meta/Blueprint/HideFunctions.md)
|
||||
- **关联项:** [HideFunctions](HideFunctions/HideFunctions.md)
|
||||
- **常用程度:★★**
|
||||
|
||||
在子类的函数覆盖列表里重新打开某些函数。
|
||||
|
||||
测试代码和效果图见HideFunctions。
|
||||
|
||||
## 原理:
|
||||
|
||||
UHT中的代码,可见ShowFunctions的作用就是去除掉之前设置的HideFunctions。
|
||||
|
||||
```cpp
|
||||
private void MergeCategories()
|
||||
{
|
||||
MergeShowCategories();
|
||||
|
||||
// Merge ShowFunctions and HideFunctions
|
||||
AppendStringListMetaData(SuperClass, UhtNames.HideFunctions, HideFunctions);
|
||||
foreach (string value in ShowFunctions)
|
||||
{
|
||||
HideFunctions.RemoveSwap(value);
|
||||
}
|
||||
ShowFunctions.Clear();
|
||||
}
|
||||
```
|
@@ -0,0 +1,263 @@
|
||||
# SparseClassDataType
|
||||
|
||||
- **功能描述:** 让Actor的一些重复不变的数据存放在一个共同的结构里,以达到减少内容使用量的目的
|
||||
- **引擎模块:** Blueprint
|
||||
- **元数据类型:** string="abc"
|
||||
- **作用机制:** 在Meta中增加[SparseClassDataTypes](../../../../Meta/Blueprint/SparseClassDataTypes.md)
|
||||
- **关联项:** [NoGetter](../../../../Meta/SparseDataType/NoGetter/NoGetter.md)
|
||||
- **常用程度:** ★★★
|
||||
|
||||
这是个重构和性能优化的点。在使用SparseClassDataType的时候,分为两种情况,一是以前的Actor想利用这个特性来优化,二是新创建的Actor一开始就想使用这个特性。
|
||||
|
||||
## 示例用法:
|
||||
|
||||
分为两部分:
|
||||
|
||||
一,旧的Actor存在冗余属性
|
||||
|
||||
简而言之是那些不会在BP改变的属性。C++方面,如果有修改这些属性,也要修改为使用Get函数来获得,从而转到SparseDataStruct里去。
|
||||
|
||||
```cpp
|
||||
UCLASS(Blueprintable, BlueprintType)
|
||||
class INSIDER_API AMyActor_SparseClassDataTypes :public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
int32 MyInt_EditDefaultOnly = 123;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly)
|
||||
int32 MyInt_BlueprintReadOnly = 1024;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
||||
FString MyString_EditDefault_ReadOnly = TEXT("MyName");
|
||||
|
||||
UPROPERTY(EditAnywhere)
|
||||
float MyFloat_EditAnywhere = 555.f;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
float MyFloat_BlueprintReadWrite = 666.f;
|
||||
};
|
||||
```
|
||||
|
||||
改为以下的代码。把属性用WITH_EDITORONLY_DATA包起来,以示意只在editor下做操作,在runtime是已经消除的。加上_DEPRECATED后缀标记也是为了进一步提醒原先BP里的访问要去除。重载MoveDataToSparseClassDataStruct以便把现在BP Class Defaults里配置的值拷贝给新的FMySparseClassData结构数值。
|
||||
|
||||
```cpp
|
||||
USTRUCT(BlueprintType)
|
||||
struct FMySparseClassData
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
int32 MyInt_EditDefaultOnly = 123;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
||||
int32 MyInt_BlueprintReadOnly = 1024;
|
||||
|
||||
// "GetByRef" means that Blueprint graphs access a const ref instead of a copy.
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta=(GetByRef))
|
||||
FString MyString_EditDefault_ReadOnly = TEXT("MyName");
|
||||
};
|
||||
|
||||
UCLASS(Blueprintable, BlueprintType,SparseClassDataTypes= MySparseClassData)
|
||||
class INSIDER_API AMyActor_SparseClassDataTypes :public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
#if WITH_EDITOR
|
||||
// ~ This function transfers existing data into FMySparseClassData.
|
||||
virtual void MoveDataToSparseClassDataStruct() const override;
|
||||
#endif // WITH_EDITOR
|
||||
public:
|
||||
#if WITH_EDITORONLY_DATA
|
||||
UPROPERTY()
|
||||
int32 MyInt_EditDefaultOnly_DEPRECATED = 123;
|
||||
|
||||
UPROPERTY()
|
||||
int32 MyInt_BlueprintReadOnly_DEPRECATED = 1024;
|
||||
|
||||
UPROPERTY()
|
||||
FString MyString_EditDefault_ReadOnly_DEPRECATED = TEXT("MyName");
|
||||
#endif // WITH_EDITORONLY_DATA
|
||||
public:
|
||||
UPROPERTY(EditAnywhere)
|
||||
float MyFloat_EditAnywhere = 555.f;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
float MyFloat_BlueprintReadWrite = 666.f;
|
||||
};
|
||||
|
||||
//cpp
|
||||
#if WITH_EDITOR
|
||||
void AMyActor_SparseClassDataTypes::MoveDataToSparseClassDataStruct() const
|
||||
{
|
||||
// make sure we don't overwrite the sparse data if it has been saved already
|
||||
UBlueprintGeneratedClass* BPClass = Cast<UBlueprintGeneratedClass>(GetClass());
|
||||
if (BPClass == nullptr || BPClass->bIsSparseClassDataSerializable == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Super::MoveDataToSparseClassDataStruct();
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
// Unreal Header Tool (UHT) will create GetMySparseClassData automatically.
|
||||
FMySparseClassData* SparseClassData = GetMySparseClassData();
|
||||
|
||||
// Modify these lines to include all Sparse Class Data properties.
|
||||
SparseClassData->MyInt_EditDefaultOnly = MyInt_EditDefaultOnly_DEPRECATED;
|
||||
SparseClassData->MyInt_BlueprintReadOnly = MyInt_BlueprintReadOnly_DEPRECATED;
|
||||
SparseClassData->MyString_EditDefault_ReadOnly = MyString_EditDefault_ReadOnly_DEPRECATED;
|
||||
#endif // WITH_EDITORONLY_DATA
|
||||
|
||||
}
|
||||
#endif // WITH_EDITOR
|
||||
```
|
||||
|
||||
在BP的PostLoad加载之后,会自动的调用MoveDataToSparseClassDataStruct,所以要在内部检测bIsSparseClassDataSerializable.
|
||||
|
||||
```cpp
|
||||
void UBlueprintGeneratedClass::PostLoadDefaultObject(UObject* Object)
|
||||
{
|
||||
FScopeLock SerializeAndPostLoadLock(&SerializeAndPostLoadCritical);
|
||||
|
||||
Super::PostLoadDefaultObject(Object);
|
||||
|
||||
if (Object == ClassDefaultObject)
|
||||
{
|
||||
// Rebuild the custom property list used in post-construct initialization logic. Note that PostLoad() may have altered some serialized properties.
|
||||
UpdateCustomPropertyListForPostConstruction();
|
||||
|
||||
// Restore any property values from config file
|
||||
if (HasAnyClassFlags(CLASS_Config))
|
||||
{
|
||||
ClassDefaultObject->LoadConfig();
|
||||
}
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
Object->MoveDataToSparseClassDataStruct();
|
||||
|
||||
if (Object->GetSparseClassDataStruct())
|
||||
{
|
||||
// now that any data has been moved into the sparse data structure we can safely serialize it
|
||||
bIsSparseClassDataSerializable = true;
|
||||
}
|
||||
|
||||
ConformSparseClassData(Object);
|
||||
#endif
|
||||
}
|
||||
```
|
||||
|
||||
在UClass下
|
||||
|
||||
```cpp
|
||||
protected:
|
||||
/** This is where we store the data that is only changed per class instead of per instance */
|
||||
void* SparseClassData;
|
||||
|
||||
/** The struct used to store sparse class data. */
|
||||
UScriptStruct* SparseClassDataStruct;
|
||||
|
||||
在构造UClass的时候,会SetSparseClassDataStruct来把结构传进去,因此就把结构关联起来。
|
||||
UClass* Z_Construct_UClass_AMyActor_SparseClassDataTypes()
|
||||
{
|
||||
if (!Z_Registration_Info_UClass_AMyActor_SparseClassDataTypes.OuterSingleton)
|
||||
{
|
||||
UECodeGen_Private::ConstructUClass(Z_Registration_Info_UClass_AMyActor_SparseClassDataTypes.OuterSingleton, Z_Construct_UClass_AMyActor_SparseClassDataTypes_Statics::ClassParams);
|
||||
Z_Registration_Info_UClass_AMyActor_SparseClassDataTypes.OuterSingleton->SetSparseClassDataStruct(AMyActor_SparseClassDataTypes::StaticGetMySparseClassDataScriptStruct());
|
||||
}
|
||||
return Z_Registration_Info_UClass_AMyActor_SparseClassDataTypes.OuterSingleton;
|
||||
}
|
||||
```
|
||||
|
||||
注意此时BP里没法blueprint get 那些ReadOnly的变量的,因为有_DEPRECATED在占用着。一种方法是自己再额外定义Gettter方法:
|
||||
|
||||
```cpp
|
||||
UFUNCTION(BlueprintPure)
|
||||
int32 GetMyMyInt_BlueprintReadOnly()const
|
||||
{
|
||||
return GetMySparseClassData()->MyInt_BlueprintReadOnly;
|
||||
}
|
||||
```
|
||||
|
||||
二,另一种方法是在MoveDataToSparseClassDataStruct之后(记得要打开编辑器,并且打开子类BP蓝图后保存)就干脆删除掉AMyActor_SparseClassDataTypes里的冗余属性,全部使用FMySparseClassData中的值。从而变成:
|
||||
|
||||
```cpp
|
||||
USTRUCT(BlueprintType)
|
||||
struct FMySparseClassData
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
int32 MyInt_EditDefaultOnly = 123;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
||||
int32 MyInt_BlueprintReadOnly = 1024;
|
||||
|
||||
// "GetByRef" means that Blueprint graphs access a const ref instead of a copy.
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta=(GetByRef))
|
||||
FString MyString_EditDefault_ReadOnly = TEXT("MyName");
|
||||
};
|
||||
|
||||
UCLASS(Blueprintable, BlueprintType,SparseClassDataTypes= MySparseClassData)
|
||||
class INSIDER_API AMyActor_SparseClassDataTypes :public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(EditAnywhere)
|
||||
float MyFloat_EditAnywhere = 555.f;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
float MyFloat_BlueprintReadWrite = 666.f;
|
||||
};
|
||||
```
|
||||
|
||||
这样就达到了最终的效果,这个效果也对新的Actor要采用冗余属性的结果也是一样的。注意此时,在BP里是依然可以访问BlueprintReadOnly属性的,因为UHT和BP系统已经帮我们加了一层访问方便的控制。
|
||||
|
||||
## 示例效果:
|
||||
|
||||
UHT会帮我们生成C++访问函数:
|
||||
|
||||
```cpp
|
||||
#define FID_Hello_Source_Insider_Class_Trait_MyClass_SparseClassDataTypes_h_30_SPARSE_DATA \
|
||||
FMySparseClassData* GetMySparseClassData(); \
|
||||
FMySparseClassData* GetMySparseClassData() const; \
|
||||
const FMySparseClassData* GetMySparseClassData(EGetSparseClassDataMethod GetMethod) const; \
|
||||
static UScriptStruct* StaticGetMySparseClassDataScriptStruct(); \
|
||||
int32 GetMyInt_EditDefaultOnly() \
|
||||
{ \
|
||||
return GetMySparseClassData()->MyInt_EditDefaultOnly; \
|
||||
} \
|
||||
int32 GetMyInt_EditDefaultOnly() const \
|
||||
{ \
|
||||
return GetMySparseClassData()->MyInt_EditDefaultOnly; \
|
||||
} \
|
||||
int32 GetMyInt_BlueprintReadOnly() \
|
||||
{ \
|
||||
return GetMySparseClassData()->MyInt_BlueprintReadOnly; \
|
||||
} \
|
||||
int32 GetMyInt_BlueprintReadOnly() const \
|
||||
{ \
|
||||
return GetMySparseClassData()->MyInt_BlueprintReadOnly; \
|
||||
} \
|
||||
const FString& GetMyString_EditDefault_ReadOnly() \
|
||||
{ \
|
||||
return GetMySparseClassData()->MyString_EditDefault_ReadOnly; \
|
||||
} \
|
||||
const FString& GetMyString_EditDefault_ReadOnly() const \
|
||||
{ \
|
||||
return GetMySparseClassData()->MyString_EditDefault_ReadOnly; \
|
||||
}
|
||||
```
|
||||
|
||||
在BP中依然可以访问:
|
||||
|
||||

|
||||
|
||||
在Class Defaults里也可以改变值:
|
||||
|
||||

|
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 18 KiB |