1/*
2 * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#ifndef LUAINTERFACE_H
24#define LUAINTERFACE_H
25
26#include "declarations.h"
27
28#include <framework/util/stats.h>
29
30
31struct lua_State;
32typedef int (*LuaCFunction) (lua_State *L);
33
34/// Class that manages LUA stuff
35class LuaInterface
36{
37public:
38 LuaInterface();
39 ~LuaInterface();
40
41 void init();
42 void terminate();
43
44 /// Register core script functions
45 void registerFunctions();
46
47 // functions that will register all script stuff in lua global environment
48 void registerSingletonClass(const std::string& className);
49 void registerClass(const std::string& className, const std::string& baseClass = "LuaObject");
50
51 void registerClassStaticFunction(const std::string& className,
52 const std::string& functionName,
53 const LuaCppFunction& function);
54
55 void registerClassMemberFunction(const std::string& className,
56 const std::string& functionName,
57 const LuaCppFunction& function);
58
59 void registerClassMemberField(const std::string& className,
60 const std::string& field,
61 const LuaCppFunction& getFunction,
62 const LuaCppFunction& setFunction);
63
64 void registerGlobalFunction(const std::string& functionName,
65 const LuaCppFunction& function);
66
67 // register shortcuts using templates
68 template<class C, class B = LuaObject>
69 void registerClass() {
70 registerClass(stdext::demangle_class<C>(), stdext::demangle_class<B>());
71 }
72
73 template<class C>
74 void registerClassStaticFunction(const std::string& functionName, const LuaCppFunction& function) {
75 registerClassStaticFunction(stdext::demangle_class<C>(), functionName, function);
76 }
77
78 template<class C>
79 void registerClassMemberFunction(const std::string& functionName, const LuaCppFunction& function) {
80 registerClassMemberFunction(stdext::demangle_class<C>(), functionName, function);
81 }
82
83 template<class C>
84 void registerClassMemberField(const std::string& field,
85 const LuaCppFunction& getFunction,
86 const LuaCppFunction& setFunction) {
87 registerClassMemberField(stdext::demangle_class<C>(), field, getFunction, setFunction);
88 }
89
90 // methods for binding functions
91 template<class C, typename F>
92 void bindSingletonFunction(const std::string& functionName, F C::*function, C *instance);
93 template<class C, typename F>
94 void bindSingletonFunction(const std::string& className, const std::string& functionName, F C::* function, C* instance);
95 template<typename F>
96 void bindSingletonFunction(const std::string& className, const std::string& functionName, const F& function);
97
98 template<class C, typename F>
99 void bindClassStaticFunction(const std::string& functionName, const F& function);
100 template<typename F>
101 void bindClassStaticFunction(const std::string& className, const std::string& functionName, const F& function);
102
103 template<class C, typename F, class FC>
104 void bindClassMemberFunction(const std::string& functionName, F FC::*function);
105 template<class C, typename F, class FC>
106 void bindClassMemberFunction(const std::string& className, const std::string& functionName, F FC::*function);
107
108 template<class C, typename F1, typename F2, class FC>
109 void bindClassMemberField(const std::string& fieldName, F1 FC::*getFunction, F2 FC::*setFunction);
110 template<class C, typename F1, typename F2, class FC>
111 void bindClassMemberField(const std::string& className, const std::string& fieldName, F1 FC::*getFunction, F2 FC::*setFunction);
112
113 template<class C, typename F, class FC>
114 void bindClassMemberGetField(const std::string& fieldName, F FC::*getFunction);
115 template<class C, typename F, class FC>
116 void bindClassMemberGetField(const std::string& className, const std::string& fieldName, F FC::*getFunction);
117
118 template<class C, typename F, class FC>
119 void bindClassMemberSetField(const std::string& fieldName, F FC::*setFunction);
120 template<class C, typename F, class FC>
121 void bindClassMemberSetField(const std::string& className, const std::string& fieldName, F FC::*setFunction);
122
123 template<typename F>
124 void bindGlobalFunction(const std::string& functionName, const F& function);
125
126private:
127 /// Metamethod that will retrieve fields values (that include functions) from the object when using '.' or ':'
128 static int luaObjectGetEvent(LuaInterface* lua);
129 /// Metamethod that is called when setting a field of the object by using the keyword '='
130 static int luaObjectSetEvent(LuaInterface* lua);
131 /// Metamethod that will check equality of objects by using the keyword '=='
132 static int luaObjectEqualEvent(LuaInterface* lua);
133 /// Metamethod that is called every two lua garbage collections
134 /// for any LuaObject that have no references left in lua environment
135 /// anymore, thus this creates the possibility of holding an object
136 /// existence by lua until it got no references left
137 static int luaObjectCollectEvent(LuaInterface* lua);
138
139public:
140 /// Loads and runs a script, any errors are printed to stdout and returns false
141 bool safeRunScript(const std::string& fileName);
142
143 /// Loads and runs a script
144 /// @exception LuaException is thrown on any lua error
145 void runScript(const std::string& fileName);
146
147 /// Loads and runs the script from buffer
148 /// @exception LuaException is thrown on any lua error
149 void runBuffer(const std::string& buffer, const std::string& source);
150
151 /// Loads a script file and pushes it's main function onto stack,
152 /// @exception LuaException is thrown on any lua error
153 void loadScript(const std::string& fileName);
154
155 /// Loads a function from buffer and pushes it onto stack,
156 /// @exception LuaException is thrown on any lua error
157 void loadFunction(const std::string& buffer, const std::string& source = "lua function buffer");
158
159 /// Evaluates a lua expression and pushes the result value onto the stack
160 /// @exception LuaException is thrown on any lua error
161 void evaluateExpression(const std::string& expression, const std::string& source = "lua expression");
162
163 /// Generates a traceback message for the current call stack
164 /// @param errorMessage is an additional error message
165 /// @param level is the level of the traceback, 0 means trace from calling function
166 /// @return the generated traceback message
167 std::string traceback(const std::string& errorMessage = "", int level = 0);
168
169 /// Throw a lua error if inside a lua call or generates an C++ stdext::exception
170 /// @param message is the error message wich will be displayed before the error traceback
171 /// @exception stdext::exception is thrown with the error message if the error is not captured by lua
172 void throwError(const std::string& message);
173
174 /// Searches for the source of the current running function
175 std::string getCurrentSourcePath(int level = 0);
176
177 /// gets current function name
178 std::string getCurrentFunction(int level = 0);
179
180 /// @brief Calls a function
181 /// The function and arguments must be on top of the stack in order,
182 /// results are pushed onto the stack.
183 /// @exception LuaException is thrown on any lua error
184 /// @return number of results
185 int safeCall(int numArgs = 0, int numRets = -1, const std::shared_ptr<std::string>& error = nullptr);
186
187 /// Same as safeCall but catches exceptions and can also calls a table of functions,
188 /// if any error occurs it will be reported to stdout and returns 0 results
189 /// @param requestedResults is the number of results requested to pushes onto the stack,
190 /// if supplied, the call will always pushes that number of results, even if it fails
191 int signalCall(int numArgs = 0, int numRets = -1);
192
193 /// @brief Creates a new environment table
194 /// The new environment table is redirected to the global environment (aka _G),
195 /// this allows to access global variables from _G in the new environment and
196 /// prevents new variables in this new environment to be set on the global environment
197 int newSandboxEnv();
198
199 template<typename... T>
200 int luaCallGlobalField(const std::string& global, const std::string& field, const T&... args);
201
202 template<typename... T>
203 void callGlobalField(const std::string& global, const std::string& field, const T&... args);
204
205 template<typename R, typename... T>
206 R callGlobalField(const std::string& global, const std::string& field, const T&... args);
207
208 bool isInCppCallback() { return m_cppCallbackDepth != 0; }
209
210private:
211 /// Load scripts requested by lua 'require'
212 static int luaScriptLoader(lua_State* L);
213 /// Run scripts requested by lua 'dofile'
214 static int lua_dofile(lua_State* L);
215 /// Run scripts requested by lua 'dofiles'
216 static int lua_dofiles(lua_State* L);
217 /// Run scripts requested by lua 'dofiles'
218 static int lua_loadfile(lua_State* L);
219 /// Handle lua errors from safeCall
220 static int luaErrorHandler(lua_State* L);
221 /// Handle bound cpp functions callbacks
222 static int luaCppFunctionCallback(lua_State* L);
223 /// Collect bound cpp function pointers
224 static int luaCollectCppFunction(lua_State* L);
225
226public:
227 void createLuaState();
228 void closeLuaState();
229
230 void collectGarbage();
231
232 void loadBuffer(const std::string& buffer, const std::string& source);
233
234 std::string generateByteCode(const std::string & buffer, std::string source);
235
236 int pcall(int numArgs = 0, int numRets = 0, int errorFuncIndex = 0);
237 void call(int numArgs = 0, int numRets = 0);
238 void error();
239
240 int ref();
241 int weakRef();
242 void unref(int ref);
243 void useValue() { pushValue(); ref(); }
244
245 const char* typeName(int index = -1);
246 std::string functionSourcePath();
247 std::string functionSource();
248
249 void insert(int index);
250 void remove(int index);
251 bool next(int index = -2);
252
253 void checkStack() { VALIDATE(getTop() <= 20); }
254 void getStackFunction(int level = 0);
255
256 void getRef(int ref);
257 void getWeakRef(int weakRef);
258
259 int getGlobalEnvironment() { return m_globalEnv; }
260 void setGlobalEnvironment(int env);
261 void resetGlobalEnvironment() { setGlobalEnvironment(m_globalEnv); }
262
263 void setMetatable(int index = -2);
264 void getMetatable(int index = -1);
265
266 void getField(const char* key, int index = -1);
267 void getField(const std::string& key, int index = -1) { return getField(key.c_str(), index); }
268 void setField(const char* key, int index = -2);
269 void setField(const std::string& key, int index = -2) { return setField(key.c_str(), index); }
270
271 void getTable(int index = -2);
272 void setTable(int index = -3);
273 void clearTable(int index = -1);
274
275 void getEnv(int index = -1);
276 void setEnv(int index = -2);
277
278 void getGlobal(const std::string& key);
279 void getGlobalField(const std::string& globalKey, const std::string& fieldKey);
280 void setGlobal(const std::string& key);
281
282 void rawGet(int index = -1);
283 void rawGeti(int n, int index = -1);
284 void rawSet(int index = -3);
285 void rawSeti(int n, int index = -2);
286
287 void newTable();
288 void createTable(int narr, int nrec);
289 void* newUserdata(int size);
290
291 void pop(int n = 1);
292 long popInteger();
293 double popNumber();
294 bool popBoolean();
295 std::string popString();
296 void* popUserdata();
297 void* popUpvalueUserdata();
298 LuaObjectPtr popObject();
299
300 void pushNil();
301 void pushInteger(long v);
302 void pushNumber(double v);
303 void pushBoolean(bool v);
304 void pushCString(const char* v);
305 void pushString(const std::string& v);
306 void pushLightUserdata(void* p);
307 void pushThread();
308 void pushValue(int index = -1);
309 void pushObject(const LuaObjectPtr& obj);
310 void pushCFunction(LuaCFunction func, int n = 0);
311 void pushCppFunction(const LuaCppFunction& func);
312
313 bool isNil(int index = -1);
314 bool isBoolean(int index = -1);
315 bool isNumber(int index = -1);
316 bool isString(int index = -1);
317 bool isTable(int index = -1);
318 bool isFunction(int index = -1);
319 bool isCFunction(int index = -1);
320 bool isLuaFunction(int index = -1) { return (isFunction() && !isCFunction()); }
321 bool isUserdata(int index = -1);
322
323 bool toBoolean(int index = -1);
324 int toInteger(int index = -1);
325 double toNumber(int index = -1);
326 const char* toCString(int index = -1);
327 std::string toString(int index = -1);
328 void* toUserdata(int index = -1);
329 LuaObjectPtr toObject(int index = -1);
330
331 int getTop();
332 int stackSize() { return getTop(); }
333 void clearStack() { pop(stackSize()); }
334 bool hasIndex(int index) { return (stackSize() >= (index < 0 ? -index : index) && index != 0); }
335
336 std::string getSource(int level = 2);
337
338 void loadFiles(std::string directory, bool recursive = false, std::string contains = "");
339
340 /// Pushes any type onto the stack
341 template<typename T, typename... Args>
342 int polymorphicPush(const T& v, const Args&... args);
343 int polymorphicPush() { return 0; }
344
345 /// Casts a value from stack to any type
346 /// @exception LuaBadValueCastException thrown if the cast fails
347 template<class T>
348 T castValue(int index = -1);
349
350 /// Same as castValue but also pops
351 template<class T>
352 T polymorphicPop() { T v = castValue<T>(); pop(1); return v; }
353
354private:
355 lua_State* L;
356 int m_weakTableRef;
357 int m_cppCallbackDepth;
358 int m_totalObjRefs;
359 int m_totalFuncRefs;
360 int m_globalEnv;
361};
362
363extern LuaInterface g_lua;
364
365// must be included after, because they need LuaInterface fully declared
366#include "luaexception.h"
367#include "luabinder.h"
368#include "luavaluecasts.h"
369
370template<typename T, typename... Args>
371int LuaInterface::polymorphicPush(const T& v, const Args&... args) {
372 int r = push_luavalue(v);
373 return r + polymorphicPush(args...);
374}
375
376// next templates must be defined after above includes
377
378template<class C, typename F>
379void LuaInterface::bindSingletonFunction(const std::string& functionName, F C::*function, C *instance) {
380 registerClassStaticFunction<C>(functionName, luabinder::bind_singleton_mem_fun(function, instance));
381}
382
383template<class C, typename F>
384void LuaInterface::bindSingletonFunction(const std::string& className, const std::string& functionName, F C::*function, C *instance) {
385 registerClassStaticFunction(className, functionName, luabinder::bind_singleton_mem_fun(function, instance));
386}
387
388template<typename F>
389void LuaInterface::bindSingletonFunction(const std::string& className, const std::string& functionName, const F& function)
390{
391 registerClassStaticFunction(className, functionName, luabinder::bind_fun(function));
392}
393
394template<class C, typename F>
395void LuaInterface::bindClassStaticFunction(const std::string& functionName, const F& function) {
396 registerClassStaticFunction<C>(functionName, luabinder::bind_fun(function));
397}
398template<typename F>
399void LuaInterface::bindClassStaticFunction(const std::string& className, const std::string& functionName, const F& function) {
400 registerClassStaticFunction(className, functionName, luabinder::bind_fun(function));
401}
402
403template<class C, typename F, class FC>
404void LuaInterface::bindClassMemberFunction(const std::string& functionName, F FC::*function) {
405 registerClassMemberFunction<C>(functionName, luabinder::bind_mem_fun<C>(function));
406}
407template<class C, typename F, class FC>
408void LuaInterface::bindClassMemberFunction(const std::string& className, const std::string& functionName, F FC::*function) {
409 registerClassMemberFunction(className, functionName, luabinder::bind_mem_fun<C>(function));
410}
411
412template<class C, typename F1, typename F2, class FC>
413void LuaInterface::bindClassMemberField(const std::string& fieldName, F1 FC::*getFunction, F2 FC::*setFunction) {
414 registerClassMemberField<C>(fieldName, luabinder::bind_mem_fun<C>(getFunction), luabinder::bind_mem_fun<C>(setFunction));
415}
416template<class C, typename F1, typename F2, class FC>
417void LuaInterface::bindClassMemberField(const std::string& className, const std::string& fieldName, F1 FC::*getFunction, F2 FC::*setFunction) {
418 registerClassMemberField(className, fieldName, luabinder::bind_mem_fun<C>(getFunction), luabinder::bind_mem_fun<C>(setFunction));
419}
420
421template<class C, typename F, class FC>
422void LuaInterface::bindClassMemberGetField(const std::string& fieldName, F FC::*getFunction) {
423 registerClassMemberField<C>(fieldName, luabinder::bind_mem_fun<C>(getFunction), LuaCppFunction());
424}
425template<class C, typename F, class FC>
426void LuaInterface::bindClassMemberGetField(const std::string& className, const std::string& fieldName, F FC::*getFunction) {
427 registerClassMemberField(className, fieldName, luabinder::bind_mem_fun<C>(getFunction), LuaCppFunction());
428}
429
430template<class C, typename F, class FC>
431void LuaInterface::bindClassMemberSetField(const std::string& fieldName, F FC::*setFunction) {
432 registerClassMemberField<C>(fieldName, LuaCppFunction(), luabinder::bind_mem_fun<C>(setFunction));
433}
434template<class C, typename F, class FC>
435void LuaInterface::bindClassMemberSetField(const std::string& className, const std::string& fieldName, F FC::*setFunction) {
436 registerClassMemberField(className, fieldName, LuaCppFunction(), luabinder::bind_mem_fun<C>(setFunction));
437}
438
439template<typename F>
440void LuaInterface::bindGlobalFunction(const std::string& functionName, const F& function) {
441 registerGlobalFunction(functionName, luabinder::bind_fun(function));
442}
443
444template<class T>
445T LuaInterface::castValue(int index) {
446 T o;
447 if (!luavalue_cast(index, o))
448 throw LuaBadValueCastException(typeName(index), stdext::demangle_type<T>());
449 return o;
450}
451
452bool luavalue_cast(int index, Size &value);
453bool luavalue_cast(int index, Point &value);
454bool luavalue_cast(int index, Rect &value);
455bool luavalue_cast(int index, Color &value);
456bool luavalue_cast(int index, std::string &value);
457bool luavalue_cast(int index, uint64 &value);
458
459// Otras sobrecargas de luavalue_cast...
460
461template<typename... T>
462int LuaInterface::luaCallGlobalField(const std::string& global, const std::string& field, const T&... args) {
463 AutoStat s(STATS_LUA, std::string(global) + ":" + field);
464
465 g_lua.getGlobalField(global, field);
466 int ret = 0;
467
468 if(!g_lua.isNil()) {
469 int numArgs = g_lua.polymorphicPush(args...);
470 ret = g_lua.signalCall(numArgs);
471 } else
472 g_lua.pop(1);
473 return ret;
474}
475
476template<typename... T>
477void LuaInterface::callGlobalField(const std::string& global, const std::string& field, const T&... args) {
478 int rets = luaCallGlobalField(global, field, args...);
479 if(rets > 0)
480 pop(rets);
481}
482
483template<typename R, typename... T>
484R LuaInterface::callGlobalField(const std::string& global, const std::string& field, const T&... args) {
485 R result;
486 int rets = luaCallGlobalField(global, field, args...);
487 if(rets > 0) {
488 VALIDATE(rets == 1);
489 result = g_lua.polymorphicPop<R>();
490 } else
491 result = R();
492 return result;
493}
494
495#endif
496