You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

100 lines
3.1 KiB

2 days ago
-- Lua Console module — execute Lua code in the game's main thread
local M = {}
-- Serialize a Lua value into a readable string
local function serialize(val, depth)
2 days ago
depth = depth or 0
if depth > 4 then return "..." end
local t = type(val)
if t == "nil" then
return "nil"
elseif t == "string" then
if #val > 200 then
return '"' .. val:sub(1, 200):gsub('[\n\r]', '\\n') .. '..." [' .. #val .. ' chars]'
end
return '"' .. val:gsub('[\n\r]', '\\n'):gsub('"', '\\"') .. '"'
elseif t == "number" or t == "boolean" then
return tostring(val)
elseif t == "table" then
local items = {}
local n = 0
-- Array part
for i, v in ipairs(val) do
if n >= 20 then
items[#items + 1] = "... +" .. (#val - n) .. " more"
break
end
items[#items + 1] = serialize(v, depth + 1)
n = n + 1
end
-- Hash part
for k, v in pairs(val) do
if type(k) ~= "number" or k < 1 or k > #val or k ~= math.floor(k) then
if n >= 20 then
items[#items + 1] = "..."
break
end
local ks = type(k) == "string" and k or "[" .. tostring(k) .. "]"
items[#items + 1] = ks .. " = " .. serialize(v, depth + 1)
n = n + 1
end
end
if #items == 0 then return "{}" end
return "{ " .. table.concat(items, ", ") .. " }"
elseif t == "function" then
return "function: " .. tostring(val)
else
return tostring(val)
end
end
function M.init(fw)
local static_dir = fw.modules_dir .. "/console/static"
fw.register_module("console", static_dir)
fw.on_api("console", "exec", function(body)
local ok, data = pcall(fw.json_decode, body)
if not ok or not data or not data.code then
return '{"ok":false,"error":"invalid body"}'
end
local code = data.code
if #code == 0 then
return '{"ok":false,"error":"empty code"}'
end
-- Try as expression first (return value), then as statement
local fn, err = loadstring("return " .. code)
if not fn then
fn, err = loadstring(code)
end
if not fn then
return fw.json_encode({ok = false, error = "Compile: " .. tostring(err)})
end
local results = {pcall(fn)}
local success = table.remove(results, 1)
if not success then
return fw.json_encode({ok = false, error = tostring(results[1])})
end
-- Format results
local parts = {}
for i, v in ipairs(results) do
parts[i] = serialize(v, 0)
end
local output = table.concat(parts, ", ")
if #parts == 0 then output = "nil" end
fw.log("INFO", "CONSOLE", "Exec: " .. code:sub(1, 80) .. " => " .. output:sub(1, 80))
return fw.json_encode({ok = true, result = output, count = #parts})
end)
fw.log("INFO", "CONSOLE", "Module loaded")
end
2 days ago
return M