风蚀之月

UE4中Sol2的接入

09 May 2018 UE4 Sol2 lua

虽然说Lua的C++接入本身在网上能找到很多示例,但是在尝试对Sol2进行接入的时候还是遇到了一些问题,所以在此进行记录。

当前使用的UE4版本为4.19.1。

Sol2是进行Lua绑定的C++类库,过程中最主要的问题是,对Lua本身一知半解,所以没有很好的理解Sol2官方文档中所描述的一些术语。

之所以会选择Sol2,是因为它号称自己是[地上最快]的~

LuaJit

似乎lua本身的脚本解释器有两个公开的版本,一个是LuaJit,一个是vanilla Lua。

由于没有仔细的对这两者之间的差别进行区分,所以并不是特别清楚其中的具体区别。

直接Google的话,Lua是指向vanilla lua的,而且LuaJit的Lua版本也比较靠前。

但是由于Sol2的官方文档中说LuaJit的速度会比较快,所以就采用了LuaJit。

那么首先第一步就是下载LuaJit,到了这一步就比较明了了。

LuaJit有提供CMake的配置文件,用CMake配置一下之后就可以进行生成了。

对于下一步的接入需要的是生成的Lua51.lib和Lua51.dll。

Sol2

这个库本身也有提供CMake,直接使用CMake配置就好了。

但是遇到的主要问题是,在和LuaJit的对接上,不过实际上在对整个库进行理清之后就不会有什么问题。

Sol2有提供很多的Test所以在使用方面会有很多的便利。

不过这里用CMake进行配置其实是不必要的,Sol2本身有提供单文件版本,其实只要include就可以了。

但是LuaJit的话还是需要进行链接的,并且必须根据使用的Lua解释器的不同来提供不同的宏。基本这样包含就可以了:

extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}

#define SOL_USING_CXX_LUA        1
#define SOL_USING_CXX_LUAJIT    1
#include "sol.hpp"

最主要的是前面的Extern “C”不能忘记,不然会报很多的链接错误~

UE4插件接入

据说以前Sol2接入的话会有一些问题,因为sol2本身对check有定义,所以会造成定冲突。

于是sol2的作者后面给出了解决方案:

#if defined(UE_BUILD_DEBUG) || defined(UE_BUILD_DEVELOPMENT) || defined(UE_BUILD_TEST) || defined(UE_BUILD_SHIPPING) || defined(UE_SERVER)
#define SOL_INSIDE_UNREAL
#endif // Unreal Engine 4 bullshit

#ifdef SOL_INSIDE_UNREAL
#ifdef check
#define SOL_INSIDE_UNREAL_REMOVED_CHECK
#undef check
#endif
#endif // Unreal Engine 4 Bullshit

总之就是回避了一下:D

不过说到UE4兼容,最近VA也新增了对UE4的特别支持。记得一开始的时候,VA经常在对UE4的函数进行跳转的时候崩掉VS,而且还有一定几率的崩掉VA建立的代码解析缓存,然后需要重新进行一次代码解析,非常的欢乐。

不过新增的UE4支持还没有完全的测试过,不知实际上有什么改进还不是特别的清楚呢~

测试

最后在UE4中使用蓝图函数进行了简单的测试:

UE_LOG(LogTemp,Log, TEXT("=== basic ==="));

// create an empty lua state
sol::state lua;

// by default, libraries are not opened
// you can open libraries by using open_libraries
// the libraries reside in the sol::lib enum class
lua.open_libraries(sol::lib::base);
// you can open all libraries by passing no arguments
//lua.open_libraries();

// call lua code directly
lua.script("print('hello world')");

// call lua code, and check to make sure it has loaded and run properly:
auto handler = &sol::script_default_on_error;
lua.script("print('hello again, world')", handler);

// Use a custom error handler if you need it
// This gets called when the result is bad
auto simple_handler = [](lua_State*, sol::protected_function_result result) {
// You can just pass it through to let the call-site handle it
  return result;
};
// the above lambda is identical to sol::simple_on_error, but it's
// shown here to show you can write whatever you like

//
{
  auto result = lua.script("print('hello hello again, world') \n return 24", simple_handler);
  if (result.valid()) {
    UE_LOG(LogTemp, Log, TEXT("the third script worked, and a double-hello statement should appear above this one!"));
    int value = result;
    ensure(value == 24);
  }
  else {
    UE_LOG(LogTemp, Log, TEXT("the third script failed, check the result type for more information!"));
  }
}

/**    <This test will log out 0xE24C4A03 */
{
  auto result = lua.script("does.not.exist", simple_handler);
  if (result.valid()) {
    UE_LOG(LogTemp, Log, TEXT("the fourth script worked, which it wasn't supposed to! Panic!"));
    int value = result;
    ensure(value == 24);
  }
  else {
    sol::error err = result;
    UE_LOG(LogTemp, Log, TEXT("the fourth script failed, which was intentional! nError: %s"), ANSI_TO_TCHAR(err.what()));
  }
}

由于接下来还没有具体的使用计划,所以就在这里了。

绑定好的Sol2插件可以到Github上下载:[Sol2UE4],这样有需要的童鞋就没有必要重新再绑一遍了~