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.
7 #include "UniScriptState.hpp"
9 #include "ConsoleCommands/Console.hpp"
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);
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);
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);
133 // Keep this object anchored.
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!
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);
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");
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.
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.
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);
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);
284 lua_pop(m_LuaState
, 1);
286 // Set the metatable to nil.
287 lua_pushnil(m_LuaState
);
288 lua_setmetatable(m_LuaState
, -2);
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()
312 UniScriptStateT::UniScriptStateT()
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
);
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
);
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.
395 va_start(vl
, Signature
);
396 const bool Result
=StartNewCoroutine(0, Signature
, vl
, std::string("custom string: ") + s
);
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.
421 va_start(vl
, Signature
);
422 const bool Result
=StartNewCoroutine(0, Signature
, vl
, std::string("custom file: ") + FileName
);
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.
450 va_start(vl
, Signature
);
451 const bool Result
=StartNewCoroutine(0, Signature
, vl
, std::string("global function ")+FuncName
+"()");
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));
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.
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
);
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
++)
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...
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).
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.
630 // Deal with the results.
631 // **********************
635 // The coroutine returned normally, now return the results to the caller.
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
++)
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;
653 const char* s
=lua_tostring(NewThread
, StackIndex
);
654 static const char* e
="";
656 *va_arg(vl
, const char**)=(s
!=NULL
) ? s
: e
;
662 const char* s
=lua_tostring(NewThread
, StackIndex
);
664 *va_arg(vl
, std::string
*)=(s
!=NULL
) ? s
: "";
669 Console
->Warning(std::string("Invalid results signature \"")+Signature
+"\" in call to "+DbgName
+".\n");
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).
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);
693 // Crt.ID =(already got a unique value assigned by CoroutineT ctor);
694 Crt
.State
=NewThread
;
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.
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).
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).
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));
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
);
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
+ ")";
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?
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
);
801 LogFile
<< s
<< " is not documented!\n";