174 lines
6.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ScriptDefaultMake
- **功能描述:** 禁用结构上的HasNativeMake在脚本里构造的时候不调用C++里的NativeMake函数而采用脚本内建的默认初始化方式。
- **使用位置:** USTRUCT
- **引擎模块:** Script
- **元数据类型:** bool
- **关联项:** [ScriptDefaultBreak](ScriptDefaultBreak.md)
- **常用程度:** ★
禁用结构上的HasNativeMake在脚本里构造的时候不调用C++里的NativeMake函数而采用脚本内建的默认初始化方式。
ScriptDefaultBreak也是同理。
## 测试代码:
```cpp
USTRUCT(BlueprintType, meta = (ScriptDefaultMake, ScriptDefaultBreak,HasNativeMake = "/Script/Insider.MyPython_MakeBreak_Test.MyNativeMake", HasNativeBreak = "/Script/Insider.MyPython_MakeBreak_Test.MyNativeBreak"))
struct INSIDER_API FMyPythonMBStructNative
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite, EditAnywhere)
int32 MyInt = 0;
UPROPERTY(BlueprintReadWrite, EditAnywhere)
FString MyString;
};
UCLASS(Blueprintable, BlueprintType)
class INSIDER_API UMyPython_MakeBreak_Test :public UObject
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintPure, meta = ())
static FMyPythonMBStructNative MyNativeMake(int32 InInt) { return FMyPythonMBStructNative{ InInt,TEXT("Hello") }; }
UFUNCTION(BlueprintPure, meta = ())
static void MyNativeBreak(const FMyPythonMBStructNative& InStruct, int& outInt) { outInt = InStruct.MyInt + 123; }
};
```
## 生成的py代码
无论有没有加ScriptDefaultMake, ScriptDefaultBreakMyPythonMBStructNative生成的py代码其实是一样的。不同点在于构成和to_tuple时候的结果不同。
```cpp
class MyPythonMBStructNative(StructBase):
r"""
My Python MBStruct Native
**C++ Source:**
- **Module**: Insider
- **File**: MyPython_ScriptMakeBreak.h
**Editor Properties:** (see get_editor_property/set_editor_property)
- ``my_int`` (int32): [Read-Write]
- ``my_string`` (str): [Read-Write]
"""
def __init__(self, int: int = 0) -> None:
...
@property
def my_int(self) -> int:
r"""
(int32): [Read-Write]
"""
...
@my_int.setter
def my_int(self, value: int) -> None:
...
@property
def my_string(self) -> str:
r"""
(str): [Read-Write]
"""
...
@my_string.setter
def my_string(self, value: str) -> None:
...
```
## 运行的结果:
- 第二段是加了ScriptDefaultMake, ScriptDefaultBreak后的效果。我故意在C++的Make和Break函数里做了一些不一样可以观察到调用到C++里的函数。
- 第一段是在代码里加上ScriptDefaultMake, ScriptDefaultBreak后保留HasNativeMakeHasNativeBreak调用的结果可见C++里的Make/Break函数就没有再被调用到了。
```cpp
LogPython: b=unreal.MyPythonMBStructNative()
LogPython: print(b)
LogPython: <Struct 'MyPythonMBStructNative' (0x0000085F2EE9E680) {my_int: 0, my_string: "Hello"}>
LogPython: print(b.to_tuple())
LogPython: (123,)
LogPython: b=unreal.MyPythonMBStructNative()
LogPython: print(b)
LogPython: <Struct 'MyPythonMBStructNative' (0x000005E6C3AAFDC0) {my_int: 0, my_string: ""}>
LogPython: print(b.to_tuple())
LogPython: (0, '')
```
## 原理:
在FindMakeBreakFunction函数里如果发现有ScriptDefaultMake或ScriptDefaultBreak标记就不去使用C++里由HasNativeMakeHasNativeBreak指定的函数。
另外py里的结构初始化会调用到默认的init或者结构的make函数而to_tuple就相当于break的作用会调用到默认的每个属性to_tuple或者是结构的自定义break函数。
```cpp
const FName ScriptDefaultMakeMetaDataKey = TEXT("ScriptDefaultMake");
const FName ScriptDefaultBreakMetaDataKey = TEXT("ScriptDefaultBreak");
namespace UE::Python
{
/**
* Finds the UFunction corresponding to the name specified by 'HasNativeMake' or 'HasNativeBreak' meta data key.
* @param The structure to inspect for the 'HasNativeMake' or 'HasNativeBreak' meta data keys.
* @param InNativeMetaDataKey The native meta data key name. Can only be 'HasNativeMake' or 'HasNativeBreak'.
* @param InScriptDefaultMetaDataKey The script default meta data key name. Can only be 'ScriptDefaultMake' or 'ScriptDefaultBreak'.
* @param NotFoundFn Function invoked if the structure specifies as Make or Break function, but the function couldn't be found.
* @return The function, if the struct has the meta key and if the function was found. Null otherwise.
*/
template<typename NotFoundFuncT>
UFunction* FindMakeBreakFunction(const UScriptStruct* InStruct, const FName& InNativeMetaDataKey, const FName& InScriptDefaultMetaDataKey, const NotFoundFuncT& NotFoundFn)
{
check(InNativeMetaDataKey == PyGenUtil::HasNativeMakeMetaDataKey || InNativeMetaDataKey == PyGenUtil::HasNativeBreakMetaDataKey);
check(InScriptDefaultMetaDataKey == PyGenUtil::ScriptDefaultMakeMetaDataKey || InScriptDefaultMetaDataKey == PyGenUtil::ScriptDefaultBreakMetaDataKey);
UFunction* MakeBreakFunc = nullptr;
if (!InStruct->HasMetaData(InScriptDefaultMetaDataKey)) // <--- 有了default, 会直接返回null
{
const FString MakeBreakFunctionName = InStruct->GetMetaData(InNativeMetaDataKey);
if (!MakeBreakFunctionName.IsEmpty())
{
// Find the function.
MakeBreakFunc = FindObject<UFunction>(/*Outer*/nullptr, *MakeBreakFunctionName, /*ExactClass*/true);
if (!MakeBreakFunc)
{
NotFoundFn(MakeBreakFunctionName);
}
}
}
return MakeBreakFunc;
}
}
struct FFuncs
{
static int Init(FPyWrapperStruct* InSelf, PyObject* InArgs, PyObject* InKwds)
{
const int SuperResult = PyWrapperStructType.tp_init((PyObject*)InSelf, InArgs, InKwds);
if (SuperResult != 0)
{
return SuperResult;
}
return FPyWrapperStruct::MakeStruct(InSelf, InArgs, InKwds);
}
};
GeneratedWrappedType->PyType.tp_init = (initproc)&FFuncs::Init;
// python wrapper 给每个类型都映射了 to_tuple 函数,会调用类型的 break 函数转换为 tuple
static PyObject* ToTuple(FPyWrapperStruct* InSelf)
{
return FPyWrapperStruct::BreakStruct(InSelf);
}
....
{ "to_tuple", PyCFunctionCast(&FMethods::ToTuple), METH_NOARGS, "to_tuple(self) -> Tuple[object, ...] -- break this Unreal struct into a tuple of its properties" },
```