forked from VoxeLibre/VoxeLibre
256 lines
9.3 KiB
Lua
256 lines
9.3 KiB
Lua
|
|
local function initialize_data(meta)
|
|
local commands = minetest.formspec_escape(meta:get_string("commands"))
|
|
end
|
|
|
|
local function construct(pos)
|
|
local meta = minetest.get_meta(pos)
|
|
|
|
meta:set_string("commands", "")
|
|
initialize_data(meta)
|
|
end
|
|
|
|
local function after_place(pos, placer)
|
|
if placer then
|
|
local meta = minetest.get_meta(pos)
|
|
initialize_data(meta)
|
|
end
|
|
end
|
|
|
|
local function resolve_commands(commands, pos)
|
|
local players = minetest.get_connected_players()
|
|
|
|
-- No players online: remove all commands containing
|
|
-- @nearest, @farthest and @random
|
|
if #players == 0 then
|
|
commands = commands:gsub("[^\r\n]+", function (line)
|
|
if line:find("@nearest") then return "" end
|
|
if line:find("@farthest") then return "" end
|
|
if line:find("@random") then return "" end
|
|
return line
|
|
end)
|
|
return commands
|
|
end
|
|
|
|
local nearest, farthest = nil, nil
|
|
local min_distance, max_distance = math.huge, -1
|
|
for index, player in pairs(players) do
|
|
local distance = vector.distance(pos, player:getpos())
|
|
if distance < min_distance then
|
|
min_distance = distance
|
|
nearest = player:get_player_name()
|
|
end
|
|
if distance > max_distance then
|
|
max_distance = distance
|
|
farthest = player:get_player_name()
|
|
end
|
|
end
|
|
local random = players[math.random(#players)]:get_player_name()
|
|
commands = commands:gsub("@nearest", nearest)
|
|
commands = commands:gsub("@farthest", farthest)
|
|
commands = commands:gsub("@random", random)
|
|
return commands
|
|
end
|
|
|
|
local function check_commands(commands, player_name)
|
|
for _, command in pairs(commands:split("\n")) do
|
|
local pos = command:find(" ")
|
|
local cmd, param = command, ""
|
|
if pos then
|
|
cmd = command:sub(1, pos - 1)
|
|
end
|
|
local cmddef = minetest.chatcommands[cmd]
|
|
if not cmddef then
|
|
-- Invalid chat command
|
|
msg = "Error: The command “"..cmd.."” does not exist; your command block has not been changed. Use the “help” chat command for a list of available commands."
|
|
if string.sub(cmd, 1, 1) == "/" then
|
|
msg = msg .. " Hint: Try to remove the trailing slash."
|
|
end
|
|
return false, msg
|
|
end
|
|
if player_name then
|
|
local player_privs = minetest.get_player_privs(player_name)
|
|
|
|
for cmd_priv, _ in pairs(cmddef.privs) do
|
|
if player_privs[cmd_priv] ~= true then
|
|
local msg = "Error: You have insufficient privileges to use the command “"..cmd.."” (missing privilege: "..cmd_priv..")! The command block has not been changed."
|
|
return false, msg
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
|
|
local function commandblock_action_on(pos, node)
|
|
if node.name ~= "mesecons_commandblock:commandblock_off" then
|
|
return
|
|
end
|
|
|
|
minetest.swap_node(pos, {name = "mesecons_commandblock:commandblock_on"})
|
|
|
|
local meta = minetest.get_meta(pos)
|
|
|
|
local commands = resolve_commands(meta:get_string("commands"), pos)
|
|
for _, command in pairs(commands:split("\n")) do
|
|
local pos = command:find(" ")
|
|
local cmd, param = command, ""
|
|
if pos then
|
|
cmd = command:sub(1, pos - 1)
|
|
param = command:sub(pos + 1)
|
|
end
|
|
local cmddef = minetest.chatcommands[cmd]
|
|
if not cmddef then
|
|
-- Invalid chat command
|
|
return
|
|
end
|
|
local dummy_player = ""
|
|
cmddef.func(dummy_player, param)
|
|
end
|
|
end
|
|
|
|
local function commandblock_action_off(pos, node)
|
|
if node.name == "mesecons_commandblock:commandblock_on" then
|
|
minetest.swap_node(pos, {name = "mesecons_commandblock:commandblock_off"})
|
|
end
|
|
end
|
|
|
|
local on_rightclick = function(pos, node, player, itemstack, pointed_thing)
|
|
-- Only allow access in Creative Mode
|
|
if not minetest.settings:get_bool("creative_mode") then
|
|
return
|
|
end
|
|
local privs = minetest.get_player_privs(player:get_player_name())
|
|
if not privs.maphack then
|
|
minetest.chat_send_player(player:get_player_name(), "Access denied. You need the “maphack” privilege to edit command blocks.")
|
|
return
|
|
end
|
|
|
|
local meta = minetest.get_meta(pos)
|
|
local commands = meta:get_string("commands")
|
|
local formspec = "invsize[9,5;]" ..
|
|
"textarea[0.5,0.5;8.5,4;commands;Commands;"..commands.."]" ..
|
|
"label[1,3.8;@nearest, @farthest, and @random are replaced by the respective player names]" ..
|
|
"button_exit[3.3,4.5;2,1;submit;Submit]" ..
|
|
"image_button[8,4.5;1,1;doc_button_icon_lores.png;doc;]" ..
|
|
"tooltip[doc;Help]"
|
|
minetest.show_formspec(player:get_player_name(), "commandblock_"..pos.x.."_"..pos.y.."_"..pos.z, formspec)
|
|
end
|
|
|
|
local on_place = function(itemstack, placer, pointed_thing)
|
|
if pointed_thing.type ~= "node" then
|
|
return itemstack
|
|
end
|
|
|
|
-- Use pointed node's on_rightclick function first, if present
|
|
local node = minetest.get_node(pointed_thing.under)
|
|
if placer and not placer:get_player_control().sneak then
|
|
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
|
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
|
|
end
|
|
end
|
|
|
|
local privs = minetest.get_player_privs(placer:get_player_name())
|
|
if not privs.maphack then
|
|
minetest.chat_send_player(placer:get_player_name(), "Placement denied. You need the “maphack” privilege to place command blocks.")
|
|
return itemstack
|
|
end
|
|
|
|
return minetest.item_place_node(itemstack, placer, pointed_thing)
|
|
end
|
|
|
|
minetest.register_node("mesecons_commandblock:commandblock_off", {
|
|
description = "Command Block",
|
|
|
|
_doc_items_longdesc =
|
|
"Command blocks are mighty redstone components which are able to alter reality itself. In other words, they cause the server to execute server commands when they are supplied with redstone power.",
|
|
_doc_items_usagehelp =
|
|
[[Using a command block which someone already placed and set up properly is easy: Just supply it with redstone power and see what happens. This will execute the commands once. To execute the commands again, turn the redstone power off and on again.
|
|
|
|
Changing the commands or breaking the command block is only possible in Creative Mode. Directly after placing, a command block does not have any commands and does nothing. Rightclick the command block (in Creative Mode!) to edit its commands. Refer to the help entry about server commands to understand how they work. Each line contains a single command, the commands will be executed from top to bottom. The commands DO NOT require a leading slash.
|
|
|
|
You can optionally use the following placeholders in your commands:
|
|
• “@nearest” is replaced by the name of the player nearest to the command block
|
|
• “@farthest” is replaced by the name of the player farthest away from the command block
|
|
• “@random” is replaced by the name of a random player currently connected]],
|
|
|
|
tiles = {{name="jeija_commandblock_off.png", animation={type="vertical_frames", aspect_w=32, aspect_h=32, length=2}}},
|
|
groups = {creative_breakable=1, mesecon_effector_off=1},
|
|
drop = "",
|
|
on_blast = function() end,
|
|
on_construct = construct,
|
|
is_ground_content = false,
|
|
on_place = on_place,
|
|
after_place_node = after_place,
|
|
on_rightclick = on_rightclick,
|
|
sounds = mcl_sounds.node_sound_stone_defaults(),
|
|
mesecons = {effector = {
|
|
action_on = commandblock_action_on,
|
|
rules = mesecon.rules.alldirs,
|
|
}},
|
|
_mcl_blast_resistance = 18000000,
|
|
_mcl_hardness = -1,
|
|
})
|
|
|
|
minetest.register_node("mesecons_commandblock:commandblock_on", {
|
|
tiles = {{name="jeija_commandblock_off.png", animation={type="vertical_frames", aspect_w=32, aspect_h=32, length=2}}},
|
|
groups = {creative_breakable=1, mesecon_effector_on=1, not_in_creative_inventory=1},
|
|
drop = "",
|
|
on_blast = function() end,
|
|
on_construct = construct,
|
|
is_ground_content = false,
|
|
on_place = on_place,
|
|
after_place_node = after_place,
|
|
on_rightclick = on_rightclick,
|
|
sounds = mcl_sounds.node_sound_stone_defaults(),
|
|
mesecons = {effector = {
|
|
action_off = commandblock_action_off,
|
|
rules = mesecon.rules.alldirs,
|
|
}},
|
|
_mcl_blast_resistance = 18000000,
|
|
_mcl_hardness = -1,
|
|
})
|
|
|
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|
if string.sub(formname, 1, 13) == "commandblock_" then
|
|
if not fields.submit and not fields.doc then
|
|
return
|
|
end
|
|
local privs = minetest.get_player_privs(player:get_player_name())
|
|
if not privs.maphack then
|
|
minetest.chat_send_player(player:get_player_name(), "Access denied. You need the “maphack” privilege to edit command blocks.")
|
|
return
|
|
end
|
|
|
|
if fields.doc and minetest.get_modpath("doc") then
|
|
doc.show_entry(player:get_player_name(), "nodes", "mesecons_commandblock:commandblock_off", true)
|
|
return
|
|
end
|
|
local index, _, x, y, z = string.find(formname, "commandblock_(-?%d+)_(-?%d+)_(-?%d+)")
|
|
if index ~= nil and x ~= nil and y ~= nil and z ~= nil then
|
|
local pos = {x=tonumber(x), y=tonumber(y), z=tonumber(z)}
|
|
local meta = minetest.get_meta(pos)
|
|
if not minetest.settings:get_bool("creative_mode") then
|
|
minetest.chat_send_player(player:get_player_name(), "Editing the command block has failed! You can only change the command block in Creative Mode!")
|
|
return
|
|
end
|
|
local check, error_message = check_commands(fields.commands, player:get_player_name())
|
|
if check == false then
|
|
-- Command block rejected
|
|
minetest.chat_send_player(player:get_player_name(), error_message)
|
|
return
|
|
else
|
|
meta:set_string("commands", fields.commands)
|
|
initialize_data(meta)
|
|
end
|
|
else
|
|
minetest.chat_send_player(player:get_player_name(), "Editing the command block has failed! The command block is gone.")
|
|
end
|
|
end
|
|
end)
|
|
|
|
-- Add entry alias for the Help
|
|
if minetest.get_modpath("doc") then
|
|
doc.add_entry_alias("nodes", "mesecons_commandblock:commandblock_off", "nodes", "mesecons_commandblock:commandblock_on")
|
|
end
|