vault backup: 2024-10-12 17:19:45
@@ -0,0 +1,36 @@
|
||||
# BlueprintAssignable
|
||||
|
||||
- **功能描述:** 在蓝图中可以为这个多播委托绑定事件
|
||||
|
||||
- **元数据类型:** bool
|
||||
- **引擎模块:** Blueprint
|
||||
- **限制类型:** Multicast Delegates
|
||||
- **作用机制:** 在PropertyFlags中加入[CPF_BlueprintAssignable](../../../../Flags/EPropertyFlags/CPF_BlueprintAssignable.md)
|
||||
- **常用程度:** ★★★
|
||||
|
||||
## C++的测试代码:
|
||||
|
||||
```cpp
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMyDynamicMulticastDelegate_One, int32, Value);
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, BlueprintAssignable, BlueprintCallable)
|
||||
FMyDynamicMulticastDelegate_One MyMulticastDelegateAssignAndCall;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, BlueprintCallable)
|
||||
FMyDynamicMulticastDelegate_One MyMulticastDelegateCall;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, BlueprintAssignable)
|
||||
FMyDynamicMulticastDelegate_One MyMulticastDelegateAssign;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
FMyDynamicMulticastDelegate_One MyMulticastDelegate;
|
||||
|
||||
```
|
||||
|
||||
## 蓝图中的表现:
|
||||
|
||||

|
||||
|
||||
因此一般建议二者标记都加上:
|
||||
|
||||

|
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,23 @@
|
||||
# BlueprintAuthorityOnly
|
||||
|
||||
- **功能描述:** 只能绑定为BlueprintAuthorityOnly的事件,让该多播委托只接受在服务端运行的事件
|
||||
|
||||
- **元数据类型:** bool
|
||||
- **引擎模块:** Blueprint, Network
|
||||
- **限制类型:** Multicast Delegates
|
||||
- **作用机制:** 在PropertyFlags中加入[CPF_BlueprintAuthorityOnly](../../../../Flags/EPropertyFlags/CPF_BlueprintAuthorityOnly.md)
|
||||
- **常用程度:** ★★★
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, BlueprintAssignable, BlueprintCallable)
|
||||
FMyDynamicMulticastDelegate_One MyMulticastDelegateAssignAndCall;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, BlueprintAssignable, BlueprintCallable, BlueprintAuthorityOnly)
|
||||
FMyDynamicMulticastDelegate_One MyMulticastDelegateAuthorityOnly;
|
||||
```
|
||||
|
||||
## 蓝图中表现:
|
||||
|
||||

|
After Width: | Height: | Size: 96 KiB |
@@ -0,0 +1,47 @@
|
||||
# BlueprintCallable
|
||||
|
||||
- **功能描述:** 在蓝图中可以调用这个多播委托
|
||||
|
||||
- **元数据类型:** bool
|
||||
- **引擎模块:** Blueprint
|
||||
- **限制类型:** Multicast Delegates
|
||||
- **作用机制:** 在PropertyFlags中加入[CPF_BlueprintCallable](../../../../Flags/EPropertyFlags/CPF_BlueprintCallable.md)
|
||||
- **常用程度:** ★★★
|
||||
|
||||
在蓝图中可以调用这个多播委托。
|
||||
|
||||
## 示例代码:
|
||||
|
||||
```cpp
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMyDynamicMulticastDelegate_One, int32, Value);
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, BlueprintAssignable, BlueprintCallable)
|
||||
FMyDynamicMulticastDelegate_One MyMulticastDelegateAssignAndCall;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, BlueprintCallable)
|
||||
FMyDynamicMulticastDelegate_One MyMulticastDelegateCall;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, BlueprintAssignable)
|
||||
FMyDynamicMulticastDelegate_One MyMulticastDelegateAssign;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
FMyDynamicMulticastDelegate_One MyMulticastDelegate;
|
||||
```
|
||||
|
||||
## 示例效果:
|
||||
|
||||

|
||||
|
||||
注意BlueprintAssignable和BlueprintCallable只能用于多播委托:
|
||||
|
||||
```cpp
|
||||
DECLARE_DYNAMIC_DELEGATE_OneParam(FMyDynamicSinglecastDelegate_One, int32, Value);
|
||||
|
||||
//编译报错:'BlueprintCallable' is only allowed on a property when it is a multicast delegate
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, BlueprintCallable)
|
||||
FMyDynamicSinglecastDelegate_One MyMyDelegate4;
|
||||
|
||||
//编译报错:'BlueprintAssignable' is only allowed on a property when it is a multicast delegate
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, BlueprintAssignable)
|
||||
FMyDynamicSinglecastDelegate_One MyMyDelegate5;
|
||||
```
|
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1,42 @@
|
||||
# BlueprintGetter
|
||||
|
||||
- **功能描述:** 为属性定义一个自定义的Get函数来读取。
|
||||
|
||||
- **元数据类型:** string="abc"
|
||||
- **引擎模块:** Blueprint
|
||||
- **作用机制:** 在PropertyFlags中加入[CPF_BlueprintReadOnly](../../../../Flags/EPropertyFlags/CPF_BlueprintReadOnly.md)、[CPF_BlueprintVisible](../../../../Flags/EPropertyFlags/CPF_BlueprintVisible.md),在Meta中加入[BlueprintGetter](../../../../Meta/Blueprint/BlueprintGetter.md)
|
||||
- **常用程度:** ★★★
|
||||
|
||||
为属性定义一个自定义的Get函数来读取。
|
||||
如果没有设置BlueprintSetter或BlueprintReadWrite,则会默认设置BlueprintReadOnly,这个属性变成只读的。
|
||||
|
||||
## 示例代码:
|
||||
|
||||
```cpp
|
||||
public:
|
||||
//(BlueprintGetter = , Category = Blueprint, ModuleRelativePath = Property/MyProperty_Test.h)
|
||||
UFUNCTION(BlueprintGetter, Category = Blueprint) //or BlueprintPure
|
||||
int32 MyInt_Getter()const { return MyInt_WithGetter * 2; }
|
||||
|
||||
//(BlueprintSetter = , Category = Blueprint, ModuleRelativePath = Property/MyProperty_Test.h)
|
||||
UFUNCTION(BlueprintSetter, Category = Blueprint) //or BlueprintCallable
|
||||
void MyInt_Setter(int NewValue) { MyInt_WithSetter = NewValue / 4; }
|
||||
private:
|
||||
//(BlueprintGetter = MyInt_Getter, Category = Blueprint, ModuleRelativePath = Property/MyProperty_Test.h)
|
||||
//PropertyFlags: CPF_BlueprintVisible | CPF_BlueprintReadOnly | CPF_ZeroConstructor | CPF_IsPlainOldData | CPF_NoDestructor | CPF_HasGetValueTypeHash | CPF_NativeAccessSpecifierPrivate
|
||||
UPROPERTY(BlueprintGetter = MyInt_Getter, Category = Blueprint)
|
||||
int32 MyInt_WithGetter = 123;
|
||||
|
||||
//(BlueprintSetter = MyInt_Setter, Category = Blueprint, ModuleRelativePath = Property/MyProperty_Test.h)
|
||||
//PropertyFlags: CPF_BlueprintVisible | CPF_ZeroConstructor | CPF_IsPlainOldData | CPF_NoDestructor | CPF_HasGetValueTypeHash | CPF_NativeAccessSpecifierPrivate
|
||||
UPROPERTY(BlueprintSetter = MyInt_Setter, Category = Blueprint)
|
||||
int32 MyInt_WithSetter = 123;
|
||||
```
|
||||
|
||||
## 示例效果:
|
||||
|
||||
可见MyInt_WithGetter是只读的。
|
||||
|
||||
而MyInt_WithSetter 是可读写的。
|
||||
|
||||

|
After Width: | Height: | Size: 39 KiB |
@@ -0,0 +1,69 @@
|
||||
# BlueprintReadOnly
|
||||
|
||||
- **功能描述:** 此属性可由蓝图读取,但不能被修改。
|
||||
- **元数据类型:** bool
|
||||
- **引擎模块:** Blueprint
|
||||
- **作用机制:** 在PropertyFlags中加入[CPF_BlueprintVisible](../../../../Flags/EPropertyFlags/CPF_BlueprintVisible.md), [CPF_BlueprintReadOnly](../../../../Flags/EPropertyFlags/CPF_BlueprintReadOnly.md)
|
||||
- **常用程度:** ★★★★★
|
||||
|
||||
此属性可由蓝图读取,但不能被修改。此说明符与 BlueprintReadWrite 说明符不兼容。
|
||||
|
||||
## 示例代码:
|
||||
|
||||
```cpp
|
||||
public:
|
||||
//PropertyFlags: CPF_BlueprintVisible | CPF_ZeroConstructor | CPF_IsPlainOldData | CPF_NoDestructor | CPF_HasGetValueTypeHash | CPF_NativeAccessSpecifierPublic
|
||||
UPROPERTY(BlueprintReadWrite, Category = Blueprint)
|
||||
int32 MyInt_ReadWrite = 123;
|
||||
//PropertyFlags: CPF_BlueprintVisible | CPF_BlueprintReadOnly | CPF_ZeroConstructor | CPF_IsPlainOldData | CPF_NoDestructor | CPF_HasGetValueTypeHash | CPF_NativeAccessSpecifierPublic
|
||||
UPROPERTY(BlueprintReadOnly, Category = Blueprint)
|
||||
int32 MyInt_ReadOnly = 123;
|
||||
```
|
||||
|
||||
## 示例效果:
|
||||
|
||||
指定蓝图中只读:
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
有CPF_BlueprintVisible 就可以Get
|
||||
|
||||
加上CPF_BlueprintReadOnly 后就不能修改。
|
||||
|
||||
```cpp
|
||||
EPropertyAccessResultFlags PropertyAccessUtil::CanGetPropertyValue(const FProperty* InProp)
|
||||
{
|
||||
if (!InProp->HasAnyPropertyFlags(CPF_Edit | CPF_BlueprintVisible | CPF_BlueprintAssignable))
|
||||
{
|
||||
return EPropertyAccessResultFlags::PermissionDenied | EPropertyAccessResultFlags::AccessProtected;
|
||||
}
|
||||
|
||||
return EPropertyAccessResultFlags::Success;
|
||||
}
|
||||
|
||||
FBlueprintEditorUtils::EPropertyWritableState FBlueprintEditorUtils::IsPropertyWritableInBlueprint(const UBlueprint* Blueprint, const FProperty* Property)
|
||||
{
|
||||
if (Property)
|
||||
{
|
||||
if (!Property->HasAnyPropertyFlags(CPF_BlueprintVisible))
|
||||
{
|
||||
return EPropertyWritableState::NotBlueprintVisible;
|
||||
}
|
||||
if (Property->HasAnyPropertyFlags(CPF_BlueprintReadOnly))
|
||||
{
|
||||
return EPropertyWritableState::BlueprintReadOnly;
|
||||
}
|
||||
if (Property->GetBoolMetaData(FBlueprintMetadata::MD_Private))
|
||||
{
|
||||
const UClass* OwningClass = Property->GetOwnerChecked<UClass>();
|
||||
if (OwningClass->ClassGeneratedBy.Get() != Blueprint)
|
||||
{
|
||||
return EPropertyWritableState::Private;
|
||||
}
|
||||
}
|
||||
}
|
||||
return EPropertyWritableState::Writable;
|
||||
}
|
||||
```
|
After Width: | Height: | Size: 45 KiB |
@@ -0,0 +1,47 @@
|
||||
# BlueprintReadWrite
|
||||
|
||||
- **功能描述:** 可从蓝图读取或写入此属性。
|
||||
|
||||
- **元数据类型:** bool
|
||||
- **引擎模块:** Blueprint
|
||||
- **作用机制:** 在PropertyFlags中加入[CPF_BlueprintVisible](../../../../Flags/EPropertyFlags/CPF_BlueprintVisible.md)
|
||||
- **常用程度:** ★★★★★
|
||||
|
||||
可从蓝图读取或写入此属性。
|
||||
|
||||
此说明符与 BlueprintReadOnly 说明符不兼容。
|
||||
|
||||
## 示例代码:
|
||||
|
||||
```cpp
|
||||
public:
|
||||
//PropertyFlags: CPF_BlueprintVisible | CPF_ZeroConstructor | CPF_IsPlainOldData | CPF_NoDestructor | CPF_HasGetValueTypeHash | CPF_NativeAccessSpecifierPublic
|
||||
UPROPERTY(BlueprintReadWrite, Category = Blueprint)
|
||||
int32 MyInt_ReadWrite = 123;
|
||||
//PropertyFlags: CPF_BlueprintVisible | CPF_BlueprintReadOnly | CPF_ZeroConstructor | CPF_IsPlainOldData | CPF_NoDestructor | CPF_HasGetValueTypeHash | CPF_NativeAccessSpecifierPublic
|
||||
UPROPERTY(BlueprintReadOnly, Category = Blueprint)
|
||||
int32 MyInt_ReadOnly = 123;
|
||||
```
|
||||
|
||||
## 示例效果:
|
||||
|
||||
蓝图中可读写:
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
如果有CPF_Edit | CPF_BlueprintVisible | CPF_BlueprintAssignable之一,则可以Get属性。
|
||||
|
||||
```cpp
|
||||
EPropertyAccessResultFlags PropertyAccessUtil::CanGetPropertyValue(const FProperty* InProp)
|
||||
{
|
||||
if (!InProp->HasAnyPropertyFlags(CPF_Edit | CPF_BlueprintVisible | CPF_BlueprintAssignable))
|
||||
{
|
||||
return EPropertyAccessResultFlags::PermissionDenied | EPropertyAccessResultFlags::AccessProtected;
|
||||
}
|
||||
|
||||
return EPropertyAccessResultFlags::Success;
|
||||
}
|
||||
|
||||
```
|
After Width: | Height: | Size: 45 KiB |
@@ -0,0 +1,58 @@
|
||||
# BlueprintSetter
|
||||
|
||||
- **功能描述:** 采用一个自定义的set函数来读取。
|
||||
|
||||
- **元数据类型:** string="abc"
|
||||
- **引擎模块:** Blueprint
|
||||
- **作用机制:** 在PropertyFlags中加入[CPF_BlueprintVisible](../../../Flags/EPropertyFlags/CPF_BlueprintVisible.md),在Meta中加入[BlueprintSetter](../../../Meta/Blueprint/BlueprintSetter.md)
|
||||
- **常用程度:** ★★★
|
||||
|
||||
采用一个自定义的set函数来读取。
|
||||
|
||||
会默认设置BlueprintReadWrite。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
public:
|
||||
//(BlueprintGetter = , Category = Blueprint, ModuleRelativePath = Property/MyProperty_Test.h)
|
||||
UFUNCTION(BlueprintGetter, Category = Blueprint) //or BlueprintPure
|
||||
int32 MyInt_Getter()const { return MyInt_WithGetter * 2; }
|
||||
|
||||
//(BlueprintSetter = , Category = Blueprint, ModuleRelativePath = Property/MyProperty_Test.h)
|
||||
UFUNCTION(BlueprintSetter, Category = Blueprint) //or BlueprintCallable
|
||||
void MyInt_Setter(int NewValue) { MyInt_WithSetter = NewValue / 4; }
|
||||
private:
|
||||
//(BlueprintGetter = MyInt_Getter, Category = Blueprint, ModuleRelativePath = Property/MyProperty_Test.h)
|
||||
//PropertyFlags: CPF_BlueprintVisible | CPF_BlueprintReadOnly | CPF_ZeroConstructor | CPF_IsPlainOldData | CPF_NoDestructor | CPF_HasGetValueTypeHash | CPF_NativeAccessSpecifierPrivate
|
||||
UPROPERTY(BlueprintGetter = MyInt_Getter, Category = Blueprint)
|
||||
int32 MyInt_WithGetter = 123;
|
||||
|
||||
//(BlueprintSetter = MyInt_Setter, Category = Blueprint, ModuleRelativePath = Property/MyProperty_Test.h)
|
||||
//PropertyFlags: CPF_BlueprintVisible | CPF_ZeroConstructor | CPF_IsPlainOldData | CPF_NoDestructor | CPF_HasGetValueTypeHash | CPF_NativeAccessSpecifierPrivate
|
||||
UPROPERTY(BlueprintSetter = MyInt_Setter, Category = Blueprint)
|
||||
int32 MyInt_WithSetter = 123;
|
||||
```
|
||||
|
||||
## 蓝图表现:
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
如果有MD_PropertySetFunction则用它来作为Set的调用。
|
||||
|
||||
```cpp
|
||||
void UK2Node_VariableSet::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
|
||||
{
|
||||
// If property has a BlueprintSetter accessor, then replace the variable get node with a call function
|
||||
if (VariableProperty)
|
||||
{
|
||||
// todo check with BP team if we need to test if the variable has native Setter
|
||||
const FString& SetFunctionName = VariableProperty->GetMetaData(FBlueprintMetadata::MD_PropertySetFunction);
|
||||
if (!SetFunctionName.IsEmpty())
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
@@ -0,0 +1,109 @@
|
||||
# Getter
|
||||
|
||||
- **功能描述:** 为属性增加一个C++的Get函数,只在C++层面应用。
|
||||
|
||||
- **元数据类型:** string="abc"
|
||||
- **引擎模块:** Blueprint
|
||||
- **常用程度:** ★★★
|
||||
|
||||
为属性增加一个C++的Get函数,只在C++层面应用。
|
||||
|
||||
- Getter上如不提供函数名,那就用默认的GetXXX的名字。也可以提供另外一个函数名。
|
||||
- 这些Getter函数是不加UFUNCTION的,这点要和BlueprintGetter区分。
|
||||
- 感觉更好的名字是NativeGetter。
|
||||
- GetXXX的函数必须自己手写,否则UHT会报错。
|
||||
- 我们当然也可以自己写GetSet函数,不需要写Getter和Setter的元数据。但写上Getter和Settter的好处是,万一在项目里别的地方,用到了反射来获取和设置值,这个时候如果没有标上Getter和Setter,就会直接从属性上获取值,从而跳过我们想要的自定义Get/Set流程。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
public:
|
||||
//GetterFunc: Has Native Getter
|
||||
UPROPERTY(BlueprintReadWrite, Getter)
|
||||
float MyFloat = 1.0f;
|
||||
|
||||
//GetterFunc: Has Native Getter
|
||||
UPROPERTY(BlueprintReadWrite, Getter = GetMyCustomFloat)
|
||||
float MyFloat2 = 1.0f;
|
||||
public:
|
||||
float GetMyFloat()const { return MyFloat + 100.f; }
|
||||
|
||||
float GetMyCustomFloat()const { return MyFloat2 + 100.f; }
|
||||
|
||||
void UMyProperty_Get::RunTest()
|
||||
{
|
||||
float Value1=MyFloat;
|
||||
|
||||
FProperty* prop=GetClass()->FindPropertyByName(TEXT("MyFloat"));
|
||||
float Value2=0.f;
|
||||
|
||||
prop->GetValue_InContainer(this,&Value2);
|
||||
}
|
||||
```
|
||||
|
||||
## 蓝图表现:
|
||||
|
||||
在测试的时候,可见如果是用GetValue_InContainer这种反射的方式来获取值,就会自动的调用到GetMyFloat,从而返回不同的值。
|
||||
|
||||
在蓝图里直接Get MyFloat 是依然是1.
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
UHT在分析Getter标记后,会在gen.cpp里生成相应的函数包装。在构建FProperty的时候,就会创建TPropertyWithSetterAndGetter,之后在GetSingleValue_InContainer的时候就会调用到CallGetter。
|
||||
|
||||
```cpp
|
||||
void UMyProperty_Get::GetMyFloat_WrapperImpl(const void* Object, void* OutValue)
|
||||
{
|
||||
const UMyProperty_Get* Obj = (const UMyProperty_Get*)Object;
|
||||
float& Result = *(float*)OutValue;
|
||||
Result = (float)Obj->GetMyFloat();
|
||||
}
|
||||
|
||||
const UECodeGen_Private::FFloatPropertyParams Z_Construct_UClass_UMyProperty_Get_Statics::NewProp_MyFloat = { "MyFloat", nullptr, (EPropertyFlags)0x0010000000000004, UECodeGen_Private::EPropertyGenFlags::Float, RF_Public|RF_Transient|RF_MarkAsNative, nullptr, &UMyProperty_Get::GetMyFloat_WrapperImpl, 1, STRUCT_OFFSET(UMyProperty_Get, MyFloat), METADATA_PARAMS(UE_ARRAY_COUNT(NewProp_MyFloat_MetaData), NewProp_MyFloat_MetaData) };
|
||||
|
||||
template <typename PropertyType, typename PropertyParamsType>
|
||||
PropertyType* NewFProperty(FFieldVariant Outer, const FPropertyParamsBase& PropBase)
|
||||
{
|
||||
const PropertyParamsType& Prop = (const PropertyParamsType&)PropBase;
|
||||
PropertyType* NewProp = nullptr;
|
||||
|
||||
if (Prop.SetterFunc || Prop.GetterFunc)
|
||||
{
|
||||
NewProp = new TPropertyWithSetterAndGetter<PropertyType>(Outer, Prop);
|
||||
}
|
||||
else
|
||||
{
|
||||
NewProp = new PropertyType(Outer, Prop);
|
||||
}
|
||||
}
|
||||
|
||||
void FProperty::GetSingleValue_InContainer(const void* InContainer, void* OutValue, int32 ArrayIndex) const
|
||||
{
|
||||
checkf(ArrayIndex <= ArrayDim, TEXT("ArrayIndex (%d) must be less than the property %s array size (%d)"), ArrayIndex, *GetFullName(), ArrayDim);
|
||||
if (!HasGetter())
|
||||
{
|
||||
// Fast path - direct memory access
|
||||
CopySingleValue(OutValue, ContainerVoidPtrToValuePtrInternal((void*)InContainer, ArrayIndex));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ArrayDim == 1)
|
||||
{
|
||||
// Slower but no mallocs. We can copy the value directly to the resulting param
|
||||
CallGetter(InContainer, OutValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Malloc a temp value that is the size of the array. Getter will then copy the entire array to the temp value
|
||||
uint8* ValueArray = (uint8*)AllocateAndInitializeValue();
|
||||
GetValue_InContainer(InContainer, ValueArray);
|
||||
// Copy the item we care about and free the temp array
|
||||
CopySingleValue(OutValue, ValueArray + ArrayIndex * ElementSize);
|
||||
DestroyAndFreeValue(ValueArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
@@ -0,0 +1,114 @@
|
||||
# Setter
|
||||
|
||||
- **功能描述:** 为属性增加一个C++的Set函数,只在C++层面应用。
|
||||
- **元数据类型:** string="abc"
|
||||
- **引擎模块:** Blueprint
|
||||
- **关联项:** [Getter](../Getter.md)
|
||||
- **常用程度:** ★★★
|
||||
|
||||
为属性增加一个C++的Set函数,只在C++层面应用。
|
||||
|
||||
- Getter上如不提供函数名,那就用默认的SetXXX的名字。也可以提供另外一个函数名。
|
||||
- 这些Getter函数是不加UFUNCTION的,这点要和BlueprintGetter区分。
|
||||
- 感觉更好的名字是NativeSetter。
|
||||
- SetXXX的函数必须自己手写,否则UHT会报错。
|
||||
- 我们当然也可以自己写GetSet函数,不需要写Getter和Setter的元数据。但写上Getter和Settter的好处是,万一在项目里别的地方,用到了反射来获取和设置值,这个时候如果没有标上Getter和Setter,就会直接从属性上获取值,从而跳过我们想要的自定义Get/Set流程。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
public:
|
||||
UPROPERTY(BlueprintReadWrite, Setter)
|
||||
float MyFloat = 1.0f;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, Setter = SetMyCustomFloat)
|
||||
float MyFloat2 = 1.0f;
|
||||
public:
|
||||
void SetMyFloat(float val) { MyFloat = val + 100.f; }
|
||||
void SetMyCustomFloat(float val) { MyFloat2 = val + 100.f; }
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void RunTest();
|
||||
};
|
||||
|
||||
void UMyProperty_Set::RunTest()
|
||||
{
|
||||
float OldValue=MyFloat;
|
||||
|
||||
FProperty* prop=GetClass()->FindPropertyByName(TEXT("MyFloat"));
|
||||
const float Value2=20.f;
|
||||
|
||||
prop->SetValue_InContainer(this,&Value2);
|
||||
|
||||
float NewValue=MyFloat;
|
||||
}
|
||||
```
|
||||
|
||||
## 蓝图表现:
|
||||
|
||||
在测试的时候,可见如果是用SetValue_InContainer这种反射的方式来获取值,就会自动的调用到SetMyFloat,从而实际上设置到不同的值。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
UHT在分析Setter标记后,会在gen.cpp里生成相应的函数包装。在构建FProperty的时候,就会创建TPropertyWithSetterAndGetter,之后在GetSingleValue_InContainer的时候就会调用到CallGetter。
|
||||
|
||||
```cpp
|
||||
void UMyProperty_Set::SetMyFloat_WrapperImpl(void* Object, const void* InValue)
|
||||
{
|
||||
UMyProperty_Set* Obj = (UMyProperty_Set*)Object;
|
||||
float& Value = *(float*)InValue;
|
||||
Obj->SetMyFloat(Value);
|
||||
}
|
||||
|
||||
const UECodeGen_Private::FFloatPropertyParams Z_Construct_UClass_UMyProperty_Set_Statics::NewProp_MyFloat = { "MyFloat", nullptr, (EPropertyFlags)0x0010000000000004, UECodeGen_Private::EPropertyGenFlags::Float, RF_Public|RF_Transient|RF_MarkAsNative, &UMyProperty_Set::SetMyFloat_WrapperImpl, nullptr, 1, STRUCT_OFFSET(UMyProperty_Set, MyFloat), METADATA_PARAMS(UE_ARRAY_COUNT(NewProp_MyFloat_MetaData), NewProp_MyFloat_MetaData) };
|
||||
|
||||
template <typename PropertyType, typename PropertyParamsType>
|
||||
PropertyType* NewFProperty(FFieldVariant Outer, const FPropertyParamsBase& PropBase)
|
||||
{
|
||||
const PropertyParamsType& Prop = (const PropertyParamsType&)PropBase;
|
||||
PropertyType* NewProp = nullptr;
|
||||
|
||||
if (Prop.SetterFunc || Prop.GetterFunc)
|
||||
{
|
||||
NewProp = new TPropertyWithSetterAndGetter<PropertyType>(Outer, Prop);
|
||||
}
|
||||
else
|
||||
{
|
||||
NewProp = new PropertyType(Outer, Prop);
|
||||
}
|
||||
}
|
||||
|
||||
void FProperty::SetSingleValue_InContainer(void* OutContainer, const void* InValue, int32 ArrayIndex) const
|
||||
{
|
||||
checkf(ArrayIndex <= ArrayDim, TEXT("ArrayIndex (%d) must be less than the property %s array size (%d)"), ArrayIndex, *GetFullName(), ArrayDim);
|
||||
if (!HasSetter())
|
||||
{
|
||||
// Fast path - direct memory access
|
||||
CopySingleValue(ContainerVoidPtrToValuePtrInternal((void*)OutContainer, ArrayIndex), InValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ArrayDim == 1)
|
||||
{
|
||||
// Slower but no mallocs. We can copy the value directly to the resulting param
|
||||
CallSetter(OutContainer, InValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Malloc a temp value that is the size of the array. We will then copy the entire array to the temp value
|
||||
uint8* ValueArray = (uint8*)AllocateAndInitializeValue();
|
||||
GetValue_InContainer(OutContainer, ValueArray);
|
||||
// Replace the value at the specified index in the temp array with the InValue
|
||||
CopySingleValue(ValueArray + ArrayIndex * ElementSize, InValue);
|
||||
// Now call a setter to replace the entire array and then destroy the temp value
|
||||
CallSetter(OutContainer, ValueArray);
|
||||
DestroyAndFreeValue(ValueArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
After Width: | Height: | Size: 368 KiB |
After Width: | Height: | Size: 316 KiB |