Merge pull request 'Alternative solution to fix crash on nether portal destruction' (#2029) from ryvnf-portal-removal into master

Reviewed-on: MineClone2/MineClone2#2029
This commit is contained in:
cora 2022-03-03 01:51:49 +00:00
commit e8ff33a741
1 changed files with 59 additions and 28 deletions

View File

@ -204,37 +204,52 @@ local function get_target(p)
end
end
-- Destroy portal if pos (portal frame or portal node) got destroyed
-- Destroy a nether portal. Connected portal nodes are searched and removed
-- using 'bulk_set_node'. This function is called from 'after_destruct' of
-- nether portal nodes. The flag 'destroying_portal' is used to avoid this
-- function being called recursively through callbacks in 'bulk_set_node'.
local destroying_portal = false
local function destroy_nether_portal(pos, node)
if not node then return end
local nn, orientation = node.name, node.param2
local obsidian = nn == OBSIDIAN
local function check_remove(pos, orientation)
local node = get_node(pos)
if node and (node.name == PORTAL and (orientation == nil or (node.param2 == orientation))) then
minetest.remove_node(pos)
remove_exit(pos)
end
end
if obsidian then -- check each of 6 sides of it and destroy every portal:
check_remove({x = pos.x - 1, y = pos.y, z = pos.z}, 0)
check_remove({x = pos.x + 1, y = pos.y, z = pos.z}, 0)
check_remove({x = pos.x, y = pos.y, z = pos.z - 1}, 1)
check_remove({x = pos.x, y = pos.y, z = pos.z + 1}, 1)
check_remove({x = pos.x, y = pos.y - 1, z = pos.z})
check_remove({x = pos.x, y = pos.y + 1, z = pos.z})
if destroying_portal then
return
end
destroying_portal = true
local orientation = node.param2
local checked_tab = { [minetest.hash_node_position(pos)] = true }
local nodes = { pos }
local function check_remove(pos)
local h = minetest.hash_node_position(pos)
if checked_tab[h] then
return
end
local node = minetest.get_node(pos)
if node and node.name == PORTAL and (orientation == nil or node.param2 == orientation) then
table.insert(nodes, pos)
checked_tab[h] = true
end
end
local i = 1
while i <= #nodes do
pos = nodes[i]
if orientation == 0 then
check_remove({x = pos.x - 1, y = pos.y, z = pos.z}, 0)
check_remove({x = pos.x + 1, y = pos.y, z = pos.z}, 0)
check_remove({x = pos.x - 1, y = pos.y, z = pos.z})
check_remove({x = pos.x + 1, y = pos.y, z = pos.z})
else
check_remove({x = pos.x, y = pos.y, z = pos.z - 1}, 1)
check_remove({x = pos.x, y = pos.y, z = pos.z + 1}, 1)
check_remove({x = pos.x, y = pos.y, z = pos.z - 1})
check_remove({x = pos.x, y = pos.y, z = pos.z + 1})
end
check_remove({x = pos.x, y = pos.y - 1, z = pos.z})
check_remove({x = pos.x, y = pos.y + 1, z = pos.z})
remove_exit(pos)
i = i + 1
end
minetest.bulk_set_node(nodes, { name = "air" })
destroying_portal = false
end
local on_rotate
@ -817,7 +832,23 @@ local usagehelp = S("To open a Nether portal, place an upright frame of obsidian
minetest.override_item(OBSIDIAN, {
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usagehelp,
after_destruct = destroy_nether_portal,
after_destruct = function(pos, node)
local function check_remove(pos, orientation)
local node = get_node(pos)
if node and node.name == PORTAL then
minetest.remove_node(pos)
end
end
-- check each of 6 sides of it and destroy every portal
check_remove({x = pos.x - 1, y = pos.y, z = pos.z})
check_remove({x = pos.x + 1, y = pos.y, z = pos.z})
check_remove({x = pos.x, y = pos.y, z = pos.z - 1})
check_remove({x = pos.x, y = pos.y, z = pos.z + 1})
check_remove({x = pos.x, y = pos.y - 1, z = pos.z})
check_remove({x = pos.x, y = pos.y + 1, z = pos.z})
end,
_on_ignite = function(user, pointed_thing)
local x, y, z = pointed_thing.under.x, pointed_thing.under.y, pointed_thing.under.z
-- Check empty spaces around obsidian and light all frames found: