Fix issue in Rocket.lua script.
[Cafu-Engine.git] / Libs / UniScriptState.cpp
blob76006d558039fe8bf7111a765ead5b282df84578
1 /*
2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
5 */
7 #include "UniScriptState.hpp"
8 #include "TypeSys.hpp"
9 #include "ConsoleCommands/Console.hpp"
11 extern "C"
13 #include <lua.h>
14 #include <lualib.h>
15 #include <lauxlib.h>
18 #include <cassert>
19 #include <cstring>
22 using namespace cf;
25 unsigned int UniScriptStateT::CoroutineT::InstCount = 0;
28 ScriptBinderT::ScriptBinderT(lua_State* LuaState)
29 : m_LuaState(LuaState)
34 void ScriptBinderT::InitState()
36 // Add a table with name "__identity_to_object" to the registry:
37 // REGISTRY["__identity_to_object"] = {}
39 // This table will be used to keep track of the bound C++ objects,
40 // mapping C++ instance pointers (identities) to Lua tables/userdata.
41 // It is used to find previously created Lua objects again by C++ pointer.
42 lua_newtable(m_LuaState);
44 // Set the new table as metatable of itself, configured for weak values.
45 lua_pushstring(m_LuaState, "v");
46 lua_setfield(m_LuaState, -2, "__mode");
47 lua_pushvalue(m_LuaState, -1);
48 lua_setmetatable(m_LuaState, -2);
50 lua_setfield(m_LuaState, LUA_REGISTRYINDEX, "__identity_to_object");
53 // Add a table with name "__has_ref_in_cpp" to the registry:
54 // REGISTRY.__has_ref_in_cpp = {}
55 lua_newtable(m_LuaState);
56 lua_setfield(m_LuaState, LUA_REGISTRYINDEX, "__has_ref_in_cpp");
60 void ScriptBinderT::Anchor(int StackIndex)
62 const StackCheckerT StackChecker(m_LuaState);
64 StackIndex = abs_index(StackIndex);
66 // Is the object at StackIndex eligible for anchoring?
67 // (Is object:GetRefCount() >= 1 ?)
68 lua_getfield(m_LuaState, StackIndex, "GetRefCount");
70 if (!lua_isfunction(m_LuaState, -1))
72 lua_pop(m_LuaState, 1);
73 return;
76 lua_pushvalue(m_LuaState, StackIndex);
77 lua_call(m_LuaState, 1, 1);
78 const int RefCount = lua_tointeger(m_LuaState, -1);
79 lua_pop(m_LuaState, 1);
81 if (RefCount < 1)
83 assert(false);
84 return;
87 // Put the REGISTRY.__has_ref_in_cpp set onto the stack.
88 lua_getfield(m_LuaState, LUA_REGISTRYINDEX, "__has_ref_in_cpp");
90 // Insert the object: __has_ref_in_cpp[Object] = true
91 lua_pushvalue(m_LuaState, StackIndex);
92 lua_pushboolean(m_LuaState, 1);
93 lua_rawset(m_LuaState, -3);
95 // Remove the __has_ref_in_cpp table.
96 lua_pop(m_LuaState, 1);
100 void ScriptBinderT::CheckCppRefs()
102 const StackCheckerT StackChecker(m_LuaState);
104 // Put the REGISTRY.__has_ref_in_cpp set onto the stack.
105 lua_getfield(m_LuaState, LUA_REGISTRYINDEX, "__has_ref_in_cpp");
106 assert(lua_istable(m_LuaState, -1));
108 // The initial key for the traversal.
109 lua_pushnil(m_LuaState);
111 while (lua_next(m_LuaState, -2) != 0)
113 // The key is now at stack index -2, the value is at index -1.
114 // Remove the unneeded boolean value (true), so that the key is at index -1.
115 // The key is also needed at index -1 in order to seed the next iteration.
116 lua_pop(m_LuaState, 1);
118 // The key is the table that represents our object.
119 assert(lua_istable(m_LuaState, -1));
121 // Should the object at index -1 remain anchored?
122 lua_getfield(m_LuaState, -1, "GetRefCount");
124 if (lua_isfunction(m_LuaState, -1))
126 lua_pushvalue(m_LuaState, -2);
127 lua_call(m_LuaState, 1, 1);
128 const int RefCount = lua_tointeger(m_LuaState, -1);
129 lua_pop(m_LuaState, 1);
131 if (RefCount > 1)
133 // Keep this object anchored.
134 continue;
137 else
139 assert(lua_isnil(m_LuaState, -1));
141 // Pop whatever is not a function.
142 lua_pop(m_LuaState, 1);
145 // Remove the object: __has_ref_in_cpp[Object] = nil
146 lua_pushvalue(m_LuaState, -1);
147 lua_pushnil(m_LuaState);
148 lua_rawset(m_LuaState, -4);
150 // The key is kept for the next iteration.
153 // Remove the __has_ref_in_cpp table.
154 lua_pop(m_LuaState, 1);
158 void ScriptBinderT::Init(const cf::TypeSys::TypeInfoManT& TIM)
160 // For each class that the TIM knows about, add a (meta-)table to the registry of the Lua state.
161 // The (meta-)table holds the Lua methods that the respective class implements in C++,
162 // and is to be used as metatable for instances of this class.
163 for (unsigned long RootNr=0; RootNr<TIM.GetTypeInfoRoots().Size(); RootNr++)
165 for (const cf::TypeSys::TypeInfoT* TI=TIM.GetTypeInfoRoots()[RootNr]; TI!=NULL; TI=TI->GetNext())
167 assert(lua_gettop(m_LuaState)==0);
169 // Create a new table MT and add it into the registry table with TI->ClassName
170 // (e.g. "cf::GuiSys::WindowT" or "cf::GameSys::EntMoverT") as the key and MT as the value.
171 // This also leaves MT on top of the stack. See PiL2 chapter 28.2 for more details.
172 luaL_newmetatable(m_LuaState, TI->ClassName);
174 // Create a new table FT and register the functions in TI->MethodsList into it.
175 // See PiL2 chapter 28.3 for more details. We intentionally don't merge FT into MT though,
176 // or else Lua code could call the __gc method! See thread "__gc visible to Lua code" at
177 // http://lua-users.org/lists/lua-l/2007-03/threads.html#00872 for more details.
178 lua_newtable(m_LuaState);
180 if (TI->MethodsList != NULL)
181 luaL_setfuncs(m_LuaState, TI->MethodsList, 0);
183 // If TI has a base class, model that relationship for FT, too, by setting the metatable of
184 // the base class as the metatable for FT. Note that this works because the for-loop (over TI)
185 // enumerates the base classes always before their child classes!
186 if (TI->Base)
188 assert(strcmp(TI->BaseClassName, TI->Base->ClassName) == 0);
190 // Get the metatable MT' with name TI->Base->ClassName (e.g. "cf::GameSys::BaseEntityT")
191 // from the registry, and set it as metatable of FT.
192 luaL_getmetatable(m_LuaState, TI->Base->ClassName);
193 lua_setmetatable(m_LuaState, -2);
196 // MT.__index = FT
197 lua_setfield(m_LuaState, -2, "__index");
199 // This would be the right thing to do, but we don't know the proper type for Destruct<> here.
200 // Therefore, MT.__gc is only set in Push().
202 // MT.__gc = Destruct
203 // lua_pushcfunction(m_LuaState, Destruct<...>);
204 // lua_setfield(m_LuaState, -2, "__gc");
206 // Clear the stack.
207 assert(lua_gettop(m_LuaState)==1);
208 lua_pop(m_LuaState, 1);
214 bool ScriptBinderT::IsBound(void* Identity)
216 const StackCheckerT StackChecker(m_LuaState);
218 // Put the REGISTRY["__identity_to_object"] table onto the stack.
219 lua_getfield(m_LuaState, LUA_REGISTRYINDEX, "__identity_to_object");
221 // Put __identity_to_object[Identity] onto the stack.
222 // This should be our table that represents the object.
223 lua_pushlightuserdata(m_LuaState, Identity);
224 lua_rawget(m_LuaState, -2);
226 // Is the object in the __identity_to_object table?
227 const bool Result = !lua_isnil(m_LuaState, -1);
229 lua_pop(m_LuaState, 1); // Pop the value.
230 lua_pop(m_LuaState, 1); // Pop the __identity_to_object table.
232 return Result;
236 // This is essentially the opposite of Push().
237 void ScriptBinderT::Disconnect(void* Identity)
239 const StackCheckerT StackChecker(m_LuaState);
241 // Put the REGISTRY["__identity_to_object"] table onto the stack.
242 lua_getfield(m_LuaState, LUA_REGISTRYINDEX, "__identity_to_object");
244 // Put __identity_to_object[Identity] onto the stack.
245 // This should be our table that represents the object.
246 lua_pushlightuserdata(m_LuaState, Identity);
247 lua_rawget(m_LuaState, -2);
249 // If the object was not found in __identity_to_object, there is nothing to do.
250 if (lua_isnil(m_LuaState, -1))
252 lua_pop(m_LuaState, 1); // Pop the nil.
253 lua_pop(m_LuaState, 1); // Pop the __identity_to_object table.
254 return;
257 // Put the contents of the "__userdata_cf" field on top of the stack.
258 lua_pushstring(m_LuaState, "__userdata_cf");
259 lua_rawget(m_LuaState, -2);
261 // Get __gc from the metatable.
262 lua_getmetatable(m_LuaState, -1);
263 lua_pushstring(m_LuaState, "__gc");
264 lua_rawget(m_LuaState, -2);
265 lua_remove(m_LuaState, -2);
267 // Run the __gc metamethod / the destructor.
268 if (lua_iscfunction(m_LuaState, -1))
270 lua_pushvalue(m_LuaState, -2);
271 lua_call(m_LuaState, 1, 0);
273 else
275 // Remove whatever was not a function (probably nil).
276 lua_pop(m_LuaState, 1);
279 // Set the metatable to nil.
280 lua_pushnil(m_LuaState);
281 lua_setmetatable(m_LuaState, -2);
283 // Pop the userdata.
284 lua_pop(m_LuaState, 1);
286 // Set the metatable to nil.
287 lua_pushnil(m_LuaState);
288 lua_setmetatable(m_LuaState, -2);
290 // Pop the table.
291 lua_pop(m_LuaState, 1);
293 // Remove the table: __identity_to_object[Identity] = nil
294 lua_pushlightuserdata(m_LuaState, Identity);
295 lua_pushnil(m_LuaState);
296 lua_rawset(m_LuaState, -3);
298 // Pop the __identity_to_object table.
299 lua_pop(m_LuaState, 1);
303 UniScriptStateT::CoroutineT::CoroutineT()
304 : ID(InstCount++),
305 State(0),
306 NumParams(0),
307 WaitTimeLeft(0)
312 UniScriptStateT::UniScriptStateT()
313 : m_LuaState(NULL),
314 m_CheckCppRefsCount(0)
316 // Open (create, init) a new Lua state.
317 m_LuaState = luaL_newstate();
319 // Open (load, init) the Lua standard libraries.
320 luaL_requiref(m_LuaState, "_G", luaopen_base, 1); lua_pop(m_LuaState, 1);
321 luaL_requiref(m_LuaState, LUA_LOADLIBNAME, luaopen_package, 1); lua_pop(m_LuaState, 1);
322 luaL_requiref(m_LuaState, LUA_COLIBNAME, luaopen_coroutine, 1); lua_pop(m_LuaState, 1);
323 luaL_requiref(m_LuaState, LUA_TABLIBNAME, luaopen_table, 1); lua_pop(m_LuaState, 1);
324 luaL_requiref(m_LuaState, LUA_IOLIBNAME, luaopen_io, 1); lua_pop(m_LuaState, 1);
325 luaL_requiref(m_LuaState, LUA_OSLIBNAME, luaopen_os, 1); lua_pop(m_LuaState, 1);
326 luaL_requiref(m_LuaState, LUA_STRLIBNAME, luaopen_string, 1); lua_pop(m_LuaState, 1);
327 luaL_requiref(m_LuaState, LUA_BITLIBNAME, luaopen_bit32, 1); lua_pop(m_LuaState, 1);
328 luaL_requiref(m_LuaState, LUA_MATHLIBNAME, luaopen_math, 1); lua_pop(m_LuaState, 1);
330 // Record a pointer to this UniScriptStateT C++ instance in the Lua state,
331 // so that our C++-implemented global methods (like \c thread below) can get back to it.
332 lua_pushlightuserdata(m_LuaState, this);
333 lua_setfield(m_LuaState, LUA_REGISTRYINDEX, "cafu_script_state");
335 // Run the one-time initializations of our binding strategy.
336 cf::ScriptBinderT Binder(m_LuaState);
337 Binder.InitState();
339 // Add a table with name "__pending_coroutines_cf" to the registry.
340 // This table will be used to keep track of the pending coroutines, making sure that Lua doesn't garbage collect them early.
341 lua_newtable(m_LuaState);
342 lua_setfield(m_LuaState, LUA_REGISTRYINDEX, "__pending_coroutines_cf");
344 // Add an additional function "thread" that registers the given Lua function as a new thread.
345 lua_pushcfunction(m_LuaState, RegisterThread);
346 lua_setglobal(m_LuaState, "thread");
348 // Run the equivalent to "wait=coroutine.yield;" and "waitFrame=coroutine.yield;", that is,
349 // provide aliases for coroutine.yield as known from Doom3 map scripting.
350 lua_getglobal(m_LuaState, "coroutine");
351 lua_getfield(m_LuaState, -1, "yield");
352 lua_setglobal(m_LuaState, "wait");
353 lua_getfield(m_LuaState, -1, "yield");
354 lua_setglobal(m_LuaState, "waitFrame");
355 lua_pop(m_LuaState, 1);
357 // Did everyone deal properly with the Lua stack so far?
358 assert(lua_gettop(m_LuaState)==0);
362 UniScriptStateT::~UniScriptStateT()
364 lua_close(m_LuaState);
368 namespace
370 void CountHookFunction(lua_State* CrtState, lua_Debug* ar)
372 assert(ar->event==LUA_HOOKCOUNT);
374 luaL_error(CrtState, "Instruction count exceeds the predefined limit (infinite loop?).");
379 bool UniScriptStateT::DoString(const char* s, const char* Signature, ...)
381 const StackCheckerT StackChecker(m_LuaState);
383 // Load the string as a chunk, then put the compiled chunk as a function onto the stack.
384 if (luaL_loadstring(m_LuaState, s) != 0)
386 // Note that we need an extra newline here, because (all?) the Lua error messages don't have one.
387 Console->Print(std::string(lua_tostring(m_LuaState, -1))+"\n");
389 lua_pop(m_LuaState, 1); // Pop the error message.
390 return false;
393 va_list vl;
395 va_start(vl, Signature);
396 const bool Result=StartNewCoroutine(0, Signature, vl, std::string("custom string: ") + s);
397 va_end(vl);
399 return Result;
403 bool UniScriptStateT::DoFile(const char* FileName, const char* Signature, ...)
405 const StackCheckerT StackChecker(m_LuaState);
407 // Load the file as a chunk, then put the compiled chunk as a function onto the stack.
408 if (luaL_loadfile(m_LuaState, FileName) != 0)
410 // Note that we need an extra newline here, because (all?) the Lua error messages don't have one.
411 // Console->Warning(std::string("Lua script \"")+FileName+"\" could not be loaded\n");
412 // Console->Print(std::string("(")+lua_tostring(m_LuaState, -1)+").\n");
413 Console->Print(std::string(lua_tostring(m_LuaState, -1))+"\n");
415 lua_pop(m_LuaState, 1); // Pop the error message.
416 return false;
419 va_list vl;
421 va_start(vl, Signature);
422 const bool Result=StartNewCoroutine(0, Signature, vl, std::string("custom file: ") + FileName);
423 va_end(vl);
425 return Result;
429 bool UniScriptStateT::Call(const char* FuncName, const char* Signature, ...)
431 // Note that when re-entrancy occurs, we do usually NOT have an empty stack here!
432 // That is, when we first call a Lua function the stack is empty, but when the called Lua function
433 // in turn calls back into our C++ code (e.g. a console function), and the C++ code in turn gets here,
434 // we have a case of re-entrancy and the stack is not empty!
435 const StackCheckerT StackChecker(m_LuaState);
437 // Get the desired global function.
438 lua_getglobal(m_LuaState, FuncName);
440 if (!lua_isfunction(m_LuaState, -1))
442 // If we get here, this usually means that the value at -1 is just nil, i.e. the
443 // function that we would like to call was just not defined in the Lua script.
444 lua_pop(m_LuaState, 1); // Pop whatever is not a function.
445 return false;
448 va_list vl;
450 va_start(vl, Signature);
451 const bool Result=StartNewCoroutine(0, Signature, vl, std::string("global function ")+FuncName+"()");
452 va_end(vl);
454 return Result;
458 void UniScriptStateT::RunPendingCoroutines(float FrameTime)
460 // Take the opportunity to check if the reference-counted objects are still referenced in C++ code.
461 // If not, they're un-anchored, and thus can be garbage collected when they're unused in Lua as well.
462 m_CheckCppRefsCount++;
464 if (m_CheckCppRefsCount > 100)
466 ScriptBinderT Binder(m_LuaState);
468 Binder.CheckCppRefs();
469 m_CheckCppRefsCount = 0;
473 // Iterate over all elements in the REGISTRY["__pending_coroutines_cf"] table, which has all the pending coroutines.
474 const int PENDING_COROUTINES_TABLE_IDX=1;
475 lua_getfield(m_LuaState, LUA_REGISTRYINDEX, "__pending_coroutines_cf"); // Put REGISTRY["__pending_coroutines_cf"] onto the stack at index 1.
476 assert(lua_gettop(m_LuaState)==1);
477 assert(lua_istable(m_LuaState, PENDING_COROUTINES_TABLE_IDX));
479 // This variable is used to handle the occurrence of re-entrancy.
480 // Re-entrancy occurs when a script that is resumed via the call to lua_resume(Crt.State, 0) below
481 // manages to add another entry into the PendingCoroutines array, e.g. by calling the game.startNewThread() function.
482 unsigned long PendingCoroutines_Size=m_PendingCoroutines.Size();
484 for (unsigned long PendingCrtNr=0; PendingCrtNr<PendingCoroutines_Size; PendingCrtNr++)
486 CoroutineT& Crt=m_PendingCoroutines[PendingCrtNr];
488 Crt.WaitTimeLeft-=FrameTime;
489 if (Crt.WaitTimeLeft>0) continue;
491 // Set the hook function for the "count" event, so that we can detect and prevent infinite loops.
492 // Must do this before the next call to lua_resume, or else the instruction count is *not* reset to zero.
493 lua_sethook(Crt.State, CountHookFunction, LUA_MASKCOUNT, 10000); // Should have a ConVar for the number of instruction counts!?
495 // Wait time is over, resume the coroutine.
496 const int Result=lua_resume(Crt.State, NULL, Crt.NumParams);
498 if (Result==LUA_YIELD)
500 // The argument to the coroutine.yield() call is the wait time in seconds until the coroutine is supposed to be resumed.
501 // If the argument is not given (or not a number), a wait time of 0 is assumed.
502 // In any case, the earliest when the coroutine will be resumed is in the next (subsequent) server Think() frame.
504 // Check the argument(s).
505 if (lua_gettop(Crt.State)==0) lua_pushnumber(Crt.State, 0);
506 if (!lua_isnumber(Crt.State, -1)) lua_pushnumber(Crt.State, 0);
508 // Re-new the wait time.
509 Crt.WaitTimeLeft=float(lua_tonumber(Crt.State, -1));
510 Crt.NumParams =0;
512 else
514 // The coroutine either completed normally (the body function returned), or an error occurred.
515 // In both cases, we remove it from the list of pending coroutines, as it makes no sense to try to resume it once more.
516 if (Result!=0)
518 // An error occurred when running the coroutine.
519 // Note that we need an extra newline here, because (all?) the Lua error messages don't have one.
520 Console->Print(std::string(lua_tostring(Crt.State, -1))+"\n");
523 // Remove the Crt.State from the __pending_coroutines_cf table, so that Lua will eventually garbage collect it.
524 // __pending_coroutines_cf[Crt.ID]=nil;
525 lua_pushnil(m_LuaState);
526 lua_rawseti(m_LuaState, PENDING_COROUTINES_TABLE_IDX, Crt.ID);
528 m_PendingCoroutines.RemoveAtAndKeepOrder(PendingCrtNr);
529 PendingCrtNr--;
530 PendingCoroutines_Size--;
534 // Make sure that everyone dealt properly with the stack so far,
535 // then remove the remaining __pending_coroutines_cf table.
536 assert(lua_gettop(m_LuaState)==1);
537 lua_pop(m_LuaState, 1);
542 * This method calls a Lua function in the context of the m_LuaState.
544 * As a prerequisite, the caller must have pushed the Lua function to be called onto the stack of m_LuaState,
545 * followed by any extra arguments (that is, arguments that are not passed in the Signature/vl parameters) at subsequent stack positions
546 * (as for example the alter ego instance of a window that is to be used as the "self" or "this" value of an object-oriented method call).
547 * At stack positions "below" the function to be called there may be other stack values that this method will not touch.
548 * Additional parameters to the Lua function are appended from the vl parameter list as described by the Signature.
549 * Return values of the Lua function are returned to the vl parameter list as described by the Signature.
551 * The function call is implemented as the resumption of a coroutine (the coroutine instance is newly created),
552 * so that the script code can call coroutine.yield() and its derivatives like wait(), waitFrame(), etc.
554 bool UniScriptStateT::StartNewCoroutine(int NumExtraArgs, const char* Signature, va_list vl, const std::string& DbgName)
556 const StackCheckerT StackChecker(m_LuaState, -(1 + NumExtraArgs));
558 // Create a new coroutine for this function call (or else they cannot call coroutine.yield()).
559 // The new coroutine is pushed onto the stack of m_LuaState as a value of type "thread".
560 lua_State* NewThread=lua_newthread(m_LuaState);
562 // Move the new thread from the top (-1) stack position to the position "below" the function and its extra parameters.
563 lua_insert(m_LuaState, -(1+NumExtraArgs+1));
565 // Move the function and its extra parameters to the stack of NewThread.
566 lua_xmove(m_LuaState, NewThread, NumExtraArgs+1);
569 // Put all other arguments for the function onto the stack of NewThread.
570 // *********************************************************************
572 const char* Results="";
574 for (const char* c=Signature; *c; c++)
576 if (*c=='>')
578 Results=c+1;
579 break;
582 switch (*c)
584 // According to the g++ compiler, bool is promoted to int, and float is promoted to double when passed through '...',
585 // and therefore we should pass int and double to va_arg() instead of bool and float.
586 case 'b': lua_pushboolean(NewThread, va_arg(vl, /*bool*/int )); break;
587 case 'i': lua_pushinteger(NewThread, va_arg(vl, int )); break;
588 case 'f': lua_pushnumber (NewThread, va_arg(vl, /*float*/double)); break;
589 case 'd': lua_pushnumber (NewThread, va_arg(vl, double )); break;
590 case 's': lua_pushstring (NewThread, va_arg(vl, char* )); break;
591 case 'G': lua_getglobal (NewThread, va_arg(vl, char* )); break;
593 // case 'O': // TODO: This is what we really need here...
594 // // Find given object in weak table...
595 // break;
597 default:
598 Console->Warning(std::string("Invalid signature \"")+Signature+"\" in call to "+DbgName+".\n");
599 lua_settop(NewThread, 0); // Clear the stack of NewThread (the function and its arguments).
600 lua_pop(m_LuaState, 1); // Pop the thread (it will then be garbage collected).
601 return false;
604 // WARNING: Do NOT issue a call like lua_tostring(NewThread, -1) here!
605 // This is because "If the value is a number, then lua_tolstring also changes the actual value in the stack to a string.",
606 // as described at http://www.lua.org/manual/5.1/manual.html#lua_tolstring
609 const int ResCount=int(strlen(Results));
612 // Do the actual function call.
613 // ****************************
615 // Set the hook function for the "count" event, so that we can detect and prevent infinite loops.
616 lua_sethook(NewThread, CountHookFunction, LUA_MASKCOUNT, 10000); // Should have a ConVar for the number of instruction counts!?
618 // Start the new coroutine.
619 const int ThreadResult=lua_resume(NewThread, NULL, lua_gettop(NewThread)-1);
621 /* if (lua_pcall(m_LuaState, 1+ArgCount, ResCount, 0)!=0)
623 Console->Warning(std::string("Calling Lua script method ")+MethodName+"() on window at 0x"+cf::va("%p", this)+" failed ("+lua_tostring(m_LuaState, -1)+").\n");
624 Console->Print(std::string(lua_tostring(m_LuaState, -1))+"\n"); // Repeat the error message in the case the console doesn't line-wrap properly.
625 lua_pop(m_LuaState, 2); // Pop the error message and the original window table from the stack.
626 return false;
627 } */
630 // Deal with the results.
631 // **********************
633 if (ThreadResult==0)
635 // The coroutine returned normally, now return the results to the caller.
636 int StackIndex=1;
638 // If we expect more arguments back than we got, push a single nil that will help to fill-up any number of missing arguments.
639 if (ResCount>lua_gettop(NewThread)) lua_pushnil(NewThread);
641 for (const char* c=Results; *c; c++)
643 switch (*c)
645 case 'b': *va_arg(vl, bool* )=lua_toboolean(NewThread, StackIndex)!=0; break;
646 case 'i': *va_arg(vl, int* )=lua_tointeger(NewThread, StackIndex); break;
647 case 'f': *va_arg(vl, float* )=float(lua_tonumber(NewThread, StackIndex)); break;
648 case 'd': *va_arg(vl, double*)=lua_tonumber(NewThread, StackIndex); break;
649 // case 'E': *va_arg(vl, BaseEntityT**)=(BaseEntityT*)ScriptStateT::GetCheckedObjectParam(NewThread, StackIndex, BaseEntityT::TypeInfo); break;
651 case 's':
653 const char* s=lua_tostring(NewThread, StackIndex);
654 static const char* e="";
656 *va_arg(vl, const char**)=(s!=NULL) ? s : e;
657 break;
660 case 'S':
662 const char* s=lua_tostring(NewThread, StackIndex);
664 *va_arg(vl, std::string*)=(s!=NULL) ? s : "";
665 break;
668 default:
669 Console->Warning(std::string("Invalid results signature \"")+Signature+"\" in call to "+DbgName+".\n");
670 break;
673 if (StackIndex<lua_gettop(NewThread)) StackIndex++;
676 lua_settop(NewThread, 0); // Pop everything (the results) from the NewThread stack.
677 lua_pop(m_LuaState, 1); // Pop the thread (it will then be garbage collected).
678 return true;
681 if (ThreadResult==LUA_YIELD)
683 // The argument to the coroutine.yield() call is the wait time in seconds until the coroutine is supposed to be resumed.
684 // If the argument is not given (or not a number), a wait time of 0 is assumed.
685 // In any case, the earliest when the coroutine will be resumed is in the next (subsequent) server Think() frame.
687 // Check the argument(s).
688 if (lua_gettop(NewThread)==0) lua_pushnumber(NewThread, 0);
689 if (!lua_isnumber(NewThread, -1)) lua_pushnumber(NewThread, 0);
691 CoroutineT Crt;
693 // Crt.ID =(already got a unique value assigned by CoroutineT ctor);
694 Crt.State =NewThread;
695 Crt.NumParams =0;
696 Crt.WaitTimeLeft=float(lua_tonumber(NewThread, -1));
698 m_PendingCoroutines.PushBack(Crt);
700 // REGISTRY["__pending_coroutines_cf"][Crt.ID]=Crt.State;
701 lua_getfield(m_LuaState, LUA_REGISTRYINDEX, "__pending_coroutines_cf"); // Put REGISTRY["__pending_coroutines_cf"] onto the stack (index -1).
702 assert(lua_istable(m_LuaState, -1)); // Make sure that REGISTRY["__pending_coroutines_cf"] really is a table.
703 lua_pushvalue(m_LuaState, -2); // Duplicate the "thread" (==Ctr.State) value from index -2 to the top of the stack.
704 lua_rawseti(m_LuaState, -2, Crt.ID); // table[Crt.ID]=Crt.State; -- Pops the value from the stack.
705 lua_pop(m_LuaState, 1); // Pop the table again.
707 if (ResCount>0)
708 Console->Warning("The call to "+DbgName+" yielded (expected return values matching signature \""+Signature+"\" instead).\n");
710 lua_settop(NewThread, 0); // Pop everything (the parameters to coroutine.yield()) from the NewThread stack.
711 lua_pop(m_LuaState, 1); // Pop the thread (it's kept inside the __pending_coroutines_cf table now).
712 return ResCount==0;
715 // ThreadResult is not 0 and not LUA_YIELD, so an error occurred when running the coroutine.
716 // Note that we need an extra newline here, because (all?) the Lua error messages don't have one.
717 Console->Warning("Lua error in call to "+DbgName+":\n");
718 Console->Print(std::string(lua_tostring(NewThread, -1))+"\n");
720 // Note that the stack of NewThread was not unwound after the error (but we currently have no use for it).
721 lua_settop(NewThread, 0); // Just pop everything from the NewThread stack.
722 lua_pop(m_LuaState, 1); // Pop the thread (it will then be garbage collected).
723 return false;
727 /*static*/ int UniScriptStateT::RegisterThread(lua_State* LuaState)
729 lua_getfield(LuaState, LUA_REGISTRYINDEX, "cafu_script_state");
730 UniScriptStateT* ScriptState=static_cast<UniScriptStateT*>(lua_touserdata(LuaState, -1));
731 lua_pop(LuaState, 1);
732 if (!ScriptState) return luaL_error(LuaState, "ScriptStateT C++ instance not found in LuaState");
734 // Our stack (parameter list) comes with the function to be registered as a new thread, and the parameters for its initial call.
735 luaL_argcheck(LuaState, lua_isfunction(LuaState, 1), 1, "function expected");
736 const unsigned long StackSize=lua_gettop(LuaState);
738 // Put the __pending_coroutines_cf table on top of the stack,
739 // where we will insert ("anchor") the new thread below.
740 lua_getfield(LuaState, LUA_REGISTRYINDEX, "__pending_coroutines_cf"); // Put REGISTRY["__pending_coroutines_cf"] onto the stack at index 1.
741 assert(lua_istable(LuaState, -1));
743 CoroutineT Crt;
745 // Crt.ID =(already got a unique value assigned by CoroutineT ctor);
746 Crt.State =lua_newthread(LuaState); // Creates a new coroutine and puts it onto the stack of LuaState.
747 Crt.NumParams =StackSize-1; // The number of function parameters in the stack of Crt.State for the upcoming call of lua_resume().
748 Crt.WaitTimeLeft=0; // Run at next opportunity, i.e. at next call to RunPendingCoroutines().
750 ScriptState->m_PendingCoroutines.PushBack(Crt);
752 // The thread value is at the top (-1) of the stack, the __pending_coroutines_cf table directly below it at -2.
753 // Now anchor the new thread at index Crt.ID in the __pending_coroutines_cf table.
754 lua_rawseti(LuaState, -2, Crt.ID); // __pending_coroutines_cf[Crt.ID]=Crt.State; -- Pops the value from the stack.
756 // Remove the __pending_coroutines_cf table from the stack again, restoring the stack to its original state.
757 lua_pop(LuaState, 1);
758 assert(lua_gettop(LuaState)==int(StackSize));
760 // Preparing for the first lua_resume() call for Crt.State,
761 // move the body ("main") function plus its paramters on the stack of Crt.State.
762 lua_xmove(LuaState, Crt.State, StackSize);
763 return 0;
767 #include <fstream>
768 #include <map>
770 /*static*/ void UniScriptStateT::CheckCallbackDoc(const cf::TypeSys::TypeInfoT* TI, const std::string& MethodName, int NumExtraArgs, const char* Signature)
772 const std::string s = std::string(TI->ClassName) + "::" + MethodName + "(" + Signature + ")";
774 while (TI)
776 if (TI->DocCallbacks)
778 for (unsigned int Nr = 0; TI->DocCallbacks[Nr].Name; Nr++)
780 if (MethodName == TI->DocCallbacks[Nr].Name)
782 // TODO: The method name matches, but does Signature also match
783 // TI->DocCallbacks[Nr].Parameters?
784 return;
789 TI = TI->Base;
792 static std::map<std::string, bool> UniqueCallbacks;
794 if (UniqueCallbacks[s]) return;
795 UniqueCallbacks[s] = true;
797 static std::ofstream LogFile("callbacks.txt", std::ios::app);
799 if (!LogFile.bad())
801 LogFile << s << " is not documented!\n";