namespace LuaInterface { using System; using System.IO; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Reflection; using System.Threading; using Lua511; /* * Main class of LuaInterface * Object-oriented wrapper to Lua API * * Author: Fabio Mascarenhas * Version: 1.0 * * // steffenj: important changes in Lua class: * - removed all Open*Lib() functions * - all libs automatically open in the Lua class constructor (just assign nil to unwanted libs) * */ [CLSCompliant(true)] public class Lua : IDisposable { static string init_luanet = "local metatable = {} \n"+ "local import_type = luanet.import_type \n"+ "local load_assembly = luanet.load_assembly \n"+ " \n"+ "-- Lookup a .NET identifier component. \n"+ "function metatable:__index(key) -- key is e.g. \"Form\" \n"+ " -- Get the fully-qualified name, e.g. \"System.Windows.Forms.Form\" \n"+ " local fqn = ((rawget(self,\".fqn\") and rawget(self,\".fqn\") .. \n"+ " \".\") or \"\") .. key \n"+ " \n"+ " -- Try to find either a luanet function or a CLR type \n"+ " local obj = rawget(luanet,key) or import_type(fqn) \n"+ " \n"+ " -- If key is neither a luanet function or a CLR type, then it is simply \n"+ " -- an identifier component. \n"+ " if obj == nil then \n"+ " -- It might be an assembly, so we load it too. \n"+ " load_assembly(fqn) \n"+ " obj = { [\".fqn\"] = fqn } \n"+ " setmetatable(obj, metatable) \n"+ " end \n"+ " \n"+ " -- Cache this lookup \n"+ " rawset(self, key, obj) \n"+ " return obj \n"+ "end \n"+ " \n"+ "-- A non-type has been called; e.g. foo = System.Foo() \n"+ "function metatable:__call(...) \n"+ " error(\"No such type: \" .. rawget(self,\".fqn\"), 2) \n"+ "end \n"+ " \n"+ "-- This is the root of the .NET namespace \n"+ "luanet[\".fqn\"] = false \n"+ "setmetatable(luanet, metatable) \n"+ " \n"+ "-- Preload the mscorlib assembly \n"+ "luanet.load_assembly(\"mscorlib\") \n"; /*readonly */ IntPtr luaState; ObjectTranslator translator; LuaCSFunction panicCallback, lockCallback, unlockCallback; /// /// Used to ensure multiple .net threads all get serialized by this single lock for access to the lua stack/objects /// object luaLock = new object(); public Lua() { luaState = LuaDLL.luaL_newstate(); // steffenj: Lua 5.1.1 API change (lua_open is gone) //LuaDLL.luaopen_base(luaState); // steffenj: luaopen_* no longer used LuaDLL.luaL_openlibs(luaState); // steffenj: Lua 5.1.1 API change (luaopen_base is gone, just open all libs right here) LuaDLL.lua_pushstring(luaState, "LUAINTERFACE LOADED"); LuaDLL.lua_pushboolean(luaState, true); LuaDLL.lua_settable(luaState, (int) LuaIndexes.LUA_REGISTRYINDEX); LuaDLL.lua_newtable(luaState); LuaDLL.lua_setglobal(luaState, "luanet"); LuaDLL.lua_pushvalue(luaState, (int)LuaIndexes.LUA_GLOBALSINDEX); LuaDLL.lua_getglobal(luaState, "luanet"); LuaDLL.lua_pushstring(luaState, "getmetatable"); LuaDLL.lua_getglobal(luaState, "getmetatable"); LuaDLL.lua_settable(luaState, -3); LuaDLL.lua_replace(luaState, (int)LuaIndexes.LUA_GLOBALSINDEX); translator=new ObjectTranslator(this,luaState); LuaDLL.lua_replace(luaState, (int)LuaIndexes.LUA_GLOBALSINDEX); LuaDLL.luaL_dostring(luaState, Lua.init_luanet); // steffenj: lua_dostring renamed to luaL_dostring // We need to keep this in a managed reference so the delegate doesn't get garbage collected panicCallback = new LuaCSFunction(PanicCallback); LuaDLL.lua_atpanic(luaState, panicCallback); //LuaDLL.lua_atlock(luaState, lockCallback = new LuaCSFunction(LockCallback)); //LuaDLL.lua_atunlock(luaState, unlockCallback = new LuaCSFunction(UnlockCallback)); } private bool _StatePassed; /* * CAUTION: LuaInterface.Lua instances can't share the same lua state! */ public Lua(Int64 luaState) { IntPtr lState = new IntPtr(luaState); LuaDLL.lua_pushstring(lState, "LUAINTERFACE LOADED"); LuaDLL.lua_gettable(lState, (int)LuaIndexes.LUA_REGISTRYINDEX); if(LuaDLL.lua_toboolean(lState,-1)) { LuaDLL.lua_settop(lState,-2); throw new LuaException("There is already a LuaInterface.Lua instance associated with this Lua state"); } else { LuaDLL.lua_settop(lState,-2); LuaDLL.lua_pushstring(lState, "LUAINTERFACE LOADED"); LuaDLL.lua_pushboolean(lState, true); LuaDLL.lua_settable(lState, (int)LuaIndexes.LUA_REGISTRYINDEX); this.luaState=lState; LuaDLL.lua_pushvalue(lState, (int)LuaIndexes.LUA_GLOBALSINDEX); LuaDLL.lua_getglobal(lState, "luanet"); LuaDLL.lua_pushstring(lState, "getmetatable"); LuaDLL.lua_getglobal(lState, "getmetatable"); LuaDLL.lua_settable(lState, -3); LuaDLL.lua_replace(lState, (int)LuaIndexes.LUA_GLOBALSINDEX); translator=new ObjectTranslator(this, this.luaState); LuaDLL.lua_replace(lState, (int)LuaIndexes.LUA_GLOBALSINDEX); LuaDLL.luaL_dostring(lState, Lua.init_luanet); // steffenj: lua_dostring renamed to luaL_dostring } _StatePassed = true; } /// /// Called for each lua_lock call /// /// /// Not yet used int LockCallback(IntPtr luaState) { // Monitor.Enter(luaLock); return 0; } /// /// Called for each lua_unlock call /// /// /// Not yet used int UnlockCallback(IntPtr luaState) { // Monitor.Exit(luaLock); return 0; } public void Close() { if (_StatePassed) return; if (luaState != IntPtr.Zero) LuaDLL.lua_close(luaState); //luaState = IntPtr.Zero; <- suggested by Christopher Cebulski http://luaforge.net/forum/forum.php?thread_id=44593&forum_id=146 } static int PanicCallback(IntPtr luaState) { // string desc = LuaDLL.lua_tostring(luaState, 1); string reason = String.Format("unprotected error in call to Lua API ({0})", LuaDLL.lua_tostring(luaState, -1)); // lua_tostring(L, -1); throw new LuaException(reason); } /// /// Assuming we have a Lua error string sitting on the stack, throw a C# exception out to the user's app /// /// Thrown if the script caused an exception void ThrowExceptionFromError(int oldTop) { object err = translator.getObject(luaState, -1); LuaDLL.lua_settop(luaState, oldTop); // A pre-wrapped exception - just rethrow it (stack trace of InnerException will be preserved) LuaScriptException luaEx = err as LuaScriptException; if (luaEx != null) throw luaEx; // A non-wrapped Lua error (best interpreted as a string) - wrap it and throw it if (err == null) err = "Unknown Lua Error"; throw new LuaScriptException(err.ToString(), ""); } /// /// Convert C# exceptions into Lua errors /// /// num of things on stack /// null for no pending exception internal int SetPendingException(Exception e) { Exception caughtExcept = e; if (caughtExcept != null) { translator.throwError(luaState, caughtExcept); LuaDLL.lua_pushnil(luaState); return 1; } else return 0; } private bool executing; /// /// True while a script is being executed /// public bool IsExecuting { get { return executing; } } /// /// /// /// /// /// public LuaFunction LoadString(string chunk, string name) { int oldTop = LuaDLL.lua_gettop(luaState); executing = true; try { if (LuaDLL.luaL_loadbuffer(luaState, chunk, name) != 0) ThrowExceptionFromError(oldTop); } finally { executing = false; } LuaFunction result = translator.getFunction(luaState, -1); translator.popValues(luaState, oldTop); return result; } /// /// /// /// /// public LuaFunction LoadFile(string fileName) { int oldTop = LuaDLL.lua_gettop(luaState); if (LuaDLL.luaL_loadfile(luaState, fileName) != 0) ThrowExceptionFromError(oldTop); LuaFunction result = translator.getFunction(luaState, -1); translator.popValues(luaState, oldTop); return result; } /* * Excutes a Lua chunk and returns all the chunk's return * values in an array */ public object[] DoString(string chunk) { int oldTop=LuaDLL.lua_gettop(luaState); if (LuaDLL.luaL_loadbuffer(luaState, chunk, "chunk") == 0) { executing = true; try { if (LuaDLL.lua_pcall(luaState, 0, -1, 0) == 0) return translator.popValues(luaState, oldTop); else ThrowExceptionFromError(oldTop); } finally { executing = false; } } else ThrowExceptionFromError(oldTop); return null; // Never reached - keeps compiler happy } /// /// Executes a Lua chnk and returns all the chunk's return values in an array. /// /// Chunk to execute /// Name to associate with the chunk /// public object[] DoString(string chunk, string chunkName) { int oldTop = LuaDLL.lua_gettop(luaState); executing = true; if (LuaDLL.luaL_loadbuffer(luaState, chunk, chunkName) == 0) { try { if (LuaDLL.lua_pcall(luaState, 0, -1, 0) == 0) return translator.popValues(luaState, oldTop); else ThrowExceptionFromError(oldTop); } finally { executing = false; } } else ThrowExceptionFromError(oldTop); return null; // Never reached - keeps compiler happy } /* * Excutes a Lua file and returns all the chunk's return * values in an array */ public object[] DoFile(string fileName) { int oldTop=LuaDLL.lua_gettop(luaState); if(LuaDLL.luaL_loadfile(luaState,fileName)==0) { executing = true; try { if (LuaDLL.lua_pcall(luaState, 0, -1, 0) == 0) return translator.popValues(luaState, oldTop); else ThrowExceptionFromError(oldTop); } finally { executing = false; } } else ThrowExceptionFromError(oldTop); return null; // Never reached - keeps compiler happy } /* * Indexer for global variables from the LuaInterpreter * Supports navigation of tables by using . operator */ public object this[string fullPath] { get { object returnValue=null; int oldTop=LuaDLL.lua_gettop(luaState); string[] path=fullPath.Split(new char[] { '.' }); LuaDLL.lua_getglobal(luaState,path[0]); returnValue=translator.getObject(luaState,-1); if(path.Length>1) { string[] remainingPath=new string[path.Length-1]; Array.Copy(path,1,remainingPath,0,path.Length-1); returnValue=getObject(remainingPath); } LuaDLL.lua_settop(luaState,oldTop); return returnValue; } set { int oldTop=LuaDLL.lua_gettop(luaState); string[] path=fullPath.Split(new char[] { '.' }); if(path.Length==1) { translator.push(luaState,value); LuaDLL.lua_setglobal(luaState,fullPath); } else { LuaDLL.lua_getglobal(luaState,path[0]); string[] remainingPath=new string[path.Length-1]; Array.Copy(path,1,remainingPath,0,path.Length-1); setObject(remainingPath,value); } LuaDLL.lua_settop(luaState,oldTop); // Globals auto-complete if (value == null) { // Remove now obsolete entries globals.Remove(fullPath); } else { // Add new entries if (!globals.Contains(fullPath)) registerGlobal(fullPath, value.GetType(), 0); } } } #region Globals auto-complete private readonly List globals = new List(); private bool globalsSorted; /// /// An alphabetically sorted list of all globals (objects, methods, etc.) externally added to this Lua instance /// /// Members of globals are also listed. The formatting is optimized for text input auto-completion. public IEnumerable Globals { get { // Only sort list when necessary if (!globalsSorted) { globals.Sort(); globalsSorted = true; } return globals; } } /// /// Adds an entry to (recursivley handles 2 levels of members) /// /// The index accessor path ot the entry /// The type of the entry /// How deep have we gone with recursion? private void registerGlobal(string path, Type type, int recursionCounter) { // If the type is a global method, list it directly if (type == typeof(LuaCSFunction)) { // Format for easy method invocation globals.Add(path + "("); } // If the type is a class or an interface and recursion hasn't been running too long, list the members else if ((type.IsClass || type.IsInterface) && type != typeof(string) && recursionCounter < 2) { #region Methods foreach (MethodInfo method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance)) { if ( // Check that the LuaHideAttribute and LuaGlobalAttribute were not applied (method.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) && (method.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0) && // Exclude some generic .NET methods that wouldn't be very usefull in Lua method.Name != "GetType" && method.Name != "GetHashCode" && method.Name != "Equals" && method.Name != "ToString" && method.Name != "Clone" && method.Name != "Dispose" && method.Name != "GetEnumerator" && method.Name != "CopyTo" && !method.Name.StartsWith("get_", StringComparison.Ordinal) && !method.Name.StartsWith("set_", StringComparison.Ordinal) && !method.Name.StartsWith("add_", StringComparison.Ordinal) && !method.Name.StartsWith("remove_", StringComparison.Ordinal)) { // Format for easy method invocation string command = path + ":" + method.Name + "("; if (method.GetParameters().Length == 0) command += ")"; globals.Add(command); } } #endregion #region Fields foreach (FieldInfo field in type.GetFields(BindingFlags.Public | BindingFlags.Instance)) { if ( // Check that the LuaHideAttribute and LuaGlobalAttribute were not applied (field.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) && (field.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0)) { // Go into recursion for members registerGlobal(path + "." + field.Name, field.FieldType, recursionCounter + 1); } } #endregion #region Properties foreach (PropertyInfo property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if ( // Check that the LuaHideAttribute and LuaGlobalAttribute were not applied (property.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) && (property.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0) // Exclude some generic .NET properties that wouldn't be very usefull in Lua && property.Name != "Item") { // Go into recursion for members registerGlobal(path + "." + property.Name, property.PropertyType, recursionCounter + 1); } } #endregion } // Otherwise simply add the element to the list else globals.Add(path); // List will need to be sorted on next access globalsSorted = false; } #endregion /* * Navigates a table in the top of the stack, returning * the value of the specified field */ internal object getObject(string[] remainingPath) { object returnValue=null; for(int i=0;i /// lua hook calback delegate /// /// Reinhard Ostermeier private LuaHookFunction hookCallback = null; /// /// Activates the debug hook /// /// Mask /// Count /// see lua docs. -1 if hook is already set /// Reinhard Ostermeier public int SetDebugHook(EventMasks mask, int count) { if (hookCallback == null) { hookCallback = new LuaHookFunction(DebugHookCallback); return LuaDLL.lua_sethook(luaState, hookCallback, (int)mask, count); } return -1; } /// /// Removes the debug hook /// /// see lua docs /// Reinhard Ostermeier public int RemoveDebugHook() { hookCallback = null; return LuaDLL.lua_sethook(luaState, null, 0, 0); } /// /// Gets the hook mask. /// /// hook mask /// Reinhard Ostermeier public EventMasks GetHookMask() { return (EventMasks)LuaDLL.lua_gethookmask(luaState); } /// /// Gets the hook count /// /// see lua docs /// Reinhard Ostermeier public int GetHookCount() { return LuaDLL.lua_gethookcount(luaState); } /// /// Gets the stack entry on a given level /// /// level /// lua debug structure /// Returns true if level was allowed, false if level was invalid. /// Reinhard Ostermeier public bool GetStack(int level, out LuaDebug luaDebug) { luaDebug = new LuaDebug(); IntPtr ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug)); System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false); try { return LuaDLL.lua_getstack(luaState, level, ld) != 0; } finally { luaDebug = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(ld, typeof(LuaDebug)); System.Runtime.InteropServices.Marshal.FreeHGlobal(ld); } } /// /// Gets info (see lua docs) /// /// what (see lua docs) /// lua debug structure /// see lua docs /// Reinhard Ostermeier public int GetInfo(String what, ref LuaDebug luaDebug) { IntPtr ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug)); System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false); try { return LuaDLL.lua_getinfo(luaState, what, ld); } finally { luaDebug = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(ld, typeof(LuaDebug)); System.Runtime.InteropServices.Marshal.FreeHGlobal(ld); } } /// /// Gets local (see lua docs) /// /// lua debug structure /// see lua docs /// see lua docs /// Reinhard Ostermeier public String GetLocal(LuaDebug luaDebug, int n) { IntPtr ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug)); System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false); try { return LuaDLL.lua_getlocal(luaState, ld, n); } finally { System.Runtime.InteropServices.Marshal.FreeHGlobal(ld); } } /// /// Sets local (see lua docs) /// /// lua debug structure /// see lua docs /// see lua docs /// Reinhard Ostermeier public String SetLocal(LuaDebug luaDebug, int n) { IntPtr ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug)); System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false); try { return LuaDLL.lua_setlocal(luaState, ld, n); } finally { System.Runtime.InteropServices.Marshal.FreeHGlobal(ld); } } /// /// Gets up value (see lua docs) /// /// see lua docs /// see lua docs /// see lua docs /// Reinhard Ostermeier public String GetUpValue(int funcindex, int n) { return LuaDLL.lua_getupvalue(luaState, funcindex, n); } /// /// Sets up value (see lua docs) /// /// see lua docs /// see lua docs /// see lua docs /// Reinhard Ostermeier public String SetUpValue(int funcindex, int n) { return LuaDLL.lua_setupvalue(luaState, funcindex, n); } /// /// Delegate that is called on lua hook callback /// /// lua state /// Pointer to LuaDebug (lua_debug) structure /// Reinhard Ostermeier private void DebugHookCallback(IntPtr luaState, IntPtr luaDebug) { try { LuaDebug ld = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(luaDebug, typeof(LuaDebug)); EventHandler temp = DebugHook; if (temp != null) { temp(this, new DebugHookEventArgs(ld)); } } catch (Exception ex) { OnHookException(new HookExceptionEventArgs(ex)); } } /// /// Event that is raised when an exception occures during a hook call. /// /// Reinhard Ostermeier public event EventHandler HookException; private void OnHookException(HookExceptionEventArgs e) { EventHandler temp = HookException; if (temp != null) { temp(this, e); } } /// /// Event when lua hook callback is called /// /// /// Is only raised if SetDebugHook is called before. /// /// Reinhard Ostermeier public event EventHandler DebugHook; /// /// Pops a value from the lua stack. /// /// Returns the top value from the lua stack. /// Reinhard Ostermeier public object Pop() { int top = Lua511.LuaDLL.lua_gettop(luaState); return translator.popValues(luaState, top - 1)[0]; } /// /// Pushes a value onto the lua stack. /// /// Value to push. /// Reinhard Ostermeier public void Push(object value) { translator.push(luaState, value); } #endregion internal void dispose(int reference) { if (luaState != IntPtr.Zero) //Fix submitted by Qingrui Li LuaDLL.lua_unref(luaState,reference); } /* * Gets a field of the table corresponding to the provided reference * using rawget (do not use metatables) */ internal object rawGetObject(int reference,string field) { int oldTop=LuaDLL.lua_gettop(luaState); LuaDLL.lua_getref(luaState,reference); LuaDLL.lua_pushstring(luaState,field); LuaDLL.lua_rawget(luaState,-2); object obj=translator.getObject(luaState,-1); LuaDLL.lua_settop(luaState,oldTop); return obj; } /* * Gets a field of the table or userdata corresponding to the provided reference */ internal object getObject(int reference,string field) { int oldTop=LuaDLL.lua_gettop(luaState); LuaDLL.lua_getref(luaState,reference); object returnValue=getObject(field.Split(new char[] {'.'})); LuaDLL.lua_settop(luaState,oldTop); return returnValue; } /* * Gets a numeric field of the table or userdata corresponding the the provided reference */ internal object getObject(int reference,object field) { int oldTop=LuaDLL.lua_gettop(luaState); LuaDLL.lua_getref(luaState,reference); translator.push(luaState,field); LuaDLL.lua_gettable(luaState,-2); object returnValue=translator.getObject(luaState,-1); LuaDLL.lua_settop(luaState,oldTop); return returnValue; } /* * Sets a field of the table or userdata corresponding the the provided reference * to the provided value */ internal void setObject(int reference, string field, object val) { int oldTop=LuaDLL.lua_gettop(luaState); LuaDLL.lua_getref(luaState,reference); setObject(field.Split(new char[] {'.'}),val); LuaDLL.lua_settop(luaState,oldTop); } /* * Sets a numeric field of the table or userdata corresponding the the provided reference * to the provided value */ internal void setObject(int reference, object field, object val) { int oldTop=LuaDLL.lua_gettop(luaState); LuaDLL.lua_getref(luaState,reference); translator.push(luaState,field); translator.push(luaState,val); LuaDLL.lua_settable(luaState,-3); LuaDLL.lua_settop(luaState,oldTop); } /* * Registers an object's method as a Lua function (global or table field) * The method may have any signature */ public LuaFunction RegisterFunction(string path, object target, MethodBase function /*MethodInfo function*/) //CP: Fix for struct constructor by Alexander Kappner (link: http://luaforge.net/forum/forum.php?thread_id=2859&forum_id=145) { // We leave nothing on the stack when we are done int oldTop = LuaDLL.lua_gettop(luaState); LuaMethodWrapper wrapper=new LuaMethodWrapper(translator,target,function.DeclaringType,function); translator.push(luaState,new LuaCSFunction(wrapper.call)); this[path]=translator.getObject(luaState,-1); LuaFunction f = GetFunction(path); LuaDLL.lua_settop(luaState, oldTop); return f; } /* * Compares the two values referenced by ref1 and ref2 for equality */ internal bool compareRef(int ref1, int ref2) { int top=LuaDLL.lua_gettop(luaState); LuaDLL.lua_getref(luaState,ref1); LuaDLL.lua_getref(luaState,ref2); int equal=LuaDLL.lua_equal(luaState,-1,-2); LuaDLL.lua_settop(luaState,top); return (equal!=0); } internal void pushCSFunction(LuaCSFunction function) { translator.pushFunction(luaState,function); } #region IDisposable Members public virtual void Dispose() { if (translator != null) { translator.pendingEvents.Dispose(); translator = null; } this.Close(); System.GC.Collect(); System.GC.WaitForPendingFinalizers(); } #endregion } /// /// Event codes for lua hook function /// /// /// Do not change any of the values because they must match the lua values /// /// Reinhard Ostermeier public enum EventCodes { LUA_HOOKCALL = 0, LUA_HOOKRET = 1, LUA_HOOKLINE = 2, LUA_HOOKCOUNT = 3, LUA_HOOKTAILRET = 4, } /// /// Event masks for lua hook callback /// /// /// Do not change any of the values because they must match the lua values /// /// Reinhard Ostermeier [Flags] public enum EventMasks { LUA_MASKCALL = (1 << EventCodes.LUA_HOOKCALL), LUA_MASKRET = (1 << EventCodes.LUA_HOOKRET), LUA_MASKLINE = (1 << EventCodes.LUA_HOOKLINE), LUA_MASKCOUNT = (1 << EventCodes.LUA_HOOKCOUNT), LUA_MASKALL = Int32.MaxValue, } /// /// Structure for lua debug information /// /// /// Do not change this struct because it must match the lua structure lua_debug /// /// Reinhard Ostermeier [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)] public struct LuaDebug { public EventCodes eventCode; [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)] public String name; [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)] public String namewhat; [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)] public String what; [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)] public String source; public int currentline; public int nups; public int linedefined; public int lastlinedefined; [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 60/*LUA_IDSIZE*/)] public String shortsrc; public int i_ci; } /// /// Event args for hook callback event /// /// Reinhard Ostermeier public class DebugHookEventArgs : EventArgs { private readonly LuaDebug luaDebug; public DebugHookEventArgs(LuaDebug luaDebug) { this.luaDebug = luaDebug; } public LuaDebug LuaDebug { get { return luaDebug; } } } public class HookExceptionEventArgs : EventArgs { private readonly Exception m_Exception; public Exception Exception { get { return m_Exception; } } public HookExceptionEventArgs(Exception ex) { m_Exception = ex; } } }