Skip to content

Commit

Permalink
Added player-local context and /luaclear command
Browse files Browse the repository at this point in the history
  • Loading branch information
prestidigitator committed Jul 4, 2014
1 parent d1ac137 commit 63d0d60
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 41 deletions.
66 changes: 66 additions & 0 deletions PlayerEnv.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
local PrintablePos =
{
__tostring = function(pos)
return "(" .. pos.x .. ", " .. pos.y .. ", " .. pos.z .. ")";
end
};
function PrintablePos:new(pos)
return setmetatable(pos, self);
end

local PlayerEnv =
{
playerContexts = setmetatable({}, { __mode = "k" }), -- weak keys

playerFuncs =
{
me = function(player)
return player;
end,

myname = function(player)
return player:get_player_name();
end,

here = function(player)
return PrintablePos:new(player:getpos());
end,

print = function(player)
return function(...)
local str = "";
for _, arg in ipairs({...}) do
str = str .. tostring(arg);
end
minetest.chat_send_player(player:get_player_name(), str, false);
end
end
};
};

function PlayerEnv:new(player)
local env = {};
self.playerContexts[env] = player;
setmetatable(env, self);
return env;
end
setmetatable(PlayerEnv, { __call = PlayerEnv.new });

function PlayerEnv.__index(env, key)
local playerFunc = PlayerEnv.playerFuncs[key];
if playerFunc then
local player = PlayerEnv.playerContexts[env];
return playerFunc(player);
else
return _G[key];
end
end

function PlayerEnv.__newindex(env, key, value)
if PlayerEnv.playerFuncs[key] then
error("cannot set special '"..key.."' player variable");
end
rawset(env, key, value);
end

return PlayerEnv;
14 changes: 13 additions & 1 deletion README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ Required Minetest Version: (tested in 0.4.9)

Dependencies: (none)

Commands: /lua <luaStatement>
Commands:
* /lua <luaStatement>
* /luaclear

Privileges: lua

Expand Down Expand Up @@ -64,6 +66,16 @@ Try the following commands:
/lua print(myname);
/lua print(here);

Version 1.2

* Release 2014-07-04
* Keeps "global" variables set by commands in a player-local context.
* Prevents setting of special variables (e.g. me, myname, here, print).
* Added /luaclear command to clear the player-local context.

To set true globals visible to mods and other players, use "_G.var = ...". Can
also be used to get any globals hidden by specials and player-local variables.

Copyright and Licensing
-----------------------

Expand Down
79 changes: 39 additions & 40 deletions init.lua
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
local function copyTable(t)
if type(t) ~= "table" then return t; end
local tc = {};
for k, v in pairs(t) do
tc[k] = v;
local MOD_NAME = minetest.get_current_modname();
local MOD_PATH = minetest.get_modpath(MOD_NAME);

local PlayerEnv = dofile(MOD_PATH.."/PlayerEnv.lua");

local playerEnvs = {};
minetest.register_on_leaveplayer(
function(player)
playerEnvs[player:get_player_name()] = nil;
end);

local function runLuaCmd(playerName, paramStr)
local cmdFunc, errMsg = loadstring(paramStr, "/lua command");
if not cmdFunc then
error(errMsg);
end
return tc;
end

local function posToStr(pos)
return "(" .. pos.x .. ", " ..pos.y.. ", " .. pos.z .. ")";
local playerEnv = playerEnvs[playerName];
if not playerEnv then
local player = minetest.get_player_by_name(playerName);
playerEnv = PlayerEnv:new(player);
playerEnvs[playerName] = playerEnv;
end

setfenv(cmdFunc, playerEnv);
cmdFunc();
end
local posMeta = { __tostring = posToStr };

minetest.register_privilege(
"lua",
Expand All @@ -26,37 +40,22 @@ minetest.register_chatcommand(
description = "Executes a lua statement (chunk), for debugging.",
privs = { lua = true },
func =
function(name, param)
local cmdFunc, success, errMsg;

cmdFunc, errMsg = loadstring(param, "/lua command");
if not cmdFunc then
minetest.chat_send_player(name, "ERROR: "..errMsg);
return;
end

local player = minetest.get_player_by_name(name);
local pos = player:getpos();
setmetatable(pos, posMeta);

local env = copyTable(getfenv(0));
env.print =
function(...)
str = "";
for _, arg in ipairs({...}) do
str = str .. tostring(arg);
end
minetest.chat_send_player(name, str, false);
end;
env.myname = name;
env.me = player;
env.here = pos;

setfenv(cmdFunc, env);

success, errMsg = pcall(cmdFunc);
function(playerName, paramStr)
local success, errMsg = pcall(runLuaCmd, playerName, paramStr);
if not success then
minetest.chat_send_player(name, "ERROR: "..errMsg);
minetest.chat_send_player(playerName, "ERROR: "..errMsg);
end
end
});

minetest.register_chatcommand(
"luaclear",
{
params = "",
description = "Clears all variables in your /lua player context",
privs = { lua = true },
func =
function(playerName, paramStr)
playerEnvs[playerName] = nil;
end
});

0 comments on commit 63d0d60

Please sign in to comment.