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 -- No players online: remove all commands containing
25 commands
= commands
:gsub("[^\r\n]+", function (line
)
26 if line
:find("@nearest") then return "" end
27 if line
:find("@farthest") then return "" end
28 if line
:find("@random") then return "" end
29 if line
:find("@commander") then return commander
end
35 local nearest
, farthest
= nil, nil
36 local min_distance
, max_distance
= math
.huge
, -1
37 for index
, player
in pairs(players
) do
38 local distance
= vector
.distance(pos
, player
:getpos())
39 if distance
< min_distance
then
40 min_distance
= distance
41 nearest
= player
:get_player_name()
43 if distance
> max_distance
then
44 max_distance
= distance
45 farthest
= player
:get_player_name()
48 local random = players
[math
.random(#players
)]:get_player_name()
49 commands
= commands
:gsub("@nearest", nearest
)
50 commands
= commands
:gsub("@farthest", farthest
)
51 commands
= commands
:gsub("@random", random)
52 commands
= commands
:gsub("@commander", commander
)
56 local function check_commands(commands
, player_name
)
57 for _
, command
in pairs(commands
:split("\n")) do
58 local pos
= command
:find(" ")
59 local cmd
, param
= command
, ""
61 cmd
= command
:sub(1, pos
- 1)
63 local cmddef
= minetest
.chatcommands
[cmd
]
65 -- Invalid chat command
66 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."
67 if string.sub(cmd
, 1, 1) == "/" then
68 msg
= msg
.. " Hint: Try to remove the trailing slash."
73 local player_privs
= minetest
.get_player_privs(player_name
)
75 for cmd_priv
, _
in pairs(cmddef
.privs
) do
76 if player_privs
[cmd_priv
] ~= true then
77 local msg
= "Error: You have insufficient privileges to use the command “"..cmd
.."” (missing privilege: "..cmd_priv
..")! The command block has not been changed."
86 local function commandblock_action_on(pos
, node
)
87 if node
.name
~= "mesecons_commandblock:commandblock_off" then
91 minetest
.swap_node(pos
, {name
= "mesecons_commandblock:commandblock_on"})
93 local meta
= minetest
.get_meta(pos
)
95 local commands
= resolve_commands(meta
:get_string("commands"), pos
)
96 for _
, command
in pairs(commands
:split("\n")) do
97 local cpos
= command
:find(" ")
98 local cmd
, param
= command
, ""
100 cmd
= command
:sub(1, cpos
- 1)
101 param
= command
:sub(cpos
+ 1)
103 local cmddef
= minetest
.chatcommands
[cmd
]
105 -- Invalid chat command
108 -- Execute command in the name of commander
109 local commander
= meta
:get_string("commander")
110 cmddef
.func(commander
, param
)
114 local function commandblock_action_off(pos
, node
)
115 if node
.name
== "mesecons_commandblock:commandblock_on" then
116 minetest
.swap_node(pos
, {name
= "mesecons_commandblock:commandblock_off"})
120 local on_rightclick
= function(pos
, node
, player
, itemstack
, pointed_thing
)
121 -- Only allow access in Creative Mode
122 if not minetest
.settings
:get_bool("creative_mode") then
125 local privs
= minetest
.get_player_privs(player
:get_player_name())
126 if not privs
.maphack
then
127 minetest
.chat_send_player(player
:get_player_name(), "Access denied. You need the “maphack” privilege to edit command blocks.")
131 local meta
= minetest
.get_meta(pos
)
132 local commands
= meta
:get_string("commands")
133 local commander
= meta
:get_string("commander")
135 if commander
== "" or commander
== nil then
136 commanderstr
= "Error: No commander! Block must be replaced."
138 commanderstr
= "Commander: "..commander
140 local formspec
= "invsize[9,5;]" ..
141 "textarea[0.5,0.5;8.5,4;commands;Commands;"..commands
.."]" ..
142 "button_exit[3.3,4.5;2,1;submit;Submit]" ..
143 "image_button[8,4.5;1,1;doc_button_icon_lores.png;doc;]" ..
144 "label[0,4;"..minetest
.formspec_escape(commanderstr
).."]" ..
146 minetest
.show_formspec(player
:get_player_name(), "commandblock_"..pos
.x
.."_"..pos
.y
.."_"..pos
.z
, formspec
)
149 local on_place
= function(itemstack
, placer
, pointed_thing
)
150 if pointed_thing
.type ~= "node" then
154 -- Use pointed node's on_rightclick function first, if present
155 local node
= minetest
.get_node(pointed_thing
.under
)
156 if placer
and not placer
:get_player_control().sneak
then
157 if minetest
.registered_nodes
[node
.name
] and minetest
.registered_nodes
[node
.name
].on_rightclick
then
158 return minetest
.registered_nodes
[node
.name
].on_rightclick(pointed_thing
.under
, node
, placer
, itemstack
) or itemstack
162 local privs
= minetest
.get_player_privs(placer
:get_player_name())
163 if not privs
.maphack
then
164 minetest
.chat_send_player(placer
:get_player_name(), "Placement denied. You need the “maphack” privilege to place command blocks.")
168 return minetest
.item_place_node(itemstack
, placer
, pointed_thing
)
171 minetest
.register_node("mesecons_commandblock:commandblock_off", {
172 description
= "Command Block",
174 _doc_items_longdesc
=
175 "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.",
176 _doc_items_usagehelp
=
177 [[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.
179 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.
181 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.
183 Command blocks support placeholders, insert one of these placerholders and they will be replaced by a player name:
184 • “@commander”: commander of this command block
185 • “@nearest”: nearest player from the command block
186 • “@farthest” farthest player from the command block
187 • “@random”: random player currently in the world
192 Sets the game clock to 12:00
195 give @nearest mcl_core:apple 5
197 → Gives the nearest player 5 apples]],
199 tiles
= {{name
="jeija_commandblock_off.png", animation
={type="vertical_frames", aspect_w
=32, aspect_h
=32, length
=2}}},
200 groups
= {creative_breakable
=1, mesecon_effector_off
=1},
202 on_blast
= function() end,
203 on_construct
= construct
,
204 is_ground_content
= false,
206 after_place_node
= after_place
,
207 on_rightclick
= on_rightclick
,
208 sounds
= mcl_sounds
.node_sound_stone_defaults(),
209 mesecons
= {effector
= {
210 action_on
= commandblock_action_on
,
211 rules
= mesecon
.rules
.alldirs
,
213 _mcl_blast_resistance
= 18000000,
217 minetest
.register_node("mesecons_commandblock:commandblock_on", {
218 tiles
= {{name
="jeija_commandblock_off.png", animation
={type="vertical_frames", aspect_w
=32, aspect_h
=32, length
=2}}},
219 groups
= {creative_breakable
=1, mesecon_effector_on
=1, not_in_creative_inventory
=1},
221 on_blast
= function() end,
222 on_construct
= construct
,
223 is_ground_content
= false,
225 after_place_node
= after_place
,
226 on_rightclick
= on_rightclick
,
227 sounds
= mcl_sounds
.node_sound_stone_defaults(),
228 mesecons
= {effector
= {
229 action_off
= commandblock_action_off
,
230 rules
= mesecon
.rules
.alldirs
,
232 _mcl_blast_resistance
= 18000000,
236 minetest
.register_on_player_receive_fields(function(player
, formname
, fields
)
237 if string.sub(formname
, 1, 13) == "commandblock_" then
238 if not fields
.submit
and not fields
.doc
then
241 local privs
= minetest
.get_player_privs(player
:get_player_name())
242 if not privs
.maphack
then
243 minetest
.chat_send_player(player
:get_player_name(), "Access denied. You need the “maphack” privilege to edit command blocks.")
247 if fields
.doc
and minetest
.get_modpath("doc") then
248 doc
.show_entry(player
:get_player_name(), "nodes", "mesecons_commandblock:commandblock_off", true)
251 local index
, _
, x
, y
, z
= string.find(formname
, "commandblock_(-?%d+)_(-?%d+)_(-?%d+)")
252 if index
~= nil and x
~= nil and y
~= nil and z
~= nil then
253 local pos
= {x
=tonumber(x
), y
=tonumber(y
), z
=tonumber(z
)}
254 local meta
= minetest
.get_meta(pos
)
255 if not minetest
.settings
:get_bool("creative_mode") then
256 minetest
.chat_send_player(player
:get_player_name(), "Editing the command block has failed! You can only change the command block in Creative Mode!")
259 local check
, error_message
= check_commands(fields
.commands
, player
:get_player_name())
260 if check
== false then
261 -- Command block rejected
262 minetest
.chat_send_player(player
:get_player_name(), error_message
)
265 meta
:set_string("commands", fields
.commands
)
268 minetest
.chat_send_player(player
:get_player_name(), "Editing the command block has failed! The command block is gone.")
273 -- Add entry alias for the Help
274 if minetest
.get_modpath("doc") then
275 doc
.add_entry_alias("nodes", "mesecons_commandblock:commandblock_off", "nodes", "mesecons_commandblock:commandblock_on")