From 569221d047f39cc409fe37940bf857719b7bb213 Mon Sep 17 00:00:00 2001 From: Raimon Zamora Date: Thu, 2 Apr 2026 13:26:52 +0200 Subject: [PATCH] =?UTF-8?q?-=20[WIP]=20Est=C3=A1=20tot=20patas=20arriba=20?= =?UTF-8?q?ara...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/lua.cpp | 2328 ++++++++---------------------------------- source/lua.debug.cpp | 1361 ++++++++++++++++++++++++ source/lua.debug.h | 17 + source/lua.h | 25 +- source/main.cpp | 14 +- source/mini.cpp | 1258 ++++++++++++----------- source/mini.h | 230 ++--- 7 files changed, 2558 insertions(+), 2675 deletions(-) create mode 100644 source/lua.debug.cpp create mode 100644 source/lua.debug.h diff --git a/source/lua.cpp b/source/lua.cpp index 18f84ed..245c4ff 100644 --- a/source/lua.cpp +++ b/source/lua.cpp @@ -1,5 +1,6 @@ #include "lua.h" #include "lua/lua.hpp" +#include "lua.debug.h" #include "mini.h" #include "jfile.h" #include "log.h" @@ -17,1271 +18,41 @@ #include #include -struct Breakpoint { - int line; - std::string condition; // puede estar vacío - std::string logMessage; // "" si no es logpoint - std::string hitCondition; // "" si no hay hit count -}; -struct FrameInfo { - int level; // nivel en lua_getstack - std::string source; - int line; - //std::vector locals; - //std::vector upvalues; -}; +//extern "C" { -struct StackFrameInfo { - std::string file; - int line; - std::string function; -}; -std::string lastExceptionTraceback; -std::vector lastExceptionStack; -std::string lastExceptionMessage; -bool hasException = false; - -std::set exceptionFilters;// {"all"}; -std::vector g_frames; - -lua_State *L; -bool is_playing = false; -bool init_exists = false; -bool update_exists = false; - -//std::unordered_map> g_breakpoints; -std::unordered_map> g_breakpoints; -std::mutex g_breakMutex; - -std::queue g_debugCommands; -std::mutex g_cmdMutex; - -std::atomic g_running = true; -std::atomic g_paused = false; - -std::string g_pauseFile; -int g_pauseLine = 0; -bool function_has_breakpoints = false; -std::stack funBreakStack; -bool debug_enabled = true; - -enum StepMode { - STEP_NONE, - STEP_INTO, - STEP_OVER, - STEP_OUT -}; - -StepMode g_stepMode = STEP_NONE; -int g_stepDepth = 0; - -namespace fs = std::filesystem; -using json = nlohmann::json; - -std::string pathToChunk(const std::string& path) { - std::filesystem::path p(path); - - // 1. Normalizar la ruta - p = p.lexically_normal(); - - // 2. Buscar el directorio "data" - auto it = std::find(p.begin(), p.end(), "data"); - if (it == p.end()) - return ""; // no es un script Lua válido - - // 3. Construir la parte relativa después de "data" - std::filesystem::path rel; - for (++it; it != p.end(); ++it) - rel /= *it; - - // 4. Quitar ".lua" - std::string s = rel.string(); - if (s.ends_with(".lua")) - s = s.substr(0, s.size() - 4); - - // 5. Convertir "/" → "." - for (char& c : s) - if (c == '/') - c = '.'; - - return s; -} - -std::string chunkToPath(const std::string& chunk) { - // 1. Convertir "ia.test" → "ia/test" - std::string rel; - rel.reserve(chunk.size() + 10); - - for (char c : chunk) - rel += (c == '.' ? '/' : c); - - // 2. Añadir prefijo y sufijo - rel = "data/" + rel + ".lua"; - - // 3. Convertir a ruta absoluta - std::filesystem::path abs = std::filesystem::current_path() / rel; - - return abs.lexically_normal().string(); -} - -int getStackDepth(lua_State* L) { - lua_Debug ar; - int depth = 0; - - while (lua_getstack(L, depth, &ar)) { - depth++; - } - - return depth; -} - -json getStackTrace(lua_State* L) { - json frames = json::array(); - lua_Debug ar; - - int depth = 0; - while (lua_getstack(L, depth, &ar)) { - lua_getinfo(L, "nSl", &ar); - - //const char* src = chunkToPath(ar.source).c_str(); - - json frame = { - { "file", chunkToPath(ar.source).c_str() }, - { "line", ar.currentline }, - { "name", ar.name ? ar.name : "?" } - }; - - frames.push_back(frame); - depth++; - } - - return json{ - { "frames", frames } - }; -} - -int allocateRefForTable(lua_State* L, int index) { - lua_pushvalue(L, index); // copia la tabla - int ref = luaL_ref(L, LUA_REGISTRYINDEX); - return ref; -} - -bool pushTableFromRef(lua_State* L, int ref) { - lua_rawgeti(L, LUA_REGISTRYINDEX, ref); - - if (!lua_istable(L, -1)) { - lua_pop(L, 1); - return false; - } - - return true; -} - -json getLocals(lua_State* L, int frame) { - json vars = json::array(); - - lua_Debug ar; - // Obtenemos el frame solicitado - if (!lua_getstack(L, frame, &ar)) { - printf("INVALID STACK FRAME\n"); - return json{ {"variables", vars} }; - } - - // Pedimos info del frame - lua_getinfo(L, "nSl", &ar); - - int i = 1; - const char* name; - - while ((name = lua_getlocal(L, &ar, i)) != NULL) { - - if (strcmp(name, "(temporary)") == 0) { - lua_pop(L, 1); - i++; - continue; - } - - json v; - v["name"] = name; - - int type = lua_type(L, -1); - - switch (type) { - case LUA_TNUMBER: - v["value"] = std::to_string(lua_tonumber(L, -1)); - v["type"] = "number"; - v["ref"] = 0; - break; - - case LUA_TBOOLEAN: - v["value"] = lua_toboolean(L, -1) ? "true" : "false"; - v["type"] = "boolean"; - v["ref"] = 0; - break; - - case LUA_TSTRING: - v["value"] = lua_tostring(L, -1); - v["type"] = "string"; - v["ref"] = 0; - break; - - case LUA_TTABLE: - v["value"] = "{table}"; - v["type"] = "table"; - v["ref"] = allocateRefForTable(L, -1); - break; - - case LUA_TFUNCTION: - v["value"] = "function"; - v["type"] = "function"; - v["ref"] = 0; - break; - - case LUA_TNIL: - v["value"] = "nil"; - v["type"] = "nil"; - v["ref"] = 0; - break; - - default: - v["value"] = lua_typename(L, type); - v["type"] = lua_typename(L, type); - v["ref"] = 0; - break; - } - - vars.push_back(v); - - // Quitamos el valor de la pila - lua_pop(L, 1); - - i++; - } - - return json{ - { "variables", vars } - }; -} - -json getUpvalues(lua_State* L, int frame) { - json vars = json::array(); - - lua_Debug ar; - if (!lua_getstack(L, frame, &ar)) { - return json{ {"variables", vars} }; - } - - // Pedimos info del frame, incluyendo la función ("f") - lua_getinfo(L, "nSlf", &ar); - - // La función está ahora en la pila - int funcIndex = lua_gettop(L); - - int i = 1; - const char* name; - - while ((name = lua_getupvalue(L, funcIndex, i)) != NULL) { - json v; - v["name"] = name; - - int type = lua_type(L, -1); - - switch (type) { - case LUA_TNUMBER: - v["value"] = std::to_string(lua_tonumber(L, -1)); - v["type"] = "number"; - v["ref"] = 0; - break; - - case LUA_TBOOLEAN: - v["value"] = lua_toboolean(L, -1) ? "true" : "false"; - v["type"] = "boolean"; - v["ref"] = 0; - break; - - case LUA_TSTRING: - v["value"] = lua_tostring(L, -1); - v["type"] = "string"; - v["ref"] = 0; - break; - - case LUA_TTABLE: - v["value"] = "{table}"; - v["type"] = "table"; - v["ref"] = allocateRefForTable(L, -1); - break; - - case LUA_TNIL: - v["value"] = "nil"; - v["type"] = "nil"; - v["ref"] = 0; - break; - - default: - v["value"] = lua_typename(L, type); - v["type"] = lua_typename(L, type); - v["ref"] = 0; - break; - } - - vars.push_back(v); - - lua_pop(L, 1); // quitamos el valor del upvalue - i++; - } - - // Quitamos la función del stack - lua_pop(L, 1); - - return json{ - { "variables", vars } - }; -} - -json getGlobals(lua_State* L) { - json vars = json::array(); - - // Empujamos _G a la pila - lua_pushglobaltable(L); // equivalente a lua_getglobal(L, "_G") - - lua_pushnil(L); // primera clave - while (lua_next(L, -2) != 0) { - // Ahora en la pila: - // -1 → valor - // -2 → clave - // -3 → _G - - // Solo aceptamos claves string - if (lua_type(L, -2) == LUA_TSTRING) { - const char* name = lua_tostring(L, -2); - - json v; - v["name"] = name; - - int type = lua_type(L, -1); - - switch (type) { - case LUA_TNUMBER: - v["value"] = std::to_string(lua_tonumber(L, -1)); - v["type"] = "number"; - v["ref"] = 0; - break; - - case LUA_TBOOLEAN: - v["value"] = lua_toboolean(L, -1) ? "true" : "false"; - v["type"] = "boolean"; - v["ref"] = 0; - break; - - case LUA_TSTRING: - v["value"] = lua_tostring(L, -1); - v["type"] = "string"; - v["ref"] = 0; - break; - - case LUA_TTABLE: - v["value"] = "{table}"; - v["type"] = "table"; - v["ref"] = allocateRefForTable(L, -1); - break; - - case LUA_TFUNCTION: - v["value"] = "function"; - v["type"] = "function"; - v["ref"] = 0; - break; - - case LUA_TNIL: - v["value"] = "nil"; - v["type"] = "nil"; - v["ref"] = 0; - break; - - default: - v["value"] = lua_typename(L, type); - v["type"] = lua_typename(L, type); - v["ref"] = 0; - break; - } - - vars.push_back(v); - } - - lua_pop(L, 1); // pop valor, deja clave para lua_next - } - - lua_pop(L, 1); // pop _G - - return json{ - { "variables", vars } - }; -} - -json expandTable(lua_State* L, int ref) { - json vars = json::array(); - - // Recuperamos la tabla del registry - lua_rawgeti(L, LUA_REGISTRYINDEX, ref); - - lua_pushnil(L); - while (lua_next(L, -2) != 0) { - json v; - - // clave - if (lua_type(L, -2) == LUA_TSTRING) { - v["name"] = lua_tostring(L, -2); - } else if (lua_type(L, -2) == LUA_TNUMBER) { - v["name"] = std::to_string(lua_tonumber(L, -2)); - } else { - v["name"] = ""; - } - - // valor - int type = lua_type(L, -1); - - switch (type) { - case LUA_TNUMBER: - v["value"] = std::to_string(lua_tonumber(L, -1)); - v["type"] = "number"; - v["ref"] = 0; - break; - - case LUA_TBOOLEAN: - v["value"] = lua_toboolean(L, -1) ? "true" : "false"; - v["type"] = "boolean"; - v["ref"] = 0; - break; - - case LUA_TSTRING: - v["value"] = lua_tostring(L, -1); - v["type"] = "string"; - v["ref"] = 0; - break; - - case LUA_TTABLE: - v["value"] = "{table}"; - v["type"] = "table"; - v["ref"] = allocateRefForTable(L, -1); - break; - - default: - v["value"] = lua_typename(L, type); - v["type"] = lua_typename(L, type); - v["ref"] = 0; - break; - } - - vars.push_back(v); - - lua_pop(L, 1); // pop valor - } - - lua_pop(L, 1); // pop tabla - - return json{ - { "kind", "expand" }, - { "variables", vars } - }; -} - -json setVariable(lua_State* L, int frame, const std::string& scope, - const std::string& name, const std::string& valueStr) +namespace mini { - lua_Debug ar; - - if (!lua_getstack(L, frame, &ar)) { - return { {"error", "invalid frame"} }; - } - - lua_getinfo(L, "nSl", &ar); - - // Convertir valueStr a valor Lua - auto pushValue = [&](const std::string& s) { - // número - char* end; - double num = strtod(s.c_str(), &end); - if (*end == '\0') { - lua_pushnumber(L, num); - return; - } - - // boolean - if (s == "true") { lua_pushboolean(L, 1); return; } - if (s == "false") { lua_pushboolean(L, 0); return; } - - // nil - if (s == "nil") { lua_pushnil(L); return; } - - // string - lua_pushstring(L, s.c_str()); - }; - - if (scope == "locals") { - int i = 1; - const char* localName; - while ((localName = lua_getlocal(L, &ar, i)) != NULL) { - lua_pop(L, 1); // pop old value - - if (name == localName) { - pushValue(valueStr); - lua_setlocal(L, &ar, i); - return { {"value", valueStr} }; - } - - i++; - } - } - - if (scope == "upvalues") { - lua_getinfo(L, "f", &ar); // push function - - int i = 1; - const char* upName; - while ((upName = lua_getupvalue(L, -1, i)) != NULL) { - lua_pop(L, 1); // pop old value - - if (name == upName) { - pushValue(valueStr); - lua_setupvalue(L, -1, i); - lua_pop(L, 1); // pop function - return { {"value", valueStr} }; - } - - i++; - } - - lua_pop(L, 1); // pop function - } - - if (scope == "globals") { - pushValue(valueStr); - lua_setglobal(L, name.c_str()); - return { {"value", valueStr} }; - } - - return { {"error", "variable not found"} }; -} - -json setTableField(lua_State* L, int ref, const std::string& key, const std::string& valueStr) -{ - // Recuperar la tabla desde tu sistema de referencias - if (!pushTableFromRef(L, ref)) { - return { {"error", "invalid table ref"} }; - } - - // Convertir el valor - auto pushValue = [&](const std::string& s) { - char* end; - double num = strtod(s.c_str(), &end); - if (*end == '\0') { lua_pushnumber(L, num); return; } - if (s == "true") { lua_pushboolean(L, 1); return; } - if (s == "false") { lua_pushboolean(L, 0); return; } - if (s == "nil") { lua_pushnil(L); return; } - lua_pushstring(L, s.c_str()); - }; - - pushValue(valueStr); - - // tabla[key] = valor - lua_setfield(L, -2, key.c_str()); - - lua_pop(L, 1); // pop tabla - - return { {"value", valueStr} }; -} - -json evalExpression(lua_State* L, const std::string& expr) { - lua_Debug ar; - if (!lua_getstack(L, 0, &ar)) { - return { {"error", "no stack"} }; - } - - lua_getinfo(L, "nSl", &ar); - - // Creamos un entorno para la evaluación - lua_newtable(L); // env - int envIndex = lua_gettop(L); - - // 1. Copiar locals al env - int i = 1; - const char* name; - while ((name = lua_getlocal(L, &ar, i)) != NULL) { - lua_setfield(L, envIndex, name); - i++; - } - - // 2. Copiar upvalues al env - lua_getinfo(L, "f", &ar); - int funcIndex = lua_gettop(L); - - i = 1; - while ((name = lua_getupvalue(L, funcIndex, i)) != NULL) { - lua_setfield(L, envIndex, name); - i++; - } - - lua_pop(L, 1); // pop función - - // 3. Copiar globals (_G) - lua_pushglobaltable(L); - lua_setfield(L, envIndex, "_G"); - // mt = { __index = _G } - lua_newtable(L); // mt - lua_pushglobaltable(L); // _G - lua_setfield(L, -2, "__index"); // mt.__index = _G - - // setmetatable(env, mt) - lua_setmetatable(L, envIndex); - - // 4. Construir código: función que recibe _ENV - std::string code = "return function(_ENV) return " + expr + " end"; - - if (luaL_loadbuffer(L, code.c_str(), code.size(), "eval") != LUA_OK) { - std::string err = lua_tostring(L, -1); - lua_pop(L, 1); - return { {"error", err} }; - } - - // Ejecutar para obtener la función interna - if (lua_pcall(L, 0, 1, 0) != LUA_OK) { - std::string err = lua_tostring(L, -1); - lua_pop(L, 1); - return { {"error", err} }; - } - - // Ahora en la pila está la función interna - // Le pasamos env como argumento - lua_pushvalue(L, envIndex); - - // Llamamos a la función(env) - if (lua_pcall(L, 1, 1, 0) != LUA_OK) { - std::string err = lua_tostring(L, -1); - lua_pop(L, 1); - return { {"error", err} }; - } - - // Convertir el resultado - json result; - - int type = lua_type(L, -1); - switch (type) { - case LUA_TNUMBER: - result["value"] = std::to_string(lua_tonumber(L, -1)); - result["type"] = "number"; - result["ref"] = 0; - break; - - case LUA_TBOOLEAN: - result["value"] = lua_toboolean(L, -1) ? "true" : "false"; - result["type"] = "boolean"; - result["ref"] = 0; - break; - - case LUA_TSTRING: - result["value"] = lua_tostring(L, -1); - result["type"] = "string"; - result["ref"] = 0; - break; - - case LUA_TTABLE: - result["value"] = "{table}"; - result["type"] = "table"; - result["ref"] = allocateRefForTable(L, -1); - break; - - default: - result["value"] = lua_typename(L, type); - result["type"] = lua_typename(L, type); - result["ref"] = 0; - break; - } - - lua_pop(L, 1); // pop result - lua_pop(L, 1); // pop env - - return result; -} - -json evalAssign(lua_State* L, int frame, const std::string& expr) { - // 1. Separar LHS y RHS - size_t eq = expr.find('='); - if (eq == std::string::npos) { - return { {"error", "not an assignment"} }; - } - - std::string lhs = expr.substr(0, eq); - std::string rhs = expr.substr(eq + 1); - - // limpiar espacios - auto trim = [](std::string& s) { - size_t a = s.find_first_not_of(" \t"); - size_t b = s.find_last_not_of(" \t"); - if (a == std::string::npos) { s = ""; return; } - s = s.substr(a, b - a + 1); - }; - - trim(lhs); - trim(rhs); - - // 2. Evaluar RHS usando tu evalExpression - json rhsValue = evalExpression(L, rhs); - if (rhsValue.contains("error")) { - return rhsValue; - } - - std::string rhsStr = rhsValue["value"]; - - // 3. Determinar si LHS es: - // - variable simple: x - // - acceso tabla: player.health - // - acceso profundo: a.b.c - if (lhs.find('.') == std::string::npos) { - // variable simple → locals, upvalues o globals - // Intentar locals - json r = setVariable(L, frame, "locals", lhs, rhsStr); - if (!r.contains("error")) return r; - - // Intentar upvalues - r = setVariable(L, frame, "upvalues", lhs, rhsStr); - if (!r.contains("error")) return r; - - // Intentar globals - r = setVariable(L, frame, "globals", lhs, rhsStr); - return r; - } - - // 4. Acceso tabla: a.b.c - // separar en partes - std::vector parts; + namespace lua { - std::stringstream ss(lhs); - std::string item; - while (std::getline(ss, item, '.')) { - trim(item); - parts.push_back(item); - } - } + lua_State *L; + bool is_playing = false; + bool init_exists = false; + bool update_exists = false; - if (parts.size() < 2) { - return { {"error", "invalid table assignment"} }; - } - - // La clave final - std::string finalKey = parts.back(); - parts.pop_back(); - - // 5. Evaluar la ruta de tabla (a.b.c → obtener tabla c) - // usando tu evalExpression - std::string tableExpr; - for (size_t i = 0; i < parts.size(); i++) { - if (i > 0) tableExpr += "."; - tableExpr += parts[i]; - } - - json tableValue = evalExpression(L, tableExpr); - if (tableValue.contains("error")) { - return tableValue; - } - - if (tableValue["type"] != "table") { - return { {"error", "LHS is not a table"} }; - } - - int ref = tableValue["ref"]; - - // 6. Asignar dentro de la tabla - return setTableField(L, ref, finalKey, rhsStr); -} - -void sendDebugResponse(const std::string& type, const json& payload) { - json msg = { - { "type", type }, - { "payload", payload } - }; - //printf("STACKTRACE: %s", msg.dump().c_str()); - std::cout << "@@DEBUG@@" << msg.dump() << std::endl; -} - -void parseLuaTraceback(const char* tb, std::vector& out) { - out.clear(); - if (!tb) return; - - std::stringstream ss(tb); - std::string line; - - bool inFrames = false; - - while (std::getline(ss, line)) { - // Quitar espacios iniciales y tabs - while (!line.empty() && (line[0] == ' ' || line[0] == '\t')) - line.erase(line.begin()); - - // Saltar la primera línea (mensaje de error) - if (!inFrames) { - if (line.rfind("stack traceback:", 0) == 0) { - inFrames = true; - } - continue; - } - - // Formato esperado: - // [string "modules.ia.hero"]:189: in field 'ia' - // - // O: - // [string "main"]:34: in function <[string "main"]:32> - - if (line.rfind("[string \"", 0) != 0) - continue; - - // Extraer chunk name - size_t q1 = line.find('"'); - size_t q2 = line.find('"', q1 + 1); - if (q1 == std::string::npos || q2 == std::string::npos) - continue; - - std::string chunk = line.substr(q1 + 1, q2 - q1 - 1); - - // Extraer línea - size_t colon1 = line.find(':', q2 + 1); - if (colon1 == std::string::npos) - continue; - - size_t colon2 = line.find(':', colon1 + 1); - if (colon2 == std::string::npos) - continue; - - int lineNumber = std::stoi(line.substr(colon1 + 1, colon2 - colon1 - 1)); - - // Extraer nombre de función (si existe) - std::string func = "unknown"; - - size_t inField = line.find("in field '"); - if (inField != std::string::npos) { - size_t start = inField + 10; - size_t end = line.find("'", start); - func = line.substr(start, end - start); - } - - size_t inFunc = line.find("in function <"); - if (inFunc != std::string::npos) { - func = "anonymous"; - } - - // Convertir chunk → ruta real - std::string filePath = chunkToPath(chunk); - - out.push_back({ filePath, lineNumber, func }); - } -} - -void processDebugCommand(const std::string& line) { - //printf("COMANDO PROCESADO: %s\n", line.c_str()); - if (!line.starts_with("@@DEBUGCMD@@")) - return; - - json j = json::parse(line.substr(12)); - - std::string cmd = j["cmd"]; - - if (cmd == "setBreakpoints") { - std::string file = j["file"]; - std::string chunk = pathToChunk(file); - std::lock_guard lock(g_breakMutex); - - g_breakpoints[chunk].clear(); - - for (auto& bp : j["breakpoints"]) { - Breakpoint b; - b.line = bp["line"]; - - if (bp.contains("condition") && bp["condition"].is_string()) - b.condition = bp["condition"]; - else - b.condition = ""; - - if (bp.contains("logMessage") && bp["logMessage"].is_string()) - b.logMessage = bp["logMessage"]; - else - b.logMessage = ""; - - if (bp.contains("hitCondition") && bp["hitCondition"].is_string()) - b.hitCondition = bp["hitCondition"]; - else - b.hitCondition = ""; - - g_breakpoints[chunk].push_back(b); - } - } - else if (cmd == "continue") { - printf("CONTINUA\n\n"); - g_stepMode = STEP_NONE; - g_paused = false; - raisewindow(); - } - else if (cmd == "pause") { - g_stepMode = STEP_INTO; - g_paused = false; - } - else if (cmd == "stepOver") { - g_stepMode = STEP_OVER; - g_stepDepth = getStackDepth(L); - g_paused = false; - } - else if (cmd == "stepInto") { - g_stepMode = STEP_INTO; - g_paused = false; - } - else if (cmd == "stepOut") { - g_stepMode = STEP_OUT; - g_stepDepth = getStackDepth(L); - g_paused = false; - } - else if (cmd == "stackTrace") { - if (hasException) { - parseLuaTraceback(lastExceptionTraceback.c_str(), lastExceptionStack); - - json frames = json::array(); - - for (size_t i = 0; i < lastExceptionStack.size(); i++) { - frames.push_back({ - { "id", (int)i + 1 }, - { "name", lastExceptionStack[i].function }, - { "line", lastExceptionStack[i].line }, - { "column", 1 }, - { "source", { - { "path", lastExceptionStack[i].file } - }} - }); - } - - json result = { - { "stackFrames", frames }, - { "totalFrames", frames.size() } - }; - - sendDebugResponse("stackTrace", result); - } else { - json result = getStackTrace(L); - sendDebugResponse("stackTrace", result); - } - } - else if (cmd == "locals") { - int frame = j.value("frame", 0); - json result = getLocals(L, frame); - json payload = { - { "kind", "locals" }, - { "variables", result["variables"] } - }; - sendDebugResponse("variables", payload); - } - else if (cmd == "upvalues") { - int frame = j.value("frame", 0); - json result = getUpvalues(L, frame); - json payload = { - { "kind", "upvalues" }, - { "variables", result["variables"] } - }; - sendDebugResponse("variables", payload); - } - else if (cmd == "globals") { - json result = getGlobals(L); - json payload = { - { "kind", "globals" }, - { "variables", result["variables"] } - }; - sendDebugResponse("variables", payload); - } - else if (cmd == "expand") { - int ref = j["ref"]; - json result = expandTable(L, ref); - sendDebugResponse("variables", result); - } - else if (cmd == "eval") { - std::string expr = j["expr"]; - json result = evalExpression(L, expr); - - json payload = { - { "kind", "eval" }, - { "result", result } - }; - sendDebugResponse("eval", payload); - } - else if (cmd == "evalAssign") { - int frame = j.value("frame", 0); - std::string expr = j["expr"]; - - json result = evalAssign(L, frame, expr); - - json payload = { - { "kind", "eval" }, - { "result", result } - }; - - sendDebugResponse("eval", payload); - } - else if (cmd == "setVariable") { - int frame = j.value("frame", 0); - std::string scope = j["scope"]; - std::string name = j["name"]; - std::string value = j["value"]; - - json result = setVariable(L, frame, scope, name, value); - - sendDebugResponse("setVariable", result); - } - else if (cmd == "setTableField") { - int ref = j["ref"]; - std::string key = j["key"]; - std::string valueStr = j["value"]; - - json result = setTableField(L, ref, key, valueStr); - - sendDebugResponse("setVariable", result); - } - else if (cmd == "setExceptionFilters") { - exceptionFilters.clear(); - for (auto& f : j["filters"]) { - exceptionFilters.insert(f.get()); - } - } -} - -bool checkBreakpointCondition(lua_State* L, const Breakpoint& bp) { - if (bp.condition.empty()) return true; - - json result = evalExpression(L, bp.condition); - if (result.contains("error")) return false; - if (result["type"] == "boolean") return result["value"] == "true"; - - // Si la condición no devuelve booleano, se considera false - return false; -} - -std::string expandLogMessage(lua_State* L, const std::string& msg) { - std::string out; - size_t i = 0; - - while (i < msg.size()) { - if (msg[i] == '{') { - size_t j = msg.find('}', i + 1); - if (j == std::string::npos) break; - - std::string expr = msg.substr(i + 1, j - i - 1); - - json r = evalExpression(L, expr); - out += r.value("value", "nil"); - - i = j + 1; - } else { - out += msg[i++]; - } - } - - return out; -} - -void sendLogOutput(const std::string& text) { - json payload = { - { "kind", "log" }, - { "text", text } - }; - sendDebugResponse("log", payload); -} - -bool isBreakpoint(const std::string& file, int line) { - std::lock_guard lock(g_breakMutex); - - auto it = g_breakpoints.find(file); - if (it == g_breakpoints.end()) - return false; - - for (auto& bp : it->second) { - if (bp.line == line) { - if (!bp.logMessage.empty()) { - std::string msg = expandLogMessage(L, bp.logMessage); - sendLogOutput(msg); - return false; // NO parar - } else if (checkBreakpointCondition(L, bp)) { - return true; - } - - } - } - - return false; -} - -void sendBreakEvent(const std::string& file, int line) { - json j = { - {"type", "break"}, - {"file", file}, - {"line", line} - }; - - std::cout << "@@DEBUG@@" << j.dump() << std::endl; - std::cout.flush(); -} - -std::string waitForDebugCommand() { - //printf("HOLA"); - while (true) { + namespace wrappers { - std::lock_guard lock(g_cmdMutex); - if (!g_debugCommands.empty()) { - std::string cmd = g_debugCommands.front(); - g_debugCommands.pop(); - return cmd; - } - } + namespace surf + { + static int create(lua_State *L) { + int w = luaL_checknumber(L, 1); + int h = luaL_checknumber(L, 2); + uint8_t s = newsurf(w, h); + if (s==255) { + luaL_error(L, "Error while creating new surface: Max surfaces reached"); + return 0; + } + lua_pushinteger(L, s); + return 1; + } - SDL_Delay(1); - } -} - -/*void debugCommandThread() { - std::string line; - - while (true) { - if (!std::getline(std::cin, line)) { - break; // stdin cerrado - } - - if (!g_running) - break; - - std::lock_guard lock(g_cmdMutex); - g_debugCommands.push(line); - } -}*/ - -bool shouldPauseForStepping(lua_State* L, lua_Debug* ar) { - int depth = getStackDepth(L); - - switch (g_stepMode) { - case STEP_INTO: - return true; // siempre parar en la siguiente línea - - case STEP_OVER: - return depth <= g_stepDepth; - - case STEP_OUT: - return depth < g_stepDepth; - - default: - return false; - } -} - -void captureStack(lua_State* L) { - g_frames.clear(); - - lua_Debug ar; - int level = 0; - - while (lua_getstack(L, level, &ar)) { - lua_getinfo(L, "nSl", &ar); - - FrameInfo fi; - fi.level = level; - fi.source = ar.source; - fi.line = ar.currentline; - - g_frames.push_back(fi); - level++; - } -} - -void pauseHere(const std::string& src, int line) { - g_paused = true; - g_pauseFile = src; - g_pauseLine = line; - g_stepMode = STEP_NONE; - - captureStack(L); - - sendBreakEvent(chunkToPath(src), line); - - while (g_paused) { - std::string cmd = waitForDebugCommand(); - processDebugCommand(cmd); - } -} - -extern "C" void luaHook(lua_State* L, lua_Debug* ar) { - lua_getinfo(L, "Sl", ar); - - const char* src = ar->source; - if (src[0]=='=') return; - - if (ar->event == LUA_HOOKCALL) { - funBreakStack.push(function_has_breakpoints); - bool new_function_has_breakpoints = false; - { - std::lock_guard lock(g_breakMutex); - auto it = g_breakpoints.find(src); - new_function_has_breakpoints = (it != g_breakpoints.end() && !it->second.empty()); - } - if (new_function_has_breakpoints || g_stepMode != STEP_NONE) { - if (!function_has_breakpoints) - lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKLINE | LUA_MASKRET, 0); - } else { - //if (function_has_breakpoints) - lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKRET, 0); - } - function_has_breakpoints = new_function_has_breakpoints; - } - else if (ar->event == LUA_HOOKRET) { - // Siempre volver al hook base - bool new_function_has_breakpoints = funBreakStack.empty() ? false : funBreakStack.top(); - funBreakStack.pop(); - if (new_function_has_breakpoints || g_stepMode != STEP_NONE) { - if (!function_has_breakpoints) - lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKLINE | LUA_MASKRET, 0); - } else { - //if (function_has_breakpoints) - lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKRET, 0); - } - function_has_breakpoints = new_function_has_breakpoints; - } - else if (ar->event == LUA_HOOKLINE) { - if (ar->currentline <= 0) return; - const char* src = ar->source; - int line = ar->currentline; - - if (isBreakpoint(src, line)) { - pauseHere(src, line); - return; - } - - // 2. Stepping - if (g_stepMode != STEP_NONE) { - if (shouldPauseForStepping(L, ar)) { - pauseHere(src, line); - return; } } } } - -extern "C" { - - uint32_t last_update = 0; - float delta_time = 0.0f; // surface // =============================================== - static int cpp_surf_new(lua_State *L) { - int w = luaL_checknumber(L, 1); - int h = luaL_checknumber(L, 2); - uint8_t s = newsurf(w, h); - if (s==255) { - luaL_error(L, "Error while creating new surface: Max surfaces reached"); - return 0; - } - lua_pushinteger(L, s); - return 1; - } static int cpp_surf_load(lua_State *L) { const char* str = luaL_checkstring(L, 1); @@ -1406,32 +177,6 @@ extern "C" { // map // =============================================== - /* - static int cpp_map_new(lua_State *L) { - int w = luaL_checknumber(L, 1); - int h = luaL_checknumber(L, 2); - uint8_t s = newsurf(w, h); - uint8_t old = getmap(); if (old) freesurf(old); - setmap(s); - return 0; - } - - static int cpp_map_load(lua_State *L) { - const char* str = luaL_checkstring(L, 1); - uint8_t s = loadsurf(str); - uint8_t old = getmap(); if (old) freesurf(old); - setmap(s); - return 0; - } - - static int cpp_map_save(lua_State *L) { - uint8_t surface = getmap(); - const char* str = luaL_checkstring(L, 1); - savesurf(surface, str, nullptr); - return 0; - } - */ - static int cpp_map_surf(lua_State *L) { if (lua_gettop(L)==1) { uint8_t surface = luaL_checkinteger(L, 1); @@ -1445,16 +190,7 @@ extern "C" { } static int cpp_map_draw(lua_State *L) { - /*uint8_t celx = luaL_checknumber(L, 1); - uint8_t cely = luaL_checknumber(L, 2); - int sx = luaL_checknumber(L, 3); - int sy = luaL_checknumber(L, 4); - uint8_t celw = luaL_checknumber(L, 5); - uint8_t celh = luaL_checknumber(L, 6); - uint8_t layer = luaL_optinteger(L, 7, 0);*/ - //uint8_t surface = luaL_checkinteger(L, 1); - //setsource(surface); - map(); //celx, cely, sx, sy, celw, celh, layer); + map(); return 0; } @@ -1637,28 +373,13 @@ extern "C" { } - // draw - // =============================================== - - /*static int cpp_draw_pen(lua_State *L) { - uint8_t col = luaL_optinteger(L, 1, 6); - color(col); - return 0; - } - - static int cpp_draw_paper(lua_State *L) { - uint8_t col = luaL_optinteger(L, 1, 6); - bcolor(col); - return 0; - }*/ - static int cpp_draw_line(lua_State *L) { int x0 = luaL_checknumber(L, 1); int y0 = luaL_checknumber(L, 2); int x1 = luaL_checknumber(L, 3); int y1 = luaL_checknumber(L, 4); uint8_t color = luaL_checkinteger(L, 5); - line(x0, y0, x1, y1, color); + mini::draw::line(x0, y0, x1, y1, color); return 0; } @@ -1667,7 +388,7 @@ extern "C" { int y = luaL_checknumber(L, 2); int x1 = luaL_checknumber(L, 3); uint8_t color = luaL_checkinteger(L, 4); - hline(x0, y, x1, color); + mini::draw::hline(x0, y, x1, color); return 0; } @@ -1676,7 +397,7 @@ extern "C" { int y0 = luaL_checknumber(L, 2); int y1 = luaL_checknumber(L, 3); uint8_t color = luaL_checkinteger(L, 4); - vline(x, y0, y1, color); + mini::draw::vline(x, y0, y1, color); return 0; } @@ -1686,7 +407,7 @@ extern "C" { int w = luaL_checknumber(L, 3); int h = luaL_checknumber(L, 4); uint8_t color = luaL_checkinteger(L, 5); - rect(x, y, w, h, color); + mini::draw::rect(x, y, w, h, color); return 0; } @@ -1696,7 +417,7 @@ extern "C" { int w = luaL_checknumber(L, 3); int h = luaL_checknumber(L, 4); uint8_t color = luaL_checkinteger(L, 5); - rectfill(x, y, w, h, color); + mini::draw::rectf(x, y, w, h, color); return 0; } @@ -1705,7 +426,7 @@ extern "C" { int y = luaL_checknumber(L, 2); int r = luaL_optnumber(L, 3, 4); uint8_t color = luaL_checkinteger(L, 4); - circ(x, y, r, color); + mini::draw::circ(x, y, r, color); return 0; } @@ -1714,7 +435,7 @@ extern "C" { int y = luaL_checknumber(L, 2); int r = luaL_optnumber(L, 3, 4); uint8_t color = luaL_checkinteger(L, 4); - circfill(x, y, r, color); + mini::draw::circf(x, y, r, color); return 0; } @@ -1725,7 +446,7 @@ extern "C" { int h = luaL_checknumber(L, 4); int r = luaL_optnumber(L, 5, 4); uint8_t color = luaL_checkinteger(L, 6); - roundrect(x, y, w, h, r, color); + mini::draw::roundrect(x, y, w, h, r, color); return 0; } @@ -1736,7 +457,7 @@ extern "C" { int h = luaL_checknumber(L, 4); int r = luaL_optnumber(L, 5, 4); uint8_t color = luaL_checkinteger(L, 6); - roundrectfill(x, y, w, h, r, color); + mini::draw::roundrectf(x, y, w, h, r, color); return 0; } @@ -1746,7 +467,7 @@ extern "C" { int x1 = luaL_checknumber(L, 3); int y1 = luaL_checknumber(L, 4); uint8_t color = luaL_checkinteger(L, 5); - oval(x0, y0, x1, y1, color); + mini::draw::oval(x0, y0, x1, y1, color); return 0; } @@ -1756,7 +477,7 @@ extern "C" { int x1 = luaL_checknumber(L, 3); int y1 = luaL_checknumber(L, 4); uint8_t color = luaL_checkinteger(L, 5); - ovalfill(x0, y0, x1, y1, color); + mini::draw::ovalf(x0, y0, x1, y1, color); return 0; } @@ -1771,43 +492,6 @@ extern "C" { return 0; } - /*static int cpp_draw_tline(lua_State *L) { - int x0 = luaL_checknumber(L, 1); - int y0 = luaL_checknumber(L, 2); - int x1 = luaL_checknumber(L, 3); - int y1 = luaL_checknumber(L, 4); - float mx = luaL_checknumber(L, 5); - float my = luaL_checknumber(L, 6); - float mdx = luaL_optnumber(L, 7, 0.125f); - float mdy = luaL_optnumber(L, 8, 0.0f); - tline(x0, y0, x1, y1, mx, my, mdx, mdy); - return 0; - } - - static int cpp_draw_thline(lua_State *L) { - int x0 = luaL_checknumber(L, 1); - int y = luaL_checknumber(L, 2); - int x1 = luaL_checknumber(L, 3); - float mx = luaL_checknumber(L, 4); - float my = luaL_checknumber(L, 5); - float mdx = luaL_optnumber(L, 6, 0.125f); - float mdy = luaL_optnumber(L, 7, 0.0f); - thline(x0, y, x1, mx, my, mdx, mdy); - return 0; - } - - static int cpp_draw_tvline(lua_State *L) { - int x = luaL_checknumber(L, 1); - int y0 = luaL_checknumber(L, 2); - int y1 = luaL_checknumber(L, 3); - float mx = luaL_checknumber(L, 4); - float my = luaL_checknumber(L, 5); - float mdx = luaL_optnumber(L, 6, 0.0f); - float mdy = luaL_optnumber(L, 7, 0.125f); - tvline(x, y0, y1, mx, my, mdx, mdy); - return 0; - }*/ - static int cpp_draw_surface(lua_State *L) { int sx = luaL_checknumber(L, 1); int sy = luaL_checknumber(L, 2); @@ -1851,7 +535,7 @@ extern "C" { static int cpp_draw_mode(lua_State *L) { int mode = luaL_checknumber(L, 1); - set_draw_mode(mode); + mini::draw::mode::set(mode); return 0; } @@ -1967,7 +651,7 @@ extern "C" { // =============================================== static int cpp_sys_delta(lua_State *L) { - lua_pushnumber(L, delta_time); + lua_pushnumber(L, delta()); return 1; } @@ -2010,6 +694,7 @@ extern "C" { } } + namespace fs = std::filesystem; static int cpp_sys_dir(lua_State *L) { std::string path = "./data"; if (lua_gettop(L) > 0) path = luaL_checkstring(L, 1); @@ -2351,587 +1036,468 @@ extern "C" { return 1; } -} - -bool lua_is_playing() { - return is_playing; -} - -void lua_process_debugger_commands() { - while (true) { - std::string cmd; - - { - std::lock_guard lock(g_cmdMutex); - if (g_debugCommands.empty()) - break; - - cmd = g_debugCommands.front(); - g_debugCommands.pop(); +namespace mini +{ + namespace lua + { + bool running() { + debug::process_commands(L); + return is_playing; } - - processDebugCommand(cmd); - } -} -void push_lua_funcs() { - lua_newtable(L); - lua_setglobal(L, "mini"); + void push_functions() { + lua_newtable(L); + lua_setglobal(L, "mini"); - lua_newtable(L); - lua_pushcfunction(L,cpp_surf_new); lua_setfield(L, -2, "new"); - lua_pushcfunction(L,cpp_surf_load); lua_setfield(L, -2, "load"); - lua_pushcfunction(L,cpp_surf_loadex); lua_setfield(L, -2, "loadex"); - lua_pushcfunction(L,cpp_surf_save); lua_setfield(L, -2, "save"); - lua_pushcfunction(L,cpp_surf_free); lua_setfield(L, -2, "free"); - lua_pushcfunction(L,cpp_surf_size); lua_setfield(L, -2, "size"); - lua_pushcfunction(L,cpp_surf_target); lua_setfield(L, -2, "target"); - lua_pushcfunction(L,cpp_surf_source); lua_setfield(L, -2, "source"); - lua_pushcfunction(L,cpp_surf_cls); lua_setfield(L, -2, "cls"); - lua_pushcfunction(L,cpp_surf_pixel); lua_setfield(L, -2, "pixel"); + lua_newtable(L); + lua_pushcfunction(L,wrappers::surf::create); lua_setfield(L, -2, "new"); + lua_pushcfunction(L,cpp_surf_load); lua_setfield(L, -2, "load"); + lua_pushcfunction(L,cpp_surf_loadex); lua_setfield(L, -2, "loadex"); + lua_pushcfunction(L,cpp_surf_save); lua_setfield(L, -2, "save"); + lua_pushcfunction(L,cpp_surf_free); lua_setfield(L, -2, "free"); + lua_pushcfunction(L,cpp_surf_size); lua_setfield(L, -2, "size"); + lua_pushcfunction(L,cpp_surf_target); lua_setfield(L, -2, "target"); + lua_pushcfunction(L,cpp_surf_source); lua_setfield(L, -2, "source"); + lua_pushcfunction(L,cpp_surf_cls); lua_setfield(L, -2, "cls"); + lua_pushcfunction(L,cpp_surf_pixel); lua_setfield(L, -2, "pixel"); - lua_pushinteger(L, 0); lua_setfield(L, -2, "SCREEN"); - lua_setglobal(L, "surf"); + lua_pushinteger(L, 0); lua_setfield(L, -2, "SCREEN"); + lua_setglobal(L, "surf"); - lua_newtable(L); - //lua_pushcfunction(L,cpp_map_new); lua_setfield(L, -2, "new"); - //lua_pushcfunction(L,cpp_map_load); lua_setfield(L, -2, "load"); - //lua_pushcfunction(L,cpp_map_save); lua_setfield(L, -2, "save"); - lua_pushcfunction(L,cpp_map_surf); lua_setfield(L, -2, "surf"); - lua_pushcfunction(L,cpp_map_draw); lua_setfield(L, -2, "draw"); - lua_pushcfunction(L,cpp_map_tile); lua_setfield(L, -2, "tile"); - lua_pushcfunction(L,cpp_map_cell); lua_setfield(L, -2, "cell"); - lua_setglobal(L, "map"); - - lua_newtable(L); - lua_pushcfunction(L,cpp_pal_load); lua_setfield(L, -2, "load"); - lua_pushcfunction(L,cpp_pal_set); lua_setfield(L, -2, "set"); - lua_pushcfunction(L,cpp_pal_color); lua_setfield(L, -2, "color"); - lua_pushcfunction(L,cpp_pal_trans); lua_setfield(L, -2, "trans"); - lua_pushcfunction(L,cpp_pal_subpal); lua_setfield(L, -2, "subpal"); - lua_setglobal(L, "pal"); + lua_newtable(L); + //lua_pushcfunction(L,cpp_map_new); lua_setfield(L, -2, "new"); + //lua_pushcfunction(L,cpp_map_load); lua_setfield(L, -2, "load"); + //lua_pushcfunction(L,cpp_map_save); lua_setfield(L, -2, "save"); + lua_pushcfunction(L,cpp_map_surf); lua_setfield(L, -2, "surf"); + lua_pushcfunction(L,cpp_map_draw); lua_setfield(L, -2, "draw"); + lua_pushcfunction(L,cpp_map_tile); lua_setfield(L, -2, "tile"); + lua_pushcfunction(L,cpp_map_cell); lua_setfield(L, -2, "cell"); + lua_setglobal(L, "map"); + + lua_newtable(L); + lua_pushcfunction(L,cpp_pal_load); lua_setfield(L, -2, "load"); + lua_pushcfunction(L,cpp_pal_set); lua_setfield(L, -2, "set"); + lua_pushcfunction(L,cpp_pal_color); lua_setfield(L, -2, "color"); + lua_pushcfunction(L,cpp_pal_trans); lua_setfield(L, -2, "trans"); + lua_pushcfunction(L,cpp_pal_subpal); lua_setfield(L, -2, "subpal"); + lua_setglobal(L, "pal"); - lua_newtable(L); - lua_pushcfunction(L,cpp_viewport_clip); lua_setfield(L, -2, "clip"); - lua_pushcfunction(L,cpp_viewport_origin); lua_setfield(L, -2, "origin"); - lua_pushcfunction(L,cpp_viewport_tolocal); lua_setfield(L, -2, "tolocal"); - lua_setglobal(L, "view"); + lua_newtable(L); + lua_pushcfunction(L,cpp_viewport_clip); lua_setfield(L, -2, "clip"); + lua_pushcfunction(L,cpp_viewport_origin); lua_setfield(L, -2, "origin"); + lua_pushcfunction(L,cpp_viewport_tolocal); lua_setfield(L, -2, "tolocal"); + lua_setglobal(L, "view"); - lua_newtable(L); - lua_pushcfunction(L,cpp_draw_line); lua_setfield(L, -2, "line"); - lua_pushcfunction(L,cpp_draw_hline); lua_setfield(L, -2, "hline"); - lua_pushcfunction(L,cpp_draw_vline); lua_setfield(L, -2, "vline"); - lua_pushcfunction(L,cpp_draw_rect); lua_setfield(L, -2, "rect"); - lua_pushcfunction(L,cpp_draw_rectfill); lua_setfield(L, -2, "rectf"); - lua_pushcfunction(L,cpp_draw_circ); lua_setfield(L, -2, "circ"); - lua_pushcfunction(L,cpp_draw_circfill); lua_setfield(L, -2, "circf"); - lua_pushcfunction(L,cpp_draw_roundrect); lua_setfield(L, -2, "rrect"); - lua_pushcfunction(L,cpp_draw_roundrectfill); lua_setfield(L, -2, "rrectf"); - lua_pushcfunction(L,cpp_draw_oval); lua_setfield(L, -2, "oval"); - lua_pushcfunction(L,cpp_draw_ovalfill); lua_setfield(L, -2, "ovalf"); - lua_pushcfunction(L,cpp_draw_pattern); lua_setfield(L, -2, "pattern"); - //lua_pushcfunction(L,cpp_draw_tline); lua_setfield(L, -2, "tline"); - //lua_pushcfunction(L,cpp_draw_thline); lua_setfield(L, -2, "thline"); - //lua_pushcfunction(L,cpp_draw_tvline); lua_setfield(L, -2, "tvline"); - lua_pushcfunction(L,cpp_draw_surface); lua_setfield(L, -2, "surf"); - lua_pushcfunction(L,cpp_draw_surfaceRotated); lua_setfield(L, -2, "surfrot"); - lua_pushcfunction(L,cpp_draw_text); lua_setfield(L, -2, "text"); - lua_pushcfunction(L,cpp_draw_mode); lua_setfield(L, -2, "mode"); + lua_newtable(L); + lua_pushcfunction(L,cpp_draw_line); lua_setfield(L, -2, "line"); + lua_pushcfunction(L,cpp_draw_hline); lua_setfield(L, -2, "hline"); + lua_pushcfunction(L,cpp_draw_vline); lua_setfield(L, -2, "vline"); + lua_pushcfunction(L,cpp_draw_rect); lua_setfield(L, -2, "rect"); + lua_pushcfunction(L,cpp_draw_rectfill); lua_setfield(L, -2, "rectf"); + lua_pushcfunction(L,cpp_draw_circ); lua_setfield(L, -2, "circ"); + lua_pushcfunction(L,cpp_draw_circfill); lua_setfield(L, -2, "circf"); + lua_pushcfunction(L,cpp_draw_roundrect); lua_setfield(L, -2, "rrect"); + lua_pushcfunction(L,cpp_draw_roundrectfill); lua_setfield(L, -2, "rrectf"); + lua_pushcfunction(L,cpp_draw_oval); lua_setfield(L, -2, "oval"); + lua_pushcfunction(L,cpp_draw_ovalfill); lua_setfield(L, -2, "ovalf"); + lua_pushcfunction(L,cpp_draw_pattern); lua_setfield(L, -2, "pattern"); + //lua_pushcfunction(L,cpp_draw_tline); lua_setfield(L, -2, "tline"); + //lua_pushcfunction(L,cpp_draw_thline); lua_setfield(L, -2, "thline"); + //lua_pushcfunction(L,cpp_draw_tvline); lua_setfield(L, -2, "tvline"); + lua_pushcfunction(L,cpp_draw_surface); lua_setfield(L, -2, "surf"); + lua_pushcfunction(L,cpp_draw_surfaceRotated); lua_setfield(L, -2, "surfrot"); + lua_pushcfunction(L,cpp_draw_text); lua_setfield(L, -2, "text"); + lua_pushcfunction(L,cpp_draw_mode); lua_setfield(L, -2, "mode"); - lua_pushinteger(L, 0); lua_setfield(L, -2, "NORMAL"); - lua_pushinteger(L, 1); lua_setfield(L, -2, "PATTERN"); - lua_pushinteger(L, 2); lua_setfield(L, -2, "AND"); - lua_pushinteger(L, 3); lua_setfield(L, -2, "OR"); - lua_pushinteger(L, 4); lua_setfield(L, -2, "XOR"); - lua_pushinteger(L, 5); lua_setfield(L, -2, "NOT"); + lua_pushinteger(L, 0); lua_setfield(L, -2, "NORMAL"); + lua_pushinteger(L, 1); lua_setfield(L, -2, "PATTERN"); + lua_pushinteger(L, 2); lua_setfield(L, -2, "AND"); + lua_pushinteger(L, 3); lua_setfield(L, -2, "OR"); + lua_pushinteger(L, 4); lua_setfield(L, -2, "XOR"); + lua_pushinteger(L, 5); lua_setfield(L, -2, "NOT"); - lua_setglobal(L, "draw"); + lua_setglobal(L, "draw"); - lua_newtable(L); - lua_pushcfunction(L,cpp_shader_init); lua_setfield(L, -2, "init"); - lua_pushcfunction(L,cpp_shader_enable); lua_setfield(L, -2, "enable"); - lua_pushcfunction(L,cpp_shader_disable); lua_setfield(L, -2, "disable"); - lua_setglobal(L, "shader"); + lua_newtable(L); + lua_pushcfunction(L,cpp_shader_init); lua_setfield(L, -2, "init"); + lua_pushcfunction(L,cpp_shader_enable); lua_setfield(L, -2, "enable"); + lua_pushcfunction(L,cpp_shader_disable); lua_setfield(L, -2, "disable"); + lua_setglobal(L, "shader"); - lua_newtable(L); - lua_pushcfunction(L,cpp_music_play); lua_setfield(L, -2, "play"); - lua_pushcfunction(L,cpp_music_pause); lua_setfield(L, -2, "pause"); - lua_pushcfunction(L,cpp_music_resume); lua_setfield(L, -2, "resume"); - lua_pushcfunction(L,cpp_music_stop); lua_setfield(L, -2, "stop"); - lua_pushcfunction(L,cpp_music_pos); lua_setfield(L, -2, "pos"); - lua_pushcfunction(L,cpp_music_enable); lua_setfield(L, -2, "enabled"); - lua_setglobal(L, "music"); + lua_newtable(L); + lua_pushcfunction(L,cpp_music_play); lua_setfield(L, -2, "play"); + lua_pushcfunction(L,cpp_music_pause); lua_setfield(L, -2, "pause"); + lua_pushcfunction(L,cpp_music_resume); lua_setfield(L, -2, "resume"); + lua_pushcfunction(L,cpp_music_stop); lua_setfield(L, -2, "stop"); + lua_pushcfunction(L,cpp_music_pos); lua_setfield(L, -2, "pos"); + lua_pushcfunction(L,cpp_music_enable); lua_setfield(L, -2, "enabled"); + lua_setglobal(L, "music"); - lua_newtable(L); - lua_pushcfunction(L,cpp_sound_load); lua_setfield(L, -2, "load"); - lua_pushcfunction(L,cpp_sound_free); lua_setfield(L, -2, "free"); - lua_pushcfunction(L,cpp_sound_play); lua_setfield(L, -2, "play"); - lua_pushcfunction(L,cpp_sound_stop); lua_setfield(L, -2, "stop"); - lua_pushcfunction(L,cpp_sound_enable); lua_setfield(L, -2, "enabled"); - lua_setglobal(L, "sound"); + lua_newtable(L); + lua_pushcfunction(L,cpp_sound_load); lua_setfield(L, -2, "load"); + lua_pushcfunction(L,cpp_sound_free); lua_setfield(L, -2, "free"); + lua_pushcfunction(L,cpp_sound_play); lua_setfield(L, -2, "play"); + lua_pushcfunction(L,cpp_sound_stop); lua_setfield(L, -2, "stop"); + lua_pushcfunction(L,cpp_sound_enable); lua_setfield(L, -2, "enabled"); + lua_setglobal(L, "sound"); - lua_newtable(L); - lua_pushcfunction(L,cpp_sys_delta); lua_setfield(L, -2, "delta"); - lua_pushcfunction(L,cpp_sys_time); lua_setfield(L, -2, "time"); - lua_pushcfunction(L,cpp_sys_chrono); lua_setfield(L, -2, "chrono"); - lua_pushcfunction(L,cpp_sys_beat); lua_setfield(L, -2, "beat"); - lua_pushcfunction(L,cpp_sys_update); lua_setfield(L, -2, "update"); - lua_pushcfunction(L,cpp_sys_dir); lua_setfield(L, -2, "dir"); - lua_pushcfunction(L,cpp_sys_exit); lua_setfield(L, -2, "quit"); - lua_pushcfunction(L,cpp_sys_fps); lua_setfield(L, -2, "fps"); - lua_pushcfunction(L,cpp_sys_debug); lua_setfield(L, -2, "debug"); - lua_pushcfunction(L,cpp_sys_clipboard); lua_setfield(L, -2, "clipboard"); - lua_pushcfunction(L,cpp_sys_version); lua_setfield(L, -2, "version"); + lua_newtable(L); + lua_pushcfunction(L,cpp_sys_delta); lua_setfield(L, -2, "delta"); + lua_pushcfunction(L,cpp_sys_time); lua_setfield(L, -2, "time"); + lua_pushcfunction(L,cpp_sys_chrono); lua_setfield(L, -2, "chrono"); + lua_pushcfunction(L,cpp_sys_beat); lua_setfield(L, -2, "beat"); + lua_pushcfunction(L,cpp_sys_update); lua_setfield(L, -2, "update"); + lua_pushcfunction(L,cpp_sys_dir); lua_setfield(L, -2, "dir"); + lua_pushcfunction(L,cpp_sys_exit); lua_setfield(L, -2, "quit"); + lua_pushcfunction(L,cpp_sys_fps); lua_setfield(L, -2, "fps"); + lua_pushcfunction(L,cpp_sys_debug); lua_setfield(L, -2, "debug"); + lua_pushcfunction(L,cpp_sys_clipboard); lua_setfield(L, -2, "clipboard"); + lua_pushcfunction(L,cpp_sys_version); lua_setfield(L, -2, "version"); - lua_pushinteger(L, 0); lua_setfield(L, -2, "UPDATE_ALWAYS"); - lua_pushinteger(L, 1); lua_setfield(L, -2, "UPDATE_WAIT"); - lua_pushinteger(L, 2); lua_setfield(L, -2, "UPDATE_TIMEOUT"); + lua_pushinteger(L, 0); lua_setfield(L, -2, "UPDATE_ALWAYS"); + lua_pushinteger(L, 1); lua_setfield(L, -2, "UPDATE_WAIT"); + lua_pushinteger(L, 2); lua_setfield(L, -2, "UPDATE_TIMEOUT"); - lua_setglobal(L, "sys"); + lua_setglobal(L, "sys"); - lua_newtable(L); - lua_pushcfunction(L,cpp_win_zoom); lua_setfield(L, -2, "zoom"); - lua_pushcfunction(L,cpp_win_fullscreen); lua_setfield(L, -2, "fullscreen"); - lua_pushcfunction(L,cpp_win_cursor); lua_setfield(L, -2, "cursor"); - lua_pushcfunction(L,cpp_win_res); lua_setfield(L, -2, "res"); - lua_setglobal(L, "win"); + lua_newtable(L); + lua_pushcfunction(L,cpp_win_zoom); lua_setfield(L, -2, "zoom"); + lua_pushcfunction(L,cpp_win_fullscreen); lua_setfield(L, -2, "fullscreen"); + lua_pushcfunction(L,cpp_win_cursor); lua_setfield(L, -2, "cursor"); + lua_pushcfunction(L,cpp_win_res); lua_setfield(L, -2, "res"); + lua_setglobal(L, "win"); - lua_newtable(L); - lua_pushcfunction(L,cpp_conf_key); lua_setfield(L, -2, "key"); - lua_pushcfunction(L,cpp_conf_folder); lua_setfield(L, -2, "folder"); - lua_setglobal(L, "config"); + lua_newtable(L); + lua_pushcfunction(L,cpp_conf_key); lua_setfield(L, -2, "key"); + lua_pushcfunction(L,cpp_conf_folder); lua_setfield(L, -2, "folder"); + lua_setglobal(L, "config"); - lua_newtable(L); - lua_pushcfunction(L,cpp_font_load); lua_setfield(L, -2, "load"); - lua_pushcfunction(L,cpp_font_current); lua_setfield(L, -2, "current"); - lua_pushcfunction(L,cpp_font_spacing); lua_setfield(L, -2, "spacing"); + lua_newtable(L); + lua_pushcfunction(L,cpp_font_load); lua_setfield(L, -2, "load"); + lua_pushcfunction(L,cpp_font_current); lua_setfield(L, -2, "current"); + lua_pushcfunction(L,cpp_font_spacing); lua_setfield(L, -2, "spacing"); - lua_pushinteger(L, 0); lua_setfield(L, -2, "DEFAULT"); - lua_setglobal(L, "font"); + lua_pushinteger(L, 0); lua_setfield(L, -2, "DEFAULT"); + lua_setglobal(L, "font"); - lua_newtable(L); - lua_pushcfunction(L,cpp_mouse_pos); lua_setfield(L, -2, "pos"); - lua_pushcfunction(L,cpp_mouse_wheel); lua_setfield(L, -2, "wheel"); - lua_pushcfunction(L,cpp_mouse_down); lua_setfield(L, -2, "down"); - lua_pushcfunction(L,cpp_mouse_press); lua_setfield(L, -2, "press"); - lua_pushcfunction(L,cpp_mouse_dblclick); lua_setfield(L, -2, "dblclick"); - lua_pushcfunction(L,cpp_mouse_discard); lua_setfield(L, -2, "discard"); - lua_pushcfunction(L,cpp_mouse_inside); lua_setfield(L, -2, "inside"); + lua_newtable(L); + lua_pushcfunction(L,cpp_mouse_pos); lua_setfield(L, -2, "pos"); + lua_pushcfunction(L,cpp_mouse_wheel); lua_setfield(L, -2, "wheel"); + lua_pushcfunction(L,cpp_mouse_down); lua_setfield(L, -2, "down"); + lua_pushcfunction(L,cpp_mouse_press); lua_setfield(L, -2, "press"); + lua_pushcfunction(L,cpp_mouse_dblclick); lua_setfield(L, -2, "dblclick"); + lua_pushcfunction(L,cpp_mouse_discard); lua_setfield(L, -2, "discard"); + lua_pushcfunction(L,cpp_mouse_inside); lua_setfield(L, -2, "inside"); - lua_pushinteger(L, 1); lua_setfield(L, -2, "LEFT"); - lua_pushinteger(L, 2); lua_setfield(L, -2, "MIDDLE"); - lua_pushinteger(L, 3); lua_setfield(L, -2, "RIGHT"); - lua_setglobal(L, "mouse"); + lua_pushinteger(L, 1); lua_setfield(L, -2, "LEFT"); + lua_pushinteger(L, 2); lua_setfield(L, -2, "MIDDLE"); + lua_pushinteger(L, 3); lua_setfield(L, -2, "RIGHT"); + lua_setglobal(L, "mouse"); - lua_newtable(L); - lua_pushcfunction(L,cpp_key_down); lua_setfield(L, -2, "down"); - lua_pushcfunction(L,cpp_key_press); lua_setfield(L, -2, "press"); - lua_pushcfunction(L,cpp_key_any); lua_setfield(L, -2, "any"); - lua_pushcfunction(L,cpp_key_text); lua_setfield(L, -2, "text"); - lua_pushcfunction(L,cpp_key_utf8char); lua_setfield(L, -2, "utf8char"); - //lua_setglobal(L, "key"); + lua_newtable(L); + lua_pushcfunction(L,cpp_key_down); lua_setfield(L, -2, "down"); + lua_pushcfunction(L,cpp_key_press); lua_setfield(L, -2, "press"); + lua_pushcfunction(L,cpp_key_any); lua_setfield(L, -2, "any"); + lua_pushcfunction(L,cpp_key_text); lua_setfield(L, -2, "text"); + lua_pushcfunction(L,cpp_key_utf8char); lua_setfield(L, -2, "utf8char"); + //lua_setglobal(L, "key"); - //lua_newtable(L); - lua_pushinteger(L, 0); lua_setfield(L, -2, "UNKNOWN"); - lua_pushinteger(L, 4); lua_setfield(L, -2, "A"); - lua_pushinteger(L, 5); lua_setfield(L, -2, "B"); - lua_pushinteger(L, 6); lua_setfield(L, -2, "C"); - lua_pushinteger(L, 7); lua_setfield(L, -2, "D"); - lua_pushinteger(L, 8); lua_setfield(L, -2, "E"); - lua_pushinteger(L, 9); lua_setfield(L, -2, "F"); - lua_pushinteger(L, 10); lua_setfield(L, -2, "G"); - lua_pushinteger(L, 11); lua_setfield(L, -2, "H"); - lua_pushinteger(L, 12); lua_setfield(L, -2, "I"); - lua_pushinteger(L, 13); lua_setfield(L, -2, "J"); - lua_pushinteger(L, 14); lua_setfield(L, -2, "K"); - lua_pushinteger(L, 15); lua_setfield(L, -2, "L"); - lua_pushinteger(L, 16); lua_setfield(L, -2, "M"); - lua_pushinteger(L, 17); lua_setfield(L, -2, "N"); - lua_pushinteger(L, 18); lua_setfield(L, -2, "O"); - lua_pushinteger(L, 19); lua_setfield(L, -2, "P"); - lua_pushinteger(L, 20); lua_setfield(L, -2, "Q"); - lua_pushinteger(L, 21); lua_setfield(L, -2, "R"); - lua_pushinteger(L, 22); lua_setfield(L, -2, "S"); - lua_pushinteger(L, 23); lua_setfield(L, -2, "T"); - lua_pushinteger(L, 24); lua_setfield(L, -2, "U"); - lua_pushinteger(L, 25); lua_setfield(L, -2, "V"); - lua_pushinteger(L, 26); lua_setfield(L, -2, "W"); - lua_pushinteger(L, 27); lua_setfield(L, -2, "X"); - lua_pushinteger(L, 28); lua_setfield(L, -2, "Y"); - lua_pushinteger(L, 29); lua_setfield(L, -2, "Z"); - lua_pushinteger(L, 30); lua_setfield(L, -2, "N1"); - lua_pushinteger(L, 31); lua_setfield(L, -2, "N2"); - lua_pushinteger(L, 32); lua_setfield(L, -2, "N3"); - lua_pushinteger(L, 33); lua_setfield(L, -2, "N4"); - lua_pushinteger(L, 34); lua_setfield(L, -2, "N5"); - lua_pushinteger(L, 35); lua_setfield(L, -2, "N6"); - lua_pushinteger(L, 36); lua_setfield(L, -2, "N7"); - lua_pushinteger(L, 37); lua_setfield(L, -2, "N8"); - lua_pushinteger(L, 38); lua_setfield(L, -2, "N9"); - lua_pushinteger(L, 39); lua_setfield(L, -2, "N0"); - lua_pushinteger(L, 40); lua_setfield(L, -2, "RETURN"); - lua_pushinteger(L, 41); lua_setfield(L, -2, "ESCAPE"); - lua_pushinteger(L, 42); lua_setfield(L, -2, "BACKSPACE"); - lua_pushinteger(L, 43); lua_setfield(L, -2, "TAB"); - lua_pushinteger(L, 44); lua_setfield(L, -2, "SPACE"); - lua_pushinteger(L, 45); lua_setfield(L, -2, "MINUS"); - lua_pushinteger(L, 46); lua_setfield(L, -2, "EQUALS"); - lua_pushinteger(L, 47); lua_setfield(L, -2, "LEFTBRACKET"); - lua_pushinteger(L, 48); lua_setfield(L, -2, "RIGHTBRACKET"); - lua_pushinteger(L, 49); lua_setfield(L, -2, "BACKSLASH"); - lua_pushinteger(L, 50); lua_setfield(L, -2, "NONUSHASH"); - lua_pushinteger(L, 51); lua_setfield(L, -2, "SEMICOLON"); - lua_pushinteger(L, 52); lua_setfield(L, -2, "APOSTROPHE"); - lua_pushinteger(L, 53); lua_setfield(L, -2, "GRAVE"); - lua_pushinteger(L, 54); lua_setfield(L, -2, "COMMA"); - lua_pushinteger(L, 55); lua_setfield(L, -2, "PERIOD"); - lua_pushinteger(L, 56); lua_setfield(L, -2, "SLASH"); - lua_pushinteger(L, 57); lua_setfield(L, -2, "CAPSLOCK"); - lua_pushinteger(L, 58); lua_setfield(L, -2, "F1"); - lua_pushinteger(L, 59); lua_setfield(L, -2, "F2"); - lua_pushinteger(L, 60); lua_setfield(L, -2, "F3"); - lua_pushinteger(L, 61); lua_setfield(L, -2, "F4"); - lua_pushinteger(L, 62); lua_setfield(L, -2, "F5"); - lua_pushinteger(L, 63); lua_setfield(L, -2, "F6"); - lua_pushinteger(L, 64); lua_setfield(L, -2, "F7"); - lua_pushinteger(L, 65); lua_setfield(L, -2, "F8"); - lua_pushinteger(L, 66); lua_setfield(L, -2, "F9"); - lua_pushinteger(L, 67); lua_setfield(L, -2, "F10"); - lua_pushinteger(L, 68); lua_setfield(L, -2, "F11"); - lua_pushinteger(L, 69); lua_setfield(L, -2, "F12"); - lua_pushinteger(L, 70); lua_setfield(L, -2, "PRINTSCREEN"); - lua_pushinteger(L, 71); lua_setfield(L, -2, "SCROLLLOCK"); - lua_pushinteger(L, 72); lua_setfield(L, -2, "PAUSE"); - lua_pushinteger(L, 73); lua_setfield(L, -2, "INSERT"); - lua_pushinteger(L, 74); lua_setfield(L, -2, "HOME"); - lua_pushinteger(L, 75); lua_setfield(L, -2, "PAGEUP"); - lua_pushinteger(L, 76); lua_setfield(L, -2, "DELETE"); - lua_pushinteger(L, 77); lua_setfield(L, -2, "END"); - lua_pushinteger(L, 78); lua_setfield(L, -2, "PAGEDOWN"); - lua_pushinteger(L, 79); lua_setfield(L, -2, "RIGHT"); - lua_pushinteger(L, 80); lua_setfield(L, -2, "LEFT"); - lua_pushinteger(L, 81); lua_setfield(L, -2, "DOWN"); - lua_pushinteger(L, 82); lua_setfield(L, -2, "UP"); - lua_pushinteger(L, 83); lua_setfield(L, -2, "NUMLOCKCLEAR"); - lua_pushinteger(L, 84); lua_setfield(L, -2, "KP_DIVIDE"); - lua_pushinteger(L, 85); lua_setfield(L, -2, "KP_MULTIPLY"); - lua_pushinteger(L, 86); lua_setfield(L, -2, "KP_MINUS"); - lua_pushinteger(L, 87); lua_setfield(L, -2, "KP_PLUS"); - lua_pushinteger(L, 88); lua_setfield(L, -2, "KP_ENTER"); - lua_pushinteger(L, 89); lua_setfield(L, -2, "KP_1"); - lua_pushinteger(L, 90); lua_setfield(L, -2, "KP_2"); - lua_pushinteger(L, 91); lua_setfield(L, -2, "KP_3"); - lua_pushinteger(L, 92); lua_setfield(L, -2, "KP_4"); - lua_pushinteger(L, 93); lua_setfield(L, -2, "KP_5"); - lua_pushinteger(L, 94); lua_setfield(L, -2, "KP_6"); - lua_pushinteger(L, 95); lua_setfield(L, -2, "KP_7"); - lua_pushinteger(L, 96); lua_setfield(L, -2, "KP_8"); - lua_pushinteger(L, 97); lua_setfield(L, -2, "KP_9"); - lua_pushinteger(L, 98); lua_setfield(L, -2, "KP_0"); - lua_pushinteger(L, 99); lua_setfield(L, -2, "KP_PERIOD"); - lua_pushinteger(L, 100); lua_setfield(L, -2, "NONUSBACKSLASH"); - lua_pushinteger(L, 101); lua_setfield(L, -2, "APPLICATION"); - lua_pushinteger(L, 224); lua_setfield(L, -2, "LCTRL"); - lua_pushinteger(L, 225); lua_setfield(L, -2, "LSHIFT"); - lua_pushinteger(L, 226); lua_setfield(L, -2, "LALT"); - lua_pushinteger(L, 227); lua_setfield(L, -2, "LGUI"); - lua_pushinteger(L, 228); lua_setfield(L, -2, "RCTRL"); - lua_pushinteger(L, 229); lua_setfield(L, -2, "RSHIFT"); - lua_pushinteger(L, 230); lua_setfield(L, -2, "RALT"); - lua_pushinteger(L, 231); lua_setfield(L, -2, "RGUI"); + //lua_newtable(L); + lua_pushinteger(L, 0); lua_setfield(L, -2, "UNKNOWN"); + lua_pushinteger(L, 4); lua_setfield(L, -2, "A"); + lua_pushinteger(L, 5); lua_setfield(L, -2, "B"); + lua_pushinteger(L, 6); lua_setfield(L, -2, "C"); + lua_pushinteger(L, 7); lua_setfield(L, -2, "D"); + lua_pushinteger(L, 8); lua_setfield(L, -2, "E"); + lua_pushinteger(L, 9); lua_setfield(L, -2, "F"); + lua_pushinteger(L, 10); lua_setfield(L, -2, "G"); + lua_pushinteger(L, 11); lua_setfield(L, -2, "H"); + lua_pushinteger(L, 12); lua_setfield(L, -2, "I"); + lua_pushinteger(L, 13); lua_setfield(L, -2, "J"); + lua_pushinteger(L, 14); lua_setfield(L, -2, "K"); + lua_pushinteger(L, 15); lua_setfield(L, -2, "L"); + lua_pushinteger(L, 16); lua_setfield(L, -2, "M"); + lua_pushinteger(L, 17); lua_setfield(L, -2, "N"); + lua_pushinteger(L, 18); lua_setfield(L, -2, "O"); + lua_pushinteger(L, 19); lua_setfield(L, -2, "P"); + lua_pushinteger(L, 20); lua_setfield(L, -2, "Q"); + lua_pushinteger(L, 21); lua_setfield(L, -2, "R"); + lua_pushinteger(L, 22); lua_setfield(L, -2, "S"); + lua_pushinteger(L, 23); lua_setfield(L, -2, "T"); + lua_pushinteger(L, 24); lua_setfield(L, -2, "U"); + lua_pushinteger(L, 25); lua_setfield(L, -2, "V"); + lua_pushinteger(L, 26); lua_setfield(L, -2, "W"); + lua_pushinteger(L, 27); lua_setfield(L, -2, "X"); + lua_pushinteger(L, 28); lua_setfield(L, -2, "Y"); + lua_pushinteger(L, 29); lua_setfield(L, -2, "Z"); + lua_pushinteger(L, 30); lua_setfield(L, -2, "N1"); + lua_pushinteger(L, 31); lua_setfield(L, -2, "N2"); + lua_pushinteger(L, 32); lua_setfield(L, -2, "N3"); + lua_pushinteger(L, 33); lua_setfield(L, -2, "N4"); + lua_pushinteger(L, 34); lua_setfield(L, -2, "N5"); + lua_pushinteger(L, 35); lua_setfield(L, -2, "N6"); + lua_pushinteger(L, 36); lua_setfield(L, -2, "N7"); + lua_pushinteger(L, 37); lua_setfield(L, -2, "N8"); + lua_pushinteger(L, 38); lua_setfield(L, -2, "N9"); + lua_pushinteger(L, 39); lua_setfield(L, -2, "N0"); + lua_pushinteger(L, 40); lua_setfield(L, -2, "RETURN"); + lua_pushinteger(L, 41); lua_setfield(L, -2, "ESCAPE"); + lua_pushinteger(L, 42); lua_setfield(L, -2, "BACKSPACE"); + lua_pushinteger(L, 43); lua_setfield(L, -2, "TAB"); + lua_pushinteger(L, 44); lua_setfield(L, -2, "SPACE"); + lua_pushinteger(L, 45); lua_setfield(L, -2, "MINUS"); + lua_pushinteger(L, 46); lua_setfield(L, -2, "EQUALS"); + lua_pushinteger(L, 47); lua_setfield(L, -2, "LEFTBRACKET"); + lua_pushinteger(L, 48); lua_setfield(L, -2, "RIGHTBRACKET"); + lua_pushinteger(L, 49); lua_setfield(L, -2, "BACKSLASH"); + lua_pushinteger(L, 50); lua_setfield(L, -2, "NONUSHASH"); + lua_pushinteger(L, 51); lua_setfield(L, -2, "SEMICOLON"); + lua_pushinteger(L, 52); lua_setfield(L, -2, "APOSTROPHE"); + lua_pushinteger(L, 53); lua_setfield(L, -2, "GRAVE"); + lua_pushinteger(L, 54); lua_setfield(L, -2, "COMMA"); + lua_pushinteger(L, 55); lua_setfield(L, -2, "PERIOD"); + lua_pushinteger(L, 56); lua_setfield(L, -2, "SLASH"); + lua_pushinteger(L, 57); lua_setfield(L, -2, "CAPSLOCK"); + lua_pushinteger(L, 58); lua_setfield(L, -2, "F1"); + lua_pushinteger(L, 59); lua_setfield(L, -2, "F2"); + lua_pushinteger(L, 60); lua_setfield(L, -2, "F3"); + lua_pushinteger(L, 61); lua_setfield(L, -2, "F4"); + lua_pushinteger(L, 62); lua_setfield(L, -2, "F5"); + lua_pushinteger(L, 63); lua_setfield(L, -2, "F6"); + lua_pushinteger(L, 64); lua_setfield(L, -2, "F7"); + lua_pushinteger(L, 65); lua_setfield(L, -2, "F8"); + lua_pushinteger(L, 66); lua_setfield(L, -2, "F9"); + lua_pushinteger(L, 67); lua_setfield(L, -2, "F10"); + lua_pushinteger(L, 68); lua_setfield(L, -2, "F11"); + lua_pushinteger(L, 69); lua_setfield(L, -2, "F12"); + lua_pushinteger(L, 70); lua_setfield(L, -2, "PRINTSCREEN"); + lua_pushinteger(L, 71); lua_setfield(L, -2, "SCROLLLOCK"); + lua_pushinteger(L, 72); lua_setfield(L, -2, "PAUSE"); + lua_pushinteger(L, 73); lua_setfield(L, -2, "INSERT"); + lua_pushinteger(L, 74); lua_setfield(L, -2, "HOME"); + lua_pushinteger(L, 75); lua_setfield(L, -2, "PAGEUP"); + lua_pushinteger(L, 76); lua_setfield(L, -2, "DELETE"); + lua_pushinteger(L, 77); lua_setfield(L, -2, "END"); + lua_pushinteger(L, 78); lua_setfield(L, -2, "PAGEDOWN"); + lua_pushinteger(L, 79); lua_setfield(L, -2, "RIGHT"); + lua_pushinteger(L, 80); lua_setfield(L, -2, "LEFT"); + lua_pushinteger(L, 81); lua_setfield(L, -2, "DOWN"); + lua_pushinteger(L, 82); lua_setfield(L, -2, "UP"); + lua_pushinteger(L, 83); lua_setfield(L, -2, "NUMLOCKCLEAR"); + lua_pushinteger(L, 84); lua_setfield(L, -2, "KP_DIVIDE"); + lua_pushinteger(L, 85); lua_setfield(L, -2, "KP_MULTIPLY"); + lua_pushinteger(L, 86); lua_setfield(L, -2, "KP_MINUS"); + lua_pushinteger(L, 87); lua_setfield(L, -2, "KP_PLUS"); + lua_pushinteger(L, 88); lua_setfield(L, -2, "KP_ENTER"); + lua_pushinteger(L, 89); lua_setfield(L, -2, "KP_1"); + lua_pushinteger(L, 90); lua_setfield(L, -2, "KP_2"); + lua_pushinteger(L, 91); lua_setfield(L, -2, "KP_3"); + lua_pushinteger(L, 92); lua_setfield(L, -2, "KP_4"); + lua_pushinteger(L, 93); lua_setfield(L, -2, "KP_5"); + lua_pushinteger(L, 94); lua_setfield(L, -2, "KP_6"); + lua_pushinteger(L, 95); lua_setfield(L, -2, "KP_7"); + lua_pushinteger(L, 96); lua_setfield(L, -2, "KP_8"); + lua_pushinteger(L, 97); lua_setfield(L, -2, "KP_9"); + lua_pushinteger(L, 98); lua_setfield(L, -2, "KP_0"); + lua_pushinteger(L, 99); lua_setfield(L, -2, "KP_PERIOD"); + lua_pushinteger(L, 100); lua_setfield(L, -2, "NONUSBACKSLASH"); + lua_pushinteger(L, 101); lua_setfield(L, -2, "APPLICATION"); + lua_pushinteger(L, 224); lua_setfield(L, -2, "LCTRL"); + lua_pushinteger(L, 225); lua_setfield(L, -2, "LSHIFT"); + lua_pushinteger(L, 226); lua_setfield(L, -2, "LALT"); + lua_pushinteger(L, 227); lua_setfield(L, -2, "LGUI"); + lua_pushinteger(L, 228); lua_setfield(L, -2, "RCTRL"); + lua_pushinteger(L, 229); lua_setfield(L, -2, "RSHIFT"); + lua_pushinteger(L, 230); lua_setfield(L, -2, "RALT"); + lua_pushinteger(L, 231); lua_setfield(L, -2, "RGUI"); - lua_setglobal(L, "key"); + lua_setglobal(L, "key"); - lua_newtable(L); - lua_pushcfunction(L,cpp_pad_down); lua_setfield(L, -2, "down"); - lua_pushcfunction(L,cpp_pad_press); lua_setfield(L, -2, "press"); - lua_pushcfunction(L,cpp_pad_any); lua_setfield(L, -2, "any"); - //lua_setglobal(L, "gamepad"); + lua_newtable(L); + lua_pushcfunction(L,cpp_pad_down); lua_setfield(L, -2, "down"); + lua_pushcfunction(L,cpp_pad_press); lua_setfield(L, -2, "press"); + lua_pushcfunction(L,cpp_pad_any); lua_setfield(L, -2, "any"); + //lua_setglobal(L, "gamepad"); - //lua_newtable(L); - lua_pushinteger(L, -1); lua_setfield(L, -2, "INVALID"); - lua_pushinteger(L, 0); lua_setfield(L, -2, "A"); - lua_pushinteger(L, 1); lua_setfield(L, -2, "B"); - lua_pushinteger(L, 2); lua_setfield(L, -2, "X"); - lua_pushinteger(L, 3); lua_setfield(L, -2, "Y"); - lua_pushinteger(L, 4); lua_setfield(L, -2, "BACK"); - lua_pushinteger(L, 5); lua_setfield(L, -2, "GUIDE"); - lua_pushinteger(L, 6); lua_setfield(L, -2, "START"); - lua_pushinteger(L, 7); lua_setfield(L, -2, "LEFTSTICK"); - lua_pushinteger(L, 8); lua_setfield(L, -2, "RIGHTSTICK"); - lua_pushinteger(L, 9); lua_setfield(L, -2, "LEFTSHOULDER"); - lua_pushinteger(L, 10); lua_setfield(L, -2, "RIGHTSHOULDER"); - lua_pushinteger(L, 11); lua_setfield(L, -2, "UP"); - lua_pushinteger(L, 12); lua_setfield(L, -2, "DOWN"); - lua_pushinteger(L, 13); lua_setfield(L, -2, "LEFT"); - lua_pushinteger(L, 14); lua_setfield(L, -2, "RIGHT"); - lua_pushinteger(L, 15); lua_setfield(L, -2, "MISC1"); - lua_pushinteger(L, 16); lua_setfield(L, -2, "PADDLE1"); - lua_pushinteger(L, 17); lua_setfield(L, -2, "PADDLE2"); - lua_pushinteger(L, 18); lua_setfield(L, -2, "PADDLE3"); - lua_pushinteger(L, 19); lua_setfield(L, -2, "PADDLE4"); - lua_pushinteger(L, 20); lua_setfield(L, -2, "TOUCHPAD"); + //lua_newtable(L); + lua_pushinteger(L, -1); lua_setfield(L, -2, "INVALID"); + lua_pushinteger(L, 0); lua_setfield(L, -2, "A"); + lua_pushinteger(L, 1); lua_setfield(L, -2, "B"); + lua_pushinteger(L, 2); lua_setfield(L, -2, "X"); + lua_pushinteger(L, 3); lua_setfield(L, -2, "Y"); + lua_pushinteger(L, 4); lua_setfield(L, -2, "BACK"); + lua_pushinteger(L, 5); lua_setfield(L, -2, "GUIDE"); + lua_pushinteger(L, 6); lua_setfield(L, -2, "START"); + lua_pushinteger(L, 7); lua_setfield(L, -2, "LEFTSTICK"); + lua_pushinteger(L, 8); lua_setfield(L, -2, "RIGHTSTICK"); + lua_pushinteger(L, 9); lua_setfield(L, -2, "LEFTSHOULDER"); + lua_pushinteger(L, 10); lua_setfield(L, -2, "RIGHTSHOULDER"); + lua_pushinteger(L, 11); lua_setfield(L, -2, "UP"); + lua_pushinteger(L, 12); lua_setfield(L, -2, "DOWN"); + lua_pushinteger(L, 13); lua_setfield(L, -2, "LEFT"); + lua_pushinteger(L, 14); lua_setfield(L, -2, "RIGHT"); + lua_pushinteger(L, 15); lua_setfield(L, -2, "MISC1"); + lua_pushinteger(L, 16); lua_setfield(L, -2, "PADDLE1"); + lua_pushinteger(L, 17); lua_setfield(L, -2, "PADDLE2"); + lua_pushinteger(L, 18); lua_setfield(L, -2, "PADDLE3"); + lua_pushinteger(L, 19); lua_setfield(L, -2, "PADDLE4"); + lua_pushinteger(L, 20); lua_setfield(L, -2, "TOUCHPAD"); - lua_setglobal(L, "pad"); + lua_setglobal(L, "pad"); - lua_getglobal(L, "utf8"); // push utf8 table - lua_pushcfunction(L, cpp_utf8_sub); // push C function - lua_setfield(L, -2, "sub"); // utf8.sub = cpp_utf8_sub - lua_pop(L, 1); // pop utf8 table -} + lua_getglobal(L, "utf8"); // push utf8 table + lua_pushcfunction(L, cpp_utf8_sub); // push C function + lua_setfield(L, -2, "sub"); // utf8.sub = cpp_utf8_sub + lua_pop(L, 1); // pop utf8 table + } -/* -int MiniLoader(lua_State *L) { - const char *name = luaL_checkstring(L, 1); - char filename[strlen(name)+5]; - strcpy(filename, name); - strcat(filename, ".lua"); - int size; - char* buffer = file_getfilebuffer(filename, size); - if (luaL_loadbuffer(L, buffer, size, filename)) { - log_msg(LOG_LUALD, "%s\n",lua_tostring(L, -1)); - lua_pop(L,1); - //return ; - } - free(buffer); - return 1; -} -*/ + int MiniLoader(lua_State *L) { + const char *name = luaL_checkstring(L, 1); -int MiniLoader(lua_State *L) { - const char *name = luaL_checkstring(L, 1); + // 1. Convertir puntos en barras + std::string path(name); + std::string regpath(name); + std::replace(path.begin(), path.end(), '.', '/'); - // 1. Convertir puntos en barras - std::string path(name); - std::string regpath(name); - std::replace(path.begin(), path.end(), '.', '/'); + // 2. Detectar comodín "/*" + bool load_all = false; + if (path.size() >= 2 && path.substr(path.size()-2) == "/*") { + load_all = true; + path = path.substr(0, path.size()-2); // quitar "/*" + regpath = regpath.substr(0, regpath.size()-2); // quitar "/*" + } - // 2. Detectar comodín "/*" - bool load_all = false; - if (path.size() >= 2 && path.substr(path.size()-2) == "/*") { - load_all = true; - path = path.substr(0, path.size()-2); // quitar "/*" - regpath = regpath.substr(0, regpath.size()-2); // quitar "/*" - } + if (load_all) { + std::vector files = file_listdir(path.c_str(), "lua"); - if (load_all) { - std::vector files = file_listdir(path.c_str(), "lua"); + // Ejecutar todos los módulos + for (auto &f : files) { + std::string fullpath = path + "/" + f; + std::string registerpath = std::string(regpath + "." + f.substr(0,f.size()-4)); - // Ejecutar todos los módulos - for (auto &f : files) { - std::string fullpath = path + "/" + f; - std::string registerpath = std::string(regpath + "." + f.substr(0,f.size()-4)); + int size; + char* buffer = file_getfilebuffer(fullpath.c_str(), size); + if (!buffer) continue; + + if (luaL_loadbuffer(L, buffer, size, registerpath.c_str()) == LUA_OK) { + lua_pcall(L, 0, 0, 0); // ejecutar módulo, sin devolver nada + lua_getglobal(L, "package"); + lua_getfield(L, -1, "loaded"); + lua_pushboolean(L, 1); + lua_setfield(L, -2, registerpath.c_str()); + lua_pop(L, 2); + } else { + log_msg(LOG_LUALD, "Error cargando %s: %s\n", fullpath.c_str(), lua_tostring(L, -1)); + lua_pop(L, 1); + } + + free(buffer); + } + + // Devolver un loader vacío + lua_pushcfunction(L, [](lua_State* L) -> int { + lua_pushboolean(L, 1); // require devuelve true + return 1; + }); + + return 1; + } + + // 3. Cargar un único archivo + std::string filename = path + ".lua"; int size; - char* buffer = file_getfilebuffer(fullpath.c_str(), size); - if (!buffer) continue; + char* buffer = file_getfilebuffer(filename.c_str(), size); + if (!buffer) { + lua_pushnil(L); + return 1; + } - if (luaL_loadbuffer(L, buffer, size, registerpath.c_str()) == LUA_OK) { - lua_pcall(L, 0, 0, 0); // ejecutar módulo, sin devolver nada - lua_getglobal(L, "package"); - lua_getfield(L, -1, "loaded"); - lua_pushboolean(L, 1); - lua_setfield(L, -2, registerpath.c_str()); - lua_pop(L, 2); - } else { - log_msg(LOG_LUALD, "Error cargando %s: %s\n", fullpath.c_str(), lua_tostring(L, -1)); + if (luaL_loadbuffer(L, buffer, size, name)) { + log_msg(LOG_LUALD, "%s\n", lua_tostring(L, -1)); lua_pop(L, 1); + free(buffer); + lua_pushnil(L); + return 1; } free(buffer); - } - - // Devolver un loader vacío - lua_pushcfunction(L, [](lua_State* L) -> int { - lua_pushboolean(L, 1); // require devuelve true return 1; - }); - - return 1; - } - - // 3. Cargar un único archivo - std::string filename = path + ".lua"; - - int size; - char* buffer = file_getfilebuffer(filename.c_str(), size); - if (!buffer) { - lua_pushnil(L); - return 1; - } - - if (luaL_loadbuffer(L, buffer, size, name)) { - log_msg(LOG_LUALD, "%s\n", lua_tostring(L, -1)); - lua_pop(L, 1); - free(buffer); - lua_pushnil(L); - return 1; - } - - free(buffer); - return 1; -} - -void lua_init(const char *main_lua_file) { - L = luaL_newstate(); - luaL_openlibs(L); - - push_lua_funcs(); - lua_register(L, "mini_loader", MiniLoader); - luaL_dostring(L, "table.insert(package.searchers,2,mini_loader)\n"); - - int size; - char* buffer = file_getfilebuffer(main_lua_file, size); - if (luaL_loadbuffer(L, buffer, size, "main")) { - log_msg(LOG_LUALD, "%s\n", lua_tostring(L, -1)); - lua_pop(L,1); - return; - } - free(buffer); - if (lua_pcall(L,0, LUA_MULTRET, 0)) { - //luaL_traceback(L, L, NULL, 1); - log_msg(LOG_LUART, "%s\n", lua_tostring(L, -1)); - lua_pop(L,1); - return; - } - - // Check if _init and _update exist - lua_getglobal(L, "mini"); - lua_getfield(L, -1, "init"); - if (lua_isfunction(L,-1)) init_exists = true; - lua_pop(L,1); - lua_pop(L,1); - - lua_getglobal(L, "mini"); - lua_getfield(L, -1, "update"); - if (lua_isfunction(L,-1)) update_exists = true; - lua_pop(L,1); - lua_pop(L,1); - - //std::thread(debugCommandThread).detach(); - printf("stdin isatty: %d\n", isatty(0)); - is_playing = true; -} - -void lua_call_init() { - if (!init_exists) return; - lua_process_debugger_commands(); - lua_getglobal(L, "mini"); - lua_getfield(L, -1, "init"); - if (lua_pcall(L, 0, 0, 0)) { - log_msg(LOG_LUART, "%s\n", lua_tostring(L, -1)); - lua_pop(L,1); - is_playing = false; - } -} - -void sendExceptionStoppedEvent(const std::string& msg) { - json payload = { - { "reason", "exception" }, - { "text", msg } - }; - sendDebugResponse("stopped", payload); -} - -int luaErrorHandler(lua_State* L) { - const char* msg = lua_tostring(L, 1); - if (!msg) msg = "Unknown error"; - - // Construir traceback - luaL_traceback(L, L, msg, 1); - - const char* tb = lua_tostring(L, -1); - if (tb) { - lastExceptionTraceback = tb; - } else { - lastExceptionTraceback = msg; - } - - // Devolver el traceback a Lua (aunque luego Lua lo sustituya) - return 1; -} - -void lua_call_update() { - if (!update_exists) return; - function_has_breakpoints = false; - while (!funBreakStack.empty()) funBreakStack.pop(); - //lua_process_debugger_commands(); - delta_time = float(SDL_GetTicks() - last_update)/1000.0f; - last_update = SDL_GetTicks(); - lua_getglobal(L, "mini"); - lua_getfield(L, -1, "update"); - - lua_pushcfunction(L, luaErrorHandler); - lua_insert(L, -2); // poner handler debajo de la función - int status = lua_pcall(L, 0, 0, -2); - lua_pop(L, 1); // quitar handler - - if (status != LUA_OK) { - is_playing = false; - lastExceptionMessage = lastExceptionTraceback; - lua_pop(L, 1); - hasException = true; - - if (exceptionFilters.count("all") || exceptionFilters.count("uncaught")) { - sendExceptionStoppedEvent(lastExceptionMessage); - return; } - sendLogOutput(lastExceptionMessage); - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Mini Runtime Exception", lastExceptionTraceback.c_str(), NULL); - return; - } -} + void init(const char *main_lua_file) { + L = luaL_newstate(); + luaL_openlibs(L); -#include + push_functions(); + lua_register(L, "mini_loader", MiniLoader); + luaL_dostring(L, "table.insert(package.searchers,2,mini_loader)\n"); -std::jthread stdinThread([](std::stop_token st) { - std::string line; - - struct pollfd pfd; - pfd.fd = 0; // stdin - pfd.events = POLLIN; // queremos saber si hay datos - - while (!st.stop_requested()) { - int ret = poll(&pfd, 1, 10); // timeout 10 ms - - if (ret > 0 && (pfd.revents & POLLIN)) { - if (!std::getline(std::cin, line)) { - break; // EOF + int size; + char* buffer = file_getfilebuffer(main_lua_file, size); + if (luaL_loadbuffer(L, buffer, size, "main")) { + log_msg(LOG_LUALD, "%s\n", lua_tostring(L, -1)); + lua_pop(L,1); + return; + } + free(buffer); + if (lua_pcall(L,0, LUA_MULTRET, 0)) { + //luaL_traceback(L, L, NULL, 1); + log_msg(LOG_LUART, "%s\n", lua_tostring(L, -1)); + lua_pop(L,1); + return; } - { - std::lock_guard lock(g_cmdMutex); - g_debugCommands.push(line); - printf("COMANDO RECIBIDO: %s\n", line.c_str()); + // Check if _init and _update exist + lua_getglobal(L, "mini"); + lua_getfield(L, -1, "init"); + if (lua_isfunction(L,-1)) init_exists = true; + lua_pop(L,1); + lua_pop(L,1); + + lua_getglobal(L, "mini"); + lua_getfield(L, -1, "update"); + if (lua_isfunction(L,-1)) update_exists = true; + lua_pop(L,1); + lua_pop(L,1); + + //std::thread(debugCommandThread).detach(); + printf("stdin isatty: %d\n", isatty(0)); + is_playing = true; + } + + void quit() { + if (!is_playing) return; + is_playing = false; + lua_close(L); + } + + void cleanup() { + debug::kill_thread(); + } + + namespace callbacks + { + void init() { + if (!init_exists) return; + debug::process_commands(L); + lua_getglobal(L, "mini"); + lua_getfield(L, -1, "init"); + + is_playing = debug::call_and_handle_exceptions(L); } - } else { - SDL_Delay(1); + + void update() { + if (!update_exists) return; + lua_getglobal(L, "mini"); + lua_getfield(L, -1, "update"); + + is_playing = debug::call_and_handle_exceptions(L); + } + } } -}); - - -void lua_quit() { - if (!is_playing) return; - is_playing = false; - lua_close(L); -} - -void lua_kill_thread() { - g_running = false; - stdinThread.request_stop(); -} - -void lua_toggle_debug() { - if (debug_enabled) { - debug_enabled = false; - lua_sethook(L, NULL,0, 0); - } else { - debug_enabled = true; - lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKRET, 0); - } } diff --git a/source/lua.debug.cpp b/source/lua.debug.cpp new file mode 100644 index 0000000..2356b9e --- /dev/null +++ b/source/lua.debug.cpp @@ -0,0 +1,1361 @@ +#include "lua.debug.h" +#include "lua/lua.hpp" +#include "mini.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mini +{ + namespace lua + { + namespace debug + { + struct Breakpoint { + int line; + std::string condition; // puede estar vacío + std::string logMessage; // "" si no es logpoint + std::string hitCondition; // "" si no hay hit count + }; + + struct FrameInfo { + int level; // nivel en lua_getstack + std::string source; + int line; + //std::vector locals; + //std::vector upvalues; + }; + + struct StackFrameInfo { + std::string file; + int line; + std::string function; + }; + std::string lastExceptionTraceback; + std::vector lastExceptionStack; + std::string lastExceptionMessage; + bool hasException = false; + + std::set exceptionFilters;// {"all"}; + std::vector g_frames; + + //std::unordered_map> g_breakpoints; + std::unordered_map> g_breakpoints; + std::mutex g_breakMutex; + + std::queue g_debugCommands; + std::mutex g_cmdMutex; + + std::atomic g_running = true; + std::atomic g_paused = false; + + std::string g_pauseFile; + int g_pauseLine = 0; + bool function_has_breakpoints = false; + std::stack funBreakStack; + bool debug_enabled = true; + + enum StepMode { + STEP_NONE, + STEP_INTO, + STEP_OVER, + STEP_OUT + }; + + StepMode g_stepMode = STEP_NONE; + int g_stepDepth = 0; + + using json = nlohmann::json; + + std::string pathToChunk(const std::string& path) { + std::filesystem::path p(path); + + // 1. Normalizar la ruta + p = p.lexically_normal(); + + // 2. Buscar el directorio "data" + auto it = std::find(p.begin(), p.end(), "data"); + if (it == p.end()) + return ""; // no es un script Lua válido + + // 3. Construir la parte relativa después de "data" + std::filesystem::path rel; + for (++it; it != p.end(); ++it) + rel /= *it; + + // 4. Quitar ".lua" + std::string s = rel.string(); + if (s.ends_with(".lua")) + s = s.substr(0, s.size() - 4); + + // 5. Convertir "/" → "." + for (char& c : s) + if (c == '/') + c = '.'; + + return s; + } + + std::string chunkToPath(const std::string& chunk) { + // 1. Convertir "ia.test" → "ia/test" + std::string rel; + rel.reserve(chunk.size() + 10); + + for (char c : chunk) + rel += (c == '.' ? '/' : c); + + // 2. Añadir prefijo y sufijo + rel = "data/" + rel + ".lua"; + + // 3. Convertir a ruta absoluta + std::filesystem::path abs = std::filesystem::current_path() / rel; + + return abs.lexically_normal().string(); + } + + int getStackDepth(lua_State* L) { + lua_Debug ar; + int depth = 0; + + while (lua_getstack(L, depth, &ar)) { + depth++; + } + + return depth; + } + + json getStackTrace(lua_State* L) { + json frames = json::array(); + lua_Debug ar; + + int depth = 0; + while (lua_getstack(L, depth, &ar)) { + lua_getinfo(L, "nSl", &ar); + + //const char* src = chunkToPath(ar.source).c_str(); + + json frame = { + { "file", chunkToPath(ar.source).c_str() }, + { "line", ar.currentline }, + { "name", ar.name ? ar.name : "?" } + }; + + frames.push_back(frame); + depth++; + } + + return json{ + { "frames", frames } + }; + } + + int allocateRefForTable(lua_State* L, int index) { + lua_pushvalue(L, index); // copia la tabla + int ref = luaL_ref(L, LUA_REGISTRYINDEX); + return ref; + } + + bool pushTableFromRef(lua_State* L, int ref) { + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + + if (!lua_istable(L, -1)) { + lua_pop(L, 1); + return false; + } + + return true; + } + + json getLocals(lua_State* L, int frame) { + json vars = json::array(); + + lua_Debug ar; + // Obtenemos el frame solicitado + if (!lua_getstack(L, frame, &ar)) { + printf("INVALID STACK FRAME\n"); + return json{ {"variables", vars} }; + } + + // Pedimos info del frame + lua_getinfo(L, "nSl", &ar); + + int i = 1; + const char* name; + + while ((name = lua_getlocal(L, &ar, i)) != NULL) { + + if (strcmp(name, "(temporary)") == 0) { + lua_pop(L, 1); + i++; + continue; + } + + json v; + v["name"] = name; + + int type = lua_type(L, -1); + + switch (type) { + case LUA_TNUMBER: + v["value"] = std::to_string(lua_tonumber(L, -1)); + v["type"] = "number"; + v["ref"] = 0; + break; + + case LUA_TBOOLEAN: + v["value"] = lua_toboolean(L, -1) ? "true" : "false"; + v["type"] = "boolean"; + v["ref"] = 0; + break; + + case LUA_TSTRING: + v["value"] = lua_tostring(L, -1); + v["type"] = "string"; + v["ref"] = 0; + break; + + case LUA_TTABLE: + v["value"] = "{table}"; + v["type"] = "table"; + v["ref"] = allocateRefForTable(L, -1); + break; + + case LUA_TFUNCTION: + v["value"] = "function"; + v["type"] = "function"; + v["ref"] = 0; + break; + + case LUA_TNIL: + v["value"] = "nil"; + v["type"] = "nil"; + v["ref"] = 0; + break; + + default: + v["value"] = lua_typename(L, type); + v["type"] = lua_typename(L, type); + v["ref"] = 0; + break; + } + + vars.push_back(v); + + // Quitamos el valor de la pila + lua_pop(L, 1); + + i++; + } + + return json{ + { "variables", vars } + }; + } + + json getUpvalues(lua_State* L, int frame) { + json vars = json::array(); + + lua_Debug ar; + if (!lua_getstack(L, frame, &ar)) { + return json{ {"variables", vars} }; + } + + // Pedimos info del frame, incluyendo la función ("f") + lua_getinfo(L, "nSlf", &ar); + + // La función está ahora en la pila + int funcIndex = lua_gettop(L); + + int i = 1; + const char* name; + + while ((name = lua_getupvalue(L, funcIndex, i)) != NULL) { + json v; + v["name"] = name; + + int type = lua_type(L, -1); + + switch (type) { + case LUA_TNUMBER: + v["value"] = std::to_string(lua_tonumber(L, -1)); + v["type"] = "number"; + v["ref"] = 0; + break; + + case LUA_TBOOLEAN: + v["value"] = lua_toboolean(L, -1) ? "true" : "false"; + v["type"] = "boolean"; + v["ref"] = 0; + break; + + case LUA_TSTRING: + v["value"] = lua_tostring(L, -1); + v["type"] = "string"; + v["ref"] = 0; + break; + + case LUA_TTABLE: + v["value"] = "{table}"; + v["type"] = "table"; + v["ref"] = allocateRefForTable(L, -1); + break; + + case LUA_TNIL: + v["value"] = "nil"; + v["type"] = "nil"; + v["ref"] = 0; + break; + + default: + v["value"] = lua_typename(L, type); + v["type"] = lua_typename(L, type); + v["ref"] = 0; + break; + } + + vars.push_back(v); + + lua_pop(L, 1); // quitamos el valor del upvalue + i++; + } + + // Quitamos la función del stack + lua_pop(L, 1); + + return json{ + { "variables", vars } + }; + } + + json getGlobals(lua_State* L) { + json vars = json::array(); + + // Empujamos _G a la pila + lua_pushglobaltable(L); // equivalente a lua_getglobal(L, "_G") + + lua_pushnil(L); // primera clave + while (lua_next(L, -2) != 0) { + // Ahora en la pila: + // -1 → valor + // -2 → clave + // -3 → _G + + // Solo aceptamos claves string + if (lua_type(L, -2) == LUA_TSTRING) { + const char* name = lua_tostring(L, -2); + + json v; + v["name"] = name; + + int type = lua_type(L, -1); + + switch (type) { + case LUA_TNUMBER: + v["value"] = std::to_string(lua_tonumber(L, -1)); + v["type"] = "number"; + v["ref"] = 0; + break; + + case LUA_TBOOLEAN: + v["value"] = lua_toboolean(L, -1) ? "true" : "false"; + v["type"] = "boolean"; + v["ref"] = 0; + break; + + case LUA_TSTRING: + v["value"] = lua_tostring(L, -1); + v["type"] = "string"; + v["ref"] = 0; + break; + + case LUA_TTABLE: + v["value"] = "{table}"; + v["type"] = "table"; + v["ref"] = allocateRefForTable(L, -1); + break; + + case LUA_TFUNCTION: + v["value"] = "function"; + v["type"] = "function"; + v["ref"] = 0; + break; + + case LUA_TNIL: + v["value"] = "nil"; + v["type"] = "nil"; + v["ref"] = 0; + break; + + default: + v["value"] = lua_typename(L, type); + v["type"] = lua_typename(L, type); + v["ref"] = 0; + break; + } + + vars.push_back(v); + } + + lua_pop(L, 1); // pop valor, deja clave para lua_next + } + + lua_pop(L, 1); // pop _G + + return json{ + { "variables", vars } + }; + } + + json expandTable(lua_State* L, int ref) { + json vars = json::array(); + + // Recuperamos la tabla del registry + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + json v; + + // clave + if (lua_type(L, -2) == LUA_TSTRING) { + v["name"] = lua_tostring(L, -2); + } else if (lua_type(L, -2) == LUA_TNUMBER) { + v["name"] = std::to_string(lua_tonumber(L, -2)); + } else { + v["name"] = ""; + } + + // valor + int type = lua_type(L, -1); + + switch (type) { + case LUA_TNUMBER: + v["value"] = std::to_string(lua_tonumber(L, -1)); + v["type"] = "number"; + v["ref"] = 0; + break; + + case LUA_TBOOLEAN: + v["value"] = lua_toboolean(L, -1) ? "true" : "false"; + v["type"] = "boolean"; + v["ref"] = 0; + break; + + case LUA_TSTRING: + v["value"] = lua_tostring(L, -1); + v["type"] = "string"; + v["ref"] = 0; + break; + + case LUA_TTABLE: + v["value"] = "{table}"; + v["type"] = "table"; + v["ref"] = allocateRefForTable(L, -1); + break; + + default: + v["value"] = lua_typename(L, type); + v["type"] = lua_typename(L, type); + v["ref"] = 0; + break; + } + + vars.push_back(v); + + lua_pop(L, 1); // pop valor + } + + lua_pop(L, 1); // pop tabla + + return json{ + { "kind", "expand" }, + { "variables", vars } + }; + } + + json setVariable(lua_State* L, int frame, const std::string& scope, + const std::string& name, const std::string& valueStr) + { + lua_Debug ar; + + if (!lua_getstack(L, frame, &ar)) { + return { {"error", "invalid frame"} }; + } + + lua_getinfo(L, "nSl", &ar); + + // Convertir valueStr a valor Lua + auto pushValue = [&](const std::string& s) { + // número + char* end; + double num = strtod(s.c_str(), &end); + if (*end == '\0') { + lua_pushnumber(L, num); + return; + } + + // boolean + if (s == "true") { lua_pushboolean(L, 1); return; } + if (s == "false") { lua_pushboolean(L, 0); return; } + + // nil + if (s == "nil") { lua_pushnil(L); return; } + + // string + lua_pushstring(L, s.c_str()); + }; + + if (scope == "locals") { + int i = 1; + const char* localName; + while ((localName = lua_getlocal(L, &ar, i)) != NULL) { + lua_pop(L, 1); // pop old value + + if (name == localName) { + pushValue(valueStr); + lua_setlocal(L, &ar, i); + return { {"value", valueStr} }; + } + + i++; + } + } + + if (scope == "upvalues") { + lua_getinfo(L, "f", &ar); // push function + + int i = 1; + const char* upName; + while ((upName = lua_getupvalue(L, -1, i)) != NULL) { + lua_pop(L, 1); // pop old value + + if (name == upName) { + pushValue(valueStr); + lua_setupvalue(L, -1, i); + lua_pop(L, 1); // pop function + return { {"value", valueStr} }; + } + + i++; + } + + lua_pop(L, 1); // pop function + } + + if (scope == "globals") { + pushValue(valueStr); + lua_setglobal(L, name.c_str()); + return { {"value", valueStr} }; + } + + return { {"error", "variable not found"} }; + } + + json setTableField(lua_State* L, int ref, const std::string& key, const std::string& valueStr) + { + // Recuperar la tabla desde tu sistema de referencias + if (!pushTableFromRef(L, ref)) { + return { {"error", "invalid table ref"} }; + } + + // Convertir el valor + auto pushValue = [&](const std::string& s) { + char* end; + double num = strtod(s.c_str(), &end); + if (*end == '\0') { lua_pushnumber(L, num); return; } + if (s == "true") { lua_pushboolean(L, 1); return; } + if (s == "false") { lua_pushboolean(L, 0); return; } + if (s == "nil") { lua_pushnil(L); return; } + lua_pushstring(L, s.c_str()); + }; + + pushValue(valueStr); + + // tabla[key] = valor + lua_setfield(L, -2, key.c_str()); + + lua_pop(L, 1); // pop tabla + + return { {"value", valueStr} }; + } + + json evalExpression(lua_State* L, const std::string& expr) { + lua_Debug ar; + if (!lua_getstack(L, 0, &ar)) { + return { {"error", "no stack"} }; + } + + lua_getinfo(L, "nSl", &ar); + + // Creamos un entorno para la evaluación + lua_newtable(L); // env + int envIndex = lua_gettop(L); + + // 1. Copiar locals al env + int i = 1; + const char* name; + while ((name = lua_getlocal(L, &ar, i)) != NULL) { + lua_setfield(L, envIndex, name); + i++; + } + + // 2. Copiar upvalues al env + lua_getinfo(L, "f", &ar); + int funcIndex = lua_gettop(L); + + i = 1; + while ((name = lua_getupvalue(L, funcIndex, i)) != NULL) { + lua_setfield(L, envIndex, name); + i++; + } + + lua_pop(L, 1); // pop función + + // 3. Copiar globals (_G) + lua_pushglobaltable(L); + lua_setfield(L, envIndex, "_G"); + // mt = { __index = _G } + lua_newtable(L); // mt + lua_pushglobaltable(L); // _G + lua_setfield(L, -2, "__index"); // mt.__index = _G + + // setmetatable(env, mt) + lua_setmetatable(L, envIndex); + + // 4. Construir código: función que recibe _ENV + std::string code = "return function(_ENV) return " + expr + " end"; + + if (luaL_loadbuffer(L, code.c_str(), code.size(), "eval") != LUA_OK) { + std::string err = lua_tostring(L, -1); + lua_pop(L, 1); + return { {"error", err} }; + } + + // Ejecutar para obtener la función interna + if (lua_pcall(L, 0, 1, 0) != LUA_OK) { + std::string err = lua_tostring(L, -1); + lua_pop(L, 1); + return { {"error", err} }; + } + + // Ahora en la pila está la función interna + // Le pasamos env como argumento + lua_pushvalue(L, envIndex); + + // Llamamos a la función(env) + if (lua_pcall(L, 1, 1, 0) != LUA_OK) { + std::string err = lua_tostring(L, -1); + lua_pop(L, 1); + return { {"error", err} }; + } + + // Convertir el resultado + json result; + + int type = lua_type(L, -1); + switch (type) { + case LUA_TNUMBER: + result["value"] = std::to_string(lua_tonumber(L, -1)); + result["type"] = "number"; + result["ref"] = 0; + break; + + case LUA_TBOOLEAN: + result["value"] = lua_toboolean(L, -1) ? "true" : "false"; + result["type"] = "boolean"; + result["ref"] = 0; + break; + + case LUA_TSTRING: + result["value"] = lua_tostring(L, -1); + result["type"] = "string"; + result["ref"] = 0; + break; + + case LUA_TTABLE: + result["value"] = "{table}"; + result["type"] = "table"; + result["ref"] = allocateRefForTable(L, -1); + break; + + default: + result["value"] = lua_typename(L, type); + result["type"] = lua_typename(L, type); + result["ref"] = 0; + break; + } + + lua_pop(L, 1); // pop result + lua_pop(L, 1); // pop env + + return result; + } + + json evalAssign(lua_State* L, int frame, const std::string& expr) { + // 1. Separar LHS y RHS + size_t eq = expr.find('='); + if (eq == std::string::npos) { + return { {"error", "not an assignment"} }; + } + + std::string lhs = expr.substr(0, eq); + std::string rhs = expr.substr(eq + 1); + + // limpiar espacios + auto trim = [](std::string& s) { + size_t a = s.find_first_not_of(" \t"); + size_t b = s.find_last_not_of(" \t"); + if (a == std::string::npos) { s = ""; return; } + s = s.substr(a, b - a + 1); + }; + + trim(lhs); + trim(rhs); + + // 2. Evaluar RHS usando tu evalExpression + json rhsValue = evalExpression(L, rhs); + if (rhsValue.contains("error")) { + return rhsValue; + } + + std::string rhsStr = rhsValue["value"]; + + // 3. Determinar si LHS es: + // - variable simple: x + // - acceso tabla: player.health + // - acceso profundo: a.b.c + if (lhs.find('.') == std::string::npos) { + // variable simple → locals, upvalues o globals + // Intentar locals + json r = setVariable(L, frame, "locals", lhs, rhsStr); + if (!r.contains("error")) return r; + + // Intentar upvalues + r = setVariable(L, frame, "upvalues", lhs, rhsStr); + if (!r.contains("error")) return r; + + // Intentar globals + r = setVariable(L, frame, "globals", lhs, rhsStr); + return r; + } + + // 4. Acceso tabla: a.b.c + // separar en partes + std::vector parts; + { + std::stringstream ss(lhs); + std::string item; + while (std::getline(ss, item, '.')) { + trim(item); + parts.push_back(item); + } + } + + if (parts.size() < 2) { + return { {"error", "invalid table assignment"} }; + } + + // La clave final + std::string finalKey = parts.back(); + parts.pop_back(); + + // 5. Evaluar la ruta de tabla (a.b.c → obtener tabla c) + // usando tu evalExpression + std::string tableExpr; + for (size_t i = 0; i < parts.size(); i++) { + if (i > 0) tableExpr += "."; + tableExpr += parts[i]; + } + + json tableValue = evalExpression(L, tableExpr); + if (tableValue.contains("error")) { + return tableValue; + } + + if (tableValue["type"] != "table") { + return { {"error", "LHS is not a table"} }; + } + + int ref = tableValue["ref"]; + + // 6. Asignar dentro de la tabla + return setTableField(L, ref, finalKey, rhsStr); + } + + void sendDebugResponse(const std::string& type, const json& payload) { + json msg = { + { "type", type }, + { "payload", payload } + }; + //printf("STACKTRACE: %s", msg.dump().c_str()); + std::cout << "@@DEBUG@@" << msg.dump() << std::endl; + } + + void parseLuaTraceback(const char* tb, std::vector& out) { + out.clear(); + if (!tb) return; + + std::stringstream ss(tb); + std::string line; + + bool inFrames = false; + + while (std::getline(ss, line)) { + // Quitar espacios iniciales y tabs + while (!line.empty() && (line[0] == ' ' || line[0] == '\t')) + line.erase(line.begin()); + + // Saltar la primera línea (mensaje de error) + if (!inFrames) { + if (line.rfind("stack traceback:", 0) == 0) { + inFrames = true; + } + continue; + } + + // Formato esperado: + // [string "modules.ia.hero"]:189: in field 'ia' + // + // O: + // [string "main"]:34: in function <[string "main"]:32> + + if (line.rfind("[string \"", 0) != 0) + continue; + + // Extraer chunk name + size_t q1 = line.find('"'); + size_t q2 = line.find('"', q1 + 1); + if (q1 == std::string::npos || q2 == std::string::npos) + continue; + + std::string chunk = line.substr(q1 + 1, q2 - q1 - 1); + + // Extraer línea + size_t colon1 = line.find(':', q2 + 1); + if (colon1 == std::string::npos) + continue; + + size_t colon2 = line.find(':', colon1 + 1); + if (colon2 == std::string::npos) + continue; + + int lineNumber = std::stoi(line.substr(colon1 + 1, colon2 - colon1 - 1)); + + // Extraer nombre de función (si existe) + std::string func = "unknown"; + + size_t inField = line.find("in field '"); + if (inField != std::string::npos) { + size_t start = inField + 10; + size_t end = line.find("'", start); + func = line.substr(start, end - start); + } + + size_t inFunc = line.find("in function <"); + if (inFunc != std::string::npos) { + func = "anonymous"; + } + + // Convertir chunk → ruta real + std::string filePath = chunkToPath(chunk); + + out.push_back({ filePath, lineNumber, func }); + } + } + + void processDebugCommand(lua_State* L, const std::string& line) { + //printf("COMANDO PROCESADO: %s\n", line.c_str()); + if (!line.starts_with("@@DEBUGCMD@@")) + return; + + json j = json::parse(line.substr(12)); + + std::string cmd = j["cmd"]; + + if (cmd == "setBreakpoints") { + std::string file = j["file"]; + std::string chunk = pathToChunk(file); + std::lock_guard lock(g_breakMutex); + + g_breakpoints[chunk].clear(); + + for (auto& bp : j["breakpoints"]) { + Breakpoint b; + b.line = bp["line"]; + + if (bp.contains("condition") && bp["condition"].is_string()) + b.condition = bp["condition"]; + else + b.condition = ""; + + if (bp.contains("logMessage") && bp["logMessage"].is_string()) + b.logMessage = bp["logMessage"]; + else + b.logMessage = ""; + + if (bp.contains("hitCondition") && bp["hitCondition"].is_string()) + b.hitCondition = bp["hitCondition"]; + else + b.hitCondition = ""; + + g_breakpoints[chunk].push_back(b); + } + } + else if (cmd == "continue") { + printf("CONTINUA\n\n"); + g_stepMode = STEP_NONE; + g_paused = false; + raisewindow(); + } + else if (cmd == "pause") { + g_stepMode = STEP_INTO; + g_paused = false; + } + else if (cmd == "stepOver") { + g_stepMode = STEP_OVER; + g_stepDepth = getStackDepth(L); + g_paused = false; + } + else if (cmd == "stepInto") { + g_stepMode = STEP_INTO; + g_paused = false; + } + else if (cmd == "stepOut") { + g_stepMode = STEP_OUT; + g_stepDepth = getStackDepth(L); + g_paused = false; + } + else if (cmd == "stackTrace") { + if (hasException) { + parseLuaTraceback(lastExceptionTraceback.c_str(), lastExceptionStack); + + json frames = json::array(); + + for (size_t i = 0; i < lastExceptionStack.size(); i++) { + frames.push_back({ + { "id", (int)i + 1 }, + { "name", lastExceptionStack[i].function }, + { "line", lastExceptionStack[i].line }, + { "column", 1 }, + { "source", { + { "path", lastExceptionStack[i].file } + }} + }); + } + + json result = { + { "stackFrames", frames }, + { "totalFrames", frames.size() } + }; + + sendDebugResponse("stackTrace", result); + } else { + json result = getStackTrace(L); + sendDebugResponse("stackTrace", result); + } + } + else if (cmd == "locals") { + int frame = j.value("frame", 0); + json result = getLocals(L, frame); + json payload = { + { "kind", "locals" }, + { "variables", result["variables"] } + }; + sendDebugResponse("variables", payload); + } + else if (cmd == "upvalues") { + int frame = j.value("frame", 0); + json result = getUpvalues(L, frame); + json payload = { + { "kind", "upvalues" }, + { "variables", result["variables"] } + }; + sendDebugResponse("variables", payload); + } + else if (cmd == "globals") { + json result = getGlobals(L); + json payload = { + { "kind", "globals" }, + { "variables", result["variables"] } + }; + sendDebugResponse("variables", payload); + } + else if (cmd == "expand") { + int ref = j["ref"]; + json result = expandTable(L, ref); + sendDebugResponse("variables", result); + } + else if (cmd == "eval") { + std::string expr = j["expr"]; + json result = evalExpression(L, expr); + + json payload = { + { "kind", "eval" }, + { "result", result } + }; + sendDebugResponse("eval", payload); + } + else if (cmd == "evalAssign") { + int frame = j.value("frame", 0); + std::string expr = j["expr"]; + + json result = evalAssign(L, frame, expr); + + json payload = { + { "kind", "eval" }, + { "result", result } + }; + + sendDebugResponse("eval", payload); + } + else if (cmd == "setVariable") { + int frame = j.value("frame", 0); + std::string scope = j["scope"]; + std::string name = j["name"]; + std::string value = j["value"]; + + json result = setVariable(L, frame, scope, name, value); + + sendDebugResponse("setVariable", result); + } + else if (cmd == "setTableField") { + int ref = j["ref"]; + std::string key = j["key"]; + std::string valueStr = j["value"]; + + json result = setTableField(L, ref, key, valueStr); + + sendDebugResponse("setVariable", result); + } + else if (cmd == "setExceptionFilters") { + exceptionFilters.clear(); + for (auto& f : j["filters"]) { + exceptionFilters.insert(f.get()); + } + } + } + + bool checkBreakpointCondition(lua_State* L, const Breakpoint& bp) { + if (bp.condition.empty()) return true; + + json result = evalExpression(L, bp.condition); + if (result.contains("error")) return false; + if (result["type"] == "boolean") return result["value"] == "true"; + + // Si la condición no devuelve booleano, se considera false + return false; + } + + std::string expandLogMessage(lua_State* L, const std::string& msg) { + std::string out; + size_t i = 0; + + while (i < msg.size()) { + if (msg[i] == '{') { + size_t j = msg.find('}', i + 1); + if (j == std::string::npos) break; + + std::string expr = msg.substr(i + 1, j - i - 1); + + json r = evalExpression(L, expr); + out += r.value("value", "nil"); + + i = j + 1; + } else { + out += msg[i++]; + } + } + + return out; + } + + void sendLogOutput(const std::string& text) { + json payload = { + { "kind", "log" }, + { "text", text } + }; + sendDebugResponse("log", payload); + } + + bool isBreakpoint(lua_State* L, const std::string& file, int line) { + std::lock_guard lock(g_breakMutex); + + auto it = g_breakpoints.find(file); + if (it == g_breakpoints.end()) + return false; + + for (auto& bp : it->second) { + if (bp.line == line) { + if (!bp.logMessage.empty()) { + std::string msg = expandLogMessage(L, bp.logMessage); + sendLogOutput(msg); + return false; // NO parar + } else if (checkBreakpointCondition(L, bp)) { + return true; + } + + } + } + + return false; + } + + void sendBreakEvent(const std::string& file, int line) { + json j = { + {"type", "break"}, + {"file", file}, + {"line", line} + }; + + std::cout << "@@DEBUG@@" << j.dump() << std::endl; + std::cout.flush(); + } + + std::string waitForDebugCommand() { + //printf("HOLA"); + while (true) { + { + std::lock_guard lock(g_cmdMutex); + if (!g_debugCommands.empty()) { + std::string cmd = g_debugCommands.front(); + g_debugCommands.pop(); + return cmd; + } + } + + SDL_Delay(1); + } + } + + bool shouldPauseForStepping(lua_State* L, lua_Debug* ar) { + int depth = getStackDepth(L); + + switch (g_stepMode) { + case STEP_INTO: + return true; // siempre parar en la siguiente línea + + case STEP_OVER: + return depth <= g_stepDepth; + + case STEP_OUT: + return depth < g_stepDepth; + + default: + return false; + } + } + + void captureStack(lua_State* L) { + g_frames.clear(); + + lua_Debug ar; + int level = 0; + + while (lua_getstack(L, level, &ar)) { + lua_getinfo(L, "nSl", &ar); + + FrameInfo fi; + fi.level = level; + fi.source = ar.source; + fi.line = ar.currentline; + + g_frames.push_back(fi); + level++; + } + } + + void pauseHere(lua_State* L, const std::string& src, int line) { + g_paused = true; + g_pauseFile = src; + g_pauseLine = line; + g_stepMode = STEP_NONE; + + captureStack(L); + + sendBreakEvent(chunkToPath(src), line); + + while (g_paused) { + std::string cmd = waitForDebugCommand(); + processDebugCommand(L, cmd); + } + } + + extern "C" void luaHook(lua_State* L, lua_Debug* ar) { + lua_getinfo(L, "Sl", ar); + + const char* src = ar->source; + if (src[0]=='=') return; + + if (ar->event == LUA_HOOKCALL) { + funBreakStack.push(function_has_breakpoints); + bool new_function_has_breakpoints = false; + { + std::lock_guard lock(g_breakMutex); + auto it = g_breakpoints.find(src); + new_function_has_breakpoints = (it != g_breakpoints.end() && !it->second.empty()); + } + if (new_function_has_breakpoints || g_stepMode != STEP_NONE) { + if (!function_has_breakpoints) + lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKLINE | LUA_MASKRET, 0); + } else { + //if (function_has_breakpoints) + lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKRET, 0); + } + function_has_breakpoints = new_function_has_breakpoints; + } + else if (ar->event == LUA_HOOKRET) { + // Siempre volver al hook base + bool new_function_has_breakpoints = funBreakStack.empty() ? false : funBreakStack.top(); + funBreakStack.pop(); + if (new_function_has_breakpoints || g_stepMode != STEP_NONE) { + if (!function_has_breakpoints) + lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKLINE | LUA_MASKRET, 0); + } else { + //if (function_has_breakpoints) + lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKRET, 0); + } + function_has_breakpoints = new_function_has_breakpoints; + } + else if (ar->event == LUA_HOOKLINE) { + if (ar->currentline <= 0) return; + const char* src = ar->source; + int line = ar->currentline; + + if (isBreakpoint(L, src, line)) { + pauseHere(L, src, line); + return; + } + + // 2. Stepping + if (g_stepMode != STEP_NONE) { + if (shouldPauseForStepping(L, ar)) { + pauseHere(L, src, line); + return; + } + } + } + } + + void sendExceptionStoppedEvent(const std::string& msg) { + json payload = { + { "reason", "exception" }, + { "text", msg } + }; + sendDebugResponse("stopped", payload); + } + + int luaErrorHandler(lua_State* L) { + const char* msg = lua_tostring(L, 1); + if (!msg) msg = "Unknown error"; + + // Construir traceback + luaL_traceback(L, L, msg, 1); + + const char* tb = lua_tostring(L, -1); + if (tb) { + lastExceptionTraceback = tb; + } else { + lastExceptionTraceback = msg; + } + + // Devolver el traceback a Lua (aunque luego Lua lo sustituya) + return 1; + } + + bool call_and_handle_exceptions(lua_State* L) + { + lua_pushcfunction(L, luaErrorHandler); + lua_insert(L, -2); // poner handler debajo de la función + int status = lua_pcall(L, 0, 0, -2); + lua_pop(L, 1); // quitar handler + + if (status != LUA_OK) { + lastExceptionMessage = lastExceptionTraceback; + lua_pop(L, 1); + hasException = true; + + if (exceptionFilters.count("all") || exceptionFilters.count("uncaught")) { + sendExceptionStoppedEvent(lastExceptionMessage); + return false; + } + + sendLogOutput(lastExceptionMessage); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Mini Runtime Exception", lastExceptionTraceback.c_str(), NULL); + return false; + } + return true; + } + + std::jthread stdinThread([](std::stop_token st) { + std::string line; + + struct pollfd pfd; + pfd.fd = 0; // stdin + pfd.events = POLLIN; // queremos saber si hay datos + + while (!st.stop_requested()) { + int ret = poll(&pfd, 1, 10); // timeout 10 ms + + if (ret > 0 && (pfd.revents & POLLIN)) { + if (!std::getline(std::cin, line)) { + break; // EOF + } + + { + std::lock_guard lock(g_cmdMutex); + g_debugCommands.push(line); + printf("COMANDO RECIBIDO: %s\n", line.c_str()); + } + } else { + SDL_Delay(1); + } + } + }); + + void process_commands(lua_State* L) { + function_has_breakpoints = false; + while (!funBreakStack.empty()) funBreakStack.pop(); + + while (true) { + std::string cmd; + + { + std::lock_guard lock(g_cmdMutex); + if (g_debugCommands.empty()) + break; + + cmd = g_debugCommands.front(); + g_debugCommands.pop(); + } + + processDebugCommand(L, cmd); + } + } + + void kill_thread() { + g_running = false; + stdinThread.request_stop(); + } + + void toggle(lua_State* L) { + if (debug_enabled) { + debug_enabled = false; + lua_sethook(L, NULL,0, 0); + } else { + debug_enabled = true; + lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKRET, 0); + } + } + + } + } +} diff --git a/source/lua.debug.h b/source/lua.debug.h new file mode 100644 index 0000000..fdb81ce --- /dev/null +++ b/source/lua.debug.h @@ -0,0 +1,17 @@ +#pragma once +struct lua_State; + +namespace mini +{ + namespace lua + { + namespace debug + { + bool call_and_handle_exceptions(lua_State* L); + void kill_thread(); + void process_commands(lua_State* L); + void toggle(lua_State* L); + } + + } +} diff --git a/source/lua.h b/source/lua.h index f1f9a0b..8ce7573 100644 --- a/source/lua.h +++ b/source/lua.h @@ -1,11 +1,18 @@ #pragma once -bool lua_is_playing(); -void lua_process_debugger_commands(); -void lua_init(const char* main_lua_file = "main.lua"); -void lua_call_init(); -void lua_call_update(); -void lua_quit(); -void lua_kill_thread(); -void lua_toggle_debug(); -//void lua_disable_debug(); +namespace mini +{ + namespace lua + { + bool runnning(); + void init(const char* main_lua_file = "main.lua"); + void quit(); + void cleanup(); + + namespace callbacks + { + void init(); + void update(); + } + } +} diff --git a/source/main.cpp b/source/main.cpp index d668b17..a763408 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -3,7 +3,7 @@ uint16_t ants = 0xc936; float t = 0; -void loop() { +void exception_loop() { //if (t==0) t= time(); if (time()-t > 0.25) { t = time(); @@ -15,13 +15,13 @@ void loop() { setcolor(1,0xff000000); const int w=scrw(); const int h=scrh(); - set_draw_mode(0); - rect(0,0,w,h,1); - rect(1,1,w-2,h-2,1); - set_draw_mode(1); + mini::draw::mode::set(0); + mini::draw::rect(0,0,w,h,1); + mini::draw::rect(1,1,w-2,h-2,1); + mini::draw::mode::set(1); fillp(ants); - rect(0,0,w,h,0); - rect(1,1,w-2,h-2,0); + mini::draw::rect(0,0,w,h,0); + mini::draw::rect(1,1,w-2,h-2,0); ants = (ants<<12) | (ants>>4); } } \ No newline at end of file diff --git a/source/mini.cpp b/source/mini.cpp index a314d87..b23c297 100644 --- a/source/mini.cpp +++ b/source/mini.cpp @@ -6,7 +6,6 @@ #include "gifenc.h" #include "jail_audio.h" #include "jshader.h" -//#include #include "log.h" #include "default_font_gif.h" @@ -19,14 +18,21 @@ #define SURF_EXTERNAL 1 #define SURF_GENERATED 2 +#define DRAWMODE_NORMAL 0 +#define DRAWMODE_PATTERN 1 +#define DRAWMODE_AND 2 +#define DRAWMODE_OR 3 +#define DRAWMODE_XOR 4 +#define DRAWMODE_NOT 5 + +#define UPDATE_ALWAYS 0 +#define UPDATE_WAIT 1 +#define UPDATE_TIMEOUT 2 + #ifdef MACOS_BUNDLE #include #endif -//DECLSPEC int SDLCALL (*event_handler_ptr)(SDL_Event*) = &SDL_PollEvent; - -#pragma pack(1) - struct surface_t { char *name {nullptr}; uint8_t *p {nullptr}; @@ -47,24 +53,22 @@ struct font_t { }; int fps=0; -int fps_counter=0; -uint32_t fps_timer=0; + char window_title[256]; char config_folder[256]; + uint16_t screen_width = 160; uint16_t screen_height = 120; uint8_t screen_zoom = 4; bool screen_fullscreen = false; bool screen_cursor = true; -int desktop_width = 0; -int desktop_height = 0; - surface_t surfaces[MAX_SURFACES]; surface_t *screen_surface = &surfaces[0]; surface_t *dest_surface = screen_surface; surface_t *source_surface = NULL; surface_t *map_surface = NULL; + uint8_t tile_width = 8; uint8_t tile_height = 8; @@ -80,11 +84,9 @@ bool override_ini = false; #define TILES(x, y) map_surface->p[x+y*map_surface->w] #define CURRENT(x, y) surfaces[i].p[(x)+(y)*surfaces[i].w] -void (*do_pset)(int,int); - namespace ds { int origin[2] = {0, 0}; - int clip[4] = {0, 0, screen_width-1, screen_height-1}; // clip (x1,y1,x2,y2) calculat intersectat amb el tamany de la surface 'dest' + int clip[4] = {0, 0, screen_width-1, screen_height-1}; uint8_t trans = 0; uint16_t fill_pattern = 0b1111111111111111; uint8_t draw_palette[256]; @@ -93,9 +95,12 @@ namespace ds { int update_mode = UPDATE_ALWAYS; int timeout = 0; +uint32_t last_update = 0; +float delta_time = 0.0f; bool should_exit = false; bool should_quit = false; + SDL_Window *mini_win; SDL_Renderer *mini_ren; SDL_Texture *mini_bak; @@ -107,16 +112,6 @@ int pitch; uint32_t palette[256] = { 0xFF1a1c2c, 0xFF5d275d, 0xFFb13e53, 0xFFef7d57, 0xFFffcd75, 0xFFa7f070, 0xFF38b764, 0xFF257179, 0xFF29366f, 0xFF3b5dc9, 0xFF41a6f6, 0xFF73eff7, 0xFFf4f4f4, 0xFF94b0c2, 0xFF566c86, 0xFF333c57 }; -//const char base64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -// -//char base64font[241] = "00@B@]0X__OnZDYK[G10:9BTDEG5j20@1h000RB:_]OBjW?odl]Wlil9_oTT__omT@@02:DA477ADid@Z=nm]_[g9a[]oIi?;a9m]_mBjGB[M]99o_][]e]M" -// "_?A]c_[eiLGBZ]e]mZ]o]Z]mlW:O9IABdTdZ000hR00__H[7?iH]3Oih;1?mXm5GjhB3M]897o]H]5^Mhm1ZchM5>LhB2]eXm2]oXZ5mlhp, col, dest_surface->size); + } + + namespace target { + void recalculate_clip() { + if (ds::clip[0]<0) ds::clip[0]=0; + if (ds::clip[1]<0) ds::clip[1]=0; + if (ds::clip[2]>=dest_surface->w) ds::clip[2]=dest_surface->w-1; + if (ds::clip[3]>=dest_surface->h) ds::clip[3]=dest_surface->h-1; + } + + void set(uint8_t surface) { + dest_surface = &surfaces[surface]; + recalculate_clip(); + } + uint8_t get() { + for (unsigned int i=0; i ds::clip[2] || y < ds::clip[1] || y > ds::clip[3]) return; + switch (ds::mode) { + case DRAWMODE_NORMAL: pset_fast(x,y,color); break; + case DRAWMODE_PATTERN: pset_pattern(x,y,color); break; + default: pset_bool(x,y,color); break; + } + } + + // Per a les funcions que van canviant de color (surf.pixel i draw.surf, bàsicament) + static inline void subst_pset(int x, int y, uint8_t color) { + direct_pset(x,y,ds::draw_palette[color]); + } + + void set(int x, int y, uint8_t color) { + subst_pset(x,y,color); + } + + uint8_t get(int x, int y) { + if (!source_surface) return 0; + if (x < 0 || x > (source_surface->w-1) || y < 0 || y > (source_surface->h-1)) return 0; + return SOURCE(x, y); + } } } -} -static inline void pset_pattern(int x, int y, uint8_t color) { - int pbx = x % 4, pby = y % 4; - int pb = pbx+pby*4; - if (ds::fill_pattern & (1 << pb)) if (ds::trans != color) DEST(x, y) = color; -} + namespace map + { + namespace surf { + void set(uint8_t surface) { + map_surface = &surfaces[surface]; + } -void set_draw_mode(uint8_t mode) { - ds::mode = mode; -} + uint8_t get() + { + for (unsigned int i=0; iw; + int celh = map_surface->h; + + int celx = 0; + int cely = 0; + + int ox = ds::origin[0]; + int oy = ds::origin[1]; + + int sx = ox; + int sy = oy; + + // Clipping global rápido + if (sx + celw * tw < ds::clip[0] || + sy + celh * th < ds::clip[1] || + sx > ds::clip[2] || + sy > ds::clip[3]) + return; + + // Recorte por izquierda + if (sx < ds::clip[0]) { + int diff = (ds::clip[0] - sx) / tw; + celx += diff; + celw -= diff; + sx += diff * tw; + } + + // Recorte por arriba + if (sy < ds::clip[1]) { + int diff = (ds::clip[1] - sy) / th; + cely += diff; + celh -= diff; + sy += diff * th; + } + + // Recorte por derecha + int max_x = ds::clip[2] - sx; + if (max_x < celw * tw) celw = max_x / tw + 1; + + // Recorte por abajo + int max_y = ds::clip[3] - sy; + if (max_y < celh * th) celh = max_y / th + 1; + + // Ahora sx, sy son relativos al origen y ya están recortados + for (int y = 0; y < celh; ++y) { + int ty = sy + y * th; + for (int x = 0; x < celw; ++x) { + uint8_t tile = mget(celx + x, cely + y); + if (!tile) continue; + int tx = sx + x * tw; + tileblit(tile, tx - ox, ty - oy); + } + } + } + + namespace tile { + uint8_t get(int celx, int cely) { + if (!map_surface) return 0; + if (celx < 0 || celx > (map_surface->w-1) || cely < 0 || cely > (map_surface->h-1)) return 0; + return TILES(celx, cely); + } + + void set(int celx, int cely, uint8_t snum) { + if (!map_surface) return; + if (celx < 0 || celx > (map_surface->w-1) || cely < 0 || cely > (map_surface->h-1)) return; + TILES(celx, cely) = snum; + } + } + + namespace cell { + uint8_t getw() { return tile_width; } + uint8_t geth() { return tile_height; } + + void set(int w, int h) { + tile_width = w; + tile_height = h; + } + } + + } + + namespace draw + { + // Bresenham Line Algorithm + void line(int x0, int y0, int x1, int y1, uint8_t color) { + int x, y; + int dx, dy; + int incx, incy; + int balance; + color = ds::draw_palette[color]; + + if (x1 >= x0) { dx = x1 - x0; incx = 1; } else { dx = x0 - x1; incx = -1; } + if (y1 >= y0) { dy = y1 - y0; incy = 1; } else { dy = y0 - y1; incy = -1; } + + x = x0; y = y0; + + if (dx >= dy) { + dy <<= 1; + balance = dy - dx; + dx <<= 1; + + while (x != x1) { + direct_pset(x, y, color); + if (balance >= 0) { y += incy; balance -= dx; } + balance += dy; + x += incx; + } + direct_pset(x, y, color); + } else { + dx <<= 1; + balance = dx - dy; + dy <<= 1; + + while (y != y1) { + direct_pset(x, y, color); + if (balance >= 0) { x += incx; balance -= dy; } + balance += dx; + y += incy; + } + direct_pset(x, y, color); + } + } + + void hline(int x0, int y, int x1, uint8_t color) { + color = ds::draw_palette[color]; + if (x0>x1) { const int tmp=x0;x0=x1;x1=tmp; } + for (int x=x0; x<=x1; ++x) direct_pset(x, y, color); + } + + void vline(int x, int y0, int y1, uint8_t color) { + color = ds::draw_palette[color]; + if (y0>y1) { const int tmp=y0;y0=y1;y1=tmp; } + for (int y=y0; y<=y1; ++y) direct_pset(x, y, color); + } + + void rect(int x, int y, int w, int h, uint8_t color) { + int x1 = w+x-1; + int y1 = h+y-1; + hline(x, y, x1, color); + hline(x, y1, x1, color); + vline(x, y, y1, color); + vline(x1, y, y1, color); + } + + void rectf(int x, int y, int w, int h, uint8_t color) { + int x1 = w+x-1; + int y1 = h+y-1; + for (int i=y; i<=y1; ++i) hline(x, i, x1, color); + } + + static inline void circ_scanline(int xc, int yc, int x, int y, uint8_t color) { + direct_pset(xc+x, yc+y, color); + direct_pset(xc-x, yc+y, color); + direct_pset(xc+x, yc-y, color); + direct_pset(xc-x, yc-y, color); + direct_pset(xc+y, yc+x, color); + direct_pset(xc-y, yc+x, color); + direct_pset(xc+y, yc-x, color); + direct_pset(xc-y, yc-x, color); + } + + void circ(int x, int y, uint8_t r, uint8_t color) { + color = ds::draw_palette[color]; + int xi=0, yi=r; + int d=3-2*r; + circ_scanline(x, y, xi, yi, color); + while (yi>=xi++) { + d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6; + circ_scanline(x, y, xi, yi, color); + } + } + + static inline void circf_scanline(int xc, int yc, int x, int y, uint8_t color) { + hline(xc-x, yc+y, xc+x, color); + hline(xc-x, yc-y, xc+x, color); + hline(xc-y, yc+x, xc+y, color); + hline(xc-y, yc-x, xc+y, color); + } + + void circf(int x, int y, uint8_t r, uint8_t color) { + int xi=0, yi=r; + int d=3-2*r; + circf_scanline(x, y, xi, yi, color); + while (yi>=xi++) { + d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6; + circf_scanline(x, y, xi, yi, color); + } + } + + + void roundrect(int x, int y, int w, int h, uint8_t r, uint8_t color) { + int xi=0, yi=r; + int d=3-2*r; + + int xf = w+x-1; + int yf = h+y-1; + int x1 = x+r, y1 = y+r; + int x2 = xf-r, y2 = yf-r; + hline(x1, y, x2, color); + hline(x1, yf, x2, color); + vline(x, y1, y2, color); + vline(xf, y1, y2, color); + + color = ds::draw_palette[color]; + while (yi>=xi++) { + d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6; + direct_pset(x2+xi, y2+yi, color); + direct_pset(x1-xi, y2+yi, color); + direct_pset(x2+xi, y1-yi, color); + direct_pset(x1-xi, y1-yi, color); + direct_pset(x2+yi, y2+xi, color); + direct_pset(x1-yi, y2+xi, color); + direct_pset(x2+yi, y1-xi, color); + direct_pset(x1-yi, y1-xi, color); + } + } + + void roundrectf(int x, int y, int w, int h, uint8_t r, uint8_t color) { + int xi=0, yi=r; + int d=3-2*r; + + int xf = w+x-1; + int yf = h+y-1; + int x1 = x+r, y1 = y+r; + int x2 = xf-r, y2 = yf-r; + for (int i=y1; i<=y2; ++i) hline(x, i, xf, color); + + while (yi>=xi++) { + d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6; + hline(x1-xi, y2+yi, x2+xi, color); + hline(x1-xi, y1-yi, x2+xi, color); + hline(x1-yi, y2+xi, x2+yi, color); + hline(x1-yi, y1-xi, x2+yi, color); + } + } + + void oval_scanline(int xc, int yc, int x, int y, float xf, float yf, uint8_t color) { + direct_pset((xc+x)*xf, (yc+y)*yf, color); + direct_pset((xc-x)*xf, (yc+y)*yf, color); + direct_pset((xc+x)*xf, (yc-y)*yf, color); + direct_pset((xc-x)*xf, (yc-y)*yf, color); + direct_pset((xc+y)*xf, (yc+x)*yf, color); + direct_pset((xc-y)*xf, (yc+x)*yf, color); + direct_pset((xc+y)*xf, (yc-x)*yf, color); + direct_pset((xc-y)*xf, (yc-x)*yf, color); + } + + void oval(int x0, int y0, int x1, int y1, uint8_t color) { + color = ds::draw_palette[color]; + int rx = (x1-x0)/2; + int ry = (y1-y0)/2; + int r = rx; + int x = x0 + rx; + int y = y0 + ry; + float xf = 1.0f, yf = 1.0f; + if (rx>=ry) {r=rx;yf=float(ry)/float(rx);} else {r=ry;xf=float(rx)/float(ry);} + int xi=0, yi=r; + int d=3-2*r; + oval_scanline(x, y, xi, yi, xf, yf, color); + while (yi>=xi++) { + d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6; + oval_scanline(x, y, xi, yi, xf, yf, color); + } + } + + static inline void ovalf_scanline(int xc, int yc, int x, int y, float xf, float yf, uint8_t color) { + hline((xc-x)*xf, (yc+y)*yf, (xc+x)*xf, color); + hline((xc-x)*xf, (yc-y)*yf, (xc+x)*xf, color); + hline((xc-y)*xf, (yc+x)*yf, (xc+y)*xf, color); + hline((xc-y)*xf, (yc-x)*yf, (xc+y)*xf, color); + } + + void ovalf(int x0, int y0, int x1, int y1, uint8_t color) { + int rx = (x1-x0)/2; + int ry = (y1-y0)/2; + int r = rx; + int x = x0 + rx; + int y = y0 + ry; + float xf = 1.0f, yf = 1.0f; + if (rx>=ry) {r=rx;yf=float(ry)/float(rx);} else {r=ry;xf=float(rx)/float(ry);} + int xi=0, yi=r; + int d=3-2*r; + ovalf_scanline(x, y, xi, yi, xf, yf, color); + while (yi>=xi++) { + d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6; + ovalf_scanline(x, y, xi, yi, xf, yf, color); + } + } + + namespace mode { + void set(uint8_t mode) { + ds::mode = mode; + } + } + } } void initaudio() { @@ -243,169 +730,9 @@ int scrh() { return screen_height; } -uint8_t newsurf(int w, int h) { - unsigned int i = 0; - while (i=dest_surface->w) ds::clip[2]=dest_surface->w-1; - if (ds::clip[3]>=dest_surface->h) ds::clip[3]=dest_surface->h-1; -} - -void setdest(uint8_t surface) { - dest_surface = &surfaces[surface]; - recalculate_clip(); -} - -void setsource(uint8_t surface) { - source_surface = &surfaces[surface]; -} - -void setmap(uint8_t surface) { - map_surface = &surfaces[surface]; -} - -uint8_t getdest() -{ - for (unsigned int i=0; i desktop_width || screen_height*screen_zoom > desktop_height) screen_zoom--; + + const SDL_DisplayMode *dm = SDL_GetDesktopDisplayMode(SDL_GetPrimaryDisplay()); + while (screen_width*screen_zoom > dm->w || screen_height*screen_zoom > dm->h) screen_zoom--; mini_win = SDL_CreateWindow(window_title, screen_width*screen_zoom, screen_height*screen_zoom, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE|(screen_fullscreen?SDL_WINDOW_FULLSCREEN:0)); windowID = SDL_GetWindowID(mini_win); @@ -612,15 +941,6 @@ int main(int argc,char*argv[]){ while (!should_quit) { should_exit=false; - // initfont() - - //int bi = 0; - //for (int ci=0; ci<96; ci+=2) { - // font[ci] = base64font[bi] - 48 + ( ( base64font[bi+1] - 48 ) << 6) + ( ( ( base64font[bi+2] - 48 ) & 7 ) << 12 ); - // font[ci+1] = ( ( base64font[bi+2] - 48 ) >> 3 ) + ( ( base64font[bi+3] - 48 ) << 3 ) + ( ( base64font[bi+4] - 48 ) << 9 ); - // bi += 5; - //} - // READ INI if (!override_ini) { @@ -640,10 +960,6 @@ int main(int argc,char*argv[]){ SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD); - const SDL_DisplayMode *dm = SDL_GetDesktopDisplayMode(SDL_GetPrimaryDisplay()); - desktop_width = dm->w; - desktop_height = dm->h; - createDisplay(); initGamePad(); @@ -656,8 +972,8 @@ int main(int argc,char*argv[]){ loadfont_from_buffer((const char*)default_font_fnt, 0, "default_font"); current_font = &fonts[0]; - lua_init(main_lua_file); - lua_call_init(); + mini::lua::init(main_lua_file); + mini::lua::callbacks::init(); Uint32 dt=SDL_GetTicks(); key_just_pressed = 0; @@ -667,6 +983,9 @@ int main(int argc,char*argv[]){ double_click = false; has_text_input = false; + int fps_counter=0; + uint32_t fps_timer=0; + while(!should_exit) { if (update_mode==UPDATE_WAIT) SDL_WaitEvent(NULL); else if (update_mode==UPDATE_TIMEOUT) SDL_WaitEventTimeout(NULL, timeout); @@ -681,8 +1000,8 @@ int main(int argc,char*argv[]){ #ifdef DEBUG if (mini_eve.key.scancode == SDL_SCANCODE_F12) { reloadsurfs(); - } else if (mini_eve.key.scancode == SDL_SCANCODE_F11) { - lua_toggle_debug(); + //} else if (mini_eve.key.scancode == SDL_SCANCODE_F11) { + // mini::lua::debug::toggle(); } else if (mini_eve.key.scancode == SDL_SCANCODE_F5) { should_exit=true; } else { @@ -727,11 +1046,14 @@ int main(int argc,char*argv[]){ if (SDL_GetTicks()-dt>13) { dt = SDL_GetTicks(); - lua_process_debugger_commands(); - if (lua_is_playing()) { - lua_call_update(); + + if (mini::lua::runnning()) { + delta_time = float(SDL_GetTicks() - last_update)/1000.0f; + last_update = SDL_GetTicks(); + + mini::lua::callbacks::update(); } else { - loop(); + exception_loop(); } if (beats==0)beats=num_beats; if (beats>0)beats--; @@ -762,7 +1084,7 @@ int main(int argc,char*argv[]){ fps_timer = SDL_GetTicks(); } } - lua_quit(); + mini::lua::quit(); quitaudio(); //Mix_Quit(); @@ -772,21 +1094,10 @@ int main(int argc,char*argv[]){ destroyDisplay(); SDL_Quit(); } - lua_kill_thread(); + mini::lua::cleanup(); return 0; } -void simple_pset(int x, int y, uint8_t color) { - x += ds::origin[0]; y += ds::origin[1]; - if (x < ds::clip[0] || x > ds::clip[2] || y < ds::clip[1] || y > ds::clip[3]) return; - if (x < 0 || x >= dest_surface->w || y < 0 || y >= dest_surface->h) return; - DEST(x, y) = color; -} - -void cls(uint8_t color) { - const uint8_t col = ds::draw_palette[color]; - SDL_memset(dest_surface->p, col, dest_surface->size); -} uint32_t *loadpal(const char* filename, uint16_t *palsize) { int size; @@ -794,22 +1105,6 @@ uint32_t *loadpal(const char* filename, uint16_t *palsize) { uint32_t *pal = LoadPalette(buffer, palsize); free(buffer); return pal; - /* - FILE *f = fopen(filename, "rb"); - if (f) { - fseek(f, 0, SEEK_END); - long size = ftell(f); - fseek(f, 0, SEEK_SET); - uint8_t *buffer = (uint8_t*)malloc(size); - fread(buffer, size, 1, f); - fclose(f); - uint32_t *pal = LoadPalette(buffer); - free(buffer); - return pal; - //memcpy(palette, pal, 1024); - //free(pal); - } - return NULL;*/ } void setpal(uint32_t *pal) { @@ -843,124 +1138,6 @@ void reset_subpal() { for (int i=0;i<256;++i) ds::draw_palette[i]=i; } -/*void pal() { - for (int i=0; i<16; ++i) { - ds::draw_palette[i] = i; - ds::screen_palette[i] = i; - } - palt(); -} - -void pal(uint8_t c0, uint8_t c1, uint8_t p) { - if (p==0) ds::draw_palette[c0] = c1; else if (p==1) ds::screen_palette[c0]=c1; -} - -void palt() { - ds::trans[0] = true; - for (int i=1; i<16; ++i) ds::trans[i] = false; -} - -void palt(uint16_t bits) { - for (int i=0; i<16; ++i) ds::trans[i] = (bits & (1< ds::clip[2] || y < ds::clip[1] || y > ds::clip[3]) return; - switch (ds::mode) { - case DRAWMODE_NORMAL: pset_fast(x,y,color); break; - case DRAWMODE_PATTERN: pset_pattern(x,y,color); break; - default: pset_bool(x,y,color); break; - } -} - -// Per a les funcions que van canviant de color (surf.pixel i draw.surf, bàsicament) -static inline void subst_pset(int x, int y, uint8_t color) { - direct_pset(x,y,ds::draw_palette[color]); -} - -void pset(int x, int y, uint8_t color) { - subst_pset(x,y,color); -} - -uint8_t pget(int x, int y) { - x += ds::origin[0]; y += ds::origin[1]; - if (x < ds::clip[0] || x > ds::clip[2] || y < ds::clip[1] || y > ds::clip[3]) return 0; - return DEST(x, y); -} - -// Bresenham Line Algorithm -void line(int x0, int y0, int x1, int y1, uint8_t color) { - int x, y; - int dx, dy; - int incx, incy; - int balance; - color = ds::draw_palette[color]; - - if (x1 >= x0) { dx = x1 - x0; incx = 1; } else { dx = x0 - x1; incx = -1; } - if (y1 >= y0) { dy = y1 - y0; incy = 1; } else { dy = y0 - y1; incy = -1; } - - x = x0; y = y0; - - if (dx >= dy) { - dy <<= 1; - balance = dy - dx; - dx <<= 1; - - while (x != x1) { - direct_pset(x, y, color); - if (balance >= 0) { y += incy; balance -= dx; } - balance += dy; - x += incx; - } - direct_pset(x, y, color); - } else { - dx <<= 1; - balance = dx - dy; - dy <<= 1; - - while (y != y1) { - direct_pset(x, y, color); - if (balance >= 0) { x += incx; balance -= dy; } - balance += dx; - y += incy; - } - direct_pset(x, y, color); - } -} - -void hline(int x0, int y, int x1, uint8_t color) { - color = ds::draw_palette[color]; - if (x0>x1) { const int tmp=x0;x0=x1;x1=tmp; } - for (int x=x0; x<=x1; ++x) direct_pset(x, y, color); -} - -void vline(int x, int y0, int y1, uint8_t color) { - color = ds::draw_palette[color]; - if (y0>y1) { const int tmp=y0;y0=y1;y1=tmp; } - for (int y=y0; y<=y1; ++y) direct_pset(x, y, color); -} - -void rect(int x, int y, int w, int h, uint8_t color) { - int x1 = w+x-1; - int y1 = h+y-1; - hline(x, y, x1, color); - hline(x, y1, x1, color); - vline(x, y, y1, color); - vline(x1, y, y1, color); -} - -void rectfill(int x, int y, int w, int h, uint8_t color) { - int x1 = w+x-1; - int y1 = h+y-1; - for (int i=y; i<=y1; ++i) hline(x, i, x1, color); -} void fillp(uint16_t pat, bool transparent) { ds::fill_pattern = pat; @@ -1022,197 +1199,68 @@ int camy() { return ds::origin[1]; } -static inline void circ_scanline(int xc, int yc, int x, int y, uint8_t color) { - direct_pset(xc+x, yc+y, color); - direct_pset(xc-x, yc+y, color); - direct_pset(xc+x, yc-y, color); - direct_pset(xc-x, yc-y, color); - direct_pset(xc+y, yc+x, color); - direct_pset(xc-y, yc+x, color); - direct_pset(xc+y, yc-x, color); - direct_pset(xc-y, yc-x, color); -} -void circ(int x, int y, uint8_t r, uint8_t color) { - color = ds::draw_palette[color]; - int xi=0, yi=r; - int d=3-2*r; - circ_scanline(x, y, xi, yi, color); - while (yi>=xi++) { - d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6; - circ_scanline(x, y, xi, yi, color); - } -} +static inline void tileblit(uint8_t n, int x, int y) { + const int tw = tile_width; + const int th = tile_height; -static inline void circfill_scanline(int xc, int yc, int x, int y, uint8_t color) { - hline(xc-x, yc+y, xc+x, color); - hline(xc-x, yc-y, xc+x, color); - hline(xc-y, yc+x, xc+y, color); - hline(xc-y, yc-x, xc+y, color); -} + const int tiles_per_row = source_surface->w / tw; -void circfill(int x, int y, uint8_t r, uint8_t color) { - int xi=0, yi=r; - int d=3-2*r; - circfill_scanline(x, y, xi, yi, color); - while (yi>=xi++) { - d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6; - circfill_scanline(x, y, xi, yi, color); - } -} + // Coordenadas del tile dentro del spritesheet + int tx = (n % tiles_per_row) * tw; + int ty = (n / tiles_per_row) * th; + int src_y = ty; -void roundrect(int x, int y, int w, int h, uint8_t r, uint8_t color) { - int xi=0, yi=r; - int d=3-2*r; + for (int yi = 0; yi < th; ++yi) { + int src_x = tx; - int xf = w+x-1; - int yf = h+y-1; - int x1 = x+r, y1 = y+r; - int x2 = xf-r, y2 = yf-r; - hline(x1, y, x2, color); - hline(x1, yf, x2, color); - vline(x, y1, y2, color); - vline(xf, y1, y2, color); - - color = ds::draw_palette[color]; - while (yi>=xi++) { - d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6; - direct_pset(x2+xi, y2+yi, color); - direct_pset(x1-xi, y2+yi, color); - direct_pset(x2+xi, y1-yi, color); - direct_pset(x1-xi, y1-yi, color); - direct_pset(x2+yi, y2+xi, color); - direct_pset(x1-yi, y2+xi, color); - direct_pset(x2+yi, y1-xi, color); - direct_pset(x1-yi, y1-xi, color); - } -} - -void roundrectfill(int x, int y, int w, int h, uint8_t r, uint8_t color) { - int xi=0, yi=r; - int d=3-2*r; - - int xf = w+x-1; - int yf = h+y-1; - int x1 = x+r, y1 = y+r; - int x2 = xf-r, y2 = yf-r; - for (int i=y1; i<=y2; ++i) hline(x, i, xf, color); - - while (yi>=xi++) { - d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6; - hline(x1-xi, y2+yi, x2+xi, color); - hline(x1-xi, y1-yi, x2+xi, color); - hline(x1-yi, y2+xi, x2+yi, color); - hline(x1-yi, y1-xi, x2+yi, color); - } -} - -void oval_scanline(int xc, int yc, int x, int y, float xf, float yf, uint8_t color) { - direct_pset((xc+x)*xf, (yc+y)*yf, color); - direct_pset((xc-x)*xf, (yc+y)*yf, color); - direct_pset((xc+x)*xf, (yc-y)*yf, color); - direct_pset((xc-x)*xf, (yc-y)*yf, color); - direct_pset((xc+y)*xf, (yc+x)*yf, color); - direct_pset((xc-y)*xf, (yc+x)*yf, color); - direct_pset((xc+y)*xf, (yc-x)*yf, color); - direct_pset((xc-y)*xf, (yc-x)*yf, color); -} - -void oval(int x0, int y0, int x1, int y1, uint8_t color) { - color = ds::draw_palette[color]; - int rx = (x1-x0)/2; - int ry = (y1-y0)/2; - int r = rx; - int x = x0 + rx; - int y = y0 + ry; - float xf = 1.0f, yf = 1.0f; - if (rx>=ry) {r=rx;yf=float(ry)/float(rx);} else {r=ry;xf=float(rx)/float(ry);} - int xi=0, yi=r; - int d=3-2*r; - oval_scanline(x, y, xi, yi, xf, yf, color); - while (yi>=xi++) { - d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6; - oval_scanline(x, y, xi, yi, xf, yf, color); - } -} - -static inline void ovalfill_scanline(int xc, int yc, int x, int y, float xf, float yf, uint8_t color) { - hline((xc-x)*xf, (yc+y)*yf, (xc+x)*xf, color); - hline((xc-x)*xf, (yc-y)*yf, (xc+x)*xf, color); - hline((xc-y)*xf, (yc+x)*yf, (xc+y)*xf, color); - hline((xc-y)*xf, (yc-x)*yf, (xc+y)*xf, color); -} - -void ovalfill(int x0, int y0, int x1, int y1, uint8_t color) { - int rx = (x1-x0)/2; - int ry = (y1-y0)/2; - int r = rx; - int x = x0 + rx; - int y = y0 + ry; - float xf = 1.0f, yf = 1.0f; - if (rx>=ry) {r=rx;yf=float(ry)/float(rx);} else {r=ry;xf=float(rx)/float(ry);} - int xi=0, yi=r; - int d=3-2*r; - ovalfill_scanline(x, y, xi, yi, xf, yf, color); - while (yi>=xi++) { - d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6; - ovalfill_scanline(x, y, xi, yi, xf, yf, color); - } -} - -uint8_t sget(int x, int y) { - if (!source_surface) return 0; - if (x < 0 || x > (source_surface->w-1) || y < 0 || y > (source_surface->h-1)) return 0; - return SOURCE(x, y); -} - -void sset(int x, int y, uint8_t color) { - if (!source_surface) return; - if (x < 0 || x > (source_surface->w-1) || y < 0 || y > (source_surface->h-1)) return; - SOURCE(x, y) = color; -} - -void spr(uint8_t n, int x, int y, float w, float h, bool flip_x, bool flip_y) { - if (!source_surface) return; - int tx = (n%(source_surface->w / tile_width))*tile_width; - int ty = (n/(source_surface->w / tile_height))*tile_height; - int tw = w*tile_width - 1; - int th = h*tile_height - 1; - //int tx2 = tx1 + tw; - //int ty2 = ty1 + th; - int txd = 1; - int tyd = 1; - if (flip_x) {tx+=tw;txd=-1;} - if (flip_y) {ty+=th;tyd=-1;} - for (int yi=0; yi<=th; ++yi) { - int ttx = tx; - for (int xi=0; xi<=tw; ++xi) { - subst_pset(x+xi, y+yi, sget(ttx, ty)); - ttx += txd; + for (int xi = 0; xi < tw; ++xi) { + uint8_t c = sget(src_x, src_y); + subst_pset(x + xi, y + yi, c); + src_x++; } - ty += tyd; + + src_y++; } } void blit(int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, bool flip_x, bool flip_y, bool invert) { - if (dw==0) dw=sw; - if (dh==0) dh=sh; - float sdx = float(sw)/float(dw); - float sdy = float(sh)/float(dh); - float ssx = sx; float ssy = sy; - if (flip_x) { sdx = -sdx; ssx += sw+sdx; } - if (flip_y) { sdy = -sdy; ssy += sh+sdy; } - float csx = ssx; - float csy = ssy; - for(int y=dy;y> 16, csy >> 16); + subst_pset(x, y, color); + csx += sdx; + } + csy += sdy; + } + } else { + for (int y = dy; y < dy + dh; ++y) { + int csx = ssx; + for (int x = dx; x < dx + dw; ++x) { + uint8_t color = sget(csy >> 16, csx >> 16); + subst_pset(x, y, color); + csx += sdx; + } + csy += sdy; } - csy += sdy; } } @@ -1302,58 +1350,6 @@ void blit_r(int sx, int sy, int sw, int sh, } } -uint8_t mget(int celx, int cely) { - if (!map_surface) return 0; - if (celx < 0 || celx > (map_surface->w-1) || cely < 0 || cely > (map_surface->h-1)) return 0; - return TILES(celx, cely); -} - -void mset(int celx, int cely, uint8_t snum) { - if (!map_surface) return; - if (celx < 0 || celx > (map_surface->w-1) || cely < 0 || cely > (map_surface->h-1)) return; - TILES(celx, cely) = snum; -} - -uint8_t gettilew() { return tile_width; } -uint8_t gettileh() { return tile_height; } -void settilesize(int w, int h) { - tile_width = w; - tile_height = h; -} - -void map() { //int celx, int cely, int sx, int sy, uint8_t celw, uint8_t celh, uint8_t layer) { - if (map_surface==NULL) return; - int celw = map_surface->w;// >> 3; - int celh = map_surface->h;// >> 3; - int celx = 0; - int cely = 0; - //if (celw <= 0 || celh <= 0 || celw >= TILES_WIDTH || celh >= TILES_HEIGHT) return; - int sx = ds::origin[0]; int sy = ds::origin[1]; - if (sx+celw*tile_width < ds::clip[0] || sx > ds::clip[2] || sy+celh*tile_height < ds::clip[1] || sy > ds::clip[3]) return; - if (sx<0) { - int diff = -sx/tile_width; - celx += diff; - celw -= diff; - sx += diff*tile_width; - } - if (sy<0) { - int diff = -sy/tile_height; - cely += diff; - celh -= diff; - sy += diff*tile_height; - } - sx -= ds::origin[0]; sy -= ds::origin[1]; - for (int y=0; yds::clip[2]) || (fy>ds::clip[3]) ) continue; - spr(tile, sx+x*tile_width, sy+y*tile_height); - } - } -} bool btn(uint8_t i) { return keys[i]; @@ -1447,6 +1443,10 @@ float time() { return float(SDL_GetTicks())/1000.0f; } +float delta() { + return delta_time; +} + bool beat(int16_t i) { if (i<0) { return beats==0; @@ -1605,6 +1605,20 @@ void exit() { should_quit = true; } +void reinit() { + log_msg(LOG_INFO, "STARTING A SYSTEM REINITIALIZATION\n"); + ds::mode = DRAWMODE_NORMAL; + ds::origin[0] = ds::origin[1] = 0; + ds::clip[0] = ds::clip[1] = 0; ds::clip[2] = screen_width-1; ds::clip[3] = screen_height-1; + ds::trans=0; + ds::fill_pattern = 0b1111111111111111; + for (unsigned int i=0; i