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 #ifndef CAFU_UNI_SCRIPT_STATE_HPP_INCLUDED
8 #define CAFU_UNI_SCRIPT_STATE_HPP_INCLUDED
10 #include "Templates/Array.hpp"
11 #include "Templates/Pointer.hpp"
12 #include "TypeSys.hpp"
27 /// This class checks if the Lua stack has the same size at the start and the end of a function.
32 StackCheckerT(lua_State
* LuaState
, int Change
=0)
33 : m_LuaState(LuaState
),
34 m_StartTop(lua_gettop(m_LuaState
) + Change
)
40 assert(m_StartTop
== lua_gettop(m_LuaState
));
46 lua_State
* m_LuaState
; ///< The Lua state we're checking the stack for.
47 const int m_StartTop
; ///< The initial size of the stack.
51 /// This class implements and encapsulates the strategy with which we bind C++ objects to Lua.
53 /// It is separate from class UniScriptStateT, because it can also be used "outside" of script states,
54 /// e.g. in the CFunctions of the bound C++ classes. Moreover, it would be possible to derive from
55 /// this class in order to implement alternative binding strategies, and to pass a concrete instance
56 /// to the UniScriptStateT constructor in order to "configure" it for a particular strategy.
58 /// Key idea: we only pass by value!
59 /// - object is copied
60 /// - Lua "owns" it and thus determines its lifetime
61 /// - per default, always create new userdata
62 /// - simple and clear if the object has no identity: push an xyz-vector twice --> two different userdata
63 /// - if the object is a smart pointer, and has identity (entities or windows):
64 /// it would work, too, with one detail issue: per-object extensions added by Lua code (e.g. attributes or callbacks) would not be consistent:
65 /// one userdata representing the identity would have them, but not another
66 /// ==> no problem, treat smart pointers as special case
68 /// Each type(name) can only be used with *one* kind of binding:
70 /// IntrusivePtrT<MyClassT> B(new MyClassT());
73 /// Push(B); // This is not possible!
74 /// This is because we can only have one __gc function per type: for this typename, would we call
75 /// Destruct<T>(...) with T == MyClassT or with T == IntrusivePtrT<MyClassT> ?
76 /// and because the type's CFunction callbacks (for example, BaseEntityT::GetOrigin()) would similary not know with which T to call GetCheckedObjectParam<T>().
79 /// - Programming in Lua, 2nd edition, Roberto Ierusalimschy
80 /// - Game Programming Gems 6, chapter 4.2, "Binding C/C++ objects to Lua", W. Celes et al.
81 /// - 2008-04-01: http://thread.gmane.org/gmane.comp.lang.lua.general/46787
87 ScriptBinderT(lua_State
* LuaState
);
89 /// This method registers all C++ classes known to the TIM in the related Lua state.
91 /// Subsequently created Lua instances of these classes will use the related information
92 /// so that script code can call the C++-implemented methods, e.g. "obj:myCppFunc()".
93 /// The method also takes inheritance into account: Lua instances of derived classes can
94 /// access the attributes and call the methods of their base classes.
95 void Init(const cf::TypeSys::TypeInfoManT
& TIM
);
97 /// Pushes the given C++ object onto the stack.
98 /// The object must support the GetType() method (should we add a "const char* TypeName" parameter instead?).
99 template<class T
> bool Push(T Object
);
101 /// Checks if the value at the given stack index is a Lua object of type T::TypeInfo,
102 /// or a subclass derived from it, and returns a reference to the related userdata.
103 /// (If T is really an IntrusivePtrT<U>, the method checks for type U::TypeInfo,
104 /// or a subclass derived from it.)
105 template<class T
> T
& GetCheckedObjectParam(int StackIndex
);
107 /// Returns if the object with the given identity is currently bound to the Lua state,
108 /// i.e. whether for the C++ object there is an alter ego in Lua.
109 bool IsBound(void* Identity
);
111 /// Breaks the connection between a C++ object and its alter ego in Lua.
112 /// If the object with the given identity still has an alter ego in the Lua state,
113 /// calling this method essentially removes all C++ parts from it: the metatable is
114 /// reset to nil, and the userdata's destructor is called (Lua will collect it later).
115 /// After this method, any attempt to access the C++-implemented methods in Lua
116 /// yields a (safe and well-defined) error message.
117 void Disconnect(void* Identity
);
122 /// Use traits for obtaining information from objects of any given type T.
123 /// If we have an instance of T, call GetType() instead, which returns the proper type
124 /// even if T is a base class pointer.
125 /// See http://erdani.com/publications/traits.html for a nice intro to traits.
126 template<class T
> class TraitsT
130 static T
* GetIdentity(T
& Object
) { return &Object
; }
131 static const cf::TypeSys::TypeInfoT
& GetTypeInfo() { return T::TypeInfo
; }
132 static const cf::TypeSys::TypeInfoT
& GetTypeInfo(const T
& Object
) { return *Object
.GetType(); }
133 static bool IsRefCounted() { return false; }
136 /// Specialization of TraitsT for IntrusivePtrTs to T.
137 template<class T
> class TraitsT
< IntrusivePtrT
<T
> >
141 static T
* GetIdentity(IntrusivePtrT
<T
> Object
) { return Object
.get(); }
142 static const cf::TypeSys::TypeInfoT
& GetTypeInfo() { return T::TypeInfo
; }
143 static const cf::TypeSys::TypeInfoT
& GetTypeInfo(IntrusivePtrT
<T
> Object
) { return *Object
->GetType(); }
144 static bool IsRefCounted() { return true; }
147 friend class UniScriptStateT
;
149 /// Implements the one-time initialization of the Lua state for this binder.
150 /// Called by the UniScriptStateT constructor.
153 /// If the object at the given stack index is an IntrusivePtrT, this method anchors it in a separate table
154 /// so that it cannot be garbage collected in Lua while it has siblings in C++.
156 /// The method first checks if the object at the given stack index is an IntrusivePtrT.
157 /// Its reference count is expected to be at least 2 if the IntrusivePtrT was just passed in from C++ code
158 /// and a copy of it was bound to Lua, or at least 1 if Lua has the only instance (that however might soon
159 /// be returned to C++ code, where it can be copied and kept, thereby increasing the reference count).
160 /// In any case, if the object is an IntrusivePtrT, it is added to the REGISTRY.__has_ref_in_cpp set.
162 /// This prevents the object, when it becomes (otherwise) unused in Lua, from being garbage collected.
163 /// It would normally not be a problem at all for an IntrusivePtrT object being collected, and it would be
164 /// perfectly possible to push another copy of an IntrusivePtrT to the same C++ object later.
166 /// The only downside with garbage collecting IntrusivePtrT's that are still referenced in C++ is that any
167 /// custom Lua data that is attached to it, such as event callback functions, gets lost.
168 /// See http://thread.gmane.org/gmane.comp.lang.lua.general/92550 for details.
170 /// Addressing this problem is in fact the sole reason for this method.
171 /// See CheckCppRefs() for the complementary method that un-anchors the objects again.
172 void Anchor(int StackIndex
);
174 /// This method un-anchors IntrusivePtrT objects that no longer have any siblings in C++.
176 /// For such IntrusivePtrT's, the Lua instance is the only remaining reference to the C++ object.
177 /// Removing such objects from the REGISTRY.__has_ref_in_cpp set ensures that they can normally be
178 /// garbage collected as soon as they become unused in Lua as well.
180 /// The user must call this method periodically (typically every n-th game frame).
182 /// In summary, the key idea of the whole anchoring process is:
183 /// 1) When an object is newly pushed, anchor it.
184 /// 2) Every now and then, run our own "pseudo garbage collection":
185 /// a) When the object becomes unused in C++, un-anchor it.
186 /// b) If the object is passed back to C++ again, re-anchor it.
188 /// See Anchor() for the complementary method that (re-)anchors IntrusivePtrT objects.
191 /// If i is a negative stack index (relative to the top), returns the related absolute index.
192 int abs_index(int i
) const
194 return (i
> 0 || i
<= LUA_REGISTRYINDEX
) ? i
: lua_gettop(m_LuaState
) + i
+ 1;
197 /// An extra object method for objects of type IntrusivePtrT<X>.
198 template<class T
> static int GetRefCount(lua_State
* LuaState
);
200 /// The callback for the __gc metamethod.
201 template<class T
> static int Destruct(lua_State
* LuaState
);
203 lua_State
* m_LuaState
; ///< The Lua state that this binder is used with.
207 /// This class represents the state of a script:
208 /// the underlying Lua state, pending coroutines, metatables for C++ class hierarchies, etc.
210 /// Its main features are:
211 /// - easy calling of Lua chunks, functions and object methods from C++ (Run() and Call()),
212 /// - easy to use support for coroutines/threads: Lua code can call "thread()" and "wait()",
213 /// - easy creation of Lua instances for C++ objects and binding of C++-implemented methods.
214 class UniScriptStateT
224 /// Loads the given string as a Lua chunk, then runs it.
225 /// (This acts very much like the stand-alone Lua interpreter.)
226 bool DoString(const char* s
, const char* Signature
= "", ...);
228 /// Loads the given file as a Lua chunk, then runs it.
229 bool DoFile(const char* FileName
, const char* Signature
= "", ...);
231 /// Calls the global script function with the given name.
233 /// @param FuncName The name of the global script function to be called.
234 /// @param Signature Describes the arguments to and results from the Lua function. See below for more details.
235 /// @param ... The arguments to the Lua function and the variables that receive its results as described by the Signature parameter.
237 /// The Signature parameter is a string of individual letters, where each letter represents a variable and its type.
238 /// The letters 'b' for bool, 'i' for int, 'f' for float, 'd' for double and 's' for const char* (string) can be used.
239 /// A '>' separates the arguments from the results, and is optional if the function returns no results.
240 /// For the results, additionally to the other letters, 'S' can be used for (address of) std::string.
242 /// @returns whether the function call was successful.
243 /// Note that when a signature was provided that expects one or more return values and the called script code yields
244 /// (calls coroutine.yield()), the returned values are undefined and thus the call is considered a failure and false is returned.
245 /// Nonetheless, the related Lua thread is added to the list of pending coroutines for later resumption.
246 bool Call(const char* FuncName
, const char* Signature
="", ...);
248 /// Calls a method with the given name of the given object.
250 /// @param Object The object whose script method is to be called.
251 /// @param MethodName The name of the method to be called.
252 /// @param Signature Describes the arguments to and results from the Lua method.
253 /// @param ... The arguments to the Lua method and the variables that receive its results as described by the Signature parameter.
255 /// For more details about the parameters and return value, see Call().
258 /// If the variable Obj is bound to Object, then CallMethod(Object, "OnTrigger", "f", 1.0);
259 /// calls the script method Obj:OnTrigger(value) where value is a number with value 1.0.
260 template<class T
> bool CallMethod(T Object
, const std::string
& MethodName
, const char* Signature
="", ...);
262 /// Like CallMethod() above, but the arguments and results are passed via vl rather than "...",
263 /// and if any extra arguments have been pushed on the stack, their number must be given.
264 /// Note that the "extra arguments" are a work-around that was not necessary if we could use
265 /// variadic templates for the implementation of CallMethod().
266 template<class T
> bool CallMethod_Impl(T Object
, const std::string
& MethodName
, int NumExtraArgs
, const char* Signature
, va_list vl
);
268 /// Runs the pending coroutines.
269 void RunPendingCoroutines(float FrameTime
);
271 /// Returns the Lua state that implements this script state.
272 lua_State
* GetLuaState() { return m_LuaState
; }
283 unsigned int ID
; ///< The unique ID of this coroutine, used to anchor it in a table in the Lua registry. Automatically set in the constructor, but not declared const so that CoroutineT objects can be kept in an ArrayT<>.
284 lua_State
* State
; ///< The state and stack of this coroutine.
285 unsigned int NumParams
; ///< Number of parameters on the stack of State for the next call to lua_resume(), i.e. the parameters for the initial function call or the return values for the pending yield().
286 float WaitTimeLeft
; ///< Wait time left until the next call to lua_resume().
291 static unsigned int InstCount
; ///< Count of created instances, used for creating unique coroutine IDs.
294 UniScriptStateT(const UniScriptStateT
&); ///< Use of the Copy Constructor is not allowed.
295 void operator = (const UniScriptStateT
&); ///< Use of the Assignment Operator is not allowed.
297 /// This method calls a Lua function in the context of the Lua state.
298 bool StartNewCoroutine(int NumExtraArgs
, const char* Signature
, va_list vl
, const std::string
& DbgName
);
300 /// A global Lua function that registers the given Lua function as a new thread.
301 static int RegisterThread(lua_State
* LuaState
);
303 /// A helper function for checking if a called Lua function is documented.
304 static void CheckCallbackDoc(const cf::TypeSys::TypeInfoT
* TI
, const std::string
& MethodName
, int NumExtraArgs
, const char* Signature
);
306 lua_State
* m_LuaState
; ///< The Lua instance. This is what "really" represents the script.
307 ArrayT
<CoroutineT
> m_PendingCoroutines
; ///< The list of active, pending coroutines.
308 unsigned int m_CheckCppRefsCount
; ///< Call Binder.CheckCppRefs() only every n-th frame.
313 template<class T
> int cf::ScriptBinderT::GetRefCount(lua_State
* LuaState
)
315 // Cannot use Binder.GetCheckedObjectParam() here, because it would cause infinite
316 // recursion (via the call to Anchor()).
317 lua_getfield(LuaState
, -1, "__userdata_cf");
319 // Note that T is an IntrusivePtrT<X>.
320 T
* UserData
=(T
*)lua_touserdata(LuaState
, -1);
323 lua_pushinteger(LuaState
, UserData
? (*UserData
)->GetRefCount() : 0);
328 template<class T
> int cf::ScriptBinderT::Destruct(lua_State
* LuaState
)
330 T
* UserData
=(T
*)lua_touserdata(LuaState
, 1);
334 // Explicitly call the destructor for the placed object.
342 template<class T
> inline bool cf::ScriptBinderT::Push(T Object
)
344 const StackCheckerT
StackChecker(m_LuaState
, 1);
346 // Put the REGISTRY["__identity_to_object"] table onto the stack.
347 lua_getfield(m_LuaState
, LUA_REGISTRYINDEX
, "__identity_to_object");
349 // Put __identity_to_object[Identity] onto the stack.
350 // This should be our table that represents the object.
351 lua_pushlightuserdata(m_LuaState
, TraitsT
<T
>::GetIdentity(Object
)); // Need the raw "identity" pointer here.
352 lua_rawget(m_LuaState
, -2);
354 // If the object was not found in __identity_to_object, create it anew.
355 if (lua_isnil(m_LuaState
, -1))
358 lua_pop(m_LuaState
, 1);
360 // Stack indices of the table and userdata that we process here.
361 const int USERDATA_INDEX
=lua_gettop(m_LuaState
) + 2;
362 const int TABLE_INDEX
=lua_gettop(m_LuaState
) + 1;
364 // Create a new object table OT, which is pushed on the stack and thus at stack index TABLE_INDEX.
365 lua_newtable(m_LuaState
);
367 // Create a new user datum UD, which is pushed on the stack and thus at stack index USERDATA_INDEX.
368 new (lua_newuserdata(m_LuaState
, sizeof(T
))) T(Object
);
370 // OT["__userdata_cf"] = UD
371 lua_pushvalue(m_LuaState
, USERDATA_INDEX
); // Duplicate the userdata on top of the stack.
372 lua_setfield(m_LuaState
, TABLE_INDEX
, "__userdata_cf");
374 // Get the table with name (key) TraitsT<T>::GetTypeInfo(Object).ClassName from the registry,
375 // and check if its __gc metamethod is already set.
376 // Note that starting with Lua 5.2, the __gc field must be set *before* the table is set as metatable (below),
377 // or else the finalizer will not be called even if it is set later (see ยง2.5.1 in the Lua Reference Manual).
378 luaL_getmetatable(m_LuaState
, TraitsT
<T
>::GetTypeInfo(Object
).ClassName
);
379 assert(lua_istable(m_LuaState
, -1));
380 lua_getfield(m_LuaState
, -1, "__gc");
381 if (lua_isnil(m_LuaState
, -1))
383 lua_pushcfunction(m_LuaState
, Destruct
<T
>);
384 lua_setfield(m_LuaState
, -3, "__gc");
386 lua_pop(m_LuaState
, 2);
388 // Get the table with name TraitsT<T>::GetTypeInfo(Object).ClassName from the registry,
389 // and set it as metatable of the newly created table.
390 // This is the crucial step that establishes the main functionality of our new table.
391 luaL_getmetatable(m_LuaState
, TraitsT
<T
>::GetTypeInfo(Object
).ClassName
);
392 assert(lua_istable(m_LuaState
, -1));
393 lua_setmetatable(m_LuaState
, TABLE_INDEX
);
395 // Get the table with name (key) TraitsT<T>::GetTypeInfo(Object).ClassName from the registry,
396 // and set it as metatable of the newly created userdata item.
397 // This is important for userdata type safety (see PiL2, chapter 28.2) and to have automatic garbage collection work
398 // (contrary to the text in the "Game Programming Gems 6" book, chapter 4.2, a __gc method in the metatable
399 // is only called for full userdata, see my email to the Lua mailing list on 2008-Apr-01 for more details).
400 luaL_getmetatable(m_LuaState
, TraitsT
<T
>::GetTypeInfo(Object
).ClassName
);
401 assert(lua_istable(m_LuaState
, -1));
402 lua_setmetatable(m_LuaState
, USERDATA_INDEX
);
404 // Get the table for the root of TraitsT<T>::GetTypeInfo(Object) from the registry,
405 // get its __index table, and check if its GetRefCount method is already set.
406 if (TraitsT
<T
>::IsRefCounted())
408 const cf::TypeSys::TypeInfoT
* TI
= &TraitsT
<T
>::GetTypeInfo(Object
);
413 luaL_getmetatable(m_LuaState
, TI
->ClassName
);
414 lua_getfield(m_LuaState
, -1, "__index");
415 lua_getfield(m_LuaState
, -1, "GetRefCount");
416 if (lua_isnil(m_LuaState
, -1))
418 lua_pushcfunction(m_LuaState
, GetRefCount
<T
>);
419 lua_setfield(m_LuaState
, -3, "GetRefCount");
421 lua_pop(m_LuaState
, 3);
424 // Remove UD from the stack, so that now the new table OT is on top of the stack.
425 lua_pop(m_LuaState
, 1);
427 // Record the table: __identity_to_object[Identity] = OT
428 lua_pushlightuserdata(m_LuaState
, TraitsT
<T
>::GetIdentity(Object
)); // Need the raw "identity" pointer here.
429 lua_pushvalue(m_LuaState
, TABLE_INDEX
); // Duplicate the table on top of the stack.
430 lua_rawset(m_LuaState
, -4);
432 // Anchor the object (table OT).
433 // Note that this is not necessary if the object was found in __identity_to_object above,
434 // because then, clearly a copy in C++ and a copy in Lua existed beforehand, so that
435 // consequently the object must also be anchored.
439 // Remove the __identity_to_object table.
440 lua_remove(m_LuaState
, -2);
442 // The requested table/userdata is now at the top of the stack.
447 template<class T
> inline T
& cf::ScriptBinderT::GetCheckedObjectParam(int StackIndex
)
449 // Don't bother with stack checking, because here it can only work in the case of success.
450 // If there is an error, not only do we not clean up the stack, but the error message itself is
451 // a problem as well: See http://thread.gmane.org/gmane.comp.lang.lua.general/103390 for details.
452 // const StackCheckerT StackChecker(m_LuaState);
454 StackIndex
= abs_index(StackIndex
);
456 // First make sure that the table that represents the object itself is at StackIndex.
457 luaL_argcheck(m_LuaState
, lua_istable(m_LuaState
, StackIndex
), StackIndex
, "Expected a table that represents an object." /*of type TypeInfo.ClassName*/);
459 // Put the contents of the "__userdata_cf" field on top of the stack (other values may be between it and the table at position StackIndex).
460 lua_getfield(m_LuaState
, StackIndex
, "__userdata_cf");
463 // This approach takes inheritance properly into account by "manually traversing up the inheritance hierarchy".
464 // See the "Game Programming Gems 6" book, page 353 for the inspiration for this code.
466 // Put the metatable of the desired type on top of the stack.
467 luaL_getmetatable(m_LuaState
, TraitsT
<T
>::GetTypeInfo().ClassName
);
469 // Put the metatable for the given userdata on top of the stack (it may belong to a derived class).
470 if (!lua_getmetatable(m_LuaState
, -2)) lua_pushnil(m_LuaState
); // Don't have it push nothing in case of failure.
472 while (lua_istable(m_LuaState
, -1))
474 if (lua_rawequal(m_LuaState
, -1, -2))
476 T
* UserData
=(T
*)lua_touserdata(m_LuaState
, -3);
479 luaL_error(m_LuaState
, "NULL userdata in object table.");
481 // Pop the two matching metatables and the userdata.
482 lua_pop(m_LuaState
, 3);
484 // We pass the object back to C++, fully expecting that it will keep a copy
485 // and, if it is an IntrusivePtrT, increase its reference count.
491 // Replace the metatable MT on top of the stack with the metatable of MT.__index.
492 lua_getfield(m_LuaState
, -1, "__index");
493 if (!lua_getmetatable(m_LuaState
, -1)) lua_pushnil(m_LuaState
); // Don't have it push nothing in case of failure.
494 lua_remove(m_LuaState
, -2);
495 lua_remove(m_LuaState
, -2);
498 // luaL_typerror(m_LuaState, StackIndex, TraitsT<T>::GetTypeInfo().ClassName);
499 luaL_argerror(m_LuaState
, StackIndex
, lua_pushfstring(m_LuaState
, "%s expected, got %s", TraitsT
<T
>::GetTypeInfo().ClassName
, luaL_typename(m_LuaState
, StackIndex
)));
501 static T
* Invalid
= NULL
;
504 // This approach is too simplistic, it doesn't work when inheritance is used.
505 T
* UserData
=(T
*)luaL_checkudata(m_LuaState
, -1, TraitsT
<T
>::GetTypeInfo().ClassName
);
508 luaL_error(m_LuaState
, "NULL userdata in object table.");
510 // Pop the userdata from the stack again. Not necessary though as it doesn't hurt there.
511 // lua_pop(m_LuaState, 1);
517 template<class T
> inline bool cf::UniScriptStateT::CallMethod(T Object
, const std::string
& MethodName
, const char* Signature
, ...)
521 va_start(vl
, Signature
);
522 const bool Result
=CallMethod_Impl(Object
, MethodName
, 0, Signature
, vl
);
529 template<class T
> inline bool cf::UniScriptStateT::CallMethod_Impl(T Object
, const std::string
& MethodName
, int NumExtraArgs
, const char* Signature
, va_list vl
)
531 const StackCheckerT
StackChecker(m_LuaState
, -NumExtraArgs
);
532 cf::ScriptBinderT
Binder(m_LuaState
);
535 CheckCallbackDoc(Object
->GetType(), MethodName
, NumExtraArgs
, Signature
);
540 // Put the desired method (directly from the object's table or
541 // from its metatables __index table) onto the stack of LuaState.
542 lua_getfield(m_LuaState
, -1, MethodName
.c_str());
544 if (!lua_isfunction(m_LuaState
, -1))
546 // If we get here, this usually means that the value at -1 is just nil, i.e. the
547 // function that we would like to call was just not defined in the Lua script.
548 // Pop whatever is not a function, the object table, and any extra arguments.
549 lua_pop(m_LuaState
, 2 + NumExtraArgs
);
553 // Rearrange the stack from "method, Object, extra arguments" to "extra arguments, Object, method",
554 // so that the function call sees the Object as its first argument (the "self" or "this" value for
555 // the object-oriented method call), followed by any extra arguments.
556 lua_insert(m_LuaState
, -2 - NumExtraArgs
); // Move the method below the Object and the extra args.
557 lua_insert(m_LuaState
, -1 - NumExtraArgs
); // Move the Object below the extra args.
559 // The stack is now prepared as required by the StartNewCoroutine() method.
560 return StartNewCoroutine(1 + NumExtraArgs
, Signature
, vl
, std::string("method ") + MethodName
+ "()");