-- LUALOCALS < --------------------------------------------------------- local ipairs, minetest, next, pairs, pcall, string, table, tonumber, vector = ipairs, minetest, next, pairs, pcall, string, table, tonumber, vector local string_format, string_gsub, string_match, table_concat = string.format, string.gsub, string.match, table.concat -- LUALOCALS > --------------------------------------------------------- local include = ... local configdb, savedb = include("configdb") local exportall = include("exportall") local mediacache, mediadirs = include("mediacache") local modname = minetest.get_current_modname() local function save_export_report() savedb() local result = exportall() local lines = { string_format("exported %d def(s) and %d media", result.exported_defs, result.exported_media) } for k, v in pairs(result.missing_defs) do lines[#lines + 1] = string_format("WARNING: %d def(s) missing from mod %q", v, k) end for k, v in pairs(result.missing_media) do lines[#lines + 1] = string_format("WARNING: %d media file(s) missing from %q", v, k) end return true, table_concat(lines, "\n") end minetest.register_chatcommand(modname, { description = "Rip all items in already marked for export", privs = {server = true}, func = save_export_report }) minetest.register_chatcommand(modname .. "_clear", { description = "Clear all saved exports", privs = {server = true}, func = function() for k in pairs(configdb.items) do configdb.items[k] = nil end return save_export_report() end }) local function ripinv(inv) local dirty for _, list in pairs(inv:get_lists()) do for _, stack in pairs(list) do local n = stack:get_name() if n and n ~= "" and not configdb.items[n] then configdb.items[n] = true dirty = true end end end return dirty end minetest.register_chatcommand(modname .. "_inv", { description = "Rip all items in inventory", privs = {server = true}, func = function(name) local player = minetest.get_player_by_name(name) if not player then return false, "invalid player" end ripinv(player:get_inventory()) return save_export_report() end }) do local function patternfunc(setto) return function(_, param) if param == "" then return false, "must supply pattern" end local ok, err = pcall(function() for k in pairs(minetest.registered_items) do if string_match(k, param) then configdb.items[k] = setto end end for k in pairs(minetest.registered_aliases) do if string_match(k, param) then configdb.items[k] = setto end end end) if not ok then return false, string_gsub(err, ".*:%d+:%s*", "") end return save_export_report() end end minetest.register_chatcommand(modname .. "_add", { description = "Rip all defs with technical names matching a pattern", params = "", privs = {server = true}, func = patternfunc(true) }) minetest.register_chatcommand(modname .. "_rm", { description = "Un-rip all defs with technical names matching a pattern", params = "", privs = {server = true}, func = patternfunc(nil) }) end local function ripradius(pos, radius) local foundids = {} do local vm = minetest.get_voxel_manip( vector.subtract(pos, radius), vector.add(pos, radius)) local data = vm:get_data() for i = 1, #data do foundids[data[i]] = true end end local dirty for k in pairs(foundids) do local n = minetest.get_name_from_content_id(k) if n and n ~= "" and not configdb.items[n] then configdb.items[n] = true dirty = true end end if minetest.settings:get_bool(modname .. "_node_inv") then for _, p in ipairs(minetest.find_nodes_with_meta( vector.subtract(pos, radius), vector.add(pos, radius))) do dirty = ripinv(minetest.get_meta(p):get_inventory()) or dirty end end return dirty end minetest.register_chatcommand(modname .. "_here", { description = "Rip all nodes within a radius", params = "[radius_x=100 [radius_y=radius_x [radius_z=radius_x]]]", privs = {server = true}, func = function(name, param) local player = minetest.get_player_by_name(name) if not player then return false, "invalid player" end local parts = param:split(" ") local rx = parts[1] and tonumber(parts[1]) or 100 local ry = parts[2] and tonumber(parts[2]) or rx local rz = parts[3] and tonumber(parts[3]) or rx ripradius(player:get_pos(), vector.new(rx, ry, rz)) return save_export_report() end }) local steprippers = {} local stepripstart do local pended local function stepriprun() pended = false if next(steprippers) == nil then return end for pname, pdata in pairs(steprippers) do local player = minetest.get_player_by_name(pname) if player then local pos = player:get_pos() local oldpos = pdata.pos if (not oldpos) or (vector.distance(pos, oldpos) >= pdata.step) then pdata.pos = pos if ripradius(pos, pdata.radius) then minetest.chat_send_player(pname, "exporting...") local _, rpt = save_export_report() minetest.chat_send_player(pname, rpt) end end end end return stepripstart() end stepripstart = function() if pended then return end minetest.after(0, stepriprun) pended = true end end minetest.register_chatcommand(modname .. "_step", { description = "Rip nodes in radius every step", params = "[radius_x=100 [radius_y=radius_x [radius_z=radius_x [stepsize=2]]]]", privs = {server = true}, func = function(name, param) local parts = param:split(" ") local rx = parts[1] and tonumber(parts[1]) or 100 local ry = parts[2] and tonumber(parts[2]) or rx local rz = parts[3] and tonumber(parts[3]) or rx steprippers[name] = rx > 0 and { radius = vector.new(rx, ry, rz), step = parts[4] and tonumber(parts[4]) or 2 } or nil stepripstart() end }) do local function mediatype(path) local parts = path:split("/") for i = #parts, 1, -1 do if mediadirs[parts[i]] then return parts[i] end end return "media" end local function mediafunc(setto) return function(_, param) if param == "" then return false, "must supply pattern" end local ok, err = pcall(function() for k, v in pairs(mediacache) do if string_match(k, param) then configdb.media[k] = setto and mediatype(v.path) end end end) if not ok then return false, string_gsub(err, ".*:%d+:%s*", "") end return save_export_report() end end minetest.register_chatcommand(modname .. "_m_add", { description = "Add all media files matching pattern as extra media", params = " ", privs = {server = true}, func = mediafunc(true) }) minetest.register_chatcommand(modname .. "_m_rm", { description = "Remove all media files matching pattern as extra media", params = "", privs = {server = true}, func = mediafunc(nil) }) end