2 local function construct(pos
)
3 local meta
= minetest
.get_meta(pos
)
5 meta
:set_string("commands", "")
6 meta
:set_string("commander", "")
9 local function after_place(pos
, placer
)
11 local meta
= minetest
.get_meta(pos
)
12 meta
:set_string("commander", placer
:get_player_name())
16 local function resolve_commands(commands
, pos
)
17 local players
= minetest
.get_connected_players()
19 local meta
= minetest
.get_meta(pos
)
20 local commander
= meta
:get_string("commander")
22 -- A non-printable character used while replacing “@@”.
23 local SUBSTITUTE_CHARACTER
= '\26' -- ASCII SUB
25 -- No players online: remove all commands containing
26 -- problematic placeholders.
28 commands
= commands
:gsub("[^\r\n]+", function (line
)
29 line
= line
:gsub("@@", SUBSTITUTE_CHARACTER
)
30 if line
:find("@n") then return "" end
31 if line
:find("@p") then return "" end
32 if line
:find("@f") then return "" end
33 if line
:find("@r") then return "" end
34 line
= line
:gsub("@c", commander
)
35 line
= line
:gsub(SUBSTITUTE_CHARACTER
, "@")
41 local nearest
, farthest
= nil, nil
42 local min_distance
, max_distance
= math
.huge
, -1
43 for index
, player
in pairs(players
) do
44 local distance
= vector
.distance(pos
, player
:getpos())
45 if distance
< min_distance
then
46 min_distance
= distance
47 nearest
= player
:get_player_name()
49 if distance
> max_distance
then
50 max_distance
= distance
51 farthest
= player
:get_player_name()
54 local random = players
[math
.random(#players
)]:get_player_name()
55 commands
= commands
:gsub("@@", SUBSTITUTE_CHARACTER
)
56 commands
= commands
:gsub("@p", nearest
)
57 commands
= commands
:gsub("@n", nearest
)
58 commands
= commands
:gsub("@f", farthest
)
59 commands
= commands
:gsub("@r", random)
60 commands
= commands
:gsub("@c", commander
)
61 commands
= commands
:gsub(SUBSTITUTE_CHARACTER
, "@")
65 local function check_commands(commands
, player_name
)
66 for _
, command
in pairs(commands
:split("\n")) do
67 local pos
= command
:find(" ")
68 local cmd
, param
= command
, ""
70 cmd
= command
:sub(1, pos
- 1)
72 local cmddef
= minetest
.chatcommands
[cmd
]
74 -- Invalid chat command
75 local 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."
76 if string.sub(cmd
, 1, 1) == "/" then
77 msg
= msg
.. " Hint: Try to remove the trailing slash."
79 return false, minetest
.colorize("#FF0000", msg
)
82 local player_privs
= minetest
.get_player_privs(player_name
)
84 for cmd_priv
, _
in pairs(cmddef
.privs
) do
85 if player_privs
[cmd_priv
] ~= true then
86 local msg
= "Error: You have insufficient privileges to use the command “"..cmd
.."” (missing privilege: "..cmd_priv
..")! The command block has not been changed."
87 return false, minetest
.colorize("#FF0000", msg
)
95 local function commandblock_action_on(pos
, node
)
96 if node
.name
~= "mesecons_commandblock:commandblock_off" then
100 minetest
.swap_node(pos
, {name
= "mesecons_commandblock:commandblock_on"})
102 local meta
= minetest
.get_meta(pos
)
104 local commands
= resolve_commands(meta
:get_string("commands"), pos
)
105 for _
, command
in pairs(commands
:split("\n")) do
106 local cpos
= command
:find(" ")
107 local cmd
, param
= command
, ""
109 cmd
= command
:sub(1, cpos
- 1)
110 param
= command
:sub(cpos
+ 1)
112 local cmddef
= minetest
.chatcommands
[cmd
]
114 -- Invalid chat command
117 -- Execute command in the name of commander
118 local commander
= meta
:get_string("commander")
119 cmddef
.func(commander
, param
)
123 local function commandblock_action_off(pos
, node
)
124 if node
.name
== "mesecons_commandblock:commandblock_on" then
125 minetest
.swap_node(pos
, {name
= "mesecons_commandblock:commandblock_off"})
129 local on_rightclick
= function(pos
, node
, player
, itemstack
, pointed_thing
)
130 -- Only allow access in Creative Mode
131 if not minetest
.settings
:get_bool("creative_mode") then
134 local privs
= minetest
.get_player_privs(player
:get_player_name())
135 if not privs
.maphack
then
136 minetest
.chat_send_player(player
:get_player_name(), "Access denied. You need the “maphack” privilege to edit command blocks.")
140 local meta
= minetest
.get_meta(pos
)
141 local commands
= meta
:get_string("commands")
142 local commander
= meta
:get_string("commander")
144 if commander
== "" or commander
== nil then
145 commanderstr
= "Error: No commander! Block must be replaced."
147 commanderstr
= "Commander: "..commander
149 local formspec
= "invsize[9,5;]" ..
150 "textarea[0.5,0.5;8.5,4;commands;Commands;"..commands
.."]" ..
151 "button_exit[3.3,4.5;2,1;submit;Submit]" ..
152 "image_button[8,4.5;1,1;doc_button_icon_lores.png;doc;]" ..
153 "label[0,4;"..minetest
.formspec_escape(commanderstr
).."]" ..
155 minetest
.show_formspec(player
:get_player_name(), "commandblock_"..pos
.x
.."_"..pos
.y
.."_"..pos
.z
, formspec
)
158 local on_place
= function(itemstack
, placer
, pointed_thing
)
159 if pointed_thing
.type ~= "node" then
163 -- Use pointed node's on_rightclick function first, if present
164 local node
= minetest
.get_node(pointed_thing
.under
)
165 if placer
and not placer
:get_player_control().sneak
then
166 if minetest
.registered_nodes
[node
.name
] and minetest
.registered_nodes
[node
.name
].on_rightclick
then
167 return minetest
.registered_nodes
[node
.name
].on_rightclick(pointed_thing
.under
, node
, placer
, itemstack
) or itemstack
171 local privs
= minetest
.get_player_privs(placer
:get_player_name())
172 if not privs
.maphack
then
173 minetest
.chat_send_player(placer
:get_player_name(), "Placement denied. You need the “maphack” privilege to place command blocks.")
177 return minetest
.item_place_node(itemstack
, placer
, pointed_thing
)
180 minetest
.register_node("mesecons_commandblock:commandblock_off", {
181 description
= "Command Block",
183 _doc_items_longdesc
=
184 "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.",
185 _doc_items_usagehelp
=
186 [[To use an already existing command block, 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.
188 To place a command block and change the commands, you need to be in Creative Mode and must have the “maphack” privilege. A new command block does not have any commands and does nothing. Rightclick the command block (in Creative Mode!) to edit its commands. Read the help entry “Advanced topics > Server Commands” to understand how they work. Each line contains a single command. You enter them like you would in the console, but without the leading slash. The commands will be executed from top to bottom.
190 All commands will be executed on behalf of the player who placed the command block, as if the player typed in the commands. This player is said to be the “commander” of the block.
192 Command blocks support placeholders, insert one of these placerholders and they will be replaced by a player name:
193 • “@c”: commander of this command block
194 • “@n” or “@p”: nearest player from the command block
195 • “@f” farthest player from the command block
196 • “@r”: random player currently in the world
197 • “@@”: literal “@” sign
202 Sets the game clock to 12:00
205 give @n mcl_core:apple 5
207 → Gives the nearest player 5 apples]],
209 tiles
= {{name
="jeija_commandblock_off.png", animation
={type="vertical_frames", aspect_w
=32, aspect_h
=32, length
=2}}},
210 groups
= {creative_breakable
=1, mesecon_effector_off
=1},
212 on_blast
= function() end,
213 on_construct
= construct
,
214 is_ground_content
= false,
216 after_place_node
= after_place
,
217 on_rightclick
= on_rightclick
,
218 sounds
= mcl_sounds
.node_sound_stone_defaults(),
219 mesecons
= {effector
= {
220 action_on
= commandblock_action_on
,
221 rules
= mesecon
.rules
.alldirs
,
223 _mcl_blast_resistance
= 18000000,
227 minetest
.register_node("mesecons_commandblock:commandblock_on", {
228 tiles
= {{name
="jeija_commandblock_off.png", animation
={type="vertical_frames", aspect_w
=32, aspect_h
=32, length
=2}}},
229 groups
= {creative_breakable
=1, mesecon_effector_on
=1, not_in_creative_inventory
=1},
231 on_blast
= function() end,
232 on_construct
= construct
,
233 is_ground_content
= false,
235 after_place_node
= after_place
,
236 on_rightclick
= on_rightclick
,
237 sounds
= mcl_sounds
.node_sound_stone_defaults(),
238 mesecons
= {effector
= {
239 action_off
= commandblock_action_off
,
240 rules
= mesecon
.rules
.alldirs
,
242 _mcl_blast_resistance
= 18000000,
246 minetest
.register_on_player_receive_fields(function(player
, formname
, fields
)
247 if string.sub(formname
, 1, 13) == "commandblock_" then
248 if not fields
.submit
and not fields
.key_enter
and not fields
.doc
then
251 local privs
= minetest
.get_player_privs(player
:get_player_name())
252 if not privs
.maphack
then
253 minetest
.chat_send_player(player
:get_player_name(), "Access denied. You need the “maphack” privilege to edit command blocks.")
257 if fields
.doc
and minetest
.get_modpath("doc") then
258 doc
.show_entry(player
:get_player_name(), "nodes", "mesecons_commandblock:commandblock_off", true)
261 local index
, _
, x
, y
, z
= string.find(formname
, "commandblock_(-?%d+)_(-?%d+)_(-?%d+)")
262 if index
~= nil and x
~= nil and y
~= nil and z
~= nil then
263 local pos
= {x
=tonumber(x
), y
=tonumber(y
), z
=tonumber(z
)}
264 local meta
= minetest
.get_meta(pos
)
265 if not minetest
.settings
:get_bool("creative_mode") then
266 minetest
.chat_send_player(player
:get_player_name(), "Editing the command block has failed! You can only change the command block in Creative Mode!")
269 local check
, error_message
= check_commands(fields
.commands
, player
:get_player_name())
270 if check
== false then
271 -- Command block rejected
272 minetest
.chat_send_player(player
:get_player_name(), error_message
)
275 meta
:set_string("commands", fields
.commands
)
278 minetest
.chat_send_player(player
:get_player_name(), "Editing the command block has failed! The command block is gone.")
283 -- Add entry alias for the Help
284 if minetest
.get_modpath("doc") then
285 doc
.add_entry_alias("nodes", "mesecons_commandblock:commandblock_off", "nodes", "mesecons_commandblock:commandblock_on")