上一回实现了运行时创建枚举,这次再试试结构体,虚幻中的反射结构体是UScriptStruct的实例.同样,蓝图新建的结构体是UUserDefinedStruct的实例.
结构体由多个字段构成,虚幻中称为属性,即FProperty,FProperty描述了一个变量在一段内存的位置和大小,结构体通过链表来保存各个字段.
要创建一个结构体,需要创建一个继承自UScriptStruct的类ULuaGeneratedStruct,然后根据所需要的字段及其类型创建FProperty,
这里并不需要手动去操作PropertyLink这个链表成员,只需要新建Fproperty,结束后调用StaticLink即可完成链表关联.
简要实现如下:
// Fill out your copyright notice in the Description page of Project Settings.
#include "LuaGeneratedStruct.h"
ULuaGeneratedStruct* ULuaGeneratedStruct::GenerateStruct(const FString& InStructName, const TMap<FString, int32>& InVariables)
{
ULuaGeneratedStruct* NewStruct = FindObject<ULuaGeneratedStruct>(ANY_PACKAGE, *InStructName);
if (!NewStruct)
{
NewStruct = NewObject<ULuaGeneratedStruct>(GetTransientPackage(), *InStructName, RF_Public | RF_Standalone | RF_Transient);
NewStruct->SetMetaData(TEXT("BlueprintType"), TEXT("true"));
NewStruct->Bind();
NewStruct->StaticLink(true);
NewStruct->AddToRoot();
}
else
{
return NewStruct;
}
int32 PropCount = 0;
int32 PropOffset = 0;
EObjectFlags ObjectFlags = EObjectFlags::RF_Standalone;
EPropertyFlags PropertyFlags = EPropertyFlags::CPF_None;
bool bIsPOD = true;
for (const TPair<FString, int32>& It : InVariables)
{
FProperty* NewProp = nullptr;
UE4CodeGen_Private::EPropertyGenFlags PropertyType = (UE4CodeGen_Private::EPropertyGenFlags)(It.Value);
switch (PropertyType)
{
case UE4CodeGen_Private::EPropertyGenFlags::Int8:
NewProp = new FInt8Property(NewStruct, FName(*It.Key), ObjectFlags, PropOffset, PropertyFlags);
NewProp->SetPropertyFlags(EPropertyFlags::CPF_IsPlainOldData);
break;
case UE4CodeGen_Private::EPropertyGenFlags::Byte:
NewProp = new FByteProperty(NewStruct, FName(*It.Key), ObjectFlags, PropOffset, PropertyFlags, nullptr);
NewProp->SetPropertyFlags(EPropertyFlags::CPF_IsPlainOldData);
break;
case UE4CodeGen_Private::EPropertyGenFlags::Int16:
NewProp = new FInt16Property(NewStruct, FName(*It.Key), ObjectFlags, PropOffset, PropertyFlags);
NewProp->SetPropertyFlags(EPropertyFlags::CPF_IsPlainOldData);
break;
case UE4CodeGen_Private::EPropertyGenFlags::UInt16:
NewProp = new FUInt16Property(NewStruct, FName(*It.Key), ObjectFlags, PropOffset, PropertyFlags);
NewProp->SetPropertyFlags(EPropertyFlags::CPF_IsPlainOldData);
break;
case UE4CodeGen_Private::EPropertyGenFlags::Int:
NewProp = new FIntProperty(NewStruct, FName(*It.Key), ObjectFlags, PropOffset, PropertyFlags);
NewProp->SetPropertyFlags(EPropertyFlags::CPF_IsPlainOldData);
break;
case UE4CodeGen_Private::EPropertyGenFlags::UInt32:
NewProp = new FUInt32Property(NewStruct, FName(*It.Key), ObjectFlags, PropOffset, PropertyFlags);
NewProp->SetPropertyFlags(EPropertyFlags::CPF_IsPlainOldData);
break;
case UE4CodeGen_Private::EPropertyGenFlags::Int64:
NewProp = new FInt64Property(NewStruct, FName(*It.Key), ObjectFlags, PropOffset, PropertyFlags);
NewProp->SetPropertyFlags(EPropertyFlags::CPF_IsPlainOldData);
break;
case UE4CodeGen_Private::EPropertyGenFlags::UInt64:
NewProp = new FUInt64Property(NewStruct, FName(*It.Key), ObjectFlags, PropOffset, PropertyFlags);
NewProp->SetPropertyFlags(EPropertyFlags::CPF_IsPlainOldData);
break;
case UE4CodeGen_Private::EPropertyGenFlags::Float:
NewProp = new FFloatProperty(NewStruct, FName(*It.Key), ObjectFlags, PropOffset, PropertyFlags);
NewProp->SetPropertyFlags(EPropertyFlags::CPF_IsPlainOldData);
break;
case UE4CodeGen_Private::EPropertyGenFlags::Str:
NewProp = new FStrProperty(NewStruct, FName(*It.Key), ObjectFlags, PropOffset, PropertyFlags);
bIsPOD = false;
break;
case UE4CodeGen_Private::EPropertyGenFlags::Array:
NewProp = new FArrayProperty(NewStruct, FName(*It.Key), ObjectFlags, PropOffset, PropertyFlags, EArrayPropertyFlags::None);
bIsPOD = false;
break;
case UE4CodeGen_Private::EPropertyGenFlags::Map:
NewProp = new FMapProperty(NewStruct, FName(*It.Key), ObjectFlags, PropOffset, PropertyFlags, EMapPropertyFlags::None);
bIsPOD = false;
break;
}
++PropCount;
PropOffset += NewProp->GetSize();
}
if(bIsPOD)
{
NewStruct->StructFlags = (EStructFlags)(NewStruct->StructFlags | EStructFlags::STRUCT_IsPlainOldData);
}
NewStruct->Bind();
NewStruct->StaticLink(true);
return NewStruct;
}
LUA中新建结构体如下:
--结构体名字,描述成员名字和类型
local TmpStructName = 'XQStruct'
local TmpVatList =
{
['MyID'] = UnrealPropertyType.EPropertyGenFlags.Int,
['MyName'] = UnrealPropertyType.EPropertyGenFlags.Str
}
local NewStruct = LuaGeneratedStruct:GenerateStruct(TmpStructName, TmpVatList)
--用LUA表填充结构体实例
local XQVal =
{
['MyID'] = 111,
['MyName'] = 'efrewfr34'
}
local MyT = Unreal.LuaNewStruct('XQStruct', XQVal)
print(MyT.MyID, MyT.MyName)
--虚幻中属性类型对应的枚举值如下,取自UE4CodeGen_Private::EPropertyGenFlags
LuaGeneratedEnum = LuaGeneratedEnum or Unreal.LuaGetUnrealCDO('LuaGeneratedEnum')
LuaGeneratedStruct = LuaGeneratedStruct or Unreal.LuaGetUnrealCDO('LuaGeneratedStruct')
UnrealProperty = UnrealProperty or {}
UnrealProperty.EPropertyGenFlags =
{
None = 0x00,
Byte = 0x00,
Int8 = 0x01,
Int16 = 0x02,
Int = 0x03,
Int64 = 0x04,
UInt16 = 0x05,
UInt32 = 0x06,
UInt64 = 0x07,
UnsizedInt = 0x08,
UnsizedUInt = 0x09,
Float = 0x0A,
Double = 0x0B,
Bool = 0x0C,
SoftClass = 0x0D,
WeakObject = 0x0E,
LazyObject = 0x0F,
SoftObject = 0x10,
Class = 0x11,
Object = 0x12,
Interface = 0x13,
Name = 0x14,
Str = 0x15,
Array = 0x16,
Map = 0x17,
Set = 0x18,
Struct = 0x19,
Delegate = 0x1A,
InlineMulticastDelegate = 0x1B,
SparseMulticastDelegate = 0x1C,
Text = 0x1D,
Enum = 0x1E,
FieldPath = 0x1F,
NativeBool = 0x20
}
return UnrealProperty