164 lines
3.5 KiB
Lua
164 lines
3.5 KiB
Lua
local path = minetest.get_modpath(minetest.get_current_modname())
|
||
|
||
local chat_send_player = minetest.chat_send_player
|
||
local colorize = minetest.colorize
|
||
local concat = table.concat
|
||
local dump = dofile(path .. '/dump.lua')
|
||
local find = string.find
|
||
local getmetatable = getmetatable
|
||
local insert = table.insert
|
||
local ipairs = ipairs
|
||
local loadstring = loadstring
|
||
local pairs = pairs
|
||
local pcall = pcall
|
||
local rep = string.rep
|
||
local select = select
|
||
local setfenv = setfenv
|
||
local setmetatable = setmetatable
|
||
local sort = table.sort
|
||
local type = type
|
||
|
||
-- players' environments
|
||
local envs = {}
|
||
|
||
-- stuff available for all players
|
||
local function pack(...)
|
||
local result = {...}
|
||
result.n = select('#', ...)
|
||
return result
|
||
end
|
||
|
||
local g_environ = {
|
||
gmt = getmetatable, -- shorthand for getmetatable
|
||
smt = setmetatable, -- shorthand for setmetatable
|
||
}
|
||
|
||
local bunch_of_lfs = rep('\n', 500)
|
||
|
||
minetest.register_on_joinplayer(function(player)
|
||
local name = player:get_player_name()
|
||
|
||
-- variables available for player which cannot be erased
|
||
local environ = {
|
||
me = player,
|
||
name = name,
|
||
}
|
||
|
||
-- imports to allow using set_node, sin, write etc.
|
||
-- without direct reference to player.
|
||
local imports = {environ, g_environ, _G, string, table, io, math, minetest}
|
||
|
||
-- player environment
|
||
local env = setmetatable({}, {
|
||
-- function for resolving imports
|
||
__index = function(table, index)
|
||
local result
|
||
|
||
for i, import in ipairs(imports) do
|
||
local result = import[index]
|
||
if result ~= nil then
|
||
return result
|
||
end
|
||
end
|
||
end
|
||
})
|
||
|
||
envs[name] = env
|
||
|
||
-- Returns a table with all keys of given table
|
||
-- matching the given pattern. If no table provided,
|
||
-- it searches for keys in all imports.
|
||
environ.hint = function(table, pattern)
|
||
local result = {}
|
||
if pattern == nil then
|
||
pattern = table
|
||
table = {}
|
||
for i, import in ipairs(imports) do
|
||
for key, value in pairs(import) do
|
||
if find(key, pattern) then
|
||
table[key] = value
|
||
end
|
||
end
|
||
end
|
||
for key, value in pairs(table) do
|
||
insert(result, key)
|
||
end
|
||
else
|
||
if type(table) ~= 'table' then
|
||
error('Table expected')
|
||
end
|
||
for key, value in pairs(table) do
|
||
if find(key, pattern) then
|
||
insert(result, key)
|
||
end
|
||
end
|
||
end
|
||
sort(result)
|
||
return result
|
||
end
|
||
|
||
-- Clears the chat window.
|
||
environ.clear = function()
|
||
chat_send_player(name, bunch_of_lfs)
|
||
end
|
||
|
||
-- Sends message to player who called it.
|
||
environ.echo = function(s)
|
||
chat_send_player(name, s)
|
||
end
|
||
|
||
local function load(name)
|
||
local result, err = loadfile(path .. '/scripts/' .. name)
|
||
|
||
if err then
|
||
error(err)
|
||
end
|
||
|
||
return setfenv(result, env)
|
||
end
|
||
|
||
environ.load = load
|
||
|
||
-- Runs a script from scripts directory.
|
||
environ.run = function(name, ...)
|
||
return load(name)(...)
|
||
end
|
||
end)
|
||
|
||
minetest.register_on_leaveplayer(function(player)
|
||
envs[player:get_player_name()] = nil
|
||
end)
|
||
|
||
minetest.register_on_chat_message(function(name, s)
|
||
local f, err = loadstring('return ' .. s)
|
||
|
||
if f == nil then
|
||
f, err = loadstring(s)
|
||
end
|
||
|
||
if f == nil then
|
||
chat_send_player(name, colorize('#F93', err))
|
||
return
|
||
end
|
||
|
||
local env = envs[name]
|
||
|
||
f = pack(pcall(setfenv(f, env)))
|
||
|
||
local result = {}
|
||
|
||
for i = 2, f.n do
|
||
result[i - 1] = dump(f[i], env)
|
||
end
|
||
|
||
result = concat(result, '(c@#999), ');
|
||
|
||
if f[1] then
|
||
env._ = f[2]
|
||
chat_send_player(name, result)
|
||
else
|
||
env._e = f[2]
|
||
chat_send_player(name, '(c@#F93)ERROR: ' .. result)
|
||
end
|
||
end)
|