Aaron Suen bd35a4df55 Standardize full protection bypass for automation
Protection mechanics are fully disabled for all actions carried
out by world mechanics itself, including machine digging/placing
and entity/fluid displacement.

This may create new opportunities for players to abuse and bypass
protection mechanics.  This is an acceptable loss; the integrity
of game mechanics is more important, or else players are forced to
remove protections anyway in order to get their builds to actually
work.
2023-06-05 07:20:55 -04:00

93 lines
2.9 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local ItemStack, ipairs, math, minetest, nodecore, vector
= ItemStack, ipairs, math, minetest, nodecore, vector
local math_random
= math.random
-- LUALOCALS > ---------------------------------------------------------
local stackonly = nodecore.group_expand("group:is_stack_only", true)
local function nuke(self)
self.itemstring = ""
self.object:remove()
return true
end
local hand = ItemStack("")
nodecore.register_item_entity_on_settle(function(self, pos)
local curnode = minetest.get_node(pos)
if curnode.name == "ignore" then return end
local below = {x = pos.x, y = pos.y - 0.55, z = pos.z}
local bnode = minetest.get_node(below)
if (pos.y - 1 >= nodecore.map_limit_min) and (bnode.name == "ignore")
then return end
local item = ItemStack(self.itemstring)
item = nodecore.stack_settle(pos, item, curnode, nil, true)
if item:is_empty() then return nuke(self) end
if nodecore.stack_can_fall_in(below, item, bnode, nil, self) then
self.object:set_pos({x = pos.x, y = pos.y - 0.55, z = pos.z})
self.object:set_velocity({x = 0, y = 0, z = 0})
return
end
item = nodecore.stack_settle(below, item, bnode)
if item:is_empty() then return nuke(self) end
if self.nextscan and nodecore.gametime < self.nextscan then return end
self.nextscan = (self.nextscan or nodecore.gametime) + 0.75 + 0.5 * math_random()
local function placeat(p)
nodecore.place_stack(p, item)
minetest.get_meta(p):set_string("tweenfrom",
minetest.serialize(self.object:get_pos()))
return nuke(self)
end
local itemname = item:get_name()
local function trydig(p)
local node = minetest.get_node(p)
if node.name ~= itemname then
local def = minetest.registered_nodes[node.name]
if def and (not def.walkable) and def.diggable
and nodecore.tool_digs(hand, def.groups) then
nodecore.protection_bypass(minetest.dig_node, p)
return placeat(p)
end
end
end
local boxes = {}
local digs = {}
for rel in nodecore.settlescan() do
local p = vector.add(pos, rel)
local n = minetest.get_node(p)
if stackonly[n.name] then
item = nodecore.stack_add(p, item)
if item:is_empty() then return nuke(self) end
else
boxes[#boxes + 1] = p
end
if ((p.y >= nodecore.map_limit_min)
and (rel.y <= 0 or (p.y - 1 < nodecore.map_limit_min)
or nodecore.walkable({x = p.x, y = p.y - 1, z = p.z}))) then
if nodecore.buildable_to(p) then
return placeat(p)
elseif rel.x == 0 and rel.z == 0 and math_random(1, 10) == 1 then
if trydig(p) then return true end
else
digs[#digs + 1] = p
end
end
end
for _, p in ipairs(boxes) do
item = nodecore.stack_add(p, item)
if item:is_empty() then return nuke(self) end
end
for _, p in ipairs(digs) do
if trydig(p) then return true end
end
self.itemstring = item:to_string()
end)