unreal-c++教程-第十章:c++和Unlua的交互
c++和Unlua的交互1. 背景2. 基本思路
2.1 (GlobalTable函数的交互)在c++定义暴露给UnLua的静态函数
2.1.1 该函数的基本需求:2.1.2 该函数的基本实现思路
2.2 (FLuaTable的交互)在c++定义暴露给UnLua的静态函数
2.2.1 该函数的基本需求2.2.2 该函数的实现思路
3. 完整的c++代码4. 注意
4.1 添加Lua的搜索路径4.2 缺少Lua库
1. 背景
我们希望频繁变动的脚本是通过lua来完成的,因此我们引入了tx的UnLua(开源库)
我们会在c++中完成socket层面的处理,然后过滤出proto的字节流,这个字节流会从
c++传递给lua,然后在lua中完成proto消息的处理
2. 基本思路
1. 定义c++的静态函数
2. 在lua中访问该静态函数2.1 (GlobalTable函数的交互)在c++定义暴露给UnLua的静态函数
UFUNCTION(BlueprintCallable, meta =(DisplayName ="CallLuaByGlobalTable", Category ="UnLua Tutorial"))staticvoidCallLuaByGlobalTable();
然后我们就可以在lua中调用该c++的函数了
在这里需要进修UnLua的入门教程
2.1.1 该函数的基本需求:
1. 我们在TestReceiveCpp.lua中定义了一个函数叫做:CallMe的函数function TestReceiveCpp.CallMe(a, b)
local ret = a + b
local msg = string.format("c++ call a = %f,b = %f,ans = %f", a, b, ret)
Screen.Print(msg)return2. 我们希望在c++中去调用这个CallMe函数2.1.2 该函数的基本实现思路
1. 拿到对应lua脚本的闭包,并用变量TRC保留该闭包的引用 UnLua::FLuaEnv Env;constauto bSuccess = Env.DoString("TRC = require 'TestReceiveCpp'");check(bSuccess);显然,到这里,我们其实就是将定义的TestReceiveCpp的lua脚本加载到当前Env的内存当中
2. 调用该闭包的CallMe函数constauto RetValues = UnLua::CallTableFunc(Env.GetMainState(),"TRC","CallMe",1.1f,2.2f);check(RetValues.Num()==1);3. 完整的函数void AClient::CallLuaByGlobalTable(){
UnLua::FLuaEnv Env;constauto bSuccess = Env.DoString("TRC = require 'TestReceiveCpp'");check(bSuccess);constauto RetValues = UnLua::CallTableFunc(Env.GetMainState(),"TRC","CallMe",1.1f,2.2f);check(RetValues.Num()==1);}2.2 (FLuaTable的交互)在c++定义暴露给UnLua的静态函数
2.2.1 该函数的基本需求
见2.1.1
2.2.2 该函数的实现思路
1. 利用UnLua自带的FLuaFuntion去加载require函数constauto Require = UnLua::FLuaFunction(&Env,"_G","require");2. 利用requre函数获取TestReceiveCpp的闭包(加载到内存并返回引用)constauto RetValues1 = Require.Call("TestReceiveCpp");check(RetValues1.Num()==2);3. 获取函数Tableconstauto RetValue = RetValues1;constauto LuaTable = UnLua::FLuaTable(&Env, RetValue);4. 调用CallMe函数constauto RetValues2 = LuaTable.Call("CallMe",3.3f,4.4f);check(RetValues2.Num()==1);5. 从lua函数的返回中解析目标值constauto Msg = FString::Printf(TEXT("收到来自Lua的返回,结果=%f"), RetValues2.Value<float>());PrintScreen(Msg);
3. 完整的c++代码
.h
// Fill out your copyright notice in the Description page of Project Settings.#pragmaonce#include"CoreMinimal.h"#include"GameFramework/Actor.h"#include"Client.generated.h"UCLASS()
class LUAX_API AClient : public AActor
{GENERATED_BODY()
public:// Sets default values for this actor's propertiesAClient();
protected:// Called when the game starts or when spawned
virtual voidBeginPlay() override;
public:// Called every frame
virtual voidTick(float DeltaTime) override;UFUNCTION(BlueprintCallable, meta =(DisplayName ="CallLuaByGlobalTable",
Category ="UnLua Tutorial"))staticvoidCallLuaByGlobalTable();UFUNCTION(BlueprintCallable, meta =(DisplayName ="CallLuaByFLuaTable", Category ="UnLua Tutorial"))staticvoidCallLuaByFLuaTable();UFUNCTION(BlueprintCallable, meta =(DisplayName ="SetupCustomLoader", Category ="UnLua Tutorial"))staticvoidSetupCustomLoader(int Index);UFUNCTION(BlueprintNativeEvent, Category ="Switch Functions")voidOnReceiveMsg(float val);voidOnReceiveMsg_Implementation(float val);};.cpp
// Fill out your copyright notice in the Description page of Project Settings.#include"Client.h"#include"UnLua.h"#include"Kismet/KismetSystemLibrary.h"//#include "UnLua/"//#include "UnLua/"// Sets default values
AClient::AClient(){// Set this actor to call Tick() every frame.You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;}// Called when the game starts or when spawned// Called every framevoid AClient::Tick(float DeltaTime){
Super::Tick(DeltaTime);OnReceiveMsg(DeltaTime);}void AClient::OnReceiveMsg_Implementation(float val){}staticvoidPrintScreen(const FString& Msg){
UKismetSystemLibrary::PrintString(nullptr, Msg, true, false,FLinearColor(0,0.66,1),100);}void AClient::CallLuaByGlobalTable(){
UnLua::FLuaEnv Env;constauto bSuccess = Env.DoString("TRC = require 'TestReceiveCpp'");check(bSuccess);constauto RetValues = UnLua::CallTableFunc(Env.GetMainState(),"TRC","CallMe",1.1f,2.2f);check(RetValues.Num()==1);}void AClient::CallLuaByFLuaTable(){PrintScreen(TEXT("CallLuaByFLuaTable 开始"));
UnLua::FLuaEnv Env;constauto Require = UnLua::FLuaFunction(&Env,"_G","require");constauto RetValues1 = Require.Call("TestReceiveCpp");check(RetValues1.Num()==2);constauto RetValue = RetValues1;constauto LuaTable = UnLua::FLuaTable(&Env, RetValue);constauto RetValues2 = LuaTable.Call("CallMe",3.3f,4.4f);check(RetValues2.Num()==1);constauto Msg = FString::Printf(TEXT("收到来自Lua的返回,结果=%f"), RetValues2.Value<float>());PrintScreen(Msg);PrintScreen(TEXT("CallLuaByFLuaTable 结束"));}
bool CustomLoader1(UnLua::FLuaEnv& Env,const FString& RelativePath, TArray<uint8>& Data, FString& FullPath){constauto SlashedRelativePath = RelativePath.Replace(TEXT("."),TEXT("/"));
FullPath = FString::Printf(TEXT("%s%s.lua"),*GLuaSrcFullPath,*SlashedRelativePath);if(FFileHelper::LoadFileToArray(Data,*FullPath, FILEREAD_Silent))return true;
FullPath.ReplaceInline(TEXT(".lua"),TEXT("/Index.lua"));if(FFileHelper::LoadFileToArray(Data,*FullPath, FILEREAD_Silent))return true;return false;}
bool CustomLoader2(UnLua::FLuaEnv& Env,const FString& RelativePath, TArray<uint8>& Data, FString& FullPath){constauto SlashedRelativePath = RelativePath.Replace(TEXT("."),TEXT("/"));constauto L = Env.GetMainState();lua_getglobal(L,"package");lua_getfield(L,-1,"path");constchar* Path =lua_tostring(L,-1);lua_pop(L,2);if(!Path)return false;
TArray<FString> Parts;FString(Path).ParseIntoArray(Parts,TEXT(";"), false);for(auto& Part : Parts){
Part.ReplaceInline(TEXT("?"),*SlashedRelativePath);
FPaths::CollapseRelativeDirectories(Part);if(FPaths::IsRelative(Part))
FullPath = FPaths::ConvertRelativePathToFull(GLuaSrcFullPath, Part);else
FullPath = Part;if(FFileHelper::LoadFileToArray(Data,*FullPath, FILEREAD_Silent))return true;}return false;}void AClient::SetupCustomLoader(int Index){switch(Index){case0:
FUnLuaDelegates::CustomLoadLuaFile.Unbind();break;case1:
FUnLuaDelegates::CustomLoadLuaFile.BindStatic(CustomLoader1);break;case2:
FUnLuaDelegates::CustomLoadLuaFile.BindStatic(CustomLoader2);break;}}void AClient::BeginPlay(){
Super::BeginPlay();SetupCustomLoader(1);}
4. 注意
4.1 添加Lua的搜索路径
bool CustomLoader1(UnLua::FLuaEnv& Env,const FString& RelativePath, TArray<uint8>& Data, FString& FullPath){constauto SlashedRelativePath = RelativePath.Replace(TEXT("."),TEXT("/"));
FullPath = FString::Printf(TEXT("%s%s.lua"),*GLuaSrcFullPath,*SlashedRelativePath);if(FFileHelper::LoadFileToArray(Data,*FullPath, FILEREAD_Silent))return true;
FullPath.ReplaceInline(TEXT(".lua"),TEXT("/Index.lua"));if(FFileHelper::LoadFileToArray(Data,*FullPath, FILEREAD_Silent))return true;return false;}4.2 缺少Lua库
如果报以下错误:
这是因为缺少Lua库
可以在.Build.cs中
添加
页:
[1]