UE4:UObjectToLua插件简介
简介

该插件继承UBlueprintFunctionLibrary,提供了一些静态函数,可以对UObject类及其子类的对象进行Get和Set操作获取或者修改对应的UPROPERTY的名称或值。

更新

添加了UEnum和TSet的UPROPERTY的独写

提供的函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
UFUNCTION(BlueprintCallable, Category = "UTL")
static FString UObjectToLuaString(UObject* Object);

UFUNCTION(BlueprintCallable, Category = "UTL")
static FString UObjectToLuaStringWithIgnore(UObject* Object, FString ignore);

UFUNCTION(BlueprintCallable, Category = "UTL")
static FString UObjectToCSV(UObject* Object);

UFUNCTION(BlueprintCallable, Category = "UTL")
static FString UObjectToCSVwithIgnore(UObject* Object, FString ignore);

UFUNCTION(BlueprintCallable, Category = "UTL")
static FString GetAimValue(UObject* Object, FString Aim);

UFUNCTION(BlueprintCallable, Category = "UTL")
static UObject* SetAimValue(UClass* classNAme, FString Aim, FString nameAndValue);

UFUNCTION(BlueprintCallable, Category = "UTL")
static UObject* LuaStringToUObject(UClass* className, FString nameAndValue);

UFUNCTION(BlueprintCallable, Category = "UTL")
static UObject* LuaStringToSetUObject(UObject* objcet, FString nameAndValue);

UFUNCTION(BlueprintCallable, Category = "UTL")
static UObject* CSVToUObject(UClass* className, FString nameAndValue);

UFUNCTION(BlueprintCallable, Category = "UTL")
static UObject* CSVToSetUObject(UObject* objcet, FString nameAndValue);

UFUNCTION(BlueprintCallable, Category = "UTL")
static UObject* CreateObject(UClass* className);

UFUNCTION(BlueprintCallable, Category = "UTL")
static FString LuaStringToCSV(FString LuaString);
使用举例

用第一个函数举例,该函数需要一个UObject的对象,或者子类的对象,最后返回一个FString变量,该变量是该Object的所有UPROPERTY的名称和值,字符串格式符合Lua的Table格式。

比如我有如下几个Object类类型

MyObject类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
UCLASS(BlueprintType, Blueprintable)
class GAMETEST_API UMyObject : public UObject
{
GENERATED_BODY()

public:

UMyObject();

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = GamePlay)
bool baseBool;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
int32 baseInt;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
float baseFloat;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
FString baseString;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
TArray<FString> baseArray;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
TMap<int32, bool> baseMap;
};

MyObjectChild类,继承自MyObject类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
UCLASS(BlueprintType, Blueprintable)
class GAMETEST_API UMyObjectChild : public UMyObject
{
GENERATED_BODY()

public:

UMyObjectChild();

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = GamePlay)
bool childBool;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
int32 childInt;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
float childFloat;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
FString childString;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
TArray<bool> childArray;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
TMap<int32, int32> childMap;
};

MyAnother类,其中成员变量有一个MyObject类和一个MyObjectChild类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
UCLASS(BlueprintType, Blueprintable)
class GAMETEST_API UMyAnotherObject : public UObject
{
GENERATED_BODY()

public:

UMyAnotherObject();

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = GamePlay)
UMyObject* a;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = GamePlay)
UMyObjectChild* b;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = GamePlay)
bool anotherbool;
};

那么假如以上所有类的成员变量在构造函数中有初始化(应该是必须有),我实例化一个MyAnotherObject的对象,将其传给此函数:

1
2
UMyAnotherObject* another = NewObject<UMyAnotherObject>();
FString getObjectProperties = UObjectToLuaParser::UObjectToLuaString(another);

最后得到的getObjectProperties应该是如下的字符串:

1
return{a={baseBool=false,baseInt=1,baseFloat=1.0,baseString='base string',baseArray={'basearray01','basearray02','basearray03',},baseMap={[1]=true,[2]=false,[3]=true,},},b={childBool=true,childInt=2,childFloat=2.0,childString='child string',childArray={true,false,true,false,true,},childMap={[1]=111,[2]=222,[3]=333,},rotate={Pitch=1.0,Yaw=1.1,Roll=1.2,},vector={X=111.0,Y=222.0,Z=333.0,},baseBool=false,baseInt=1,baseFloat=1.0,baseString='base string',baseArray={'basearray01','basearray02','basearray03',},baseMap={[1]=true,[2]=false,[3]=true,},},anotherbool=false,}

注意这里是没有任何空格和换行符的,最外层的大括号和return是为了Lua拿到后直接就可以dump为table进行处理,此处也可以修改最后输出的地方进行修改。下面是处理过格式的,方便对比:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
return{
a={
baseBool=false,
baseInt=1,
baseFloat=1.0,
baseString='base string',
baseArray={
'basearray01',
'basearray02',
'basearray03',
},
baseMap={
[1]=true,
[2]=false,
[3]=true,
},
},
b={
childBool=true,
childInt=2,
childFloat=2.0,
childString='child string',
childArray={
true,
false,
true,
false,
true,
},
childMap={
[1]=111,
[2]=222,
[3]=333,
},
rotate={
Pitch=1.0,
Yaw=1.1,
Roll=1.2,
},
vector={
X=111.0,
Y=222.0,
Z=333.0,
},
baseBool=false,
baseInt=1,
baseFloat=1.0,
baseString='base string',
baseArray={
'basearray01',
'basearray02',
'basearray03',
},
baseMap={
[1]=true,
[2]=false,
[3]=true,},
},
}
anotherbool=false,
}
}

需要指出的是目前仅支持基本数据类型,TArray,TMap,FVector,FRotator,不支持不支持不支持自定义结构体。具体原因可以参考大致原理部分。

函数简介
1
static FString UObjectToLuaString(UObject* Object);

上文已经举例,不再赘述。

1
static FString UObjectToLuaStringWithIgnore(UObject* Object, FString ignore);

ignore参数中是用逗号分隔的不需要的UPROPERTY的name,最后一个后面也要有逗号,做成字符串是为了可以直接用Lua调用方便,ignore中的UPROPERTY会在Get信息的过程中跳过

1
static FString UObjectToCSV(UObject* Object);

该函数会最后将字符串修改为符合CSV文件要求的格式,在收集信息到表格的过程中可以使用

1
static FString UObjectToCSVwithIgnore(UObject* Object, FString ignore);

ignore和上面第二个一样,最后的字符串和上面第三个一样符合CSV格式

1
static FString GetAimValue(UObject* Object, FString Aim);

Aim和上文的ignore不同,只能存放一个UPROPERTY的name,不会进一步处理,最后返回的字符串只有这一个UPROPERTY的信息

1
static UObject* SetAimValue(UClass* classNAme, FString Aim, FString nameAndValue);

第一个参数是UCLass*类,函数内部会新建一个该UClass对应的对象实例,Aim依然是一个UPROPERTY的name,会将该UPROPERTY的value设置为第三个参数中的值。注意第三个参数要求写成name=value的形式

1
static UObject* LuaStringToUObject(UClass* className, FString nameAndValue);

这里注意第二个参数,第二个参数的形式和上面第一个函数最后输出的形式相同,但不需要最外层的return和大括号

1
static UObject* LuaStringToSetUObject(UObject* objcet, FString nameAndValue);

和上一个函数的区别在于第一个参数,这个可以理解为给已存在的实例对象的Set方法

1
static UObject* CSVToUObject(UClass* className, FString nameAndValue);

从csv字符串新建一个对象并使用第二个参数进行赋值

1
static UObject* CSVToSetUObject(UObject* objcet, FString nameAndValue);

用csv字符串设置一个已存在的对象

1
static UObject* CreateObject(UClass* className);

自己封装的一个从UClass创建对应对象的函数

1
static FString LuaStringToCSV(FString LuaString);

一个将Lua风格的字符串改为CSV风格的函数

下载和使用

项目地址:https://github.com/muchenhen/UObjectToLua

Git: git@github.com:muchenhen/UObjectToLua.git

将UObjectToLua文件夹复制进项目或者引擎的Plungins文件夹,重新生成项目的解决方案,重新编译项目

在其他插件中使用的话在对应的插件的.build.cs文件包含UObjectToLua模块,运行时使用的话在项目的.build.cs中包含。在要使用的地方包含对应的头文件。

欢迎交流和捉虫,毕竟作者只是一个菜鸡……

Author: 木尘痕
Link: https://muchenhen.com/2020/10/21/UE4%EF%BC%9AUObjectToLua%E6%8F%92%E4%BB%B6%E7%AE%80%E4%BB%8B/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.