6.5 KiB
Raw Permalink Blame History

ScriptMethodMutable

  • 功能描述: 把ScriptMethod的第一个const结构参数在调用上改成引用参数函数内修改的值会保存下来。
  • 使用位置: UFUNCTION
  • 引擎模块: Script
  • 元数据类型: bool
  • 限制类型: 第一个参数是结构类型
  • 关联项: ScriptMethod
  • 常用程度: ★★

把ScriptMethod的第一个const结构参数在调用上改成引用参数函数内修改的值会保存下来。

  • 在const参数上如果想改变值依然要标记c++里的mutable。
  • 虽然py生成的代码一模一样但实际调用上ScriptMethodMutable会真正改变参数的值而没有ScriptMethodMutable的函数并不会改变参数的原始值。
  • ScriptMethodMutable和UPARAM(ref) 在调用效果上都可以改变参数的值。但区别是UPARAM(ref) 生成的py代码会返回第一个参数作为返回值。
USTRUCT(BlueprintType)
struct INSIDER_API FMyPythonStruct_ScriptMethod
{
	GENERATED_BODY()
public:
	UPROPERTY(BlueprintReadWrite, EditAnywhere)
	mutable FString MyString;

};

UCLASS(Blueprintable, BlueprintType)
class INSIDER_API UMyPython_ScriptMethod_Test :public UObject
{
	GENERATED_BODY()
public:
	UFUNCTION(BlueprintCallable, meta = (ScriptMethod))
	static void SetStringOnStruct(const FMyPythonStruct_ScriptMethod& myStruct, FString val);

	UFUNCTION(BlueprintCallable, meta = (ScriptMethod, ScriptMethodMutable))
	static void SetStringOnStructMutable(const FMyPythonStruct_ScriptMethod& myStruct, FString val);

	UFUNCTION(BlueprintCallable, meta = (ScriptMethod, ScriptMethodMutable))
	static void SetStringOnStructViaRef(UPARAM(ref) FMyPythonStruct_ScriptMethod& myStruct, FString val);
};

测试效果:

看py里生成的代码是一致的如果用UPARAM(ref)则在MyPython_ScriptMethod_Test里面生成的my_func_on_struct_via_ref会返回结构MyPythonStruct_ScriptMethod来达成引用的效果。

然而my_func_on_struct_mutable返回的是None同不加ScriptMethodMutable的my_func_on_struct并没有区别。但是实际上在真正调用的时候会真正有区别。

class MyPythonStruct_ScriptMethod(StructBase):
    r"""
    My Python Struct Script Method
    
    **C++ Source:**
    
    - **Module**: Insider
    - **File**: MyPython_ScriptMethod.h
    
    """
    def __init__(self) -> None:
        ...
    def my_func_on_struct_via_ref(self, val: str) -> None:
        r"""
        x.my_func_on_struct_via_ref(val) -> None
        My Func on Struct Via Ref
        
        Args:
            val (str):
        """
        ...
    def my_func_on_struct_mutable(self, val: str) -> None:
        r"""
        x.my_func_on_struct_mutable(val) -> None
        My Func on Struct Mutable
        
        Args:
            val (str):
        """
        ...
    def my_func_on_struct(self, val: str) -> None:
        r"""
        x.my_func_on_struct(val) -> None
        My Func on Struct
        
        Args:
            val (str):
        """
        ...

        
class MyPython_ScriptMethod_Test(Object):
    r"""
    My Python Script Method Test
    
    **C++ Source:**
    
    - **Module**: Insider
    - **File**: MyPython_ScriptMethod.h
    
    """
    @classmethod
    def my_func_on_struct_via_ref(cls, my_struct: MyPythonStruct_ScriptMethod, val: str) -> MyPythonStruct_ScriptMethod:
        r"""
        X.my_func_on_struct_via_ref(my_struct, val) -> MyPythonStruct_ScriptMethod
        My Func on Struct Via Ref
        
        Args:
            my_struct (MyPythonStruct_ScriptMethod): 
            val (str): 
        
        Returns:
            MyPythonStruct_ScriptMethod: 
        
            my_struct (MyPythonStruct_ScriptMethod):
        """
        ...
    @classmethod
    def my_func_on_struct_mutable(cls, my_struct: MyPythonStruct_ScriptMethod, val: str) -> None:
        r"""
        X.my_func_on_struct_mutable(my_struct, val) -> None
        My Func on Struct Mutable
        
        Args:
            my_struct (MyPythonStruct_ScriptMethod): 
            val (str):
        """
        ...
   @classmethod
    def my_func_on_struct(cls, my_struct: MyPythonStruct_ScriptMethod, val: str) -> None:
        r"""
        X.my_func_on_struct(my_struct, val) -> None
        My Func on Struct
        
        Args:
            my_struct (MyPythonStruct_ScriptMethod): 
            val (str):
        """
        ...

在UE Python控制台里调用的记录分析调用顺序

  • 一开始调用set_string_on_struct_mutable再print(a)可以打印出Hello说明值真正的设置到了a结构里。
  • 再尝试set_string_on_struct再print(a)无法打印出FFF说明值并没有设置到a结构里。说明py在调用的时候很可能构造了一个临时值来当作调对象调用完成的新值并没有设置到a对象上。
  • 再尝试set_string_on_struct_via_ref再print(a)可以打印出First说明用UPARAM(ref)可以也达成改变参数的效果。
LogPython: a=unreal.MyPythonStruct_ScriptMethod()
LogPython: print(a)
LogPython: <Struct 'MyPythonStruct_ScriptMethod' (0x0000092D08CD6ED0) {my_string: ""}>
LogPython: a.set_string_on_struct_mutable("Hello")
LogBlueprintUserMessages: [None] UMyPython_ScriptMethod_Test::SetStringOnStructMutable
LogPython: print(a)
LogPython: <Struct 'MyPythonStruct_ScriptMethod' (0x0000092D08CD6ED0) {my_string: "Hello"}>
LogPython: a.set_string_on_struct("FFF")
LogBlueprintUserMessages: [None] UMyPython_ScriptMethod_Test::SetStringOnStruct
LogPython: print(a)
LogPython: <Struct 'MyPythonStruct_ScriptMethod' (0x0000092D08CD6ED0) {my_string: "Hello"}>
LogPython: a.set_string_on_struct_via_ref("First")
LogBlueprintUserMessages: [None] UMyPython_ScriptMethod_Test::SetStringOnStructViaRef
LogPython: print(a)
LogPython: <Struct 'MyPythonStruct_ScriptMethod' (0x0000092D08CD6ED0) {my_string: "First"}>

原理:

判断如果有ScriptMethodMutable会设置SelfReturn从而再最后把函数调用中的临时值复制给原本的参数值达成可变引用调用的效果。

// The function may have been flagged as mutable, in which case we always consider it to need a 'self' return
if (!GeneratedWrappedDynamicMethod.SelfReturn.ParamProp && InFunc->HasMetaData(PyGenUtil::ScriptMethodMutableMetaDataKey))
{
	if (!SelfParam.ParamProp->IsA<FStructProperty>())
	{
		REPORT_PYTHON_GENERATION_ISSUE(Error, TEXT("Function '%s.%s' is marked as 'ScriptMethodMutable' but the 'self' argument is not a struct."), *InFunc->GetOwnerClass()->GetName(), *InFunc->GetName());
		return;
	}
	GeneratedWrappedDynamicMethod.SelfReturn = SelfParam;
}