SLua Overrider

SLua Overrider

以源码版本slua 2.1.4

  1. LuaActor的构造函数是如何进入到LuaOverrider::ClassConstructor的

image-20250105121900779.png

LuaOverrider监听UObject创建的事件

UObject创建后调用所有FUObjectArray中的NotifyUObjectCreated。

这个时机在UObjectBase构造函数中的AddObject中,此时最终的LuaActor的构造函数还没被调用,因此能Hook。

这就涉及到NewObject的构造原理了,UObjectBase的构造在第一次分配完内存后首先被调用。

image-20250105180635002.png

StaticConstructObject_Internal

[UE4 UObject] UObject 的创建流程 - 知乎

LuaOverrider如何知道哪个UObject是我需要被重载掉的?

tyyHook之前isHookable通过UClass判断实现了ULuaOverriderInterface接口的类就是要被Hook的对象。

bool LuaOverrider::isHookable(const UObjectBaseUtility* obj)
{
    UClass* cls = obj->GetClass();
    if (cls->IsChildOf<UPackage>() || cls->IsChildOf<UClass>())
    {
        return false;
    }
    static UClass* interfaceClass = ULuaOverriderInterface::StaticClass();
    if (cls->ImplementsInterface(interfaceClass))
    {
        return true;
    }
    return false;
}

在hook的时候每次修改一个cls的constructor都保存在一个map中,这样之后可以用到。

在CustomClassConstructor中要调用cls实际的构造函数,这时hook时收集的constructor就有用了,从中取出真实的constructor然后调用。在一切都结束后最重要的绑定重载函数bindOverrideFuncs。

  1. LuaActor的BeginPlay等函数是如何被Lua脚本重载的

image-20250105204702266.png

LuaOverrider::bindOverrideFuncs

LuaActor的构造过程中(CustomClassConstructor),会将对应的Lua脚本Require进来并获取其中所有的函数,然后利用UClass在其中查找是否有同名的,如果有的话那就调用hookBpScript来进行hook。注意这里Lua只能Override蓝图Event方法。因此这里重载的ReceiveBeginPlay而不是BeginPlay。

image-20250105230846328.png

(hookBpScript的原理大概是修改了原本BP函数的字节码。。。)

如果蓝图中已经实现了某些方法比如EventTick,Lua中的ReceiveTick就会覆盖掉实际的ReceiveTick函数,就需要通过self.Super:ReceiveTick调用到BP中的方法。逻辑上 self->C++类(ALuaActor),self.Super->BP类

关于Tick

在Actor的Tick函数中,似乎ReceiveTick必须是蓝图类才会调用,所以要想在Lua中执行Tick就必须先创建蓝图再绑定LuaFile,直接创建C++类的实例并不能在Lua中使用ReceiveTick。

当然直接在Actor的Tick、BeginPlay等方法中直接调用CallFunction来调用Lua中的函数也是可行的。

CC BY-NC-SA 4.0 Deed | 署名-非商业性使用-相同方式共享
最后更新时间:2025-01-07 18:12:44