xoreos  0.0.5
scriptman.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #include "lua/lualib.h"
26 
27 #include "toluapp/tolua++.h"
28 
29 #include "src/common/error.h"
30 #include "src/common/util.h"
31 #include "src/common/scopedptr.h"
32 
33 #include "src/aurora/resman.h"
34 #include "src/aurora/util.h"
35 
37 #include "src/aurora/lua/stack.h"
40 #include "src/aurora/lua/table.h"
42 
44 
45 namespace Aurora {
46 
47 namespace Lua {
48 
49 ScriptManager::ScriptManager() : _luaState(0), _regNestingLevel(0) {
50 
51 }
52 
54  try {
55  deinit();
56  } catch (...) {
57  }
58 }
59 
61  assert(!ready());
62 
63  openLuaState();
66 }
67 
69  if (!_objectLuaInstances.empty()) {
70  warning("Lua instances were not freed properly");
71 
72  _objectLuaInstances.clear();
73  }
74 
75  closeLuaState();
76 }
77 
78 bool ScriptManager::ready() const {
79  return _luaState != 0;
80 }
81 
83  assert(_luaState && _regNestingLevel == 0);
84 
85  if (isIgnoredFile(path)) {
86  return;
87  }
88 
90  if (!stream) {
91  const Common::UString fileName = TypeMan.setFileType(path, kFileTypeLUC);
92  throw Common::Exception("No such LUC \"%s\"", fileName.c_str());
93  }
94 
95  Common::ScopedPtr<Common::MemoryReadStream> memStream(stream->readStream(stream->size()));
96  const char *data = reinterpret_cast<const char *>(memStream->getData());
97  const int dataSize = memStream->size();
98 
99  const int execResult = lua_dobuffer(_luaState, data, dataSize, path.c_str());
100  if (execResult != 0) {
101  const Common::UString fileName = TypeMan.setFileType(path, kFileTypeLUC);
102  throw Common::Exception("Failed to execute Lua file: %s", fileName.c_str());
103  }
104 }
105 
107  assert(_luaState && _regNestingLevel == 0);
108 
109  const int execResult = lua_dostring(_luaState, code.c_str());
110  if (execResult != 0) {
111  throw Common::Exception("Failed to execute Lua code: %s", code.c_str());
112  }
113 }
114 
116  assert(!name.empty());
117  assert(_luaState && _regNestingLevel == 0);
118 
119  std::vector<Common::UString> parts;
120  Common::UString::split(name, '.', parts);
121  if (parts.empty()) {
122  error("Lua call \"%s\" failed: bad name", name.c_str());
123  return Variables();
124  }
125 
126  const Common::UString funcName = parts.back();
127  parts.pop_back();
128 
129  if (parts.empty()) {
130  return getGlobalFunction(funcName).call(params);
131  }
132 
133  TableRef table = getGlobalTable(parts[0]);
134  for (uint32 i = 1; i < parts.size(); ++i) {
135  table = table.getTableAt(parts[i]);
136  }
137  return table.getFunctionAt(funcName).call(params);
138 }
139 
141  return callFunction(name, Variables());
142 }
143 
145  StackGuard guard(*_luaState);
146 
147  lua_getglobal(_luaState, name.c_str());
148 
149  Stack stack(*_luaState);
150  return stack.getVariableAt(-1);
151 }
152 
154  return getGlobalVariable(name).getTable();
155 }
156 
158  return getGlobalVariable(name).getFunction();
159 }
160 
162  _ignoredFiles.insert(path);
163 }
164 
166  _ignoredFiles.erase(path);
167 }
168 
170  return _ignoredFiles.find(path) != _ignoredFiles.end();
171 }
172 
174  assert(!name.empty());
175  assert(_luaState && _regNestingLevel == 0);
176 
177  tolua_usertype(_luaState, name.c_str());
178 }
179 
181  assert(_luaState && _regNestingLevel == 0);
182 
184 
185  tolua_module(_luaState, 0, 1);
186  tolua_beginmodule(_luaState, 0);
187 }
188 
190  assert(_luaState && _regNestingLevel == 1);
191 
193 
194  tolua_endmodule(_luaState);
195 }
196 
198  assert(!name.empty());
199  assert(_luaState && _regNestingLevel > 0);
200 
202 
203  tolua_module(_luaState, name.c_str(), 1);
204  tolua_beginmodule(_luaState, name.c_str());
205 }
206 
208  assert(_luaState && _regNestingLevel > 1);
209 
211 
212  tolua_endmodule(_luaState);
213 }
214 
216  lua_CFunction deleter) {
217 
218  assert(!name.empty());
219  assert(_luaState && _regNestingLevel > 0);
220 
222 
223  requireDeclaredClass(name);
224  requireDeclaredClass(baseName);
225 
226  tolua_cclass(_luaState, name.c_str(), name.c_str(), baseName.c_str(), deleter);
227  tolua_beginmodule(_luaState, name.c_str());
228 }
229 
231  assert(_luaState && _regNestingLevel > 1);
232 
234 
235  tolua_endmodule(_luaState);
236 }
237 
238 void ScriptManager::registerConstant(const Common::UString &name, float value) {
239  assert(!name.empty());
240  assert(_luaState &&_regNestingLevel > 0);
241 
242  tolua_constant(_luaState, name.c_str(), value);
243 }
244 
245 void ScriptManager::registerVariable(const Common::UString &name, lua_CFunction getter, lua_CFunction setter) {
246  assert(!name.empty() && getter);
247  assert(_luaState && _regNestingLevel > 0);
248 
249  tolua_variable(_luaState, name.c_str(), getter, setter);
250 }
251 
252 void ScriptManager::registerFunction(const Common::UString &name, lua_CFunction func) {
253  assert(!name.empty() && func);
254  assert(_luaState && _regNestingLevel > 0);
255 
256  tolua_function(_luaState, name.c_str(), func);
257 }
258 
260  return lua_getgccount(_luaState);
261 }
262 
263 void ScriptManager::setLuaInstanceForObject(void *object, const TableRef &luaInstance) {
264  assert(object);
265  // TODO: Commented out to make stubs work
266  // assert(_objectLuaInstances.find(object) == _objectLuaInstances.end());
267 
268  _objectLuaInstances[object] = luaInstance;
269 }
270 
272  assert(object);
273 
274  _objectLuaInstances.erase(object);
275 }
276 
278  assert(object);
279 
280  static const TableRef invalidInstance;
281 
282  ObjectLuaInstanceMap::const_iterator found = _objectLuaInstances.find(object);
283  if (found == _objectLuaInstances.end())
284  {
285  return invalidInstance;
286  }
287  return found->second;
288 }
289 
291  const FunctionRef fn = getGlobalFunction("mt_new_index");
292  TableRef metaTable = table.getMetaTable();
293  metaTable.setFunctionAt("__newindex", fn);
294 }
295 
297  _luaState = lua_open();
298  if (!_luaState) {
299  throw Common::Exception("Failed to open Lua state");
300  }
301 
302  luaopen_base(_luaState);
303  luaopen_io(_luaState);
304  luaopen_math(_luaState);
305  luaopen_string(_luaState);
306  luaopen_table(_luaState);
307  luaopen_loadlib(_luaState);
308  luaopen_debug(_luaState);
309 
310  tolua_open(_luaState);
311 
312  lua_atpanic(_luaState, &ScriptManager::atPanic);
313 }
314 
316  if (_luaState) {
317  lua_close(_luaState);
318  _luaState = 0;
319  }
320  _regNestingLevel = 0;
321 }
322 
324  assert(_luaState);
325 
326  if (name.empty()) {
327  return;
328  }
329 
330  luaL_getmetatable(_luaState, name.c_str());
331  if (lua_isnil(_luaState, -1)) {
332  lua_pop(_luaState, 1);
333  throw Common::Exception("Class \"%s\" wasn't declared for Lua", name.c_str());
334  }
335  lua_pop(_luaState, 1);
336 }
337 
339  declareClass("ScriptManager");
340 
341  beginRegister();
342 
344 
345  beginRegisterClass("ScriptManager");
352 
353  endRegister();
354 }
355 
357  static const Common::UString fnNewIndexSource =
358  "function mt_new_index(table, key, value)"
359  " local objClass = getmetatable(table).__objectClass"
360  " if objClass ~= nil then"
361  " local cppInstance = rawget(table, \"CPP_instance\")"
362  " if cppInstance[key] ~= nil then"
363  " cppInstance[key] = value"
364  " end"
365  " return"
366  " end"
367  " rawset(table, key, value)"
368  "end";
369 
370  executeString(fnNewIndexSource);
371 }
372 
373 int ScriptManager::atPanic(lua_State *state) {
374  const char *message = luaL_checkstring(state, -1);
375  error("Lua has panicked: %s", message);
376  lua_pop(state, 1);
377  return 0;
378 }
379 
380 int ScriptManager::luaGetLua(lua_State *state) {
381  assert(state);
382 
383  Stack stack(*state);
384  stack.pushUserType<ScriptManager>(LuaScriptMan, "ScriptManager");
385  return 1;
386 }
387 
388 int ScriptManager::luaPlayFile(lua_State *state) {
389  assert(state);
390 
391  Stack stack(*state);
392  assert(stack.getSize() > 1);
393 
394  const Common::UString scriptFile = stack.getStringAt(2);
395  LuaScriptMan.executeFile(scriptFile);
396  return 0;
397 }
398 
399 int ScriptManager::luaSetGCInterval(lua_State *UNUSED(state)) {
400  // TODO
401  return 0;
402 }
403 
404 int ScriptManager::luaRegisterSubst(lua_State *state) {
405  assert(state);
406 
407  Aurora::Lua::Stack stack(*state);
408  assert(stack.getSize() == 3);
409 
410  ScriptManager* scriptMan = stack.getUserTypeAt<ScriptManager>(1);
411  assert(scriptMan == &LuaScriptMan);
412  void* object = stack.getRawUserTypeAt(2);
413  assert(object);
414  const TableRef instance = stack.getTableAt(3);
415 
416  scriptMan->setLuaInstanceForObject(object, instance);
417  return 0;
418 }
419 
420 int ScriptManager::luaUnregisterSubst(lua_State *state) {
421  assert(state);
422 
423  Aurora::Lua::Stack stack(*state);
424  assert(stack.getSize() == 2);
425 
426  ScriptManager* scriptMan = stack.getUserTypeAt<ScriptManager>(1);
427  assert(scriptMan == &LuaScriptMan);
428  void* object = stack.getRawUserTypeAt(2);
429  assert(object);
430 
431  scriptMan->unsetLuaInstanceForObject(object);
432  return 0;
433 }
434 
435 int ScriptManager::luaRegisterHandler(lua_State *state) {
436  assert(state);
437 
438  Aurora::Lua::Stack stack(*state);
439  assert(stack.getTypeAt(1) == Aurora::Lua::kTypeUserType);
440  assert(stack.getTypeAt(2) == Aurora::Lua::kTypeUserType);
441  assert(stack.getTypeAt(3) == Aurora::Lua::kTypeString);
442 
443  // TODO
444  return 0;
445 }
446 
447 } // End of namespace Lua
448 
449 } // End of namespace Aurora
450 
#define ResMan
Shortcut for accessing the sound manager.
Definition: resman.h:557
TableRef getGlobalTable(const Common::UString &name) const
Definition: scriptman.cpp:153
static int luaSetGCInterval(lua_State *state)
Definition: scriptman.cpp:399
void beginRegisterClass(const Common::UString &name, const Common::UString &baseName="", lua_CFunction deleter=0)
Begin registration of a class.
Definition: scriptman.cpp:215
#define TypeMan
Shortcut for accessing the file type manager.
Definition: util.h:85
TableRef getTableAt(int index) const
Return a table at the given index in the stack.
Definition: stack.cpp:162
static int luaPlayFile(lua_State *state)
Definition: scriptman.cpp:388
A class holding an UTF-8 string.
Definition: ustring.h:48
const TableRef & getLuaInstanceForObject(void *object) const
Definition: scriptman.cpp:277
void unsetLuaInstanceForObject(void *object)
Definition: scriptman.cpp:271
Common::UString getStringAt(int index) const
Return a string at the given index in the stack.
Definition: stack.cpp:155
Variables call(const Variables &params) const
Definition: function.cpp:85
TableRef getTableAt(int index) const
Definition: table.cpp:312
void closeLuaState()
Close the current Lua state.
Definition: scriptman.cpp:315
A reference to a Lua function.
T * getUserTypeAt(int index, const Common::UString &type="") const
Return a usertype value at the given index in the stack.
Definition: stack.h:143
void endRegisterNamespace()
End registration of the current namespace.
Definition: scriptman.cpp:207
const FunctionRef & getFunction() const
Definition: variable.cpp:343
TableRef & getTable()
Definition: variable.cpp:327
int getSize() const
Return the number of elements in the stack.
Definition: stack.cpp:48
void removeIgnoredFile(const Common::UString &path)
Remove a file from the ignore list.
Definition: scriptman.cpp:165
static int atPanic(lua_State *state)
Handler of the Lua panic situations.
Definition: scriptman.cpp:373
Utility functions to handle files used in BioWare&#39;s Aurora engine.
Lua stack guard.
Script, LUA bytecode.
Definition: types.h:167
static int luaRegisterSubst(lua_State *state)
Definition: scriptman.cpp:404
void pushUserType(T &value, const Common::UString &type)
Push a usertype value onto the stack.
Definition: stack.h:138
void declareClass(const Common::UString &name)
Declare a class with the given name.
Definition: scriptman.cpp:173
A simple scoped smart pointer template.
void registerConstant(const Common::UString &name, float value)
Register a constant.
Definition: scriptman.cpp:238
FunctionRef getFunctionAt(int index) const
Definition: table.cpp:328
static int luaRegisterHandler(lua_State *state)
Definition: scriptman.cpp:435
Basic exceptions to throw.
void addIgnoredFile(const Common::UString &path)
Add a file to the ignore list.
Definition: scriptman.cpp:161
const byte * getData() const
static int luaGetLua(lua_State *state)
Lua bindings.
Definition: scriptman.cpp:380
const char * c_str() const
Return the (utf8 encoded) string data.
Definition: ustring.cpp:249
TableRef getMetaTable() const
Definition: table.cpp:116
void executeString(const Common::UString &code)
Execute a script string.
Definition: scriptman.cpp:106
Lua script manager.
Definition: scriptman.h:43
void endRegister()
End registration of the entities.
Definition: scriptman.cpp:189
#define UNUSED(x)
Definition: system.h:170
Utility templates and functions.
#define DECLARE_SINGLETON(T)
Note that you need to use this macro from the global namespace.
Definition: singleton.h:122
void registerVariable(const Common::UString &name, lua_CFunction getter, lua_CFunction setter=0)
Register a variable.
Definition: scriptman.cpp:245
void * getRawUserTypeAt(int index, const Common::UString &type="") const
Return a raw usertype value at the given index in the stack.
Definition: stack.cpp:176
Type getTypeAt(int index) const
Definition: stack.cpp:218
void endRegisterClass()
End registration of the current class.
Definition: scriptman.cpp:230
static int luaUnregisterSubst(lua_State *state)
Definition: scriptman.cpp:420
bool empty() const
Is the string empty?
Definition: ustring.cpp:245
void beginRegisterNamespace(const Common::UString &name)
Begin registration of a namespace.
Definition: scriptman.cpp:197
StackException Exception
Definition: error.h:59
Lua stack guard.
Definition: stackguard.h:37
A Lua stack wrapper.
Definition: stack.h:41
std::vector< Variable > Variables
Definition: types.h:50
ObjectLuaInstanceMap _objectLuaInstances
Definition: scriptman.h:125
void warning(const char *s,...)
Definition: util.cpp:33
void setFunctionAt(int index, const FunctionRef &value)
Definition: table.cpp:206
A reference to a Lua function.
Definition: function.h:35
void init()
Initialize the script subsystem.
Definition: scriptman.cpp:60
static ScriptManager & instance()
Definition: singleton.h:91
bool isIgnoredFile(const Common::UString &path) const
Is this file in the ignore list?
Definition: scriptman.cpp:169
Variable getGlobalVariable(const Common::UString &name) const
Definition: scriptman.cpp:144
void executeFile(const Common::UString &path)
Execute a script file.
Definition: scriptman.cpp:82
int _regNestingLevel
The current nesting level of the registration process.
Definition: scriptman.h:121
void deinit()
Deinitialize the script subsystem.
Definition: scriptman.cpp:68
void requireDeclaredClass(const Common::UString &name) const
Check whether a class with the given name was declared.
Definition: scriptman.cpp:323
void injectNewIndexMetaEventIntoTable(const TableRef &table)
Definition: scriptman.cpp:290
uint32_t uint32
Definition: types.h:204
void beginRegister()
Begin registration of the entities.
Definition: scriptman.cpp:180
lua_State * _luaState
The Lua state.
Definition: scriptman.h:119
Lua script manager.
std::set< Common::UString > _ignoredFiles
A list of files that the script subsystem ignores.
Definition: scriptman.h:123
bool ready() const
Was the script subsystem successfully initialized?
Definition: scriptman.cpp:78
A reference to a Lua table.
Definition: table.h:37
A reference to a Lua table.
size_t size() const
Obtains the total size of the stream, measured in bytes.
void split(iterator splitPoint, UString &left, UString &right, bool remove=false) const
Definition: ustring.cpp:621
#define LuaScriptMan
Shortcut for accessing the script engine.
Definition: scriptman.h:157
FunctionRef getGlobalFunction(const Common::UString &name) const
Definition: scriptman.cpp:157
Lua variable.
void NORETURN_PRE error(const char *s,...)
Definition: util.cpp:86
int getUsedMemoryAmount() const
Return the amount of memory in use by Lua (in Kbytes).
Definition: scriptman.cpp:259
Variables callFunction(const Common::UString &name, const Variables &params)
Call a Lua function.
Definition: scriptman.cpp:115
A Lua stack wrapper.
void registerFunction(const Common::UString &name, lua_CFunction func)
Register a function.
Definition: scriptman.cpp:252
The global resource manager for Aurora resources.
void setLuaInstanceForObject(void *object, const TableRef &luaInstance)
Definition: scriptman.cpp:263
void openLuaState()
Open and setup a new Lua state.
Definition: scriptman.cpp:296