找回密码
 立即注册
查看: 280|回复: 0

unreal-c++教程-第十章:c++和Unlua的交互

[复制链接]
发表于 2023-4-11 19:07 | 显示全部楼层 |阅读模式
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. 背景
  1. 我们希望频繁变动的脚本是通过lua来完成的,因此我们引入了tx的UnLua(开源库)
  2. 我们会在c++中完成socket层面的处理,然后过滤出proto的字节流,这个字节流会从
  3. c++传递给lua,然后在lua中完成proto消息的处理
复制代码
2. 基本思路
  1. 1. 定义c++的静态函数
  2. 2. 在lua中访问该静态函数
复制代码
2.1 (GlobalTable函数的交互)在c++定义暴露给UnLua的静态函数
  1. UFUNCTION(BlueprintCallable, meta =(DisplayName ="CallLuaByGlobalTable", Category ="UnLua Tutorial"))staticvoidCallLuaByGlobalTable();
复制代码

然后我们就可以在lua中调用该c++的函数了

在这里需要进修UnLua的入门教程
2.1.1 该函数的基本需求:
  1. 1. 我们在TestReceiveCpp.lua中定义了一个函数叫做:CallMe的函数
复制代码
  1. function TestReceiveCpp.CallMe(a, b)
  2.     local ret = a + b
  3.     local msg = string.format("c++ call a = %f,b = %f,ans = %f", a, b, ret)
  4.     Screen.Print(msg)return
复制代码
  1. 2. 我们希望在c++中去调用这个CallMe函数
复制代码
2.1.2 该函数的基本实现思路
  1. 1. 拿到对应lua脚本的闭包,并用变量TRC保留该闭包的引用
复制代码
  1.         UnLua::FLuaEnv Env;constauto bSuccess = Env.DoString("TRC = require 'TestReceiveCpp'");check(bSuccess);
复制代码
  1. 显然,到这里,我们其实就是将定义的TestReceiveCpp的lua脚本加载到当前Env的内存当中
复制代码

  1. 2. 调用该闭包的CallMe函数
复制代码
  1. constauto RetValues = UnLua::CallTableFunc(Env.GetMainState(),"TRC","CallMe",1.1f,2.2f);check(RetValues.Num()==1);
复制代码
  1. 3. 完整的函数
复制代码
  1. void AClient::CallLuaByGlobalTable(){       
  2.         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. 1. 利用UnLua自带的FLuaFuntion去加载require函数
复制代码
  1. constauto Require = UnLua::FLuaFunction(&Env,"_G","require");
复制代码
  1. 2. 利用requre函数获取TestReceiveCpp的闭包(加载到内存并返回引用)
复制代码
  1. constauto RetValues1 = Require.Call("TestReceiveCpp");check(RetValues1.Num()==2);
复制代码
  1. 3. 获取函数Table
复制代码
  1. constauto RetValue = RetValues1[0];constauto LuaTable = UnLua::FLuaTable(&Env, RetValue);
复制代码
  1. 4. 调用CallMe函数
复制代码
  1. constauto RetValues2 = LuaTable.Call("CallMe",3.3f,4.4f);check(RetValues2.Num()==1);
复制代码
  1. 5. 从lua函数的返回中解析目标值
复制代码
  1. constauto Msg = FString::Printf(TEXT("[C++]收到来自Lua的返回,结果=%f"), RetValues2[0].Value<float>());PrintScreen(Msg);
复制代码
3. 完整的c++代码

.h
  1. // 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()
  2. class LUAX_API AClient : public AActor
  3. {GENERATED_BODY()
  4.        
  5. public:// Sets default values for this actor's propertiesAClient();
  6. protected:// Called when the game starts or when spawned
  7.         virtual voidBeginPlay() override;
  8. public:// Called every frame
  9.         virtual voidTick(float DeltaTime) override;UFUNCTION(BlueprintCallable, meta =(DisplayName ="CallLuaByGlobalTable",
  10.         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
  1. // 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
  2. AClient::AClient(){// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
  3.         PrimaryActorTick.bCanEverTick = true;}// Called when the game starts or when spawned// Called every framevoid AClient::Tick(float DeltaTime){
  4.         Super::Tick(DeltaTime);OnReceiveMsg(DeltaTime);}void AClient::OnReceiveMsg_Implementation(float val){}staticvoidPrintScreen(const FString& Msg){
  5.         UKismetSystemLibrary::PrintString(nullptr, Msg, true, false,FLinearColor(0,0.66,1),100);}void AClient::CallLuaByGlobalTable(){       
  6.         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("[C++]CallLuaByFLuaTable 开始"));
  7.         UnLua::FLuaEnv Env;constauto Require = UnLua::FLuaFunction(&Env,"_G","require");constauto RetValues1 = Require.Call("TestReceiveCpp");check(RetValues1.Num()==2);constauto RetValue = RetValues1[0];constauto LuaTable = UnLua::FLuaTable(&Env, RetValue);constauto RetValues2 = LuaTable.Call("CallMe",3.3f,4.4f);check(RetValues2.Num()==1);constauto Msg = FString::Printf(TEXT("[C++]收到来自Lua的返回,结果=%f"), RetValues2[0].Value<float>());PrintScreen(Msg);PrintScreen(TEXT("[C++]CallLuaByFLuaTable 结束"));}
  8. bool CustomLoader1(UnLua::FLuaEnv& Env,const FString& RelativePath, TArray<uint8>& Data, FString& FullPath){constauto SlashedRelativePath = RelativePath.Replace(TEXT("."),TEXT("/"));
  9.         FullPath = FString::Printf(TEXT("%s%s.lua"),*GLuaSrcFullPath,*SlashedRelativePath);if(FFileHelper::LoadFileToArray(Data,*FullPath, FILEREAD_Silent))return true;
  10.         FullPath.ReplaceInline(TEXT(".lua"),TEXT("/Index.lua"));if(FFileHelper::LoadFileToArray(Data,*FullPath, FILEREAD_Silent))return true;return false;}
  11. 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;
  12.         TArray<FString> Parts;FString(Path).ParseIntoArray(Parts,TEXT(";"), false);for(auto& Part : Parts){
  13.                 Part.ReplaceInline(TEXT("?"),*SlashedRelativePath);
  14.                 FPaths::CollapseRelativeDirectories(Part);if(FPaths::IsRelative(Part))
  15.                         FullPath = FPaths::ConvertRelativePathToFull(GLuaSrcFullPath, Part);else
  16.                         FullPath = Part;if(FFileHelper::LoadFileToArray(Data,*FullPath, FILEREAD_Silent))return true;}return false;}void AClient::SetupCustomLoader(int Index){switch(Index){case0:
  17.                 FUnLuaDelegates::CustomLoadLuaFile.Unbind();break;case1:
  18.                 FUnLuaDelegates::CustomLoadLuaFile.BindStatic(CustomLoader1);break;case2:
  19.                 FUnLuaDelegates::CustomLoadLuaFile.BindStatic(CustomLoader2);break;}}void AClient::BeginPlay(){
  20.         Super::BeginPlay();SetupCustomLoader(1);}
复制代码
4. 注意

4.1 添加Lua的搜索路径
  1. bool CustomLoader1(UnLua::FLuaEnv& Env,const FString& RelativePath, TArray<uint8>& Data, FString& FullPath){constauto SlashedRelativePath = RelativePath.Replace(TEXT("."),TEXT("/"));
  2.         FullPath = FString::Printf(TEXT("%s%s.lua"),*GLuaSrcFullPath,*SlashedRelativePath);if(FFileHelper::LoadFileToArray(Data,*FullPath, FILEREAD_Silent))return true;
  3.         FullPath.ReplaceInline(TEXT(".lua"),TEXT("/Index.lua"));if(FFileHelper::LoadFileToArray(Data,*FullPath, FILEREAD_Silent))return true;return false;}
复制代码
4.2 缺少Lua库

如果报以下错误:


这是因为缺少Lua库
可以在.Build.cs中


添加

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-5-5 05:20 , Processed in 0.095298 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表