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