Skip to content

Commit 66f38f6

Browse files
committed
Add LuaBridge library.
Add some docs on how to add C++ classes to Lua.
1 parent 7d7987e commit 66f38f6

File tree

10 files changed

+101
-234
lines changed

10 files changed

+101
-234
lines changed

apps/freeablo/fagui/console/console.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ namespace FAGui
1010
static const char* nullFile = "/dev/null";
1111
#endif
1212
static char consoleStdoutBuffer[BUFSIZ];
13-
std::unique_ptr<Console> Console::mInstance = nullptr;
13+
std::shared_ptr<Console> Console::mInstance = nullptr;
1414
static std::stringstream consoleCout;
1515

16-
Console::Console() : mBuffer({}), bufferLen(0), inputLen(0), mScript({})
16+
Console::Console() : mBuffer({}), bufferLen(0), inputLen(0), mScript(Script::LuaScript::getInstance())
1717
{
1818
std::cout.rdbuf(consoleCout.rdbuf());
1919
freopen(nullFile, "a", stdout);
@@ -26,7 +26,7 @@ namespace FAGui
2626
fclose(stdout);
2727
}
2828

29-
std::unique_ptr<Console>& Console::getInstance()
29+
std::shared_ptr<Console> Console::getInstance()
3030
{
3131
if (!mInstance)
3232
mInstance = std::unique_ptr<Console>(new Console());
@@ -61,7 +61,7 @@ namespace FAGui
6161
bufferLen += inputLen;
6262
inputLen = 0;
6363

64-
mScript.eval(command.c_str());
64+
mScript->eval(command.c_str());
6565
std::string msg = ">> ";
6666
msg.append(consoleStdoutBuffer, strlen(consoleStdoutBuffer));
6767
std::memset(consoleStdoutBuffer, '\0', BUFSIZ);

apps/freeablo/fagui/console/console.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ namespace FAGui
1515
static constexpr size_t inputSize = 512;
1616
char mInput[inputSize];
1717
int inputLen;
18-
Script::LuaScript mScript;
19-
static std::unique_ptr<Console> mInstance;
18+
std::shared_ptr<Script::LuaScript> mScript;
19+
static std::shared_ptr<Console> mInstance;
2020

2121
public:
22-
static std::unique_ptr<Console>& getInstance();
22+
static std::shared_ptr<Console> getInstance();
2323
~Console();
2424

2525
char* getInput() { return mInput; };

apps/freeablo/fagui/guimanager.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ namespace FAGui
530530

531531
void GuiManager::consolePanel(nk_context* ctx)
532532
{
533-
auto& c = Console::getInstance();
533+
auto c = Console::getInstance();
534534
drawPanel(ctx,
535535
PanelType::console,
536536
[&]() {

components/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,5 +157,5 @@ add_library(Script
157157
script/luascript.h
158158
)
159159

160-
target_link_libraries(Script lua Filesystem Misc)
160+
target_link_libraries(Script lua LuaBridge Misc)
161161
set_target_properties(Script PROPERTIES COMPILE_FLAGS "${FA_COMPILER_FLAGS}")

components/script/luascript.cpp

Lines changed: 5 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
namespace Script
77
{
8+
std::shared_ptr<LuaScript> LuaScript::mInstance = nullptr;
9+
810
LuaScript::LuaScript() : mState(luaL_newstate()) { luaL_openlibs(mState); }
911

1012
LuaScript::~LuaScript()
@@ -13,117 +15,6 @@ namespace Script
1315
lua_close(mState);
1416
}
1517

16-
void LuaScript::printError(const std::string& variable, const std::string& reason)
17-
{
18-
#ifdef NDEBUG
19-
(void)variable;
20-
(void)reason;
21-
#else
22-
std::cerr << "Can't get variable " << variable << ".\nReason: " << reason << "\n";
23-
#endif
24-
}
25-
26-
template <> std::string LuaScript::luaGetDefault<std::string>() { return "null"; }
27-
28-
template <> bool LuaScript::luaGet<bool>(const std::string& variable)
29-
{
30-
(void)variable;
31-
return static_cast<bool>(lua_toboolean(mState, -1));
32-
}
33-
template <> int LuaScript::luaGet<int>(const std::string& variable)
34-
{
35-
(void)variable;
36-
return static_cast<int>(lua_tointeger(mState, -1));
37-
}
38-
template <> int64_t LuaScript::luaGet<int64_t>(const std::string& variable)
39-
{
40-
(void)variable;
41-
return static_cast<int64_t>(lua_tointeger(mState, -1));
42-
}
43-
44-
template <> FixedPoint LuaScript::luaGet<FixedPoint>(const std::string& variable)
45-
{
46-
(void)variable;
47-
return static_cast<FixedPoint>(luaL_checknumber(mState, 1));
48-
}
49-
50-
template <> std::string LuaScript::luaGet<std::string>(const std::string& variable)
51-
{
52-
std::string ret = "null";
53-
54-
release_assert(lua_isstring(mState, -1));
55-
56-
if (lua_isstring(mState, -1))
57-
ret = std::string(lua_tostring(mState, -1));
58-
else
59-
printError(variable, "Not a string");
60-
61-
return ret;
62-
}
63-
64-
bool LuaScript::luaGetToStack(const std::string& variable, int& level)
65-
{
66-
level = 0;
67-
std::string var{};
68-
69-
for (char c : variable)
70-
{
71-
if (c == '.')
72-
{
73-
if (level == 0)
74-
{
75-
lua_getglobal(mState, var.c_str());
76-
}
77-
78-
else
79-
{
80-
lua_getfield(mState, -1, var.c_str());
81-
}
82-
83-
if (lua_isnil(mState, -1))
84-
{
85-
printError(variable, var + " is not defined");
86-
return false;
87-
}
88-
89-
else
90-
{
91-
var = "";
92-
++level;
93-
}
94-
}
95-
96-
else
97-
{
98-
var += c;
99-
}
100-
}
101-
102-
if (level == 0)
103-
{
104-
lua_getglobal(mState, var.c_str());
105-
}
106-
107-
else
108-
{
109-
lua_getfield(mState, -1, var.c_str());
110-
}
111-
112-
if (lua_isnil(mState, -1))
113-
{
114-
printError(variable, var + " is not defined");
115-
return false;
116-
}
117-
118-
return true;
119-
}
120-
121-
void LuaScript::clean()
122-
{
123-
int n = lua_gettop(mState);
124-
lua_pop(mState, n);
125-
}
126-
12718
void LuaScript::runScript(const std::string& path)
12819
{
12920
lua_settop(mState, 0);
@@ -146,4 +37,7 @@ namespace Script
14637
lua_pop(mState, 1);
14738
}
14839
}
40+
41+
template <> float LuaScript::get<float>(const std::string &variable) = delete;
42+
template <> double LuaScript::get<double>(const std::string &variable) = delete;
14943
}

components/script/luascript.h

Lines changed: 20 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -11,105 +11,53 @@
1111
#include "lua.h"
1212
#include "lualib.h"
1313

14+
#include "LuaBridge/LuaBridge.h"
15+
#include "LuaBridge/Vector.h"
16+
1417
namespace Script
1518
{
1619
class LuaScript
1720
{
1821
lua_State* mState;
22+
static std::shared_ptr<LuaScript> mInstance;
1923

2024
public:
21-
LuaScript();
2225
~LuaScript();
2326

24-
template <typename T> void registerGlobalType();
27+
template <typename T> void registerType();
2528

2629
template <typename Func> void registerGlobalFunction(const std::string& functionName, Func&& func)
2730
{
28-
lua_pushcfunction(mState, func);
29-
lua_setglobal(mState, functionName.c_str());
31+
luabridge::getGlobalNamespace(mState).addFunction(functionName.c_str(), func);
3032
}
3133

32-
template <typename T> void pushObject(T& obj, const char* varName)
34+
template <typename T> void pushGlobalObject(T& obj, const char* varName)
3335
{
34-
static bool registered = false;
35-
if (!registered)
36-
{
37-
registerGlobalType<T>();
38-
registered = true;
39-
}
40-
41-
T** udata = reinterpret_cast<T**>(lua_newuserdata(mState, sizeof(T*)));
42-
(*udata) = &obj;
43-
const std::string typeName = typeid(T).name();
44-
luaL_setmetatable(mState, typeName.substr(1).c_str());
36+
registerType<T>();
37+
luabridge::push(mState, obj);
4538
lua_setglobal(mState, varName);
4639
}
4740

4841
template <typename T> T get(const std::string& variable)
4942
{
50-
release_assert(mState);
51-
int level;
52-
53-
T result;
54-
if (luaGetToStack(variable, level))
55-
result = luaGet<T>(variable);
56-
57-
else
58-
result = luaGetDefault<T>();
59-
60-
lua_pop(mState, level + 1);
61-
return result;
62-
}
63-
64-
template <typename T> std::vector<T> getVector(const std::string& variable)
65-
{
66-
std::vector<T> ret;
67-
lua_getglobal(mState, variable.c_str());
68-
if (lua_isnil(mState, -1))
69-
{
70-
return {};
71-
}
72-
73-
lua_pushnil(mState);
74-
75-
while (lua_next(mState, -2))
76-
{
77-
T aux;
78-
if constexpr (std::is_same<T, std::string>::value)
79-
{
80-
ret.push_back(lua_tostring(mState, -1));
81-
}
82-
83-
else
84-
{
85-
ret.push_back(static_cast<T>(lua_tonumber(mState, -1)));
86-
}
87-
88-
lua_pop(mState, 1);
89-
}
90-
91-
clean();
92-
return ret;
43+
luabridge::LuaRef ret = luabridge::getGlobal(mState, variable.c_str());
44+
return ret.cast<T>();
9345
}
9446

9547
void runScript(const std::string& path);
9648
void eval(const char* script);
9749

98-
private:
99-
bool luaGetToStack(const std::string& variable, int& level);
100-
101-
void clean();
102-
103-
void printError(const std::string& variable, const std::string& reason);
50+
static std::shared_ptr<LuaScript> getInstance()
51+
{
52+
if (!mInstance)
53+
mInstance = std::shared_ptr<LuaScript>(new LuaScript());
10454

105-
template <typename T> T luaGet(const std::string& variable = "");
55+
return mInstance;
56+
}
10657

107-
template <typename T> T luaGetDefault() { return {}; }
58+
operator lua_State*() { return mState; }
10859

109-
template <typename Func> void pushFunction(Func&& f, const char* funcName)
110-
{
111-
lua_pushcfunction(mState, f);
112-
lua_setfield(mState, -2, funcName);
113-
}
60+
private:
61+
LuaScript();
11462
};
11563
}

docs/cpp_class_to_lua.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
## Registering a C++ class into Lua
2+
3+
Suppose you have the following class:
4+
5+
```cpp
6+
class Greeter
7+
{
8+
const char* msg
9+
public:
10+
Greeter() {}
11+
Greeter(const char *msg) {}
12+
void hello(const char* name) { std::cout << "Hello, " << name << "\n"; }
13+
void print() { std::cout << msg << "\n"; }
14+
};
15+
```
16+
17+
If you want to use it inside Lua, you should implement Script::LuaScript::registerType for it:
18+
19+
```cpp
20+
namespace Script
21+
{
22+
template <> void LuaScript::registerType<Greeter>()
23+
{
24+
luabridge::getGlobalNamespace(mState)
25+
.beginNamespace("example") // optionally, you can wrap the class inside a namespace
26+
.beginClass<Greeter>("Greeter")
27+
.addConstructor<void (*)(void)>()
28+
.addConstructor<void (*)(const char*)>()
29+
.addFunction("hello", &Greeter::hello)
30+
.addFunction("print", &Greeter::print)
31+
.endClass()
32+
.endNamespace();
33+
}
34+
}
35+
```
36+
37+
Make sure you call 'registerType' before using the class in Lua. Now, to use in Lua:
38+
39+
```lua
40+
local greeter = example.Greeter()
41+
greeter:hello("John Smith")
42+
43+
local greeter2 = example.Greeter("Hello world")
44+
greeter2:print()
45+
```
46+
47+
For more information, see [LuaBridge Reference](https://vinniefalco.github.io/LuaBridge/Manual.html).

extern/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ add_subdirectory(SDL_image)
2323
add_subdirectory(StormLib)
2424
add_subdirectory(gtest)
2525
add_subdirectory(lua)
26+
add_subdirectory(LuaBridge)
2627

2728
unset(MESSAGE_QUIET)

0 commit comments

Comments
 (0)