TAPython除了能够方便得创建编辑器界面,它还提供了若干编辑器扩展库。
在最新的1.0.5版本中的,PythonEnumLib, PythonStructLib, PythonDataTableLib 新增和扩展了对User Defined Enum,User Defined Struct,DataTable的支持。使得这些数据的操作可以完全Python化,进而将通过Python、其他策划数据工具,创建、查询、修改这些数据变得简单
Make it as simple as possible, but not simpler.
简而言之,在编辑器里能手动做的,现在用Python都可以做到了
下面是示例
User Defined Enum¶
创建User Defined Enum¶
下面的代码,可以在"/Content/CreatedByPython/IAmAEnum"位置,创建一个User Defined Enum。这使用的是UE内置功能,实际上,大部分的其他类型资源也都可以通过这个方法来创建:
asset_tools = unreal.AssetToolsHelpers.get_asset_tools()
new_enum = asset_tools.create_asset("IAmAEnum", "/Game/CreatedByPython", unreal.UserDefinedEnum, unreal.EnumFactory())
然后可以对其设置枚举项:
items = ["A", "BB", "CCC", "DDDD", "EEEEE"]
unreal.PythonEnumLib.set_enum_items(self.current_enum, items)
上面 self.current_enum 就是上面新创建的User Defined Enum,当然我们也可以从工程中读取:
self.current_enum = unreal.load_asset("/Game/CreatedByPython/IAmAEnum")
修改User Defined Enum¶
我们可以通过 PythonEnumLib.set_display_name 修改指定的枚举项。实际上User Defined Enum中有所谓的Display Name 和 "Raw Name",Display Name只用于显示,"Raw Name" 是实际的枚举项
# The enum item at index 3 will be: "iAmItem_3"
unreal.PythonEnumLib.set_display_name(self.current_enum, 3, "iAmItem_{}".format(3))
修改 Enum's 描述¶
Enum上的描述文字是Enum对象自身的一个EditorProperty,因此可以通过 SetEditorProperty 对其进行修改:
# set the description of enum
self.current_enum.set_editor_property("enum_description", "Enum Description setted by Python")
修改枚举项描述¶
每个枚举项自身的文字描述可以通过PythonEnumLib中的set_description_by_index来修改:
# we can iter each enum item, and set
for i in range(unreal.PythonEnumLib.get_enum_len(self.current_enum)):
unreal.PythonEnumLib.set_description_by_index(self.current_enum, i, f"item description {i}")
修改 BigFlags¶
unreal.PythonEnumLib.set_bitflags_type(self.current_enum, True)
移动枚举项¶
我们移动特定的枚举项到指定位置,其他的枚举项将依次按序移动。比如将[A, B, C, D, E], index 1 移动到 index 3 时结果将会是 [A, C, D, B, E]:
unreal.PythonEnumLib.move_enum_item(self.current_enum, 1, 3)
User Defined Struct¶
作为一个重要的“数据资源”,User defined Struct 当然也需要能够创建、查询和修改
创建User Defined Struct¶
创建User Defined Struct的方法和上面创建User Defined Enum的方式类似:
asset_tools = unreal.AssetToolsHelpers.get_asset_tools()
result = asset_tools.create_asset("IAMStruct", "/Game/CreateByPython", unreal.UserDefinedStruct, unreal.StructureFactory())
修改 User Defined Struct¶
添加变量¶
在Struct中添加变量会比在Enum中添加一个枚举项要复杂一些。因为变量可以是各种基础类型,也可以是其他Struct,接口,对象,甚至是一个“对象类的软引用”,同时Struct中的变量类型还可以指定为“单个”,“数组”,“集合”和“映射”(字典)类型
下面是 PythonStructLib.add_variable 的函数文档
``` add_variable(...) X.add_variable(struct, category, sub_category, sub_category_object, container_type_value, is_reference=False) -> bool Add a new variable to specified User Defineded Strcut
Args:
struct (UserDefinedStruct): The User Defineded Strcut you want to modify.
category (Name): The Category of the new Variable
sub_category (Name): The SubCategory of the new Variable
sub_category_object (Object): The SubCategoryObject of the new Variable
container_type_value (int32): Container type. 0: single, 1: array, 2: set. Use add_directory_variable if you want add a map variable
is_reference (bool): Whether e new Variable passed as reference
Returns:
bool: True if the new variable has been added
```
下面直接举例:
- 添加一个布尔变量:
unreal.PythonStructLib.add_variable(self.current_struct, "bool", "", None, 0, False)
- 添加一个int变量:
unreal.PythonStructLib.add_variable(self.current_struct, "int", "", None, 0, False)
- 添加一个int64变量:
unreal.PythonStructLib.add_variable(self.current_struct, "int64", "", None, 0, False)
- 添加一个float类型的数组变量:
unreal.PythonStructLib.add_variable(self.current_struct, "real", "double", None, container_type_value=1, is_reference=False)
- 添加一个Name类型的集合变量:
unreal.PythonStructLib.add_variable(self.current_struct, "string", "", None, container_type_value=2, False)
- 添加一个Vector变量
unreal.PythonStructLib.add_variable(self.current_struct, "struct", "", unreal.Vector.static_struct(), 0, False)
- 添加一个Transform变量
unreal.PythonStructLib.add_variable(self.current_struct, "struct", "", unreal.Transform.static_struct(), 0, False)
事实上,Factor, Vector, Rotator, Tranform 都是struct类型
- 添加其他Struct类型的变量
unreal.PythonStructLib.add_directory_variable(self.current_struct, 'struct', '', unreal.AbcMaterialSettings.static_struct(), 0)
- 添加一个接口类型的变量
unreal.PythonStructLib.add_variable(self.current_struct, 'interface', '', unreal.AnimationDataController.static_class(), 0, False)
- 添加一个我们在上文中创建的User Defined Enum类型的变量
unreal.PythonStructLib.add_variable(self.current_struct, "byte", "", unreal.load_asset('/Game/CreatedByPython/IAmAEnum'), 0, False)
- 添加一个在引擎资源中的User Denfind Enum为类型的变量
unreal.PythonStructLib.add_variable(self.current_struct, 'byte', '', unreal.load_asset('/Landmass/Landscape/BP/Enums/SectionSizeOptions'), 0)
- 添加一个Actor类型的变量`
# Add Actor Reference
unreal.PythonStructLib.add_variable(self.current_struct, "object", "", unreal.Actor.static_class(), 0, False)
- 添加一个以“Actor类”为类型的变量
# Object Class Reference
unreal.PythonStructLib.add_variable(self.current_struct, "class", "", unreal.Actor.static_class(), 0, False)
- 添加一个以“Actor软引用”为类型的变量
# Object Reference
unreal.PythonStructLib.add_variable(self.current_struct, "softobject", "", unreal.Actor.static_class(), 0, False)
- 添加一个以“Actor类软引用”为类型的变量
unreal.PythonStructLib.add_variable(self.current_struct, "softclass", "", unreal.Actor.static_class(), 0, False)
注意¶
- 不是所有的举例类型都可以成为集合或者映射(字典)类型,只有可哈希的类型可以
- 布尔类型的值,比如True是可哈希的,但却不能成为集合或者映射(字典)类型的变量
在PythonStructLib.add_variable中,我们用参数container_type_value来指定变量的container类型是"Single", "Array"或者"Set",如果我们想要创建一个Map集合(dict字典) 类型的变量,我们可以用:PythonStructLib.add_directory_variable
下面这行python代码将 - 添加一个key为 actor soft calss类型的,值为string类型的映射(字典)类型变量:
unreal.PythonStructLib.add_directory_variable(self.current_struct, "softclass", "", unreal.Actor.static_class(), False, "string", "", None)
那么我要如何才能知道变量的所谓"Category", "SubCategory" 和 "sub_category_object"分布都是什么呢?¶
我们先在编辑器中添加一个想要的变量,然后通过PythonStructLib.log_var_desc来查看:
unreal.PythonStructLib.log_var_desc(self.current_struct)
比如上图,Category: softclass|None 分别是"Category", "SubCategory"的值,SubCategoryObject为 /Script/Engine.Actor;PinValueType: string|None 中的分别是字典类型Value的 "Terminal_Category" 和 "Terminal_Sub_Category"的值,TerminalSubCategoryObject为 None。
SubCategoryObject 和TerminalSubCategoryObject为对于类型的static_class或static_struct。具体可见上文范例
另外,我们也可以通过unreal.PythonStructLib.get_variable_description 以字典的形式获得指定变量的具体“变量描述”
desc = unreal.PythonStructLib.get_variable_description(self.current_struct, var_name)
DataTable¶
创建DataTable¶
作为UE引擎的“正统数据表”,DataTable也是可以用Python创建的,唯一的不同是在DataTableFactory中需要指定该DataTable所使用的Struct,比如下面的例子直接使用了上文中同样通过python创建的IAMStruct
asset_tools = unreal.AssetToolsHelpers.get_asset_tools()
factory = unreal.DataTableFactory()
factory.struct = unreal.load_asset("/Game/CreatedByPython/MyStruct")
result = asset_tools.create_asset("IAmADataTable", "/Game/CreatedByPython", unreal.DataTable, factory)
修改 DataTable¶
添加行¶
我们可以给DataTable添加一行:
unreal.PythonDataTableLib.add_row(self.current_datatable, row_name)
上面的"row_name"作为行名是需要在这个DataTable中是唯一的,不许同名。所以我们需要查询该name是否已经存在
exists_names = unreal.PythonDataTableLib.get_row_names(self.current_datatable)
bUnique = name not in exists_names
移除一行¶
unreal.PythonDataTableLib.remove_row(self.current_datatable, row_name)
重命名一行¶
重命名也是必需的
unreal.PythonDataTableLib.rename_row(self.current_datatable, row_name, new_row_name)
取得DataTable中内容¶
PythonDataTableLib 提供了多种方法来查询DataTable中的内容
我们可以将其整个以一个JSON文件的形式返回:
unreal.PythonDataTableLib.get_table_as_json(self.current_datatable)
或者将其一个1D数组的形式返回。当然这个时候我们需要知道它的行列数量,通过下面的PythonDataTableLib.get_shape来获得:
unreal.PythonDataTableLib.get_flatten_data_table(self.current_datatable, include_header=False)`
row_count, column_count = unreal.PythonDataTableLib.get_shape(self.current_datatable)
此外,还可以通过指定某个单元格的形式来获取
# get value
current_value = unreal.PythonDataTableLib.get_property_as_string_at(self.current_datatable, row_index, column_index)
设置DataTable内容¶
我们可以通过unreal.PythonDataTableLib.set_property_by_string_at来设置指定“单元格”中的内容
# set value
unreal.PythonDataTableLib.set_property_by_string_at(self.current_datatable, row_index, column_index, new_value)
例如,下面的例子将把DataTable中引用的static_mesh指定为:'/Game/Somewhere/YourMesh'这个路径中的mesh
# modify the static mesh reference in datatable at row 1 column 2
new_value = "StaticMesh'/Game/Somewhere/YourMesh.YourMesh_0'"
unreal.PythonDataTableLib.set_property_by_string_at(self.current_datatable, 1, 2, new_value)
小结¶
至此,我们可以通过TAPython中的 PythonEnumLib,PythonStructLib, PythonDataTableLib “掌控”工程中的User Defined Enum,Struct 和DataTable。用脚本维护这些数据类型资源将会变得方便。那下一步是通过python创建整个工程的资源?