//returns false if game was busy public bool SaveLoadedFiles() { bool wasRunning = this.DebugEngine.CurrentState == DebugState.Running; if (wasRunning) { if (!GameLoopHook.PauseGame()) { return(false); } } string data = CreateFileString(); BBLua.lua_newtable(this.L); int i = 1; foreach (string substr in data.SplitBy(15000)) //the limit in shok seems to be at ~ 2^14, otherwise crashes savegame loading { BBLua.lua_pushstring(this.L, substr); BBLua.lua_rawseti(this.L, -2, i); i++; } BBLua.lua_setglobal(this.L, "_LuaDebugger_FileData"); if (wasRunning) { GameLoopHook.ResumeGame(); } return(true); }
protected void GetVarAndCleanG(string varName) { BBLua.lua_getglobal(ls.L, varName); //fetch value BBLua.lua_pushnil(ls.L); BBLua.lua_setglobal(ls.L, varName); //remove from _G }
protected void RegisterLogFunction() { BBLua.lua_pushstring(this.ls.L, "LuaDebugger"); BBLua.lua_newtable(this.ls.L); BBLua.lua_pushstring(this.ls.L, "Log"); BBLua.lua_pushcclosure(this.ls.L, Marshal.GetFunctionPointerForDelegate(this.logCallback), 0); BBLua.lua_rawset(this.ls.L, -3); BBLua.lua_rawset(this.ls.L, (int)LuaPseudoIndices.GLOBALSINDEX); }
protected unsafe void DebugHook(UIntPtr L, IntPtr ptr) //unsafe for speed { LuaStackRecord *sr = (LuaStackRecord *)ptr; BBLua.lua_getstack(L, 0, ptr); if (sr->debugEvent == LuaEvent.Call) { this.callStack++; } else if (sr->debugEvent == LuaEvent.Return || sr->debugEvent == LuaEvent.TailReturn) { this.callStack--; if ((this.callStack == 0) && //stepping into engine code is not possible -> resume (this.CurrentRequest == DebugRequest.StepIn || this.CurrentRequest == DebugRequest.StepToLevel)) { this.CurrentRequest = DebugRequest.Resume; this.CurrentState = DebugState.Running; FireStateChangedEvent(); } } // event == line else if (this.CurrentRequest == DebugRequest.Pause || this.CurrentRequest == DebugRequest.StepIn) { NormalBreak(); } else if (this.CurrentRequest == DebugRequest.StepToLevel && (this.callStack <= this.targetCallStackLevel)) { NormalBreak(); } // request == resume else { List <Breakpoint> bpsAtLine; if (!this.lineToBP.TryGetValue(sr->currentline, out bpsAtLine)) { return; //no breakpoints on this line } BBLua.lua_getinfo(L, "S", ptr); LuaDebugSourceRecord dr = (LuaDebugSourceRecord)Marshal.PtrToStructure(ptr, typeof(LuaDebugSourceRecord)); foreach (Breakpoint bp in bpsAtLine) { if (bp.File.Filename == dr.source) { NormalBreak(); break; } } } }
public static LuaFunctionInfo ReadFunctionInfo(LuaState ls, int level) { IntPtr memBlock = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LuaDebugRecord))); if (BBLua.lua_getstack(ls.L, level, memBlock) == 0) { return(null); } BBLua.lua_getinfo(ls.L, "nSlu", memBlock); LuaDebugRecord ldr = (LuaDebugRecord)Marshal.PtrToStructure(memBlock, typeof(LuaDebugRecord)); LuaFunctionInfo lfi = new LuaFunctionInfo(memBlock, ls, ldr.nups); if (ldr.source.Length > 1 && ldr.source[0] != '=') { lfi.Source = ldr.source; lfi.Line = ldr.currentline; } else { lfi.Source = "unavailable"; lfi.Line = 0; } if (ldr.what == "C") { lfi.FunctionName = "Game Engine (direct call)"; } else if (ldr.what == "main") { lfi.FunctionName = "Game Engine (code outside function)"; } else if (ldr.name != "" && ldr.namewhat != "") { lfi.FunctionName = ldr.namewhat + " " + ldr.name + "()"; } else if (ldr.what == "Lua" || ldr.what == "tail") { lfi.FunctionName = "Lua Code"; } if (ls.LoadedFiles.ContainsKey(lfi.Source)) { lfi.CanFakeEnvironment = true; } return(lfi); }
static int ErrorCatcher(UIntPtr L) //could be moved into DebugEngine, but this would cost perfomance to fetch the correct delegate for each pcall { string errMsg = BBLua.lua_tostring(L, -1); BBLua.lua_settop(L, -2); LuaErrorCaught callback; if (stateErrHandler.TryGetValue(L, out callback)) { callback(errMsg); } return(0); }
protected void TryFakeVar(string varName, int n, List <FakeVar> memory) { BBLua.lua_getglobal(ls.L, varName); bool fakePossible = BBLua.lua_type(ls.L, -1) == LuaType.Nil; BBLua.lua_settop(ls.L, -2); //remove nil if (fakePossible) { memory.Add(new FakeVar(n, varName)); BBLua.lua_setglobal(ls.L, varName); } else { BBLua.lua_settop(ls.L, -2); //remove value } }
//returns false if game was busy public bool RestoreLoadedFiles() { bool wasRunning = this.DebugEngine.CurrentState == DebugState.Running; if (wasRunning) { if (!GameLoopHook.PauseGame()) { return(false); } } BBLua.lua_getglobal(this.L, "_LuaDebugger_FileData"); if (BBLua.lua_type(this.L, -1) != LuaType.Table) { if (wasRunning) { GameLoopHook.ResumeGame(); } return(true); } StringBuilder sb = new StringBuilder(); for (int i = 1; ; i++) { BBLua.lua_rawgeti(this.L, -1, i); if (BBLua.lua_type(this.L, -1) != LuaType.String) { BBLua.lua_settop(this.L, -2); break; } sb.Append(BBLua.lua_tostring(this.L, -1)); BBLua.lua_settop(this.L, -2); } if (wasRunning) { GameLoopHook.ResumeGame(); } this.LoadedFiles.Clear(); RestoreFromFileString(sb.ToString()); return(true); }
static LuaResult FakePcall(UIntPtr L, int nargs, int nresults, int errfunc) { if (!GlobalState.CatchErrors) { return(BBLua.lua_pcall(L, nargs, nresults, errfunc)); } BBLua.lua_pushcclosure(L, ErrorHook.errorHandlerPtr, 0); BBLua.lua_insert(L, -nargs - 2); LuaResult res; if (nresults >= 0) { res = BBLua.lua_pcall(L, nargs, nresults, -nargs - 2); } else //LUA_MULTRET { int stackBefore = BBLua.lua_gettop(L); res = BBLua.lua_pcall(L, nargs, nresults, -nargs - 2); int stackNow = BBLua.lua_gettop(L); if (res == LuaResult.OK) { nresults = stackNow - stackBefore + nargs + 1; } else { nresults = 0; } } if (res != LuaResult.OK) { BBLua.lua_settop(L, -2); //remove errormsg for (int i = 0; i < nresults; i++) //push dummy returns, hopefully settlers accepts this { BBLua.lua_pushnil(L); } } BBLua.lua_remove(L, -nresults - 1); //remove error handler return(LuaResult.OK); }
public void FakeG() { this.fakedLocals = new List <FakeVar>(); this.fakedUpvalues = new List <FakeVar>(); if (!this.CanFakeEnvironment) { return; } string varName; BBLua.lua_getinfo(ls.L, "f", this.funcInfo); // 'f': pushes func onto stack for (int i = 1; ; i++) { varName = BBLua.lua_getupvalue(ls.L, -1, i); if (varName == null) { break; } TryFakeVar(varName, i, this.fakedUpvalues); } BBLua.lua_settop(ls.L, -2); //remove func from stack for (int i = 1; ; i++) { varName = BBLua.lua_getlocal(ls.L, this.funcInfo, i); if (varName == null) { break; } if (varName.Length > 0 && varName[0] != '(') { TryFakeVar(varName, i, this.fakedLocals); } else { BBLua.lua_settop(ls.L, -2); //remove value } } }
protected string GetTosFunctionInfo() { IntPtr memBlock = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LuaDebugRecord))); BBLua.lua_getinfo(this.L, ">nSf", memBlock); //fill structure and pop func back onto stack after removing it LuaDebugRecord ldr = (LuaDebugRecord)Marshal.PtrToStructure(memBlock, typeof(LuaDebugRecord)); Marshal.FreeHGlobal(memBlock); string source; if (ldr.what == "C") { source = "Game Engine at 0x" + BBLua.lua_tocfunction(this.L, -1).ToInt32().ToString("X"); } else { source = '\b' + ldr.source + ':' + ldr.linedefined + '\b';//" (line " + ldr.linedefined + ")"; } return("<Function, defined in " + source + ">"); }
public void UnFakeG() { if (!this.CanFakeEnvironment) { return; } BBLua.lua_getinfo(ls.L, "f", this.funcInfo); // 'f': pushes func onto stack foreach (FakeVar fv in this.fakedUpvalues) { GetVarAndCleanG(fv.VarName); string vn = BBLua.lua_setupvalue(ls.L, -2, fv.Number); } BBLua.lua_settop(ls.L, -2); //remove func foreach (FakeVar fv in this.fakedLocals) { GetVarAndCleanG(fv.VarName); string vn = BBLua.lua_setlocal(ls.L, this.funcInfo, fv.Number); } }
public static void lua_newtable(UIntPtr L) { BBLua.lua_createtable(L, 0, 0); }
public void SetHook() { BBLua.lua_sethook(this.ls.L, this.debugHook, LuaHookType.Line | LuaHookType.Call | LuaHookType.Return, 0); }
public void RemoveHook() { BBLua.lua_sethook(this.ls.L, this.debugHook, LuaHookType.Nothing, 0); }
public string TosToString(bool popStack, bool noExpand, Dictionary <IntPtr, bool> printedTables) { LuaType type = BBLua.lua_type(this.L, -1); string result; switch (type) { case LuaType.Nil: result = "nil"; break; case LuaType.Boolean: result = BBLua.lua_toboolean(this.L, -1).ToString(); break; case LuaType.Number: result = BBLua.lua_tonumber(this.L, -1).ToString(); break; case LuaType.String: result = "\"" + BBLua.lua_tostring(this.L, -1) + "\""; break; case LuaType.Function: result = GetTosFunctionInfo(); break; case LuaType.Table: if (noExpand) { goto default; } IntPtr tblPtr = BBLua.lua_topointer(this.L, -1); if (printedTables.ContainsKey(tblPtr)) { result = "<Table, recursion>"; break; } result = "{"; BBLua.lua_pushnil(this.L); while (BBLua.lua_next(this.L, -2) != 0) { printedTables.Add(tblPtr, true); string val = IndentMultiLine(TosToString(true, false, printedTables)); string key = TosToString(false, true, printedTables); printedTables.Remove(tblPtr); if (key[0] == '\"') { string rawString = key.Substring(1, key.Length - 2); if (alphaNumeric.IsMatch(rawString)) { result += "\n " + rawString + " = " + val + ","; } else { result += "\n [" + key + "] = " + val + ","; } } else { result += "\n [" + key + "] = " + val + ","; } } result += "\n}"; break; case LuaType.UserData: case LuaType.LightUserData: IntPtr ptr = BBLua.lua_touserdata(this.L, -1); result = "<" + type.ToString() + ", at 0x" + ptr.ToInt32().ToString("X") + ">"; break; default: result = "<" + type.ToString() + ">"; break; } if (popStack) { BBLua.lua_settop(this.L, -2); } return(result); }
public string EvaluateLua(string expression) { bool unfreeze = false; if (this.CurrentState == DebugState.Running) { unfreeze = true; if (!GameLoopHook.PauseGame()) { return("Error: Game is busy!"); } } this.DebugEngine.RemoveHook(); string asStatement = expression; expression = "return " + expression; string result = ""; LuaResult err = BBLua.luaL_loadbuffer(this.L, expression, expression.Length, "from console"); if (err == LuaResult.OK) { int stackTop = BBLua.lua_gettop(this.L); err = BBLua.lua_pcall(this.L, 0, -1, 0); int nResults = 1 + BBLua.lua_gettop(this.L) - stackTop; if (nResults == 1) { result = TosToString(); } else if (nResults > 1) { string[] results = new string[nResults]; do { nResults--; results[nResults] = TosToString(true); } while (nResults != 0); result = "(" + string.Join(", ", results) + ")"; } } else { string parseErrExpr = TosToString(); err = BBLua.luaL_loadbuffer(this.L, asStatement, asStatement.Length, "from console"); if (err == LuaResult.OK) { err = BBLua.lua_pcall(this.L, 0, 0, 0); //statement -> no return values } if (err != LuaResult.OK) { result = TosToString(); } } this.DebugEngine.SetHook(); if (unfreeze) { GameLoopHook.ResumeGame(); } return(result); }
public static void lua_setglobal(UIntPtr L, string name) { BBLua.lua_pushstring(L, name); BBLua.lua_insert(L, -2); BBLua.lua_rawset(L, (int)LuaPseudoIndices.GLOBALSINDEX); }