diff --git a/README.md b/README.md index 3c912af..1da2be0 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ MoreMesecons is a mod for minetest which adds some mesecons items. * `Igniter` : This node is a lighter that ignites its adjacent flammable nodes (including TNT). * `Injector Controller` : This node is useful to activate/deactivate a pipeworks filter injector : it sends a blinky signal. * `Jammer` : If turned on, this node stops mesecons in a radius of 10 nodes. +* `LuaBlock`: This block allows its owner to execute any Lua code in the global environment when turned on. Using it requires the server privilege. * `Luacontroller Template Tool` : This tool is very useful to manipulate templates with luacontrollers. Just click with it on a luacontroller, then you'll see a formspec. * `Player Killer` : This block kills the nearest player (with a maximal distance of 8 blocks by default) (if this player isn't its owner) when it receives a mesecons signal. * `Sayer` : This node sends a message to every players inside a radius of 8 nodes. diff --git a/moremesecons_luablock/depends.txt b/moremesecons_luablock/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/moremesecons_luablock/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/moremesecons_luablock/init.lua b/moremesecons_luablock/init.lua new file mode 100644 index 0000000..cc697eb --- /dev/null +++ b/moremesecons_luablock/init.lua @@ -0,0 +1,113 @@ +local function make_formspec(meta, pos) + local code = meta:get_string("code") + local errmsg = minetest.formspec_escape(meta:get_string("errmsg")) + meta:set_string("formspec", + "size[10,8;]" .. + "textarea[0.5,0.5;10,7;code;Code;"..code.."]" .. + "label[0.1,7;"..errmsg.."]" .. + "button_exit[4,7.5;2,1;submit;Submit]") +end + +minetest.register_node("moremesecons_luablock:luablock", { + description = "Lua Block", + tiles = {"moremesecons_luablock.png"}, + groups = {cracky = 2}, + on_place = function(itemstack, placer, pointed_thing) + local under = pointed_thing.under + local node = minetest.get_node(under) + local udef = minetest.registered_nodes[node.name] + if udef and udef.on_rightclick and + not (placer and placer:get_player_control().sneak) then + return udef.on_rightclick(under, node, placer, itemstack, + pointed_thing) or itemstack + end + + local pos + if minetest.registered_items[minetest.get_node(under).name].buildable_to then + pos = under + else + pos = pointed_thing.above + end + + local name = placer:get_player_name() + if minetest.is_protected(pos, name) and + not minetest.check_player_privs(name, {protection_bypass = true}) then + minetest.record_protection_violation(pos, name) + return itemstack + end + if not minetest.check_player_privs(name, {server = true}) then + minetest.chat_send_player(name, "You can't use a LuaBlock without the server privilege.") + return itemstack + end + + local node_def = minetest.registered_nodes[minetest.get_node(pos).name] + if not node_def or not node_def.buildable_to then + return itemstack + end + + minetest.set_node(pos, {name = "moremesecons_luablock:luablock"}) + + local meta = minetest.get_meta(pos) + meta:set_string("owner", name) + meta:set_string("infotext", "LuaBlock owned by " .. name) + make_formspec(meta, pos) + + if not (creative and creative.is_enabled_for + and creative.is_enabled_for(placer:get_player_name())) then + itemstack:take_item() + end + return itemstack + end, + on_receive_fields = function(pos, form_name, fields, sender) + if not fields.submit then + return + end + local name = sender:get_player_name() + local meta = minetest.get_meta(pos) + if name ~= meta:get_string("owner") then + minetest.chat_send_player(name, "You don't own this LuaBlock.") + return + end + if not minetest.check_player_privs(name, {server = true}) then + minetest.chat_send_player(name, "You can't use a LuaBlock without the server privilege.") + return + end + + meta:set_string("code", fields.code) + make_formspec(meta, pos) + end, + can_dig = function(pos, player) + local meta = minetest.get_meta(pos) + return meta:get_string("owner") == player:get_player_name() + end, + mesecons = {effector = { + action_on = function(pos, node) + local meta = minetest.get_meta(pos) + local code = meta:get_string("code") + if code == "" then + return + end + -- We do absolutely no check there. + -- There is no limitation in the number of instruction the LuaBlock can execute + -- or the usage it can make of loops. + -- It is executed in the global namespace. + -- Remember: *The LuaBlock is highly dangerous and should be manipulated cautiously!* + local func, err = loadstring(code) + if not func then + meta:set_string("errmsg", err) + make_formspec(meta, pos) + return + end + local good, err = pcall(func) + -- Still alive! No shutdown requested? No infinite loop? + if not good then -- Runtime error + meta:set_string("errmsg", err) + make_formspec(meta, pos) + return + end + + meta:set_string("errmsg", "") + make_formspec(meta, pos) + end + }} +}) diff --git a/moremesecons_luablock/textures/moremesecons_luablock.png b/moremesecons_luablock/textures/moremesecons_luablock.png new file mode 100644 index 0000000..89d245a Binary files /dev/null and b/moremesecons_luablock/textures/moremesecons_luablock.png differ