]> git.lizzy.rs Git - worldedit.git/blob - worldedit_gui/init.lua
d44d8bb9c24ac6c39b69ffebefdce112daf4839c
[worldedit.git] / worldedit_gui / init.lua
1 worldedit = worldedit or {}
2
3 --[[
4 Example:
5
6     worldedit.register_gui_function("worldedit_gui_hollow_cylinder", {
7         name = "Make Hollow Cylinder",
8         privs = {worldedit=true},
9         get_formspec = function(name) return "some formspec here" end,
10         on_select = function(name) print(name .. " clicked the button!") end,
11     })
12
13 Use `nil` for the `options` parameter to unregister the function associated with the given identifier.
14
15 Use `nil` for the `get_formspec` field to denote that the function does not have its own screen.
16
17 The `privs` field may not be `nil`.
18
19 If the identifier is already registered to another function, it will be replaced by the new one.
20
21 The `on_select` function must not call `worldedit.show_page`
22 ]]
23
24 worldedit.pages = {} --mapping of identifiers to options
25 local identifiers = {} --ordered list of identifiers
26 worldedit.register_gui_function = function(identifier, options)
27         if options.privs == nil or next(options.privs) == nil then
28                 error("privs unset")
29         end
30         worldedit.pages[identifier] = options
31         table.insert(identifiers, identifier)
32 end
33
34 --[[
35 Example:
36
37     worldedit.register_gui_handler("worldedit_gui_hollow_cylinder", function(name, fields)
38         print(minetest.serialize(fields))
39     end)
40 ]]
41
42 worldedit.register_gui_handler = function(identifier, handler)
43         local enabled = true
44         minetest.register_on_player_receive_fields(function(player, formname, fields)
45                 if not enabled then return false end
46                 enabled = false
47                 minetest.after(0.2, function() enabled = true end)
48                 local name = player:get_player_name()
49
50                 --ensure the player has permission to perform the action
51                 local entry = worldedit.pages[identifier]
52                 if entry and minetest.check_player_privs(name, entry.privs) then
53                         return handler(name, fields)
54                 end
55                 return false
56         end)
57 end
58
59 worldedit.get_formspec_header = function(identifier)
60         local entry = worldedit.pages[identifier] or {}
61         return "button[0,0;2,0.5;worldedit_gui;Back]" ..
62                 string.format("label[2,0;WorldEdit GUI > %s]", entry.name or "")
63 end
64
65 local get_formspec = function(name, identifier)
66         if worldedit.pages[identifier] then
67                 return worldedit.pages[identifier].get_formspec(name)
68         end
69         return worldedit.pages["worldedit_gui"].get_formspec(name) --default to showing main page if an unknown page is given
70 end
71
72 --implement worldedit.show_page(name, page) in different ways depending on the available APIs
73 if rawget(_G, "unified_inventory") then --unified inventory installed
74         local old_func = worldedit.register_gui_function
75         worldedit.register_gui_function = function(identifier, options)
76                 old_func(identifier, options)
77                 unified_inventory.register_page(identifier, {get_formspec=function(player) return {formspec=options.get_formspec(player:get_player_name())} end})
78         end
79
80         unified_inventory.register_button("worldedit_gui", {
81                 type = "image",
82                 image = "inventory_plus_worldedit_gui.png",
83         })
84
85         minetest.register_on_player_receive_fields(function(player, formname, fields)
86                 local name = player:get_player_name()
87                 if fields.worldedit_gui then --main page
88                         worldedit.show_page(name, "worldedit_gui")
89                         return true
90                 elseif fields.worldedit_gui_exit then --return to original page
91                         local player = minetest.get_player_by_name(name)
92                         if player then
93                                 unified_inventory.set_inventory_formspec(player, "craft")
94                         end
95                         return true
96                 end
97                 return false
98         end)
99
100         worldedit.show_page = function(name, page)
101                 local player = minetest.get_player_by_name(name)
102                 if player then
103                         player:set_inventory_formspec(get_formspec(name, page))
104                 end
105         end
106 elseif rawget(_G, "inventory_plus") then --inventory++ installed
107         minetest.register_on_joinplayer(function(player)
108                 local can_worldedit = minetest.check_player_privs(player:get_player_name(), {worldedit=true})
109                 if can_worldedit then
110                         inventory_plus.register_button(player, "worldedit_gui", "WorldEdit")
111                 end
112         end)
113
114         --show the form when the button is pressed and hide it when done
115         local gui_player_formspecs = {}
116         minetest.register_on_player_receive_fields(function(player, formname, fields)
117                 local name = player:get_player_name()
118                 if fields.worldedit_gui then --main page
119                         gui_player_formspecs[name] = player:get_inventory_formspec()
120                         worldedit.show_page(name, "worldedit_gui")
121                         return true
122                 elseif fields.worldedit_gui_exit then --return to original page
123                         if gui_player_formspecs[name] then
124                                 inventory_plus.set_inventory_formspec(player, inventory_plus.get_formspec(player, "main"))
125                         end
126                         return true
127                 end
128                 return false
129         end)
130
131         worldedit.show_page = function(name, page)
132                 local player = minetest.get_player_by_name(name)
133                 if player then
134                         inventory_plus.set_inventory_formspec(player, get_formspec(name, page))
135                 end
136         end
137 elseif rawget(_G, "sfinv") then --sfinv installed (part of minetest_game since 0.4.15)
138         assert(sfinv.enabled)
139         local orig_get = sfinv.pages["sfinv:crafting"].get
140         sfinv.override_page("sfinv:crafting", {
141                 get = function(self, player, context)
142                         local can_worldedit = minetest.check_player_privs(player, {worldedit=true})
143                         local fs = orig_get(self, player, context)
144                         return fs .. (can_worldedit and "image_button[0,0;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]" or "")
145                 end
146         })
147
148         --compatibility with pre-0.4.16 sfinv
149         local set_page = sfinv.set_page or function(player, name)
150                 --assumptions: src pg has no leave callback, dst pg has no enter callback
151                 local ctx = {page=name}
152                 sfinv.contexts[player:get_player_name()] = ctx
153                 sfinv.set_player_inventory_formspec(player, ctx)
154         end
155
156         --show the form when the button is pressed and hide it when done
157         minetest.register_on_player_receive_fields(function(player, formname, fields)
158                 if fields.worldedit_gui then --main page
159                         worldedit.show_page(player:get_player_name(), "worldedit_gui")
160                         return true
161                 elseif fields.worldedit_gui_exit then --return to original page
162                         set_page(player, "sfinv:crafting")
163                         return true
164                 end
165                 return false
166         end)
167
168         worldedit.show_page = function(name, page)
169                 local player = minetest.get_player_by_name(name)
170                 if player then
171                         player:set_inventory_formspec(get_formspec(name, page))
172                 end
173         end
174 else --fallback button
175         -- FIXME: this is a huge clusterfuck and the back button is broken
176         local player_formspecs = {}
177
178         local update_main_formspec = function(name)
179                 local formspec = player_formspecs[name]
180                 if not formspec then
181                         return
182                 end
183                 local player = minetest.get_player_by_name(name)
184                 if not player then --this is in case the player signs off while the media is loading
185                         return
186                 end
187                 if (minetest.check_player_privs(name, {creative=true}) or
188                                 minetest.setting_getbool("creative_mode")) and
189                                 creative then --creative is active, add button to modified formspec
190                         local creative_formspec = player:get_inventory_formspec()
191                         local tab_id = tonumber(creative_formspec:match("tabheader%[.-;(%d+)%;"))
192
193                         if tab_id == 1 then
194                                 formspec = creative_formspec ..
195                                         "image_button[0,1;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]"
196                         elseif not tab_id then
197                                 formspec = creative_formspec ..
198                                         "image_button[6,0;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]"
199                         else
200                                 return
201                         end
202                 else
203                         formspec = formspec .. "image_button[0,0;1,1;inventory_plus_worldedit_gui.png;worldedit_gui;]"
204                 end
205                 player:set_inventory_formspec(formspec)
206         end
207
208         minetest.register_on_joinplayer(function(player)
209                 local name = player:get_player_name()
210                 minetest.after(1, function()
211                         if minetest.get_player_by_name(name) then --ensure the player is still signed in
212                                 player_formspecs[name] = player:get_inventory_formspec()
213                                 minetest.after(0.01, function()
214                                         update_main_formspec(name)
215                                 end)
216                         end
217                 end)
218         end)
219
220         minetest.register_on_leaveplayer(function(player)
221                 player_formspecs[player:get_player_name()] = nil
222         end)
223
224         local gui_player_formspecs = {}
225         minetest.register_on_player_receive_fields(function(player, formname, fields)
226                 local name = player:get_player_name()
227                 if fields.worldedit_gui then --main page
228                         gui_player_formspecs[name] = player:get_inventory_formspec()
229                         worldedit.show_page(name, "worldedit_gui")
230                         return true
231                 elseif fields.worldedit_gui_exit then --return to original page
232                         if gui_player_formspecs[name] then
233                                 player:set_inventory_formspec(gui_player_formspecs[name])
234                         end
235                         return true
236                 else --deal with creative_inventory setting the formspec on every single message
237                         minetest.after(0.01,function()
238                                 update_main_formspec(name)
239                         end)
240                         return false --continue processing in creative inventory
241                 end
242         end)
243
244         worldedit.show_page = function(name, page)
245                 local player = minetest.get_player_by_name(name)
246                 if player then
247                         player:set_inventory_formspec(get_formspec(name, page))
248                 end
249         end
250 end
251
252 worldedit.register_gui_function("worldedit_gui", {
253         name = "WorldEdit GUI",
254         privs = {interact=true},
255         get_formspec = function(name)
256                 --create a form with all the buttons arranged in a grid
257                 local buttons, x, y, index = {}, 0, 1, 0
258                 local width, height = 3, 0.8
259                 local columns = 5
260                 for i, identifier in pairs(identifiers) do
261                         if identifier ~= "worldedit_gui" then
262                                 local entry = worldedit.pages[identifier]
263                                 table.insert(buttons, string.format((entry.get_formspec and "button" or "button_exit") ..
264                                         "[%g,%g;%g,%g;%s;%s]", x, y, width, height, identifier, minetest.formspec_escape(entry.name)))
265
266                                 index, x = index + 1, x + width
267                                 if index == columns then --row is full
268                                         x, y = 0, y + height
269                                         index = 0
270                                 end
271                         end
272                 end
273                 if index == 0 then --empty row
274                         y = y - height
275                 end
276                 return string.format("size[%g,%g]", math.max(columns * width, 5), math.max(y + 0.5, 3)) ..
277                         "button[0,0;2,0.5;worldedit_gui_exit;Back]" ..
278                         "label[2,0;WorldEdit GUI]" ..
279                         table.concat(buttons)
280         end,
281 })
282
283 worldedit.register_gui_handler("worldedit_gui", function(name, fields)
284         for identifier, entry in pairs(worldedit.pages) do --check for WorldEdit GUI main formspec button selection
285                 if fields[identifier] and identifier ~= "worldedit_gui" then
286                         --ensure player has permission to perform action
287                         local has_privs, missing_privs = minetest.check_player_privs(name, entry.privs)
288                         if not has_privs then
289                                 worldedit.player_notify(name, "you are not allowed to use this function (missing privileges: " .. table.concat(missing_privs, ", ") .. ")")
290                                 return false
291                         end
292                         if entry.on_select then
293                                 entry.on_select(name)
294                         end
295                         if entry.get_formspec then
296                                 worldedit.show_page(name, identifier)
297                         end
298                         return true
299                 end
300         end
301         return false
302 end)
303
304 dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/functionality.lua")