defripper-cd2025/commands.lua
Aaron Suen 262340c945 Add more "rip nodes in radius" functionality
Refactor out the single "rip radius now"
command, and add one that works
constantly while the player is walking, so
e.g. a player can explore an existing map
or load schematics and rip their nodes
automatically.
2022-11-24 10:18:19 -05:00

170 lines
4.7 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local minetest, next, pairs, pcall, string, tonumber, vector
= minetest, next, pairs, pcall, string, tonumber, vector
local string_format, string_gsub, string_match
= string.format, string.gsub, string.match
-- LUALOCALS > ---------------------------------------------------------
local include = ...
local exportdb, savedb = include("exportdb")
local exportall = include("exportall")
local modname = minetest.get_current_modname()
local function save_export_report()
savedb()
local defs, media = exportall()
return true, string_format("exported %d defs and %d media", defs, media)
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(exportdb) do exportdb[k] = nil end
return save_export_report()
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
for _, list in pairs(player:get_inventory():get_lists()) do
for _, stack in pairs(list) do
if not stack:is_empty() then
exportdb[stack:get_name()] = true
end
end
end
return save_export_report()
end
})
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
exportdb[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)
})
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 not exportdb[n] then
exportdb[n] = true
dirty = true
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
})