在UnLua插件中可以直接使用协程编写蓝图中LatentAction逻辑,实现延迟执行线性逻辑。
典型用例:在蓝图中可以调用delay函数,不过,仅能在事件图表使用,因为整个事件图标是作为一个蓝图函数处理的,在Delay或者说是LatentAction位置就记录节点ID,待计时器触发,继续执行图表函数的对于节点。
在LUA中可以新建一个LUA线程执行LatentAction及其后续逻辑,虽然不如蓝图表达上那么自然,但也不太复杂。
主要实现如下:
| static FName LatentPropName = FName("LatentInfo"); |
| |
| int32 FastLuaHelper::CallUnrealFunction(lua_State* InL) |
| { |
| |
| UFunction* Func = (UFunction*)lua_touserdata(InL, lua_upvalueindex(1)); |
| FLuaObjectWrapper* Wrapper = (FLuaObjectWrapper*)lua_touserdata(InL, 1); |
| UObject* Obj = nullptr; |
| |
| if (Wrapper && Wrapper->WrapperType == ELuaWrapperType::Object) |
| { |
| Obj = Wrapper->GetObject(); |
| } |
| int32 StackTop = 2; |
| if (Obj == nullptr) |
| { |
| lua_pushnil(InL); |
| return 1; |
| } |
| |
| if (Func->NumParms < 1) |
| { |
| Obj->ProcessEvent(Func, nullptr); |
| return 0; |
| } |
| else |
| { |
| FStructOnScope FuncParam(Func); |
| FProperty* ReturnProp = nullptr; |
| FStructProperty* LatentProp = nullptr; |
| |
| for (TFieldIterator<FProperty> It(Func); It; ++It) |
| { |
| FProperty* Prop = *It; |
| if (Prop->HasAnyPropertyFlags(CPF_ReturnParm)) |
| { |
| ReturnProp = Prop; |
| } |
| else |
| { |
| FastLuaHelper::FetchProperty(InL, Prop, FuncParam.GetStructMemory(), StackTop++); |
| if (Prop->GetFName() == LatentPropName) |
| { |
| LatentProp = (FStructProperty*)Prop; |
| } |
| } |
| } |
| |
| |
| if (LatentProp) |
| { |
| if (lua_pushthread(InL) == 1) |
| { |
| UE_LOG(LogTemp, Warning, TEXT("never use latent in main thread!")); |
| return 0; |
| } |
| |
| FLatentActionInfo LatentInfo; |
| |
| ULuaLatentActionWrapper* LatentWrapper = NewObject<ULuaLatentActionWrapper>(GetTransientPackage()); |
| LatentWrapper->AddToRoot(); |
| LatentInfo.CallbackTarget = LatentWrapper; |
| LatentWrapper->MainThread = InL->l_G->mainthread; |
| LatentWrapper->WorkerThread = InL; |
| LatentInfo.ExecutionFunction = LatentWrapper->GetWrapperFunctionName(); |
| |
| LatentInfo.Linkage = luaL_ref(InL, LUA_REGISTRYINDEX); |
| LatentInfo.UUID = GetTypeHash(FGuid::NewGuid()); |
| |
| LatentProp->CopySingleValue(LatentProp->ContainerPtrToValuePtr<void>(FuncParam.GetStructMemory()), &LatentInfo); |
| } |
| |
| Obj->ProcessEvent(Func, FuncParam.GetStructMemory()); |
| |
| int32 ReturnNum = 0; |
| if (ReturnProp) |
| { |
| FastLuaHelper::PushProperty(InL, ReturnProp, FuncParam.GetStructMemory()); |
| ++ReturnNum; |
| } |
| |
| if (Func->HasAnyFunctionFlags(FUNC_HasOutParms)) |
| { |
| for (TFieldIterator<FProperty> It(Func); It; ++It) |
| { |
| FProperty* Prop = *It; |
| if (Prop->HasAnyPropertyFlags(CPF_OutParm) && !Prop->HasAnyPropertyFlags(CPF_ConstParm)) |
| { |
| FastLuaHelper::PushProperty(InL, *It, FuncParam.GetStructMemory()); |
| ++ReturnNum; |
| } |
| } |
| } |
| if (LatentProp == nullptr) |
| { |
| return ReturnNum; |
| } |
| else |
| { |
| |
| return lua_yield(InL, ReturnNum); |
| } |
| } |
| |
| } |
| |
| |
| #pragma once |
| |
| #include "CoreMinimal.h" |
| #include "UObject/NoExportTypes.h" |
| #include "LuaLatentActionWrapper.generated.h" |
| |
| |
| struct lua_State; |
| class FastLuaUnrealWrapper; |
| |
| |
| |
| |
| UCLASS() |
| class FASTLUASCRIPT_API ULuaLatentActionWrapper : public UObject |
| { |
| GENERATED_BODY() |
| public: |
| |
| UFUNCTION() |
| void TestFunction(int32 InParam); |
| |
| static FName GetWrapperFunctionName() { return FName(TEXT("TestFunction")); } |
| |
| lua_State* MainThread = nullptr; |
| lua_State* WorkerThread = nullptr; |
| }; |
| |
| |
| |
| |
| #include "LuaLatentActionWrapper.h" |
| #include "lua/lua.hpp" |
| #include "FastLuaUnrealWrapper.h" |
| |
| void ULuaLatentActionWrapper::TestFunction(int32 InParam) |
| { |
| int32 nres = 0; |
| |
| int32 Result = lua_resume(WorkerThread, MainThread, 0, &nres); |
| |
| if (Result == LUA_OK) |
| { |
| luaL_unref(MainThread, LUA_REGISTRYINDEX, InParam); |
| } |
| |
| this->RemoveFromRoot(); |
| this->MarkPendingKill(); |
| } |
| |
| function Main() |
| |
| print = Unreal.PrintLog |
| print(("----Lua Ram: %.2fMB----"):format(collectgarbage("count") / 1024)) |
| G_Timer:SetTimer('MainDelayInit', 1, 0.1, DelayInit, nil) |
| |
| end |
| |
| |
| function DelayInit() |
| |
| local co = coroutine.create( |
| function() |
| KismetSystemLibrary:Delay(GameInstance, 2.0) |
| print(222) |
| end |
| |
| ) |
| |
| coroutine.resume(co) |
| |
| print(111) |
| |
| |
| end |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
· 如何给本地部署的DeepSeek投喂数据,让他更懂你
· 超详细,DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方Dee
· 用 DeepSeek 给对象做个网站,她一定感动坏了
· .NET 8.0 + Linux 香橙派,实现高效的 IoT 数据采集与控制解决方案
· .NET中 泛型 + 依赖注入 的实现与应用