1 -- Minetest: builtin/misc_helpers.lua
3 --------------------------------------------------------------------------------
4 function basic_dump2(o)
5 if type(o) == "number" then
7 elseif type(o) == "string" then
8 return string.format("%q", o)
9 elseif type(o) == "boolean" then
11 elseif type(o) == "function" then
13 elseif type(o) == "userdata" then
15 elseif type(o) == "nil" then
18 error("cannot dump a " .. type(o))
23 --------------------------------------------------------------------------------
24 function dump2(o, name, dumped)
28 if type(o) == "number" or type(o) == "string" or type(o) == "boolean"
29 or type(o) == "function" or type(o) == "nil"
30 or type(o) == "userdata" then
31 io.write(basic_dump2(o), "\n")
32 elseif type(o) == "table" then
34 io.write(dumped[o], "\n")
37 io.write("{}\n") -- new table
38 for k,v in pairs(o) do
39 local fieldname = string.format("%s[%s]", name, basic_dump2(k))
40 dump2(v, fieldname, dumped)
44 error("cannot dump a " .. type(o))
49 --------------------------------------------------------------------------------
50 function dump(o, dumped)
52 if type(o) == "number" then
54 elseif type(o) == "string" then
55 return string.format("%q", o)
56 elseif type(o) == "table" then
58 return "<circular reference>"
62 for k,v in pairs(o) do
63 t[#t+1] = "[" .. dump(k, dumped) .. "] = " .. dump(v, dumped)
65 return "{" .. table.concat(t, ", ") .. "}"
66 elseif type(o) == "boolean" then
68 elseif type(o) == "function" then
70 elseif type(o) == "userdata" then
72 elseif type(o) == "nil" then
75 error("cannot dump a " .. type(o))
80 --------------------------------------------------------------------------------
81 function string:split(sep)
82 local sep, fields = sep or ",", {}
83 local pattern = string.format("([^%s]+)", sep)
84 self:gsub(pattern, function(c) fields[#fields+1] = c end)
88 --------------------------------------------------------------------------------
89 function file_exists(filename)
90 local f = io.open(filename, "r")
99 --------------------------------------------------------------------------------
100 function string:trim()
101 return (self:gsub("^%s*(.-)%s*$", "%1"))
104 assert(string.trim("\n \t\tfoo bar\t ") == "foo bar")
106 --------------------------------------------------------------------------------
107 function math.hypot(x, y)
113 if x == 0 then return 0 end
115 return x * math.sqrt(1 + t * t)
118 --------------------------------------------------------------------------------
119 function get_last_folder(text,count)
120 local parts = text:split(DIR_DELIM)
128 retval = retval .. parts[#parts - (count-i)] .. DIR_DELIM
134 --------------------------------------------------------------------------------
135 function cleanup_path(temppath)
137 local parts = temppath:split("-")
140 if temppath ~= "" then
141 temppath = temppath .. "_"
143 temppath = temppath .. parts[i]
146 parts = temppath:split(".")
149 if temppath ~= "" then
150 temppath = temppath .. "_"
152 temppath = temppath .. parts[i]
155 parts = temppath:split("'")
158 if temppath ~= "" then
159 temppath = temppath .. ""
161 temppath = temppath .. parts[i]
164 parts = temppath:split(" ")
167 if temppath ~= "" then
170 temppath = temppath .. parts[i]
176 function core.formspec_escape(text)
178 text = string.gsub(text,"\\","\\\\")
179 text = string.gsub(text,"%]","\\]")
180 text = string.gsub(text,"%[","\\[")
181 text = string.gsub(text,";","\\;")
182 text = string.gsub(text,",","\\,")
188 function core.splittext(text,charlimit)
191 local current_idx = 1
193 local start,stop = string.find(text," ",current_idx)
194 local nl_start,nl_stop = string.find(text,"\n",current_idx)
195 local gotnewline = false
196 if nl_start ~= nil and (start == nil or nl_start < start) then
202 while start ~= nil do
203 if string.len(last_line) + (stop-start) > charlimit then
204 table.insert(retval,last_line)
208 if last_line ~= "" then
209 last_line = last_line .. " "
212 last_line = last_line .. string.sub(text,current_idx,stop -1)
215 table.insert(retval,last_line)
221 start,stop = string.find(text," ",current_idx)
222 nl_start,nl_stop = string.find(text,"\n",current_idx)
224 if nl_start ~= nil and (start == nil or nl_start < start) then
231 --add last part of text
232 if string.len(last_line) + (string.len(text) - current_idx) > charlimit then
233 table.insert(retval,last_line)
234 table.insert(retval,string.sub(text,current_idx))
236 last_line = last_line .. " " .. string.sub(text,current_idx)
237 table.insert(retval,last_line)
243 --------------------------------------------------------------------------------
245 if INIT == "game" then
246 local dirs1 = {9, 18, 7, 12}
247 local dirs2 = {20, 23, 22, 21}
249 function core.rotate_and_place(itemstack, placer, pointed_thing,
250 infinitestacks, orient_flags)
251 orient_flags = orient_flags or {}
253 local unode = core.get_node_or_nil(pointed_thing.under)
257 local undef = core.registered_nodes[unode.name]
258 if undef and undef.on_rightclick then
259 undef.on_rightclick(pointed_thing.under, unode, placer,
260 itemstack, pointed_thing)
263 local pitch = placer:get_look_pitch()
264 local fdir = core.dir_to_facedir(placer:get_look_dir())
265 local wield_name = itemstack:get_name()
267 local above = pointed_thing.above
268 local under = pointed_thing.under
269 local iswall = (above.y == under.y)
270 local isceiling = not iswall and (above.y < under.y)
271 local anode = core.get_node_or_nil(above)
275 local pos = pointed_thing.above
278 if undef and undef.buildable_to then
279 pos = pointed_thing.under
284 if core.is_protected(pos, placer:get_player_name()) then
285 core.record_protection_violation(pos,
286 placer:get_player_name())
290 local ndef = core.registered_nodes[node.name]
291 if not ndef or not ndef.buildable_to then
295 if orient_flags.force_floor then
298 elseif orient_flags.force_ceiling then
301 elseif orient_flags.force_wall then
304 elseif orient_flags.invert_wall then
309 core.set_node(pos, {name = wield_name,
310 param2 = dirs1[fdir+1]})
311 elseif isceiling then
312 if orient_flags.force_facedir then
313 core.set_node(pos, {name = wield_name,
316 core.set_node(pos, {name = wield_name,
317 param2 = dirs2[fdir+1]})
319 else -- place right side up
320 if orient_flags.force_facedir then
321 core.set_node(pos, {name = wield_name,
324 core.set_node(pos, {name = wield_name,
329 if not infinitestacks then
330 itemstack:take_item()
336 --------------------------------------------------------------------------------
337 --Wrapper for rotate_and_place() to check for sneak and assume Creative mode
338 --implies infinite stacks when performing a 6d rotation.
339 --------------------------------------------------------------------------------
342 core.rotate_node = function(itemstack, placer, pointed_thing)
343 core.rotate_and_place(itemstack, placer, pointed_thing,
344 core.setting_getbool("creative_mode"),
345 {invert_wall = placer:get_player_control().sneak})
350 --------------------------------------------------------------------------------
351 function core.explode_table_event(evt)
353 local parts = evt:split(":")
355 local t = parts[1]:trim()
356 local r = tonumber(parts[2]:trim())
357 local c = tonumber(parts[3]:trim())
358 if type(r) == "number" and type(c) == "number" and t ~= "INV" then
359 return {type=t, row=r, column=c}
363 return {type="INV", row=0, column=0}
366 --------------------------------------------------------------------------------
367 function core.explode_textlist_event(evt)
369 local parts = evt:split(":")
371 local t = parts[1]:trim()
372 local r = tonumber(parts[2]:trim())
373 if type(r) == "number" and t ~= "INV" then
374 return {type=t, index=r}
378 return {type="INV", index=0}
381 function core.pos_to_string(pos)
382 return "(" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ")"
385 --------------------------------------------------------------------------------
386 -- mainmenu only functions
387 --------------------------------------------------------------------------------
388 if INIT == "mainmenu" then
389 function core.get_game(index)
390 local games = game.get_games()
392 if index > 0 and index <= #games then
399 function fgettext(text, ...)
400 text = core.gettext(text)
401 local arg = {n=select('#', ...), ...}
403 -- Insert positional parameters ($1, $2, ...)
406 while pos <= text:len() do
407 newpos = text:find('[$]', pos)
408 if newpos == nil then
409 result = result .. text:sub(pos)
412 paramindex = tonumber(text:sub(newpos+1, newpos+1))
413 result = result .. text:sub(pos, newpos-1) .. tostring(arg[paramindex])
419 return core.formspec_escape(text)