]> git.r.bdr.sh - rbdr/pico-engine/blame - LuaScript.cpp
first commit
[rbdr/pico-engine] / LuaScript.cpp
CommitLineData
10a0e290
BB
1// ---------------------------------------------------------------------------\r
2// FILE NAME : LuaScript.cpp\r
3// ---------------------------------------------------------------------------\r
4// DESCRIPTION :\r
5//\r
6// Simple debugging routines\r
7// \r
8// ---------------------------------------------------------------------------\r
9// VERSION : 1.00\r
10// DATE : 1-Sep-2005\r
11// AUTHOR : Richard Shephard\r
12// ---------------------------------------------------------------------------\r
13// LIBRARY INCLUDE FILES\r
14#include <assert.h>\r
15#include "luainc.h"\r
16#include "luascript.h"\r
17#include "luarestorestack.h"\r
18#include "luathis.h"\r
19// ---------------------------------------------------------------------------\r
20\r
21#define BEGIN_LUA_CHECK(vm) lua_State *state = (lua_State *) vm; \\r
22 if (vm.Ok ()) { \r
23#define END_LUA_CHECK }\r
24\r
25\r
26//============================================================================\r
27// int LuaCallback\r
28//---------------------------------------------------------------------------\r
29// Lua C-API calling that figures out which object to hand over to\r
30//\r
31// Parameter Dir Description\r
32// --------- --- -----------\r
33// lua IN State variable\r
34//\r
35// Return\r
36// ------\r
37// Number of return varaibles on the stack\r
38//\r
39// Comments\r
40// --------\r
41// This is the function lua calls for each C-Function that is\r
42// registered with lua. At the time of registering the function\r
43// with lua, we make lua record the method "number" so we can\r
44// know what method was actually called. The lua stack is the\r
45// following structure:\r
46// 0: 'this' (table)\r
47// 1 - ...: parameters passed in\r
48//\r
49//============================================================================\r
50static int LuaCallback (lua_State *lua)\r
51{\r
52 // Locate the psudo-index for the function number\r
53 int iNumberIdx = lua_upvalueindex (1);\r
54 int nRetsOnStack = 0;\r
55\r
56 bool fSuccess = false;\r
57\r
58 // Check for the "this" table\r
59 if (lua_istable (lua, 1))\r
60 {\r
61 // Found the "this" table. The object pointer is at the index 0\r
62 lua_rawgeti (lua, 1, 0);\r
63 \r
64 if (lua_islightuserdata (lua, -1))\r
65 {\r
66 // Found the pointer, need to cast it\r
67 CLuaScript *pThis = (CLuaScript *) lua_touserdata (lua, -1);\r
68\r
69 // Get the method index\r
70 int iMethodIdx = (int) lua_tonumber (lua, iNumberIdx);\r
71\r
72 // Check that the method is correct index\r
73 assert (!(iMethodIdx > pThis->methods ()));\r
74\r
75 // Reformat the stack so our parameters are correct\r
76 // Clean up the "this" table\r
77 lua_remove (lua, 1);\r
78 // Clean up the pThis pointer\r
79 lua_remove (lua, -1);\r
80\r
81 // Call the class\r
82 nRetsOnStack = pThis->ScriptCalling (pThis->vm (), iMethodIdx);\r
83\r
84 fSuccess = true;\r
85 }\r
86 }\r
87\r
88 if (fSuccess == false)\r
89 {\r
90 lua_pushstring (lua, "LuaCallback -> Failed to call the class function");\r
91 lua_error (lua);\r
92 }\r
93\r
94 // Number of return variables\r
95 return nRetsOnStack;\r
96}\r
97\r
98\r
99//============================================================================\r
100// CLuaScript::CLuaScript\r
101//---------------------------------------------------------------------------\r
102// Constructor. Sets up the lua stack and the "this" table\r
103//\r
104// Parameter Dir Description\r
105// --------- --- -----------\r
106// CLuaVirtualMachine IN VM to run on\r
107//\r
108// Return\r
109// ------\r
110// None.\r
111//\r
112//============================================================================\r
113CLuaScript::CLuaScript (CLuaVirtualMachine& vm)\r
114 : m_vm (vm), m_nMethods (0), m_iThisRef (0), m_nArgs (0)\r
115{\r
116 BEGIN_LUA_CHECK (vm)\r
117 // Create a reference to the "this" table. Each reference is unique\r
118 lua_newtable (state);\r
119 m_iThisRef = luaL_ref (state, LUA_REGISTRYINDEX);\r
120\r
121 // Save the "this" table to index 0 of the "this" table\r
122 CLuaRestoreStack rs (vm);\r
123 lua_rawgeti (state, LUA_REGISTRYINDEX, m_iThisRef);\r
124 lua_pushlightuserdata (state, (void *) this);\r
125 lua_rawseti (state, -2, 0);\r
126 END_LUA_CHECK\r
127}\r
128\r
129//============================================================================\r
130// CLuaScript::~CLuaScript\r
131//---------------------------------------------------------------------------\r
132// Destructor\r
133//\r
134// Parameter Dir Description\r
135// --------- --- -----------\r
136// None.\r
137//\r
138// Return\r
139// ------\r
140// None.\r
141//\r
142//============================================================================\r
143CLuaScript::~CLuaScript (void)\r
144{\r
145 CLuaRestoreStack rs (m_vm);\r
146\r
147 BEGIN_LUA_CHECK (m_vm)\r
148 // Get the reference "this" table\r
149 lua_rawgeti (state, LUA_REGISTRYINDEX, m_iThisRef);\r
150\r
151 // Clear index 0\r
152 lua_pushnil (state);\r
153 lua_rawseti (state, -2, 0);\r
154 END_LUA_CHECK\r
155 \r
156}\r
157\r
158//============================================================================\r
159// bool CLuaScript::CompileBuffer\r
160//---------------------------------------------------------------------------\r
161// Compiles a given buffer\r
162//\r
163// Parameter Dir Description\r
164// --------- --- -----------\r
165// pbBuffer IN Data buffer\r
166// szLen IN Length of buffer\r
167//\r
168// Return\r
169// ------\r
170// Success\r
171//\r
172//============================================================================\r
173bool CLuaScript::CompileBuffer (unsigned char *pbBuffer, size_t szLen)\r
174{\r
175 assert (pbBuffer != NULL && "CLuaScript::CompileBuffer -> pbBuffer == NULL");\r
176 assert (szLen != 0 && "CLuaScript::CompileBuffer -> szLen == 0");\r
177 assert (m_vm.Ok () && "VM Not OK");\r
178\r
179 // Make sure we have the correct "this" table\r
180 CLuaThis luaThis (m_vm, m_iThisRef);\r
181\r
182 return m_vm.RunBuffer (pbBuffer, szLen);\r
183}\r
184\r
185//============================================================================\r
186// bool CLuaScript::CompileBuffer\r
187//---------------------------------------------------------------------------\r
188// Compiles a given file\r
189//\r
190// Parameter Dir Description\r
191// --------- --- -----------\r
192// strFilename IN File name to compile\r
193//\r
194// Return\r
195// ------\r
196// Success\r
197//\r
198//============================================================================\r
199bool CLuaScript::CompileFile (const char *strFilename)\r
200{\r
201 assert (strFilename != NULL && "CLuaScript::CompileFile -> strFilename == NULL");\r
202 assert (m_vm.Ok () && "VM Not OK");\r
203\r
204 // Make sure we have the correct "this" table\r
205 CLuaThis luaThis (m_vm, m_iThisRef);\r
206\r
207 return m_vm.RunFile (strFilename);\r
208}\r
209\r
210//============================================================================\r
211// int CLuaScript::RegisterFunction\r
212//---------------------------------------------------------------------------\r
213// Registers a function with Lua\r
214//\r
215// Parameter Dir Description\r
216// --------- --- -----------\r
217// strFuncName IN Function name\r
218//\r
219// Return\r
220// ------\r
221// Success\r
222//\r
223//============================================================================\r
224int CLuaScript::RegisterFunction (const char *strFuncName)\r
225{\r
226 assert (strFuncName != NULL && "CLuaScript::RegisterFunction -> strFuncName == NULL");\r
227 assert (m_vm.Ok () && "VM Not OK");\r
228\r
229 int iMethodIdx = -1;\r
230\r
231 CLuaRestoreStack rs (m_vm);\r
232\r
233 BEGIN_LUA_CHECK (m_vm)\r
234 iMethodIdx = ++m_nMethods;\r
235\r
236 // Register a function with the lua script. Added it to the "this" table\r
237 lua_rawgeti (state, LUA_REGISTRYINDEX, m_iThisRef);\r
238\r
239 // Push the function and parameters\r
240 lua_pushstring (state, strFuncName);\r
241 lua_pushnumber (state, (lua_Number) iMethodIdx);\r
242 lua_pushcclosure (state, LuaCallback, 1);\r
243 lua_settable (state, -3);\r
244\r
245 END_LUA_CHECK\r
246\r
247 return iMethodIdx;\r
248}\r
249\r
250//============================================================================\r
251// bool CLuaScript::SelectScriptFunction\r
252//---------------------------------------------------------------------------\r
253// Selects a script function to run\r
254//\r
255// Parameter Dir Description\r
256// --------- --- -----------\r
257// strFuncName IN Function name\r
258//\r
259// Return\r
260// ------\r
261// Success\r
262//\r
263//============================================================================\r
264bool CLuaScript::SelectScriptFunction (const char *strFuncName)\r
265{\r
266 assert (strFuncName != NULL && "CLuaScript::SelectScriptFunction -> strFuncName == NULL");\r
267 assert (m_vm.Ok () && "VM Not OK");\r
268\r
269 bool fSuccess = true;\r
270\r
271 BEGIN_LUA_CHECK (m_vm)\r
272 // Look up function name\r
273 lua_rawgeti (state, LUA_REGISTRYINDEX, m_iThisRef);\r
274 lua_pushstring (state, strFuncName);\r
275 lua_rawget (state, -2);\r
276 lua_remove (state, -2);\r
277\r
278 // Put the "this" table back\r
279 lua_rawgeti (state, LUA_REGISTRYINDEX, m_iThisRef);\r
280\r
281 // Check that we have a valid function\r
282 if (!lua_isfunction (state, -2))\r
283 {\r
284 fSuccess = false;\r
285 lua_pop (state, 2);\r
286 }\r
287 else\r
288 {\r
289 m_nArgs = 0;\r
290 m_strFunctionName = strFuncName;\r
291 }\r
292 END_LUA_CHECK\r
293 \r
294 return fSuccess;\r
295}\r
296\r
297//============================================================================\r
298// bool CLuaScript::ScriptHasFunction\r
299//---------------------------------------------------------------------------\r
300// Checks to see if a function exists\r
301//\r
302// Parameter Dir Description\r
303// --------- --- -----------\r
304// strScriptName IN Function name\r
305//\r
306// Return\r
307// ------\r
308// Success\r
309//\r
310//============================================================================\r
311bool CLuaScript::ScriptHasFunction (const char *strScriptName)\r
312{\r
313 assert (strScriptName != NULL && "CLuaScript::ScriptHasFunction -> strScriptName == NULL");\r
314 assert (m_vm.Ok () && "VM Not OK");\r
315\r
316 CLuaRestoreStack rs (m_vm);\r
317\r
318 bool fFoundFunc = false;\r
319\r
320 BEGIN_LUA_CHECK (m_vm)\r
321 lua_rawgeti (state, LUA_REGISTRYINDEX, m_iThisRef);\r
322 lua_pushstring (state, strScriptName);\r
323 lua_rawget (state, -2);\r
324 lua_remove (state, -2);\r
325\r
326 if (lua_isfunction (state, -1))\r
327 {\r
328 fFoundFunc = true;\r
329 }\r
330 END_LUA_CHECK\r
331\r
332 return fFoundFunc;\r
333}\r
334\r
335//============================================================================\r
336// void CLuaScript::AddParam\r
337//---------------------------------------------------------------------------\r
338// Adds a parameter to the parameter list\r
339//\r
340// Parameter Dir Description\r
341// --------- --- -----------\r
342// string IN string param\r
343//\r
344// Return\r
345// ------\r
346// None.\r
347//\r
348//============================================================================\r
349void CLuaScript::AddParam (char *string)\r
350{\r
351 assert (string != NULL && "CLuaScript::AddParam -> string == NULL");\r
352 assert (m_vm.Ok () && "VM Not OK");\r
353\r
354 BEGIN_LUA_CHECK (m_vm)\r
355 lua_pushstring (state, string);\r
356 ++m_nArgs;\r
357 END_LUA_CHECK\r
358}\r
359\r
360//============================================================================\r
361// void CLuaScript::AddParam\r
362//---------------------------------------------------------------------------\r
363// Adds a parameter to the parameter list\r
364//\r
365// Parameter Dir Description\r
366// --------- --- -----------\r
367// iInt IN int param\r
368//\r
369// Return\r
370// ------\r
371// None.\r
372//\r
373//============================================================================\r
374void CLuaScript::AddParam (int iInt)\r
375{\r
376 assert (m_vm.Ok () && "VM Not OK");\r
377\r
378 BEGIN_LUA_CHECK (m_vm)\r
379 lua_pushnumber (state, (lua_Number) iInt);\r
380 ++m_nArgs;\r
381 END_LUA_CHECK\r
382}\r
383\r
384//============================================================================\r
385// void CLuaScript::AddParam\r
386//---------------------------------------------------------------------------\r
387// Adds a parameter to the parameter list\r
388//\r
389// Parameter Dir Description\r
390// --------- --- -----------\r
391// fFloat IN float param\r
392//\r
393// Return\r
394// ------\r
395// None.\r
396//\r
397//============================================================================\r
398void CLuaScript::AddParam (float fFloat)\r
399{\r
400 assert (m_vm.Ok () && "VM Not OK");\r
401\r
402 BEGIN_LUA_CHECK (m_vm)\r
403 lua_pushnumber (state, (lua_Number) fFloat);\r
404 ++m_nArgs;\r
405 END_LUA_CHECK\r
406}\r
407\r
408//============================================================================\r
409// bool CLuaScript::Go\r
410//---------------------------------------------------------------------------\r
411// Runs the selected script function\r
412//\r
413// Parameter Dir Description\r
414// --------- --- -----------\r
415// nReturns IN Number of expected returns\r
416//\r
417// Return\r
418// ------\r
419// None.\r
420//\r
421//============================================================================\r
422bool CLuaScript::Go (int nReturns /* = 0 */)\r
423{\r
424 assert (m_vm.Ok () && "VM Not OK");\r
425\r
426 // At this point there should be a parameters and a function on the\r
427 // Lua stack. Each function get a "this" parameter as default and is\r
428 // pushed onto the stack when the method is selected\r
429\r
430 bool fSuccess = m_vm.CallFunction (m_nArgs + 1, nReturns);\r
431\r
432 if (fSuccess == true && nReturns > 0)\r
433 {\r
434 // Check for returns\r
435 HandleReturns (m_vm, m_strFunctionName);\r
436 lua_pop ((lua_State *) m_vm, nReturns);\r
437 }\r
438\r
439 return fSuccess;\r
440}