UE4SS Lua API 实战:Property 类详解——操纵 UE 反射属性元数据与底层值

发布时间:2026/10/4 10:39:34
UE4SS Lua API 实战:Property 类详解——操纵 UE 反射属性元数据与底层值 游戏开发逆向工程【免费下载链接】RE-UE4SSInjectable LUA scripting system, SDK generator, live property editor and other dumping utilities for UE4/5 games项目地址https://gitcode.com/gh_mirrors/re/RE-UE4SS点击查看免费下载本篇技术指南围绕 UE4SS 的 Lua API 中Property类展开它封装了 Unreal Engine 的FProperty反射元数据是读取属性全名、判断属性类型、定位容器内属性内存地址乃至通过ImportText批量注入属性值的核心入口。读完本文你将掌握如何通过UObjectReflection:GetProperty()与UStruct:ForEachProperty()拿到属性对象并熟练运用GetFullName、GetFName、IsA、ContainerPtrToValuePtr、ImportText等全部方法在 UE4/UE5 游戏内编写可复用的属性级 Lua 工具脚本。Property 类是什么UE 反射系统的 Lua 化身在 Unreal Engine 中FProperty是反射系统Reflection System中描述一个属性的元数据对象它记录属性名、属性类型、在容器对象内的偏移量Offset等信息。UE4SS 将这一概念完整映射到了 Lua 侧即本文介绍的Property类。Property在 UE4SS 的对象体系中继承自 RemoteObject意味着它内部持有的是一个指向游戏中 C 对象的指针由游戏拥有而非 Lua 拥有因此与UObject一样具备IsValid()、GetAddress()等来自基类的能力可以用来判断底层FProperty指针是否仍然有效。按照 Lua API 总览 的定义Property的完整方法集如下方法返回类型说明GetFullName()string返回属性的完整名称与路径GetFName()FName按拷贝返回属性的 FNameIsA(PropertyTypes PropertyType)bool判断属性是否为指定类型GetClass()PropertyClass返回属性的类FieldClassContainerPtrToValuePtr(Container, ArrayIndex)LightUserdata计算属性在容器内的值地址等价FProperty::ContainerPtrToValuePtruint8ImportText(Buffer, Data, PortFlags, OwnerObject)无从文本导入属性值等价FProperty::ImportText去掉了ErrorText参数第一步如何拿到一个 Property 对象Property对象不会凭空出现它通常通过以下两条反射路径获得。途径一UObjectReflection:GetProperty()UObject上的Reflection()方法会返回一个UObjectReflection对象其 GetProperty(string PropertyName) 方法按属性名查找并返回对应的Property元数据对象local Actor FindFirstOf(Actor) if Actor ~ nil and Actor:IsValid() then local Reflection Actor:Reflection() local Property Reflection:GetProperty(RootComponent) if Property:IsValid() then print(Property:GetFullName()) end end从源码看Reflection()与GetProperty的实现位于 UE4SS/include/LuaType/LuaUObject.hpp它先从反射表中取出被反射的 UObject若该对象本身就是UStruct则直接作为查找目标否则取GetClassPrivate()即对象的类随后调用FindProperty(FName(property_name, FNAME_Find))定位属性最后调用construct_xproperty(lua, property)把原生FProperty包装成 Lua 的Property对象返回。如果属性不存在返回的 Property 内部指针为nullptr——此时调用:IsValid()会得到false脚本应据此做判空源码注释也明确说明这是为了支持安全链式调用safe chaining而设计的行为。途径二UStruct:ForEachProperty()如果你需要遍历某个 UClass/UStruct 的全部属性例如批量导出、批量检查可以使用UStruct上的 ForEachPropertylocal UClass FindFirstOf(PlayerCharacter) -- 示例任意 UClass if UClass ~ nil then UClass:ForEachProperty(function(Property) print(Property:GetFullName()) -- 返回 true 可提前终止遍历 if Property:GetFName():ToString() Health then return true end end) end其底层实现在 UE4SS/src/LuaType/LuaUStruct.cpp通过Unreal::TFieldRangeUnreal::FProperty(..., Unreal::EFieldIterationFlags::IncludeDeprecated)遍历结构体上所有属性包含已弃用属性对每个属性调用auto_construct_property(lua, property)构造 Lua 对象后回调 Lua 函数回调返回true时break终止遍历。这段源码也揭示了ForEachProperty与Reflection:GetProperty背后的共同纽带——auto_construct_property这一统一构造入口。核心方法逐个拆解GetFullName()获取属性的完整路径返回类型string返回内容属性的完整名称与路径格式与 UE 的FProperty::GetFullName一致例如ObjectProperty /Script/Engine.Actor:RootComponent包含属性类型、所属对象路径与属性名。实现位于 UE4SS/src/LuaType/LuaXProperty.cpp调用底层GetFullName()后通过to_string(...)转成 ANSI 字符串压入 Lua 栈。一个值得注意的细节若底层FProperty指针为nullptr例如用不存在的属性名调用了Reflection:GetProperty此方法返回的不是空字符串而是nil便于在 Lua 侧做对象是否真实存在的判断——这与 UObject 的GetFullName行为一致。GetFName()按拷贝获取属性名返回类型FName返回内容该属性的FName按值拷贝。文档特别强调了一条规则所有通过__index返回的FName都是按引用reference返回的而GetFName()是按拷贝by copy返回的。两者差异在实际脚本中体现为通过__index即直接访问Property.属性名拿到的 FName 指向共享的底层名称实例适合只读比较而GetFName()返回一个独立的拷贝配合FName:ToString()可以安全地转成字符串而不必担心被后续操作覆盖local Prop Actor:Reflection():GetProperty(RootComponent) local Name Prop:GetFName() -- FName拷贝 print(Name:ToString()) -- RootComponent源码对应 UE4SS/src/LuaType/LuaXProperty.cpp直接FName::construct(lua, ...GetFName())构造一个全新的 FName 对象。IsA()判断属性类型返回类型bool参数PropertyTypes表中的一项见下文返回内容属性是否为指定类型true/false。在 Lua 中调用形式为if Property:IsA(PropertyTypes.ObjectProperty) then -- 这是一个对象引用属性 endPropertyTypes是 UE4SS 预定义的一张类型表在 Lua API 总览 中有完整清单取值包括ObjectProperty、ObjectPtrProperty、Int8Property、Int16Property、IntProperty、Int64Property、NameProperty、FloatProperty、StrProperty、ByteProperty、UInt16Property、UIntProperty、UInt64Property、BoolProperty、ArrayProperty、MapProperty、StructProperty、ClassProperty、WeakObjectProperty、EnumProperty、TextProperty等。从源码看UE4SS/src/LuaType/LuaXProperty.cppIsA在 C 侧要求传入一张包含整数键FFieldClassPointer的 table这正是PropertyTypes表中每个条目的内部表示随后根据 UE 版本做分叉处理UE 4.25 及以上把该指针bit_cast为FFieldClass*调用FProperty::IsA(FFieldClass)4.25 以下则bit_cast为UClass*调用重载。若参数不是合法 table会抛出如下错误No overload found for function IsA. Overloads: #1: IsA(PropertyTypes PropertyType)GetClass()获取属性的类元数据返回类型PropertyClass返回一个PropertyClass对象底层为FFieldClass用于描述该属性属于哪个 Unreal 字段类。该返回对象在 UE4SS 中对应文档中的 FieldClass 类其继承自LocalObject提供GetFName()方法返回类的 FName按拷贝。典型用法local Class Property:GetClass() print(Class:GetFName():ToString()) -- 例如 ObjectProperty实现见 UE4SS/src/LuaType/LuaXProperty.cpp直接对底层FProperty::GetClass()结果调用XFieldClass::construct。ContainerPtrToValuePtr()定位属性在容器内的值地址返回类型LightUserdata参数Container一个UObject或其派生对象属性的容器即拥有该属性的对象实例ArrayIndex可选整数数组下标用于定位数组/固定大小数组中的具体元素等价于 UE 中的FProperty::ContainerPtrToValuePtruint8给定容器对象指针与数组下标计算出该属性值在容器内存中的实际字节地址。返回值是LightUserdata轻量用户数据它不是一个可调用方法的 Lua 对象而是可以直接传递给其他底层 API如ImportText的Data参数的裸指针。local Property Actor:Reflection():GetProperty(SomeInt) local ValuePtr Property:ContainerPtrToValuePtr(Actor, 0) -- lightuserdata -- ValuePtr 可传入 ImportText 等需要原生地址的 API源码实现UE4SS/src/LuaType/LuaXProperty.cpp展示了参数校验细节Container必须是 userdata 且被解释为UObject第二个参数既接受整数作为int32_t数组下标也接受nil视为默认值 0否则报出重载错误。最终通过lua_pushlightuserdata把计算出的uint8_t*地址压栈返回。ImportText()从文本导入属性值参数Bufferstring要解析的属性文本例如1234、True或对象路径字符串DataLightUserdata目标内存地址通常来自ContainerPtrToValuePtr的返回值PortFlagsinteger导入时使用的端口标志位对应 UE 的EPropertyPortFlags如PPF_Copy等OwnerObjectUObject属性所属的对象等价于 UE 的FProperty::ImportText唯一的差别是去掉了ErrorText输出参数。这是 UE4SS 提供的少数几个从文本直接写属性值的底层通道适合实现属性导入/序列化类工具例如把存档文本还原到对象上local Prop Actor:Reflection():GetProperty(Health) local Ptr Prop:ContainerPtrToValuePtr(Actor, 0) Prop:ImportText(100, Ptr, 0, Actor)实现UE4SS/src/LuaType/LuaXProperty.cpp严格校验四个参数的类型Buffer必须是 stringData必须是 lightuserdata通过lua_islightuserdata判定PortFlags必须是 integerOwnerObject必须是 userdata解析为UObject。任一类型不符都会抛出包含全部重载信息的运行时错误No overload found for function ImportText. Overloads: #1: ImportText(string Buffer, lightuserdata Data, integer PortFlags, UObject OwnerObject)源码级机制类型分派与 Property 子类家族阅读本文开头如何获取 Property时你可能会好奇为什么ForEachProperty回调里拿到的对象有的能调用GetPropertyClass()有的能调用GetStruct()这背后的机制是auto_construct_property的运行时类型分派。其完整实现位于 UE4SS/src/LuaType/LuaXProperty.cpp拿到原生FProperty*后依次用CastField尝试转换为具体的 Unreal 字段类型命中即构造对应的 Lua 子类对象判定顺序原生类型构造的 Lua 类1FObjectPropertyXObjectProperty文档ObjectProperty提供GetPropertyClass())2FBoolPropertyXBoolProperty文档BoolProperty提供GetByteMask()/GetByteOffset()/GetFieldMask()/GetFieldSize()3FStructPropertyXStructProperty文档StructProperty提供GetStruct()4FEnumPropertyXEnumProperty文档EnumProperty5FArrayPropertyXArrayProperty文档ArrayProperty提供GetInner()6其余类型兜底构造为基类XProperty这些子类全部继承自Property因此GetFullName()、IsA()、ContainerPtrToValuePtr()等方法在任何子类上都可用。另外注意分派顺序先判定FObjectProperty再判FBoolProperty、FStructProperty、FEnumProperty、FArrayProperty最后才是兜底基类——CastField的语义保证了只有精确类型才会命中各自分支。值得留意的是XProperty::setup_metamethods是空的注释明确写着XProperty has no metamethods说明Property本身不定义__index/__newindex等元方法属性值读写走的是UObject层的__index/__newindex体系而非 Property 对象自身。一个实用的类型分派示例——只打印对象引用类属性并读取其引用local Class FindFirstOf(PlayerCharacter) if Class ~ nil then Class:ForEachProperty(function(Property) if Property:IsA(PropertyTypes.ObjectProperty) then print(Object property:, Property:GetFullName()) -- ObjectProperty 子类可继续调用 GetPropertyClass() 等 end end) end组合实战遍历 判断 定位 导入把本文所有方法串起来一个典型的按类型过滤并批量导入属性脚本长这样-- 找到目标 Actor local Actor FindFirstOf(Actor) if Actor nil or not Actor:IsValid() then return end -- 1) 通过反射拿到属性的元数据 local Reflection Actor:Reflection() local HealthProp Reflection:GetProperty(Health) -- 2) 判断类型后再动手 if HealthProp:IsValid() and HealthProp:IsA(PropertyTypes.IntProperty) then -- 3) 在容器Actor 实例内定位属性值的地址 local ValuePtr HealthProp:ContainerPtrToValuePtr(Actor, 0) -- 4) 用文本方式把新值写入该地址 HealthProp:ImportText(999, ValuePtr, 0, Actor) print(Health 已更新属性路径:, HealthProp:GetFullName()) end几个容易踩的坑结合文档与源码一并提醒Reflection:GetProperty找不到属性时返回的 Property 内部指针为nullptr调用GetFullName()会得到nil且此时任何底层操作都可能失败——务必先用:IsValid()继承自 RemoteObject做判空ContainerPtrToValuePtr返回的是 lightuserdata 而非完整 Lua 对象不能对它调用方法只能作为裸地址传给ImportText或用于打印/比较地址配合基类的GetAddress()思路IsA的参数必须来自PropertyTypes表直接传字符串如ObjectProperty不会命中任何重载会抛出未找到重载错误ImportText的PortFlags通常是 0除非你明确需要 UE 的PPF_*行为如PPF_Copy否则保持 0 即可。以上全部方法与行为均可在仓库源码 UE4SS/src/LuaType/LuaXProperty.cpp 及其头文件 UE4SS/include/LuaType/LuaXProperty.hpp 中逐行验证若需进一步了解属性值读写的上层机制__index/__newindex如何把属性映射为 Lua 值可继续阅读 UObject 类文档 与 Lua API 总览。赞分享游戏开发逆向工程【免费下载链接】RE-UE4SSInjectable LUA scripting system, SDK generator, live property editor and other dumping utilities for UE4/5 games项目地址https://gitcode.com/gh_mirrors/re/RE-UE4SS点击查看免费下载相关推荐UE4SS C Mod 开发指南通过反射元数据安全读写 UE 属性UE4SS C Mod 开发指南通过反射元数据安全读写 UE 属性 本指南讲解如何在 UE4SS 的 C Mod 中通过游戏自带的反射元数据Ref游戏开发逆向工程RE-UE4SS Lua API 指南ObjectProperty 对象属性类型详解与实战RE UE4SS Lua API 指南ObjectProperty 对象属性类型详解与实战 导读 ObjectProperty 是 RE UE4SS 提供给游戏开发逆向工程UE4SS Lua API 深度指南UStruct 反射类型UE4SS Lua API 深度指南UStruct 反射类型 引言 UStruct 是 UE4/UE5 反射体系的核心类型它定义了所有含反射字段的 Unre游戏开发逆向工程上一篇10分钟快速上手StyleGAN2-PyTorch完整安装与配置教程下一篇Convex 组件 API 导入模式解析convex-backend 中 components-api-import demo 与 legacyComponentApi 配置实战创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考