Aaron Suen 89236813e4 Allow admin command to "degrade" a dais
This effectively destroys the dais, converting it back
into its source materials in-place, not destroying any
contents/customizations, returning craft inputs,
and clearing the dais status for that player.

This can be used to return materials to the world
after a player has been destroyed, similar to how
YCTIWY automatically drops inventory.
2023-10-10 00:29:10 -04:00

289 lines
8.5 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local io, ipairs, math, minetest, nodecore, pairs, string, tonumber,
type, vector
= io, ipairs, math, minetest, nodecore, pairs, string, tonumber,
type, vector
local io_open, math_floor, string_format
= io.open, math.floor, string.format
-- LUALOCALS > ---------------------------------------------------------
local modname = minetest.get_current_modname()
local modstore = minetest.get_mod_storage()
local function getsetting(n, v)
return tonumber(minetest.settings:get(modname .. "_" .. n)) or v
end
local exmachina = {
path = minetest.get_worldpath() .. "/" .. modname,
extent = math_floor(getsetting("extent", 3)),
height = math_floor(getsetting("height", 3)),
}
nodecore[modname] = exmachina
exmachina.txr_puff = modname .. "_pattern.png^[mask:" .. modname .. "_mask.png"
exmachina.txr_frame = "nc_terrain_stone.png^(" .. modname .. "_pattern.png^[opacity:32)"
exmachina.txr_core = exmachina.txr_frame .. "^(" .. exmachina.txr_puff .. "^[opacity:128])"
exmachina.txr_sparkle = modname .. "_sparkle.png"
minetest.mkdir(exmachina.path)
local function getplayer(pspec)
if type(pspec) == "userdata" then
return pspec, pspec:get_player_name()
end
return minetest.get_player_by_name(pspec), pspec
end
function exmachina.location_get(pspec)
local player, pname = getplayer(pspec)
local pos = modstore:get_string(pname)
if pos == "X" then return end
if pos and pos ~= "" then return minetest.string_to_pos(pos) end
if not player then return end
pos = player:get_meta():get_string(modname)
if pos and pos ~= "" then
modstore:set_string(pname, pos)
return minetest.string_to_pos(pos)
end
end
function exmachina.location_set(pspec, pos)
local _, pname = getplayer(pspec)
pos = pos and minetest.pos_to_string(pos) or "X"
modstore:set_string(pname, pos)
end
minetest.register_on_joinplayer(function(player)
-- Automatically migrate legacy data.
return exmachina.location_get(player)
end)
local dxz = exmachina.extent + 1
local dy = exmachina.height + 1
function exmachina.getbounds(pos, margin)
margin = margin or 0
return {
x = pos.x - dxz - margin,
y = pos.y - margin,
z = pos.z - dxz - margin
}, {
x = pos.x + dxz + margin,
y = pos.y + dy + margin,
z = pos.z + dxz + margin
}
end
function exmachina.owner_search(pos)
for k, v in pairs(modstore:to_table().fields) do
v = minetest.string_to_pos(v)
if v then
local min, max = exmachina.getbounds(v, 0.5)
if pos.x >= min.x and pos.x <= max.x
and pos.y >= min.y and pos.y <= max.y
and pos.z >= min.z and pos.z <= max.z then return k end
end
end
end
function exmachina.areapuffs(pos, qty, time)
local minpos, maxpos = exmachina.getbounds(pos, 0.5)
return minetest.add_particlespawner({
amount = qty,
time = time,
minpos = minpos,
maxpos = maxpos,
minvel = {x = -0.2, y = -0.2, z = -0.2},
maxvel = {x = 0.2, y = 0.2, z = 0.2},
minexptime = 1,
maxexptime = 2,
texture = exmachina.txr_puff,
glow = 2
})
end
function exmachina.finalcheck(pos)
local minpos, maxpos = exmachina.getbounds(pos)
for z = minpos.z, maxpos.z do
for y = minpos.y, maxpos.y do
for x = minpos.x, maxpos.x do
nodecore.visinv_update_ents({x = x, y = y, z = z})
end
end
end
for _, p in pairs(minetest.find_nodes_in_area(minpos,
maxpos, "group:falling_node")) do
nodecore.fallcheck(p)
end
end
function exmachina.summon_start(pos, pname)
local minpos, maxpos = exmachina.getbounds(pos)
minetest.place_schematic(minpos, exmachina.schematic_trans)
for z = minpos.z, maxpos.z do
for y = minpos.y, maxpos.y do
for x = minpos.x, maxpos.x do
local p = {x = x, y = y, z = z}
minetest.get_meta(p):get_inventory():set_size("solo", 0)
nodecore.visinv_update_ents(p)
end
end
end
minetest.get_meta(pos):set_string(modname, pname)
exmachina.location_set(pname, pos)
return exmachina.areapuffs(pos, 250, 0.01)
end
function exmachina.summon_occupied(pos)
local minpos, maxpos = exmachina.getbounds(pos, 1)
for _, player in pairs(minetest.get_connected_players()) do
if nodecore.interact(player) then
local pp = player:get_pos()
if (pp.x > minpos.x)
and (pp.x < maxpos.x)
and (pp.z > minpos.z)
and (pp.z < maxpos.z)
and (pp.y > minpos.y - 1)
and (pp.y < maxpos.y) then
return player
end
end
end
end
function exmachina.pathbase(pname)
return exmachina.path .. "/" .. pname:gsub("%W", "")
.. "_" .. minetest.sha1(pname)
end
function exmachina.summon_complete(pos, pname)
local pathbase = exmachina.pathbase(pname)
local minpos, maxpos = exmachina.getbounds(pos)
local path = pathbase .. ".mts"
local anymts
local f = io_open(path, "rb")
if f then
anymts = f:read(1)
f:close()
end
if anymts then
minetest.place_schematic(minpos, path)
else
minetest.place_schematic(minpos, exmachina.schematic_final)
end
for _, mp in pairs(minetest.find_nodes_with_meta(minpos, maxpos)) do
minetest.get_meta(mp):from_table()
end
for z = minpos.z, maxpos.z do
for y = minpos.y, maxpos.y do
for x = minpos.x, maxpos.x do
minetest.get_meta({
x = pos.x + x,
y = pos.y + y,
z = pos.z + z
}):from_table()
end
end
end
path = pathbase .. ".meta"
f = io_open(path, "rb")
if f then
local s = f:read("*all")
f:close()
s = s and s ~= "" and minetest.deserialize(s) or {}
for k, v in pairs(s) do
minetest.get_meta(vector.add(pos, k)):from_table(v)
end
end
minetest.get_meta(pos):set_string(modname, pname)
local found = minetest.find_nodes_in_area(minpos, maxpos, "group:visinv")
for _, p in pairs(found) do nodecore.visinv_update_ents(p) end
exmachina.location_set(pname, pos)
exmachina.finalcheck(pos)
return exmachina.areapuffs(pos, 250, 0.01)
end
function exmachina.commit(pos, pname)
local pathbase = exmachina.pathbase(pname)
local minpos, maxpos = exmachina.getbounds(pos)
minetest.create_schematic(minpos, maxpos, nil, pathbase .. ".mts")
local allmeta = {}
for _, p in pairs(minetest.find_nodes_with_meta(minpos, maxpos)) do
local meta = minetest.get_meta(p):to_table()
for _, v1 in pairs(meta.inventory or {}) do
for k2, v2 in pairs(v1) do
if type(v2) == "userdata" then
v1[k2] = v2:to_string()
end
end
end
allmeta[vector.subtract(p, pos)] = meta
end
minetest.safe_file_write(
pathbase .. ".meta",
minetest.serialize(allmeta)
)
end
function exmachina.banish(pos, pname, nuke)
local minpos, maxpos = exmachina.getbounds(pos)
minetest.place_schematic(minpos, exmachina.schematic_banish)
for _, mp in pairs(minetest.find_nodes_with_meta(minpos, maxpos)) do
minetest.get_meta(mp):from_table()
end
if nuke then
local pathbase = exmachina.pathbase(pname)
minetest.safe_file_write(pathbase .. ".mts", "")
minetest.safe_file_write(pathbase .. ".meta", "")
end
exmachina.location_set(pname)
exmachina.finalcheck(pos)
nodecore.item_eject({x = pos.x, y = pos.y + 1, z = pos.z}, "nc_tree:eggcorn 5")
return exmachina.areapuffs(pos, 250, 0.01)
end
function exmachina.degrade(pos, pname)
local minpos = exmachina.getbounds(pos)
minetest.place_schematic(minpos, exmachina.schematic_degrade)
local pathbase = exmachina.pathbase(pname)
minetest.safe_file_write(pathbase .. ".mts", "")
minetest.safe_file_write(pathbase .. ".meta", "")
exmachina.location_set(pname)
exmachina.finalcheck(pos)
nodecore.item_eject({x = pos.x, y = pos.y + 1, z = pos.z}, "nc_tree:eggcorn 5")
return exmachina.areapuffs(pos, 250, 0.01)
end
function exmachina.arealoaded(pos)
return minetest.get_node_or_nil(vector.add(pos, {x = -dxz, y = 0, z = -dxz}))
and minetest.get_node_or_nil(vector.add(pos, {x = dxz, y = 0, z = -dxz}))
and minetest.get_node_or_nil(vector.add(pos, {x = -dxz, y = 0, z = dxz}))
and minetest.get_node_or_nil(vector.add(pos, {x = dxz, y = 0, z = dxz}))
and minetest.get_node_or_nil(vector.add(pos, {x = -dxz, y = dy, z = -dxz}))
and minetest.get_node_or_nil(vector.add(pos, {x = dxz, y = dy, z = -dxz}))
and minetest.get_node_or_nil(vector.add(pos, {x = -dxz, y = dy, z = dxz}))
and minetest.get_node_or_nil(vector.add(pos, {x = dxz, y = dy, z = dxz}))
end
function exmachina.validate(pos)
for _, v in ipairs(exmachina.craftnodes_operating) do
local np = vector.add(v, pos)
if not nodecore.match(np, v.match) then
nodecore.log("warning", string_format("%s: validation failed for dais "
.. " at %s: found %s (expected %s) at %s",
modname,
minetest.pos_to_string(pos),
minetest.get_node(np).name,
minetest.serialize(v.match):gsub("^return ", ""),
minetest.pos_to_string(np)))
return
end
end
return true
end