zoukankan      html  css  js  c++  java
  • 用LUA协程处理Unreal中的LatentAction

    在UnLua插件中可以直接使用协程编写蓝图中LatentAction逻辑,实现延迟执行线性逻辑。
    典型用例:在蓝图中可以调用delay函数,不过,仅能在事件图表使用,因为整个事件图标是作为一个蓝图函数处理的,在Delay或者说是LatentAction位置就记录节点ID,待计时器触发,继续执行图表函数的对于节点。
    在LUA中可以新建一个LUA线程执行LatentAction及其后续逻辑,虽然不如蓝图表达上那么自然,但也不太复杂。
    主要实现如下:

    static FName LatentPropName = FName("LatentInfo");
    
    int32 FastLuaHelper::CallUnrealFunction(lua_State* InL)
    {
    	//SCOPE_CYCLE_COUNTER(STAT_LuaCallBP);
    	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;
    				}
    			}
    		}
    
                    //重新纠正latent参数
    		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
    		{
                            //目前是在子线程工作,调用完UFunction要让出,回到主线程
    			return lua_yield(InL, ReturnNum);
    		}
    	}
    
    }
    
    // Fill out your copyright notice in the Description page of Project Settings.
    
    #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;
    };
    
    // Fill out your copyright notice in the Description page of Project Settings.
    
    
    #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)
    
    	--编辑器日志界面先打印了111,2秒后打印了222
    end
    
  • 相关阅读:
    win10右键在此处打开CMD
    练习1-20 编写程序detab,将输入中的制表符替换成适当数目的空格.
    编写一个程序,打印输入中单词长度的直方图.垂直方向
    王爽 汇编 实验14
    python 文件
    函数和方法
    python-格式化字符串
    MPC&MAGIC
    python-super1
    小知识点
  • 原文地址:https://www.cnblogs.com/rpg3d/p/12744096.html
Copyright © 2011-2022 走看看