Uso de la rutina de LUA para manejar LatentAction en Unreal

En el complemento UnLua, puede usar directamente la rutina para escribir la lógica LatentAction en el plano para darse cuenta de la ejecución retardada de la lógica lineal.
Caso de uso típico: la función de retraso se puede invocar en el plano, pero solo se puede usar en el gráfico de eventos, porque todo el ícono del evento se maneja como una función de plano, y la ID del nodo se registra en la posición de Retardo o Acción Latente, y el temporizador se activa para continuar Para nodos que realizan funciones de gráfico.
En LUA, puede crear un nuevo hilo LUA para ejecutar LatentAction y su lógica posterior. Aunque no es tan natural como el plano, no es demasiado complicado.
La implementación principal es la siguiente:


//简单判断函数是否需要协程,比较粗略,实际使用应该包含FLatentActionInfo的子类
static FStructProperty* GetLatentActionProperty(class UFunction* InFunction)
{
	for (TFieldIterator<FProperty> It(InFunction); It; ++It)
	{
		FStructProperty* Prop = CastField<FStructProperty>(*It);
		if (Prop && Prop->Struct == FLatentActionInfo::StaticStruct())
		{
			return Prop;
		}
	}
	return nullptr;
}

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 = GetLatentActionProperty(Func);

		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++);
			}
		}

                //重新纠正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

Supongo que te gusta

Origin www.cnblogs.com/rpg3d/p/12744096.html
Recomendado
Clasificación