Skip to content

Slua 2.0 特性介绍

zjhongxian edited this page Apr 23, 2023 · 1 revision

Slua 2.0 特性介绍

Slua 2.0是PUBG Mobile内部业务驱动孵化出来的Slua Unreal高级版本。稳定支撑PUBG Mobile海量GamePlay开发业务。

Slua Overrider机制

Overrider 机制是指用Lua去扩展、覆写蓝图甚至C++ UFunction,尽量用Lua去替代蓝图进行开发的机制。替代原有的LuaActor,并解决它原有的各种问题。

这个机制在PUBGM内部2020年5月提交第一行代码,9月PR给Slua Unreal官方:https://github.com/Tencent/sluaunreal/pull/374 但是因为各种原因耽搁暂未合入。

直到现在迎来Slua 2.0的发布(暂时放在https://github.com/zjhongxian/sluaunreal 分支),后续等待文档、样例完善后将合入到官版。

如何使用

  • c++代码端可参考LuaActor类
  • 蓝图
    • step1: 添加LuaOverrideInterface类 image

    • step2:实现GetLuaFilePath函数,并填写返回Lua模块名 image

Lua模块支持类继承形式书写,例如:

-- LuaActor.lua
local LuaActor ={}

-- override event from blueprint
function LuaActor:ReceiveBeginPlay()
    self.bCanEverTick = true
    -- set bCanBeDamaged property in parent
    self.bCanBeDamaged = false
    print("actor:ReceiveBeginPlay")
end

-- override event from blueprint
function LuaActor:ReceiveEndPlay(reason)
    print("actor:ReceiveEndPlay")
end

return Class(nil, nil, LuaActor)

-- LuaBpActor.lua
local LuaBpActor = {}

-- override event from blueprint
function LuaBpActor:ReceiveBeginPlay()
    print("bpactor:ReceiveBeginPlay")
    -- call LuaActor super ReceiveBeginPlay
    LuaBpActor.__super.ReceiveBeginPlay(self)
    
    -- call blueprint super ReceiveBeginPlay
    self.Super:ReceiveBeginPlay()
end

local CLuaActor = require("LuaActor")
-- CLuaActor is base class
return Class(CLuaActor, nil, LuaBpActor)

支持Lua定义RPC函数

-- LuaActor.lua
local LuaActor = 
{
    ServerRPC = {},     --C2S类RPC列表,类似UFUNCTION宏中的Server
    ClientRPC = {},     --S2C类RPC列表,类似UFUNCTION宏中的Client
    MulticastRPC = {},  --多播类RPC列表,类似UFUNCTION宏中的NetMulticast
}

local EPropertyClass = import("EPropertyClass")

LuaActor.ServerRPC.TestServerRPC = {
    -- 是否可靠RPC
    Reliable = true, 
    -- 定义参数列表
    Params = 
    { 
        UEnums.EPropertyClass.Int, 
        UEnums.EPropertyClass.Str, 
        UEnums.EPropertyClass.bool, 
    }
}

LuaActor.ClientRPC.TestClientRPC = {
    -- 是否可靠RPC
    Reliable = true, 
    -- 定义参数列表
    Params = 
    { 
        UEnums.EPropertyClass.Int, 
        UEnums.EPropertyClass.Str, 
        UEnums.EPropertyClass.bool, 
    }
}

LuaActor.MulticastRPC.TestMulticastRPC = {
    -- 是否可靠RPC
    Reliable = true, 
    -- 定义参数列表
    Params = 
    { 
        UEnums.EPropertyClass.Int, 
        UEnums.EPropertyClass.Str, 
        UEnums.EPropertyClass.bool, 
    }
}

function LuaActor:TestServerRPC(ArgInt, ArgStr, ArgBool)
    
end

function LuaActor:TestClientRPC(ArgInt, ArgStr, ArgBool)
    
end

function LuaActor:TestMulticastRPC(ArgInt, ArgStr, ArgBool)
    
end

支持Lua定义"值复制"信息,并且支持“条件”值复制、struct、数组

-- LuaActor.lua
local LuaActor ={}

function LuaActor:GetLifetimeReplicatedProps()
    local ELifetimeCondition = import("ELifetimeCondition")
    local FVectorType = import("FVector")
    return {
        { "Name", ELifetimeCondition.COND_InitialOnly, EPropertyClass.Str},
        { "HP", ELifetimeCondition.COND_OwnerOnly, EPropertyClass.Float},
        { "Position", ELifetimeCondition.COND_SimulatedOnly, FVectorType},
        { "TeamateNameList", ELifetimeCondition.COND_None, EPropertyClass.Array, EPropertyClass.Str},
        { "TeamatePositions", ELifetimeCondition.COND_None, EPropertyClass.Array, FVectorType},
    }
end

return Class(nil, nil, LuaActor)

被Override的Cpp函数里面可以直接调用对应Lua函数

-- MyActor.cpp
class MyActor : public Actor, public ILuaOverriderInterface
{
public:
    void CallDemoFunction()
    {
        CallLuaFunction<bool>(TEXT("IsTestEnable"), Arg1, Arg2);
    }
}
-- MyActor.lua

local MyActor ={}

function MyActor:IsTestEnable(Arg1, Args)
    return true
end

return Class(nil, nil, MyActor)

重要修复

  • 解决1.x版本的生命周期管理问题
  • 解决1.x self.Super:Func() 调用,在蓝图有jump指令时崩溃的问题

机制修改

  • struct访问由拷贝改为引用,收益如下:
--- 以修改一个Vector类型字段为例

--- 老代码
local Position = Actor.Position
Position.X = 1
Actor.Position = Position

--- 新代码
Actor.Position.X = 1

Slua交互性能优化

  • 函数索引相比 1.x 版本有10倍速度提升
  • 属性访问、函数调用等,普遍有20%~800%的提升(大部分API速度是原来的1.5~3倍)。

稳定性更加强大

支撑PUBG Mobile 线上业务开发,稳定性得到充分验证。

工具链

  • slua profiler
    • 解决 1.x 版本cpu profiler大量调用卡死问题、且支持协程
    • 完善memory profiler
    • 支持保存profiler数据
    • 支持stat录制lua性能(运行 slua_profile.setHook(true)这段lua代码)

版本支持

  • UE4.18、UE4.26完整支持,其他版本因为时间精力问题暂时无法支持到位
  • 兼容lua 5.4版本接入

为何选择Slua 2.0

  • 强大的稳定性,lua随便写而不会有因slua底层而导致的崩溃(不排除业务或引擎自身的问题)。

  • 完善的Override机制,Override本身设计实现的时候需要考虑到各种复杂情况,它经受住了量子工作室内部2个项目海量业务的严峻考验。且它有独家的Lua定义RPCLua值复制功能。

  • 完备的内存管理

    • PUBG Mobile海量业务验证,slua本身无C++内存泄露。
    • 强大的类型检查功能,无须担心传错类型而导致崩溃,传错类型slua会有完善的报错提示。
    • lua只会引用主动创建的UObject,大大减少lua导致的UObject泄露。
    • Override形式的UI无须调用Destroy API,正常从父Panel移除,且解开外部对它的引用即可。
  • 更快的属性、函数交互速度。

  • 强大便捷的CPU、Memory分析定位工具(PUBG Mobile内部还有lua引用UObject导致泄露的定位工具,因为涉及到UE引擎API的导出修改,不符合插件开发的原则所以暂不公开)。

展望

  • profiler功能规划改进: 1、现在profile内存占用过大,原因是路径有大量重复冗余。 2、边录制边streaming落地磁盘功能。

附:竞品性能对比

系统Win10 64位

CPU: AMD Ryzen 7 4700G with Radeon Graphics 3.60 GHZ

10万次/秒 Slua UnLua Unlua/Slua
TestStaticCall 0.01894 0.02667 1.41
TestEmptyCall 0.0183 0.03351 1.83
TestSetBoolCall 0.02541 0.04206 1.66
TestGetBoolCall 0.02134 0.04893 2.29
TestSetIntCall 0.02381 0.04222 1.77
TestGetIntCall 0.02085 0.04239 2.03
TestSetFloatCall 0.02265 0.04031 1.78
TestGetFloatCall 0.02167 0.03701 1.71
TestSetFStringCall 0.04986 0.08801 1.77
TestGetFStringCall 0.03032 0.07163 2.36
TestSetVectorCall 0.03339 0.07208 2.16
TestGetVectorCall 0.05619 0.0878 1.56
TestSetStructCall 0.0376 0.07982 2.12
TestGetStructCall 0.08137 0.08871 1.09
TestGetObjectCall 0.03054 0.04709 1.54
TestSetIntVar 0.01305 0.01745 1.34
TestGetIntVar 0.01396 0.01553 1.11
TestSetStrVar 0.02573 0.03327 1.29
TestGetStrVar 0.01743 0.02555 1.47
TestSetBoolVar 0.01362 0.01559 1.14
TestGetBoolVar 0.01406 0.01435 1.02
TestSetFloatVar 0.01336 0.01557 1.17
TestGetFloatVar 0.01381 0.01585 1.15
TestSetVectorVar 0.0194 0.01773 0.91
TestGetVectorVar 0.01109 0.02358 2.13
TestSetStructVar 0.01918 0.02197 1.15
TestGetStructVar 0.01085 0.02408 2.22
TestGetObjectVar 0.02111 0.02322 1.10
TestAddArrayElement 0.05216 0.07207 1.38
TestGetArrayElement 0.04115 0.08281 2.01
TestAddSetElement 0.08038 0.09814 1.22
TestGetSetElement 0.02821
TestAddMapElement 0.10757 0.16673 1.55
TestGetMapElement 0.09039 0.14266 1.58
TestBPEmptyCall 0.06335 0.07548 1.19
TestBPSetIntCall 0.10759 0.13205 1.23
TestBPGetIntCall 0.10575 0.13338 1.26
TestBPSetBoolCall 0.10951 0.13201 1.21
TestBPGetBoolCall 0.10572 0.13193 1.25
TestBPSetStringCall 0.13069 0.18015 1.38
TestBPGetStringCall 0.12013 0.15976 1.33
TestBPSetFloatCall 0.10626 0.12982 1.22
TestBPGetFloatCall 0.10486 0.1291 1.23
TestBPSetVectorCall 0.1204 0.16478 1.37
TestBPGetVectorCall 0.17194 0.18061 1.05
TestBPSetStructCall 0.12453 0.17291 1.39
TestBPGetStructCall 0.17526 0.18216 1.04
TestBPSetObjectCall 0.11112 0.1445 1.30
TestBPGetObjectCall 0.11979 0.14663 1.22
TestSetBPIntVar 0.01288 0.01696 1.32
TestGetBPIntVar 0.01432 0.01654 1.16
TestSetBPStrVar 0.02481 0.03447 1.39
TestGetBPStrVar 0.01701 0.02515 1.48
TestSetBPBoolVar 0.01318 0.01801 1.37
TestGetBPBoolVar 0.0131 0.0163 1.24
TestSetBPFloatVar 0.01194 0.01646 1.38
TestGetBPFloatVar 0.01352 0.01554 1.15
TestSetBPVectorVar 0.02013 0.01738 0.86
TestGetBPVectorVar 0.01127 0.02289 2.03
TestSetBPStructVar 0.02006 0.01987 0.99
TestGetBPStructVar 0.01154 0.02252 1.95
TestSetBPObjectVar 0.018 0.01898 1.05
TestGetBPObjectVar 0.01885 0.02216 1.18
TestAddBPArrayElement 0.04994 0.07266 1.45
TestGetBPArrayElement 0.04117 0.08902 2.16
TestAddBPSetElement 0.07719 0.10107 1.31
TestGetBPSetElement 0.08785
TestAddBPMapElement 0.10685 0.15537 1.45
TestGetBPMapElement 0.08607 0.14564 1.69
TestOverrideSetIntVar 0.01253 0.01691 1.35
TestOverrideGetIntVar 0.01315 0.01526 1.16
TestOverrideSetStrVar 0.02569 0.03261 1.27
TestOverrideGetStrVar 0.01637 0.02755 1.68
TestOverrideSetBoolVar 0.01357 0.01731 1.28
TestOverrideGetBoolVar 0.01312 0.01598 1.22
TestOverrideSetFloatVar 0.01298 0.0168 1.29
TestOverrideGetFloatVar 0.01325 0.01613 1.22
TestOverrideSetVectorVar 0.02141 0.01795 0.84
TestOverrideGetVectorVar 0.0103 0.02297 2.23
TestOverrideSetStructVar 0.01906 0.01902 1.00
TestOverrideGetStructVar 0.01135 0.02313 2.04
TestOverrideSetObjectVar 0.02002 0.02091 1.04
TestOverrideGetObjectVar 0.01871 0.0226 1.21
TestOverrideAddArrayElement 0.04959 0.07026 1.42
TestOverrideGetArrayElement 0.04033 0.08686 2.15
TestOverrideAddSetElement 0.07604 0.09988 1.31
TestOverrideGetSetElement 0.08807
TestOverrideAddMapElement 0.1035 0.15905 1.54
TestOverrideGetMapElement 0.08564 0.14475 1.69
TestOverrideReceiveBeginPlay 0.00135 0.03956 29.30
TestOverrideTestFunc 0.01313 0.09633 7.34
TestIndexStaticCall 0.00125 0.00535 4.28
TestIndexEmptyCall 0.00126 0.00559 4.44
TestIndexSetBoolCall 0.00134 0.0058 4.33
TestIndexGetBoolCall 0.00142 0.00572 4.03
TestIndexOverrideTestFunc 0.00109 0.00069 0.63