defripper-cd2025/commands.lua
2023-11-20 16:40:16 -05:00

245 lines
6.8 KiB
Lua

-- 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 = "<lua pattern>",
privs = {server = true},
func = patternfunc(true)
})
minetest.register_chatcommand(modname .. "_rm", {
description = "Un-rip all defs with technical names matching a pattern",
params = "<lua pattern>",
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 = "<sounds/textures/models> <lua pattern>",
privs = {server = true},
func = mediafunc(true)
})
minetest.register_chatcommand(modname .. "_m_rm", {
description = "Remove all media files matching pattern as extra media",
params = "<lua pattern>",
privs = {server = true},
func = mediafunc(nil)
})
end