Otclient 1.0  14/8/2020
luainterface.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-2020 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 #include "luainterface.h"
24 #include "luaobject.h"
25 
27 #include <lua.hpp>
28 
29 #include "lbitlib.h"
30 
32 
34 {
35  L = nullptr;
36  m_cppCallbackDepth = 0;
37  m_weakTableRef = 0;
38  m_totalObjRefs = 0;
39  m_totalFuncRefs = 0;
40 }
41 
43 {
44 }
45 
47 {
49 
50  // store global environment reference
51  pushThread();
52  getEnv();
53  m_globalEnv = ref();
54  pop();
55 
56  // check if demangle_class is working as expected
57  assert(stdext::demangle_class<LuaObject>() == "LuaObject");
58 
59  // register LuaObject, the base of all other objects
60  registerClass<LuaObject>();
61  bindClassMemberFunction<LuaObject>("getUseCount", &LuaObject::getUseCount);
62  bindClassMemberFunction<LuaObject>("getClassName", &LuaObject::getClassName);
63 
64  registerClassMemberFunction<LuaObject>("getFieldsTable", static_cast<LuaCppFunction>([](LuaInterface*) -> int
65  {
67  obj->luaGetFieldsTable();
68  return 1;
69  }));
70 }
71 
73 {
74  // close lua state, it will release all objects
75  closeLuaState();
76  assert(m_totalFuncRefs == 0);
77  assert(m_totalObjRefs == 0);
78 }
79 
80 void LuaInterface::registerSingletonClass(const std::string& className)
81 {
82  newTable();
83  pushValue();
84  setGlobal(className);
85  pop();
86 }
87 
88 void LuaInterface::registerClass(const std::string& className, const std::string& baseClass)
89 {
90  // creates the class table (that it's also the class methods table)
91  newTable();
92  pushValue();
93  setGlobal(className);
94  const int klass = getTop();
95 
96  // creates the class fieldmethods table
97  newTable();
98  pushValue();
99  setGlobal(className + "_fieldmethods");
100  int klass_fieldmethods = getTop();
101 
102  // creates the class metatable
103  newTable();
104  pushValue();
105  setGlobal(className + "_mt");
106  int klass_mt = getTop();
107 
108  // set metatable metamethods
109  pushCppFunction(&LuaInterface::luaObjectGetEvent);
110  setField("__index", klass_mt);
111  pushCppFunction(&LuaInterface::luaObjectSetEvent);
112  setField("__newindex", klass_mt);
113  pushCppFunction(&LuaInterface::luaObjectEqualEvent);
114  setField("__eq", klass_mt);
115  pushCppFunction(&LuaInterface::luaObjectCollectEvent);
116  setField("__gc", klass_mt);
117 
118  // set some fields that will be used later in metatable
119  pushValue(klass);
120  setField("methods", klass_mt);
121  pushValue(klass_fieldmethods);
122  setField("fieldmethods", klass_mt);
123 
124  // redirect methods and fieldmethods to the base class ones
125  if (!className.empty() && className != "LuaObject") {
126  // the following code is what create classes hierarchy for lua, by reproducing:
127  // DerivedClass = { __index = BaseClass }
128  // DerivedClass_fieldmethods = { __index = BaseClass_methods }
129 
130  // redirect the class methods to the base methods
131  pushValue(klass);
132  newTable();
133  getGlobal(baseClass);
134  setField("__index");
135  setMetatable();
136  pop();
137 
138  // redirect the class fieldmethods to the base fieldmethods
139  pushValue(klass_fieldmethods);
140  newTable();
141  getGlobal(baseClass + "_fieldmethods");
142  setField("__index");
143  setMetatable();
144  pop();
145  }
146 
147  // pops klass, klass_mt, klass_fieldmethods
148  pop(3);
149 }
150 
151 void LuaInterface::registerClassStaticFunction(const std::string& className,
152  const std::string& functionName,
153  const LuaCppFunction& function)
154 {
155  registerClassMemberFunction(className, functionName, function);
156 }
157 
158 void LuaInterface::registerClassMemberFunction(const std::string& className,
159  const std::string& functionName,
160  const LuaCppFunction& function)
161 {
162  getGlobal(className);
163  pushCppFunction(function);
164  setField(functionName);
165  pop();
166 }
167 
168 void LuaInterface::registerClassMemberField(const std::string& className,
169  const std::string& field,
170  const LuaCppFunction& getFunction,
171  const LuaCppFunction& setFunction)
172 {
173  getGlobal(className + "_fieldmethods");
174 
175  if (getFunction) {
176  pushCppFunction(getFunction);
177  setField(stdext::format("get_%s", field));
178  }
179 
180  if (setFunction) {
181  pushCppFunction(setFunction);
182  setField(stdext::format("set_%s", field));
183  }
184 
185  pop();
186 }
187 
188 void LuaInterface::registerGlobalFunction(const std::string& functionName, const LuaCppFunction& function)
189 {
190  pushCppFunction(function);
191  setGlobal(functionName);
192 }
193 
194 int LuaInterface::luaObjectGetEvent(LuaInterface* lua)
195 {
196  // stack: obj, key
197  LuaObjectPtr obj = lua->toObject(-2);
198  std::string key = lua->toString(-1);
199  assert(obj);
200 
201  lua->remove(-1); // removes key
202 
203  // if a get method for this key exists, calls it
204  lua->getMetatable(); // pushes obj metatable
205  lua->getField("fieldmethods"); // push obj fieldmethods
206  lua->remove(-2); // removes obj metatable
207  lua->getField("get_" + key); // pushes get method
208  lua->remove(-2); // remove obj fieldmethods
209  if (!lua->isNil()) { // is the get method not nil?
210  lua->insert(-2); // moves obj to the top
211  lua->signalCall(1, 1); // calls get method, arguments: obj
212  return 1;
213  }
214  lua->pop(); // pops the nil get method
215 
216  // if the field for this key exists, returns it
217  obj->luaGetField(key);
218  if (!lua->isNil()) {
219  lua->remove(-2); // removes the obj
220  // field value is on the stack
221  return 1;
222  }
223  lua->pop(); // pops the nil field
224 
225  // pushes the method assigned by this key
226  lua->getMetatable(); // pushes obj metatable
227  lua->getField("methods"); // push obj methods
228  lua->remove(-2); // removes obj metatable
229  lua->getField(key); // pushes obj method
230  lua->remove(-2); // remove obj methods
231  lua->remove(-2); // removes obj
232 
233  // the result value is on the stack
234  return 1;
235 }
236 
237 int LuaInterface::luaObjectSetEvent(LuaInterface* lua)
238 {
239  // stack: obj, key, value
240  LuaObjectPtr obj = lua->toObject(-3);
241  std::string key = lua->toString(-2);
242  assert(obj);
243 
244  lua->remove(-2); // removes key
245  lua->insert(-2); // moves obj to the top
246 
247  // check if a set method for this field exists and call it
248  lua->getMetatable(); // pushes obj metatable
249  lua->getField("fieldmethods"); // push obj fieldmethods
250  lua->remove(-2); // removes obj metatable
251  lua->getField("set_" + key); // pushes set method
252  lua->remove(-2); // remove obj fieldmethods
253  if (!lua->isNil()) { // is the set method not nil?
254  lua->insert(-3); // moves func to -3
255  lua->insert(-2); // moves obj to -2, and value to -1
256  lua->signalCall(2, 0); // calls set method, arguments: obj, value
257  return 0;
258  }
259  lua->pop(); // pops the nil set method
260 
261  // no set method exists, then treats as an field and set it
262  lua->pop(); // pops the object
263  obj->luaSetField(key); // sets the obj field
264  return 0;
265 }
266 
267 int LuaInterface::luaObjectEqualEvent(LuaInterface* lua)
268 {
269  // stack: obj1, obj2
270  bool ret = false;
271 
272  // check if obj1 == obj2
273  if (lua->isUserdata(-1) && lua->isUserdata(-2)) {
274  LuaObjectPtr* objPtr2 = static_cast<LuaObjectPtr*>(lua->popUserdata());
275  LuaObjectPtr* objPtr1 = static_cast<LuaObjectPtr*>(lua->popUserdata());
276  assert(objPtr1 && objPtr2);
277  if (*objPtr1 == *objPtr2)
278  ret = true;
279  }
280  else
281  lua->pop(2);
282 
283  lua->pushBoolean(ret);
284  return 1;
285 }
286 
287 int LuaInterface::luaObjectCollectEvent(LuaInterface* lua)
288 {
289  // gets object pointer
290  auto objPtr = static_cast<LuaObjectPtr*>(lua->popUserdata());
291  assert(objPtr);
292 
293  // resets pointer to decrease object use count
294  objPtr->reset();
295  g_lua.m_totalObjRefs--;
296  return 0;
297 }
298 
299 
301 
302 
303 bool LuaInterface::safeRunScript(const std::string& fileName)
304 {
305  try {
306  runScript(fileName);
307  return true;
308  }
309  catch (stdext::exception& e) {
310  g_logger.error(stdext::format("Failed to load script '%s': %s", fileName, e.what()));
311  return false;
312  }
313 }
314 
315 void LuaInterface::runScript(const std::string& fileName)
316 {
317  loadScript(fileName);
318  safeCall(0, 0);
319 }
320 
321 void LuaInterface::runBuffer(const std::string& buffer, const std::string& source)
322 {
323  loadBuffer(buffer, source);
324  safeCall(0, 0);
325 }
326 
327 void LuaInterface::loadScript(const std::string& fileName)
328 {
329  // resolve file full path
330  std::string filePath = fileName;
331  if (!stdext::starts_with(fileName, "/"))
332  filePath = getCurrentSourcePath() + "/" + filePath;
333 
334  filePath = g_resources.guessFilePath(filePath, "lua");
335 
336  std::string buffer = g_resources.readFileContents(filePath);
337  std::string source = "@" + filePath;
338  loadBuffer(buffer, source);
339 }
340 
341 void LuaInterface::loadFunction(const std::string& buffer, const std::string& source)
342 {
343  if (buffer.empty()) {
344  pushNil();
345  return;
346  }
347 
348  std::string buf;
349  if (stdext::starts_with(buffer, "function"))
350  buf = stdext::format("__func = %s", buffer);
351  else
352  buf = stdext::format("__func = function(self)\n%s\nend", buffer);
353 
354  loadBuffer(buf, source);
355  safeCall();
356 
357  // get the function
358  getGlobal("__func");
359 
360  // reset the global __func
361  pushNil();
362  setGlobal("__func");
363 }
364 
365 void LuaInterface::evaluateExpression(const std::string& expression, const std::string& source)
366 {
367  // evaluates the expression
368  if (!expression.empty()) {
369  std::string buffer = stdext::format("__exp = (%s)", expression);
370  loadBuffer(buffer, source);
371  safeCall();
372 
373  // gets the expression result
374  getGlobal("__exp");
375 
376  // resets global __exp
377  pushNil();
378  setGlobal("__exp");
379  }
380  else
381  pushNil();
382 }
383 
384 std::string LuaInterface::traceback(const std::string& errorMessage, int level)
385 {
386  // gets debug.traceback
387  getGlobal("debug");
388  getField("traceback");
389  remove(-2); // remove debug
390 
391  // calls debug.traceback(errorMessage, level)
392  pushString(errorMessage);
393  pushInteger(level);
394  call(2, 1);
395 
396  // returns the traceback message
397  return popString();
398 }
399 
400 void LuaInterface::throwError(const std::string& message)
401 {
402  if (isInCppCallback()) {
403  pushString(message);
404  error();
405  }
406  else
407  throw stdext::exception(message);
408 }
409 
411 {
412  std::string path;
413  if (!L)
414  return path;
415 
416  // check all stack functions for script source path
417  while (true) {
418  getStackFunction(level); // pushes stack function
419 
420  // only lua functions is wanted, because only them have a working directory
421  if (isLuaFunction()) {
422  path = functionSourcePath();
423  break;
424  }
425  else if (isNil()) {
426  pop();
427  break;
428  }
429  else
430  pop();
431 
432  // next level
433  level++;
434  }
435 
436  return path;
437 }
438 
439 int LuaInterface::safeCall(int numArgs, int numRets)
440 {
441  assert(hasIndex(-numArgs - 1));
442 
443  // saves the current stack size for calculating the number of results later
444  int previousStackSize = stackSize();
445 
446  // pushes error function
447  int errorFuncIndex = previousStackSize - numArgs;
448  pushCFunction(&LuaInterface::luaErrorHandler);
449  insert(errorFuncIndex);
450 
451  // calls the function in protected mode (means errors will be caught)
452  int ret = pcall(numArgs, LUA_MULTRET, errorFuncIndex);
453 
454  remove(errorFuncIndex); // remove error func
455 
456  // if there was an error throw an exception
457  if (ret != 0)
458  throw LuaException(popString());
459 
460  int rets = (stackSize() + numArgs + 1) - previousStackSize;
461  while (numRets != -1 && rets != numRets) {
462  if (rets < numRets) {
463  pushNil();
464  rets++;
465  }
466  else {
467  pop();
468  rets--;
469  }
470  }
471 
472  // returns the number of results
473  return rets;
474 }
475 
476 int LuaInterface::signalCall(int numArgs, int numRets)
477 {
478  int rets = 0;
479  int funcIndex = -numArgs - 1;
480 
481  try {
482  // must be a function
483  if (isFunction(funcIndex)) {
484  rets = safeCall(numArgs);
485 
486  if (numRets != -1) {
487  if (rets != numRets)
488  throw LuaException("function call didn't return the expected number of results", 0);
489  }
490  }
491  // can also calls table of functions
492  else if (isTable(funcIndex)) {
493  // loop through table values
494  pushNil();
495  bool done = false;
496  while (next(funcIndex - 1)) {
497  if (isFunction()) {
498  // repush arguments
499  for (int i = 0; i < numArgs; ++i)
500  pushValue(-numArgs - 2);
501 
502  rets = safeCall(numArgs);
503  if (rets == 1) {
504  done = popBoolean();
505  if (done) {
506  pop();
507  break;
508  }
509  }
510  else if (rets != 0)
511  throw LuaException("function call didn't return the expected number of results", 0);
512  }
513  else {
514  throw LuaException("attempt to call a non function", 0);
515  }
516  }
517  pop(numArgs + 1); // pops the table of function and arguments
518 
519  if (numRets == 1 || numRets == -1) {
520  rets = 1;
521  pushBoolean(done);
522  }
523  }
524  // nil values are ignored
525  else if (isNil(funcIndex)) {
526  pop(numArgs + 1); // pops the function and arguments
527  }
528  // if not nil, warn
529  else {
530  throw LuaException("attempt to call a non function value", 0);
531  }
532  }
533  catch (stdext::exception& e) {
534  g_logger.error(stdext::format("protected lua call failed: %s", e.what()));
535  }
536 
537  // pushes nil values if needed
538  while (numRets != -1 && rets < numRets) {
539  pushNil();
540  rets++;
541  }
542 
543  // returns the number of results on the stack
544  return rets;
545 }
546 
548 {
549  newTable(); // pushes the new environment table
550  newTable(); // pushes the new environment metatable
551  getRef(getGlobalEnvironment()); // pushes the global environment
552  setField("__index"); // sets metatable __index to the global environment
553  setMetatable(); // assigns environment metatable
554  return ref(); // return a reference to the environment table
555 }
556 
558 // lua C functions
559 
560 int LuaInterface::luaScriptLoader(lua_State*)
561 {
562  // loads the script as a function
563  std::string fileName = g_lua.popString();
564 
565  try {
566  g_lua.loadScript(fileName);
567  return 1;
568  }
569  catch (stdext::exception& e) {
570  g_lua.pushString(std::string("\n\t") + e.what());
571  return 1;
572  }
573 }
574 
575 int LuaInterface::lua_dofile(lua_State*)
576 {
577  std::string file = g_lua.popString();
578 
579  try {
580  g_lua.loadScript(file);
581  g_lua.call(0, LUA_MULTRET);
582  return g_lua.stackSize();
583  }
584  catch (stdext::exception& e) {
585  g_lua.pushString(e.what());
586  g_lua.error();
587  return 0;
588  }
589 }
590 
591 int LuaInterface::lua_dofiles(lua_State*)
592 {
593  std::string contains = "";
594  if (g_lua.getTop() > 2) {
595  contains = g_lua.popString();
596  }
597 
598  bool recursive = false;
599  if (g_lua.getTop() > 1) {
600  recursive = g_lua.popBoolean();
601  }
602 
603  std::string directory = g_lua.popString();
604  g_lua.loadFiles(directory, recursive, contains);
605 
606  return 0;
607 }
608 
609 int LuaInterface::lua_loadfile(lua_State*)
610 {
611  std::string fileName = g_lua.popString();
612 
613  try {
614  g_lua.loadScript(fileName);
615  return 1;
616  }
617  catch (stdext::exception& e) {
618  g_lua.pushNil();
619  g_lua.pushString(e.what());
620  g_lua.error();
621  return 2;
622  }
623 }
624 
625 int LuaInterface::luaErrorHandler(lua_State*)
626 {
627  // pops the error message
628  auto error = g_lua.popString();
629 
630  // prevents repeated tracebacks
631  if (error.find("stack traceback:") == std::string::npos)
632  error = g_lua.traceback(error, 1);
633 
634  // pushes the new error message with traceback information
636  return 1;
637 }
638 
639 int LuaInterface::luaCppFunctionCallback(lua_State*)
640 {
641  // retrieves function pointer from userdata
642  auto funcPtr = static_cast<LuaCppFunctionPtr*>(g_lua.popUpvalueUserdata());
643  assert(funcPtr);
644 
645  int numRets = 0;
646 
647  // do the call
648  try {
649  g_lua.m_cppCallbackDepth++;
650  numRets = (*(funcPtr->get()))(&g_lua);
651  g_lua.m_cppCallbackDepth--;
652  assert(numRets == g_lua.stackSize());
653  }
654  catch (stdext::exception& e) {
655  // cleanup stack
656  while (g_lua.stackSize() > 0)
657  g_lua.pop();
658  numRets = 0;
659  g_lua.pushString(stdext::format("C++ call failed: %s", g_lua.traceback(e.what())));
660  g_lua.error();
661  }
662 
663  return numRets;
664 }
665 
666 int LuaInterface::luaCollectCppFunction(lua_State*)
667 {
668  auto funcPtr = static_cast<LuaCppFunctionPtr*>(g_lua.popUserdata());
669  assert(funcPtr);
670  funcPtr->reset();
671  g_lua.m_totalFuncRefs--;
672  return 0;
673 }
674 
675 
677 // from here all next functions are interfaces for the Lua API
678 
680 {
681  // creates lua state
682  L = luaL_newstate();
683  if (!L)
684  g_logger.fatal("Unable to create lua state");
685 
686  // load lua standard libraries
687  luaL_openlibs(L);
688 
689  // load bit32 lib for bitwise operations
690  luaopen_bit32(L);
691 
692  // creates weak table
693  newTable();
694  newTable();
695  pushString("v");
696  setField("__mode");
697  setMetatable();
698  m_weakTableRef = ref();
699 
700  // installs script loader
701  getGlobal("package");
702  getField("loaders");
703  pushCFunction(&LuaInterface::luaScriptLoader);
704  rawSeti(5);
705  pop(2);
706 
707  // replace dofile
708  pushCFunction(&LuaInterface::lua_dofile);
709  setGlobal("dofile");
710 
711  // dofiles
712  pushCFunction(&LuaInterface::lua_dofiles);
713  setGlobal("dofiles");
714 
715  // replace loadfile
716  pushCFunction(&LuaInterface::lua_loadfile);
717  setGlobal("loadfile");
718 }
719 
721 {
722  if (L) {
723  // close lua, it also collects
724  lua_close(L);
725  L = nullptr;
726  }
727 }
728 
730 {
731  // prevents recursive collects
732  static bool collecting = false;
733  if (!collecting) {
734  collecting = true;
735 
736  // we must collect two times because __gc metamethod
737  // is called on uservalues only the second time
738  for (int i = 0; i < 2; ++i)
739  lua_gc(L, LUA_GCCOLLECT, 0);
740 
741  collecting = false;
742  }
743 }
744 
745 void LuaInterface::loadBuffer(const std::string& buffer, const std::string& source)
746 {
747  // loads lua buffer
748  int ret = luaL_loadbuffer(L, buffer.c_str(), buffer.length(), source.c_str());
749  if (ret != 0)
750  throw LuaException(popString(), 0);
751 }
752 
753 int LuaInterface::pcall(int numArgs, int numRets, int errorFuncIndex)
754 {
755  assert(hasIndex(-numArgs - 1));
756  return lua_pcall(L, numArgs, numRets, errorFuncIndex);
757 }
758 
759 void LuaInterface::call(int numArgs, int numRets)
760 {
761  assert(hasIndex(-numArgs - 1));
762  lua_call(L, numArgs, numRets);
763 }
764 
766 {
767  assert(hasIndex(-1));
768  lua_error(L);
769 }
770 
772 {
773  int ref = luaL_ref(L, LUA_REGISTRYINDEX);
774  assert(ref != LUA_NOREF);
775  assert(ref < 2147483647);
776  return ref;
777 }
778 
780 {
781  static int id = 0;
782 
783  // generates a new id
784  ++id;
785  if (id == 2147483647)
786  id = 0;
787 
788  // gets weak table
789  getRef(m_weakTableRef);
790  insert(-2);
791 
792  // sets weak_table[id] = v
793  rawSeti(id);
794 
795  // pops weak table
796  pop();
797 
798  return id;
799 }
800 
801 void LuaInterface::unref(int ref)
802 {
803  if (ref >= 0 && L != nullptr)
804  luaL_unref(L, LUA_REGISTRYINDEX, ref);
805 }
806 
807 const char* LuaInterface::typeName(int index)
808 {
809  assert(hasIndex(index));
810  int type = lua_type(L, index);
811  return lua_typename(L, type);
812 }
813 
815 {
816  std::string path;
817 
818  // gets function source path
819  lua_Debug ar;
820  memset(&ar, 0, sizeof(ar));
821  lua_getinfo(L, ">Sn", &ar);
822  if (ar.source) {
823  // scripts coming from files has source beginning with '@'
824  if (ar.source[0] == '@') {
825  path = ar.source;
826  path = path.substr(1, path.find_last_of("/") - 1);
827  path = path.substr(0, path.find_last_of(":"));
828  }
829  }
830 
831  return path;
832 }
833 
834 void LuaInterface::insert(int index)
835 {
836  assert(hasIndex(index));
837  lua_insert(L, index);
838 }
839 
840 void LuaInterface::remove(int index)
841 {
842  assert(hasIndex(index));
843  lua_remove(L, index);
844 }
845 
846 bool LuaInterface::next(int index)
847 {
848  assert(hasIndex(index));
849  return lua_next(L, index);
850 }
851 
853 {
854  lua_Debug ar;
855  if (lua_getstack(L, level, &ar) == 1)
856  lua_getinfo(L, "f", &ar);
857  else
858  pushNil();
859 }
860 
861 void LuaInterface::getRef(int ref)
862 {
863  lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
864 }
865 
866 void LuaInterface::getWeakRef(int weakRef)
867 {
868  // pushes weak_table[weakRef]
869  getRef(m_weakTableRef);
870  rawGeti(weakRef);
871  remove(-2);
872 }
873 
875 {
876  pushThread();
877  getRef(env);
878  assert(isTable());
879  setEnv();
880  pop();
881 }
882 
884 {
885  assert(hasIndex(index));
886  lua_setmetatable(L, index);
887 }
888 
890 {
891  assert(hasIndex(index));
892  lua_getmetatable(L, index);
893 }
894 
895 void LuaInterface::getField(const char* key, int index)
896 {
897  assert(hasIndex(index));
898  assert(isUserdata(index) || isTable(index));
899  lua_getfield(L, index, key);
900 }
901 
902 void LuaInterface::setField(const char* key, int index)
903 {
904  assert(hasIndex(index));
905  assert(isUserdata(index) || isTable(index));
906  lua_setfield(L, index, key);
907 }
908 
909 void LuaInterface::getEnv(int index)
910 {
911  assert(hasIndex(index));
912  lua_getfenv(L, index);
913 }
914 
915 void LuaInterface::setEnv(int index)
916 {
917  assert(hasIndex(index));
918  lua_setfenv(L, index);
919 }
920 
921 void LuaInterface::getTable(int index)
922 {
923  assert(hasIndex(index));
924  lua_gettable(L, index);
925 }
926 
927 void LuaInterface::setTable(int index)
928 {
929  assert(hasIndex(index));
930  lua_settable(L, index);
931 }
932 
934 {
935  assert(hasIndex(index) && isTable(index));
936 
937  pushNil(); // table, nil
938 
939  while (next(index - 1)) { // table, key, value
940  pop(); // table, key
941  pushValue(); // table, key, key
942  if (next(index - 2)) { // table, key, nextkey, value
943  pop(); // table, key, nextkey
944  insert(-2); // table, nextkey, key
945  pushNil(); // table, nextkey, key, nil
946  rawSet(index - 3); // table, nextkey
947  }
948  else { // table, key
949  pushNil(); // table, key, nil
950  rawSet(index - 2); // table
951  break;
952  }
953  }
954 }
955 
956 void LuaInterface::getGlobal(const std::string& key)
957 {
958  lua_getglobal(L, key.c_str());
959 }
960 
961 void LuaInterface::getGlobalField(const std::string& globalKey, const std::string& fieldKey)
962 {
963  getGlobal(globalKey);
964  if (!isNil()) {
965  assert(isTable() || isUserdata());
966  getField(fieldKey);
967  remove(-2);
968  }
969 }
970 
971 void LuaInterface::setGlobal(const std::string& key)
972 {
973  assert(hasIndex(-1));
974  lua_setglobal(L, key.c_str());
975 }
976 
977 void LuaInterface::rawGet(int index)
978 {
979  assert(hasIndex(index));
980  lua_rawget(L, index);
981 }
982 
983 void LuaInterface::rawGeti(int n, int index)
984 {
985  assert(hasIndex(index));
986  lua_rawgeti(L, index, n);
987 }
988 
989 void LuaInterface::rawSet(int index)
990 {
991  assert(hasIndex(index));
992  lua_rawset(L, index);
993 }
994 
995 void LuaInterface::rawSeti(int n, int index)
996 {
997  assert(hasIndex(index));
998  lua_rawseti(L, index, n);
999 }
1000 
1002 {
1003  lua_newtable(L);
1004 }
1005 
1006 void LuaInterface::createTable(int narr, int nrec)
1007 {
1008  lua_createtable(L, narr, nrec);
1009 }
1010 
1012 {
1013  return lua_newuserdata(L, size);
1014 }
1015 
1017 {
1018  if (n > 0) {
1019  assert(hasIndex(-n));
1020  lua_pop(L, n);
1021  }
1022 }
1023 
1025 {
1026  assert(hasIndex(-1));
1027  long v = toInteger(-1);
1028  pop();
1029  return v;
1030 }
1031 
1033 {
1034  assert(hasIndex(-1));
1035  double v = toNumber(-1);
1036  pop();
1037  return v;
1038 }
1039 
1041 {
1042  assert(hasIndex(-1));
1043  bool v = toBoolean(-1);
1044  pop();
1045  return v;
1046 }
1047 
1049 {
1050  assert(hasIndex(-1));
1051  std::string v = toString(-1);
1052  pop();
1053  return v;
1054 }
1055 
1057 {
1058  assert(hasIndex(-1));
1059  void* v = toUserdata(-1);
1060  pop();
1061  return v;
1062 }
1063 
1065 {
1066  assert(hasIndex(-1));
1067  LuaObjectPtr v = toObject(-1);
1068  pop();
1069  return v;
1070 }
1071 
1073 {
1074  return lua_touserdata(L, lua_upvalueindex(1));
1075 }
1076 
1078 {
1079  lua_pushnil(L);
1080  checkStack();
1081 }
1082 
1084 {
1085  lua_pushinteger(L, v);
1086  checkStack();
1087 }
1088 
1090 {
1091  lua_pushnumber(L, v);
1092  checkStack();
1093 }
1094 
1096 {
1097  lua_pushboolean(L, v);
1098  checkStack();
1099 }
1100 
1101 void LuaInterface::pushCString(const char* v)
1102 {
1103  assert(v);
1104  lua_pushstring(L, v);
1105  checkStack();
1106 }
1107 
1108 void LuaInterface::pushString(const std::string& v)
1109 {
1110  lua_pushlstring(L, v.c_str(), v.length());
1111  checkStack();
1112 }
1113 
1115 {
1116  lua_pushlightuserdata(L, p);
1117  checkStack();
1118 }
1119 
1121 {
1122  lua_pushthread(L);
1123  checkStack();
1124 }
1125 
1127 {
1128  // fills a new userdata with a new LuaObjectPtr pointer
1129  new(newUserdata(sizeof(LuaObjectPtr))) LuaObjectPtr(obj);
1130  m_totalObjRefs++;
1131 
1132  obj->luaGetMetatable();
1133  if (isNil())
1134  g_logger.fatal(stdext::format("metatable for class '%s' not found, did you bind the C++ class?", obj->getClassName()));
1135  setMetatable();
1136 }
1137 
1139 {
1140  lua_pushcclosure(L, func, n);
1141  checkStack();
1142 }
1143 
1145 {
1146  // create a pointer to func (this pointer will hold the function existence)
1148  m_totalFuncRefs++;
1149 
1150  // sets the userdata __gc metamethod, needed to free the function pointer when it gets collected
1151  newTable();
1152  pushCFunction(&LuaInterface::luaCollectCppFunction);
1153  setField("__gc");
1154  setMetatable();
1155 
1156  // actually pushes a C function callback that will call the cpp function
1157  pushCFunction(&LuaInterface::luaCppFunctionCallback, 1);
1158 }
1159 
1161 {
1162  assert(hasIndex(index));
1163  lua_pushvalue(L, index);
1164  checkStack();
1165 }
1166 
1167 bool LuaInterface::isNil(int index)
1168 {
1169  assert(hasIndex(index));
1170  return lua_isnil(L, index);
1171 }
1172 
1174 {
1175  assert(hasIndex(index));
1176  return lua_isboolean(L, index);
1177 }
1178 
1179 bool LuaInterface::isNumber(int index)
1180 {
1181  assert(hasIndex(index));
1182  return lua_isnumber(L, index);
1183 }
1184 
1185 bool LuaInterface::isString(int index)
1186 {
1187  assert(hasIndex(index));
1188  return lua_isstring(L, index);
1189 }
1190 
1191 bool LuaInterface::isTable(int index)
1192 {
1193  assert(hasIndex(index));
1194  return lua_istable(L, index);
1195 }
1196 
1198 {
1199  assert(hasIndex(index));
1200  return lua_isfunction(L, index);
1201 }
1202 
1204 {
1205  assert(hasIndex(index));
1206  return lua_iscfunction(L, index);
1207 }
1208 
1210 {
1211  assert(hasIndex(index));
1212  return lua_isuserdata(L, index);
1213 }
1214 
1216 {
1217  assert(hasIndex(index));
1218  return static_cast<bool>(lua_toboolean(L, index));
1219 }
1220 
1222 {
1223  assert(hasIndex(index));
1224  return lua_tointeger(L, index);
1225 }
1226 
1227 double LuaInterface::toNumber(int index)
1228 {
1229  assert(hasIndex(index));
1230  return lua_tonumber(L, index);
1231 }
1232 
1233 const char* LuaInterface::toCString(int index)
1234 {
1235  assert(hasIndex(index));
1236  return lua_tostring(L, index);
1237 }
1238 
1239 std::string LuaInterface::toString(int index)
1240 {
1241  assert(hasIndex(index));
1242  std::string str;
1243  size_t len;
1244  const char* c_str = lua_tolstring(L, index, &len);
1245  if (c_str && len > 0)
1246  str.assign(c_str, len);
1247  return str;
1248 }
1249 
1251 {
1252  assert(hasIndex(index));
1253  return lua_touserdata(L, index);
1254 }
1255 
1257 {
1258  assert(hasIndex(index));
1259  if (isUserdata(index)) {
1260  LuaObjectPtr* objRef = static_cast<LuaObjectPtr*>(toUserdata(index));
1261  if (objRef && *objRef)
1262  return *objRef;
1263  }
1264  return nullptr;
1265 }
1266 
1268 {
1269  return lua_gettop(L);
1270 }
1271 
1272 void LuaInterface::loadFiles(std::string directory, bool recursive, std::string contains)
1273 {
1274  for (const std::string& fileName : g_resources.listDirectoryFiles(directory)) {
1275  std::string fullPath = directory + "/" + fileName;
1276 
1277  if (recursive && g_resources.directoryExists(fullPath)) {
1278  loadFiles(fullPath, true, contains);
1279  continue;
1280  }
1281 
1282  if (!g_resources.isFileType(fileName, "lua"))
1283  continue;
1284 
1285  if (!contains.empty() && fileName.find(contains) == std::string::npos)
1286  continue;
1287 
1288  try {
1289  g_lua.loadScript(fullPath);
1290  g_lua.call(0, 0);
1291  }
1292  catch (stdext::exception& e) {
1293  g_lua.pushString(e.what());
1294  g_lua.error();
1295  }
1296  }
1297 }
ResourceManager::isFileType
bool isFileType(const std::string &filename, const std::string &type)
Definition: resourcemanager.cpp:360
ResourceManager::listDirectoryFiles
std::list< std::string > listDirectoryFiles(const std::string &directoryPath="")
Definition: resourcemanager.cpp:268
LuaInterface::insert
void insert(int index)
Definition: luainterface.cpp:834
LuaInterface::rawSeti
void rawSeti(int n, int index=-2)
Definition: luainterface.cpp:995
LuaCppFunction
std::function< int(LuaInterface *)> LuaCppFunction
Definition: declarations.h:31
LuaInterface::newUserdata
void * newUserdata(int size)
Definition: luainterface.cpp:1011
LuaInterface::setGlobal
void setGlobal(const std::string &key)
Definition: luainterface.cpp:971
LuaInterface::isString
bool isString(int index=-1)
Definition: luainterface.cpp:1185
LuaInterface::isLuaFunction
bool isLuaFunction(int index=-1)
Definition: luainterface.h:309
LuaInterface::stackSize
int stackSize()
Definition: luainterface.h:321
LuaInterface::toString
std::string toString(int index=-1)
Definition: luainterface.cpp:1239
LuaInterface::ref
int ref()
Definition: luainterface.cpp:771
LuaInterface::getTop
int getTop()
Definition: luainterface.cpp:1267
LuaInterface::call
void call(int numArgs=0, int numRets=0)
Definition: luainterface.cpp:759
LuaInterface::isNumber
bool isNumber(int index=-1)
Definition: luainterface.cpp:1179
LuaInterface::registerClassMemberFunction
void registerClassMemberFunction(const std::string &className, const std::string &functionName, const LuaCppFunction &function)
Definition: luainterface.cpp:158
LuaInterface::toObject
LuaObjectPtr toObject(int index=-1)
Definition: luainterface.cpp:1256
ResourceManager::directoryExists
bool directoryExists(const std::string &directoryName)
Definition: resourcemanager.cpp:163
LuaInterface::isCFunction
bool isCFunction(int index=-1)
Definition: luainterface.cpp:1203
resourcemanager.h
luainterface.h
Logger::error
void error(const std::string &what)
Definition: logger.h:54
LuaInterface::popObject
LuaObjectPtr popObject()
Definition: luainterface.cpp:1064
LuaInterface::popUpvalueUserdata
void * popUpvalueUserdata()
Definition: luainterface.cpp:1072
LuaInterface::checkStack
void checkStack()
Definition: luainterface.h:242
LuaInterface::closeLuaState
void closeLuaState()
Definition: luainterface.cpp:720
LuaInterface::registerSingletonClass
void registerSingletonClass(const std::string &className)
Definition: luainterface.cpp:80
LuaInterface::getGlobal
void getGlobal(const std::string &key)
Definition: luainterface.cpp:956
LuaInterface::init
void init()
Definition: luainterface.cpp:46
LuaInterface::setGlobalEnvironment
void setGlobalEnvironment(int env)
Definition: luainterface.cpp:874
LuaInterface::isFunction
bool isFunction(int index=-1)
Definition: luainterface.cpp:1197
LuaObjectPtr
stdext::shared_object_ptr< LuaObject > LuaObjectPtr
Definition: declarations.h:35
LuaInterface::loadScript
void loadScript(const std::string &fileName)
Definition: luainterface.cpp:327
LuaInterface::hasIndex
bool hasIndex(int index)
Definition: luainterface.h:323
stdext::format
std::string format()
Definition: format.h:84
LuaInterface::traceback
std::string traceback(const std::string &errorMessage="", int level=0)
Definition: luainterface.cpp:384
lbitlib.h
stdext::starts_with
bool starts_with(const std::string &str, const std::string &test)
Definition: string.cpp:263
LuaInterface::throwError
void throwError(const std::string &message)
Definition: luainterface.cpp:400
LuaInterface::clearTable
void clearTable(int index=-1)
Definition: luainterface.cpp:933
luaobject.h
LuaObject::getClassName
std::string getClassName()
Returns the derived class name, its the same name used in Lua.
Definition: luaobject.cpp:117
LuaException
Definition: luaexception.h:28
LuaInterface::getField
void getField(const char *key, int index=-1)
Definition: luainterface.cpp:895
Logger::fatal
void fatal(const std::string &what)
Definition: logger.h:55
g_resources
ResourceManager g_resources
Definition: resourcemanager.cpp:32
LuaInterface::getTable
void getTable(int index=-2)
Definition: luainterface.cpp:921
LuaInterface::safeRunScript
bool safeRunScript(const std::string &fileName)
Loads and runs a script, any errors are printed to stdout and returns false.
Definition: luainterface.cpp:303
LuaInterface::pushNumber
void pushNumber(double v)
Definition: luainterface.cpp:1089
LuaInterface::toUserdata
void * toUserdata(int index=-1)
Definition: luainterface.cpp:1250
LuaInterface::createTable
void createTable(int narr, int nrec)
Definition: luainterface.cpp:1006
LuaInterface::popString
std::string popString()
Definition: luainterface.cpp:1048
LuaInterface::weakRef
int weakRef()
Definition: luainterface.cpp:779
g_logger
Logger g_logger
Definition: logger.cpp:35
LuaInterface::isNil
bool isNil(int index=-1)
Definition: luainterface.cpp:1167
LuaInterface::popInteger
long popInteger()
Definition: luainterface.cpp:1024
LuaInterface::newSandboxEnv
int newSandboxEnv()
Creates a new environment table The new environment table is redirected to the global environment (ak...
Definition: luainterface.cpp:547
g_lua
LuaInterface g_lua
Definition: luainterface.cpp:31
LuaInterface::setEnv
void setEnv(int index=-2)
Definition: luainterface.cpp:915
luaopen_bit32
int luaopen_bit32(lua_State *L)
Definition: lbitlib.cpp:371
LuaInterface::rawGeti
void rawGeti(int n, int index=-1)
Definition: luainterface.cpp:983
LuaInterface::getEnv
void getEnv(int index=-1)
Definition: luainterface.cpp:909
LuaInterface::unref
void unref(int ref)
Definition: luainterface.cpp:801
LuaInterface::runBuffer
void runBuffer(const std::string &buffer, const std::string &source)
Definition: luainterface.cpp:321
LuaInterface::typeName
const char * typeName(int index=-1)
Definition: luainterface.cpp:807
LuaInterface::createLuaState
void createLuaState()
Definition: luainterface.cpp:679
LuaObject::getUseCount
int getUseCount()
Definition: luaobject.cpp:112
LuaInterface::getMetatable
void getMetatable(int index=-1)
Definition: luainterface.cpp:889
LuaInterface::pushCString
void pushCString(const char *v)
Definition: luainterface.cpp:1101
LuaInterface::pushObject
void pushObject(const LuaObjectPtr &obj)
Definition: luainterface.cpp:1126
LuaCFunction
int(* LuaCFunction)(lua_State *L)
Definition: luainterface.h:29
LuaInterface::getGlobalField
void getGlobalField(const std::string &globalKey, const std::string &fieldKey)
Definition: luainterface.cpp:961
LuaInterface::setMetatable
void setMetatable(int index=-2)
Definition: luainterface.cpp:883
LuaInterface
Class that manages LUA stuff.
Definition: luainterface.h:32
LuaInterface::loadBuffer
void loadBuffer(const std::string &buffer, const std::string &source)
Definition: luainterface.cpp:745
LuaInterface::pushString
void pushString(const std::string &v)
Definition: luainterface.cpp:1108
LuaInterface::pushValue
void pushValue(int index=-1)
Definition: luainterface.cpp:1160
LuaInterface::popNumber
double popNumber()
Definition: luainterface.cpp:1032
LuaInterface::getCurrentSourcePath
std::string getCurrentSourcePath(int level=0)
Searches for the source of the current running function.
Definition: luainterface.cpp:410
LuaInterface::registerClassStaticFunction
void registerClassStaticFunction(const std::string &className, const std::string &functionName, const LuaCppFunction &function)
Definition: luainterface.cpp:151
LuaInterface::registerClass
void registerClass()
Definition: luainterface.h:66
LuaInterface::functionSourcePath
std::string functionSourcePath()
Definition: luainterface.cpp:814
LuaInterface::pushCppFunction
void pushCppFunction(const LuaCppFunction &func)
Definition: luainterface.cpp:1144
ResourceManager::readFileContents
std::string readFileContents(const std::string &fileName)
Definition: resourcemanager.cpp:185
LuaInterface::toCString
const char * toCString(int index=-1)
Definition: luainterface.cpp:1233
LuaInterface::terminate
void terminate()
Definition: luainterface.cpp:72
stdext::exception::what
virtual const char * what() const
Definition: exception.h:37
LuaInterface::signalCall
int signalCall(int numArgs=0, int numRets=-1)
Definition: luainterface.cpp:476
LuaInterface::isTable
bool isTable(int index=-1)
Definition: luainterface.cpp:1191
LuaInterface::loadFiles
void loadFiles(std::string directory, bool recursive=false, std::string contains="")
Definition: luainterface.cpp:1272
LuaInterface::pop
void pop(int n=1)
Definition: luainterface.cpp:1016
stdext::shared_object_ptr
Definition: shared_object.h:39
LuaInterface::setField
void setField(const char *key, int index=-2)
Definition: luainterface.cpp:902
LuaInterface::isUserdata
bool isUserdata(int index=-1)
Definition: luainterface.cpp:1209
LuaInterface::registerGlobalFunction
void registerGlobalFunction(const std::string &functionName, const LuaCppFunction &function)
Definition: luainterface.cpp:188
LuaInterface::pushThread
void pushThread()
Definition: luainterface.cpp:1120
LuaInterface::runScript
void runScript(const std::string &fileName)
Definition: luainterface.cpp:315
LuaInterface::pcall
int pcall(int numArgs=0, int numRets=0, int errorFuncIndex=0)
Definition: luainterface.cpp:753
LuaInterface::getGlobalEnvironment
int getGlobalEnvironment()
Definition: luainterface.h:248
LuaInterface::isInCppCallback
bool isInCppCallback()
Definition: luainterface.h:200
LuaInterface::setTable
void setTable(int index=-3)
Definition: luainterface.cpp:927
LuaInterface::popBoolean
bool popBoolean()
Definition: luainterface.cpp:1040
LuaInterface::getWeakRef
void getWeakRef(int weakRef)
Definition: luainterface.cpp:866
LuaCppFunctionPtr
std::unique_ptr< LuaCppFunction > LuaCppFunctionPtr
Definition: declarations.h:34
LuaInterface::pushCFunction
void pushCFunction(LuaCFunction func, int n=0)
Definition: luainterface.cpp:1138
LuaInterface::LuaInterface
LuaInterface()
Definition: luainterface.cpp:33
LuaInterface::loadFunction
void loadFunction(const std::string &buffer, const std::string &source="lua function buffer")
Definition: luainterface.cpp:341
LuaInterface::pushLightUserdata
void pushLightUserdata(void *p)
Definition: luainterface.cpp:1114
LuaInterface::pushInteger
void pushInteger(long v)
Definition: luainterface.cpp:1083
LuaInterface::error
void error()
Definition: luainterface.cpp:765
LuaInterface::collectGarbage
void collectGarbage()
Definition: luainterface.cpp:729
LuaInterface::toBoolean
bool toBoolean(int index=-1)
Definition: luainterface.cpp:1215
LuaInterface::getStackFunction
void getStackFunction(int level=0)
Definition: luainterface.cpp:852
LuaInterface::pushNil
void pushNil()
Definition: luainterface.cpp:1077
LuaInterface::getRef
void getRef(int ref)
Definition: luainterface.cpp:861
LuaInterface::remove
void remove(int index)
Definition: luainterface.cpp:840
LuaInterface::isBoolean
bool isBoolean(int index=-1)
Definition: luainterface.cpp:1173
LuaInterface::rawSet
void rawSet(int index=-3)
Definition: luainterface.cpp:989
LuaInterface::toInteger
int toInteger(int index=-1)
Definition: luainterface.cpp:1221
LuaInterface::popUserdata
void * popUserdata()
Definition: luainterface.cpp:1056
LuaInterface::next
bool next(int index=-2)
Definition: luainterface.cpp:846
LuaInterface::~LuaInterface
~LuaInterface()
Definition: luainterface.cpp:42
LuaInterface::evaluateExpression
void evaluateExpression(const std::string &expression, const std::string &source="lua expression")
Definition: luainterface.cpp:365
LuaInterface::safeCall
int safeCall(int numArgs=0, int numRets=-1)
Calls a function The function and arguments must be on top of the stack in order, results are pushed ...
Definition: luainterface.cpp:439
LuaInterface::pushBoolean
void pushBoolean(bool v)
Definition: luainterface.cpp:1095
LuaInterface::registerClassMemberField
void registerClassMemberField(const std::string &className, const std::string &field, const LuaCppFunction &getFunction, const LuaCppFunction &setFunction)
Definition: luainterface.cpp:168
LuaInterface::rawGet
void rawGet(int index=-1)
Definition: luainterface.cpp:977
ResourceManager::guessFilePath
std::string guessFilePath(const std::string &filename, const std::string &type)
Definition: resourcemanager.cpp:353
LuaInterface::toNumber
double toNumber(int index=-1)
Definition: luainterface.cpp:1227
LuaInterface::newTable
void newTable()
Definition: luainterface.cpp:1001
stdext::exception
Definition: exception.h:31