[mcl_beds] Fix screwdriver/bed duplication glitch, https://git.minetest.land/MineClone2/MineClone2/issues/1149

This commit is contained in:
kay27 2021-04-21 00:36:07 +04:00
parent c7d91baadf
commit 1e5ae0bbac
1 changed files with 94 additions and 53 deletions

View File

@ -1,23 +1,95 @@
local S = minetest.get_translator("mcl_beds") local S = minetest.get_translator("mcl_beds")
local function destruct_bed(pos, oldnode) local minetest_get_node = minetest.get_node
local node = oldnode or minetest.get_node(pos) local minetest_get_node_or_nil = minetest.get_node_or_nil
local minetest_remove_node = minetest.remove_node
local minetest_facedir_to_dir = minetest.facedir_to_dir
local minetest_add_item = minetest.add_item
local vector_add = vector.add
local vector_subtract = vector.subtract
local function get_bed_next_node(pos, node)
local node = node or minetest_get_node_or_nil(pos)
if not node then return end if not node then return end
local dir = minetest.facedir_to_dir(node.param2)
local pos2, node2 local dir = minetest_facedir_to_dir(node.param2)
local pos2, bottom
if string.sub(node.name, -4) == "_top" then if string.sub(node.name, -4) == "_top" then
pos2 = vector.subtract(pos, dir) pos2 = vector_subtract(pos, dir)
node2 = minetest.get_node(pos2) else
if node2 and string.sub(node2.name, -7) == "_bottom" then pos2 = vector_add(pos, dir)
minetest.remove_node(pos2) bottom = true
end end
minetest.check_for_falling(pos)
elseif string.sub(node.name, -7) == "_bottom" then local node2 = minetest_get_node(pos2)
minetest.add_item(pos, node.name) return pos2, node2, bottom, dir
pos2 = vector.add(pos, dir) end
node2 = minetest.get_node(pos2)
local function rotate(pos, node, user, mode, new_param2)
if mode ~= screwdriver.ROTATE_FACE then
return false
end
local p, node2, bottom = get_bed_next_node(pos, node)
if not node2 then return end
local name = node2.name
if not minetest.get_item_group(name, "bed") == 2 or not node.param2 == node2.param2 then return false end
if bottom then
name = string.sub(name, 1, -5)
else
name = string.sub(name, 1, -8)
end
if minetest.is_protected(p, user:get_player_name()) then
minetest.record_protection_violation(p, user:get_player_name())
return false
end
local new_dir, newp = minetest_facedir_to_dir(new_param2)
if bottom then
newp = vector_add(pos, new_dir)
else
newp = vector_subtract(pos, new_dir)
end
local node3 = minetest_get_node_or_nil(newp)
if not node3 then return false end
local node_def = minetest.registered_nodes[node3.name]
if not node_def or not node_def.buildable_to then return false end
if minetest.is_protected(newp, user:get_player_name()) then
minetest.record_protection_violation(newp, user:get_player_name())
return false
end
node.param2 = new_param2
-- do not remove_node here - it will trigger destroy_bed()
minetest.swap_node(p, {name = "air"})
minetest.swap_node(pos, node)
minetest.swap_node(newp, {name = name .. (bottom and "_top" or "_bottom"), param2 = new_param2})
return true
end
local function destruct_bed(pos, oldnode)
local node = oldnode or minetest_get_node_or_nil(pos)
if not node then return end
local pos2, node2, bottom = get_bed_next_node(pos, oldnode)
if bottom then
minetest_add_item(pos, node.name)
if node2 and string.sub(node2.name, -4) == "_top" then if node2 and string.sub(node2.name, -4) == "_top" then
minetest.remove_node(pos2) minetest_remove_node(pos2)
end
else
if node2 and string.sub(node2.name, -7) == "_bottom" then
minetest_remove_node(pos2)
end end
end end
end end
@ -94,7 +166,7 @@ function mcl_beds.register_bed(name, def)
local under = pointed_thing.under local under = pointed_thing.under
-- Use pointed node's on_rightclick function first, if present -- Use pointed node's on_rightclick function first, if present
local node = minetest.get_node(under) local node = minetest_get_node(under)
if placer and not placer:get_player_control().sneak then if placer and not placer:get_player_control().sneak then
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
@ -102,7 +174,7 @@ function mcl_beds.register_bed(name, def)
end end
local pos local pos
local undername = minetest.get_node(under).name local undername = minetest_get_node(under).name
if minetest.registered_items[undername] and minetest.registered_items[undername].buildable_to then if minetest.registered_items[undername] and minetest.registered_items[undername].buildable_to then
pos = under pos = under
else else
@ -115,13 +187,13 @@ function mcl_beds.register_bed(name, def)
return itemstack return itemstack
end end
local node_def = minetest.registered_nodes[minetest.get_node(pos).name] local node_def = minetest.registered_nodes[minetest_get_node(pos).name]
if not node_def or not node_def.buildable_to then if not node_def or not node_def.buildable_to then
return itemstack return itemstack
end end
local dir = minetest.dir_to_facedir(placer:get_look_dir()) local dir = minetest.dir_to_facedir(placer:get_look_dir())
local botpos = vector.add(pos, minetest.facedir_to_dir(dir)) local botpos = vector_add(pos, minetest_facedir_to_dir(dir))
if minetest.is_protected(botpos, placer:get_player_name()) and if minetest.is_protected(botpos, placer:get_player_name()) and
not minetest.check_player_privs(placer, "protection_bypass") then not minetest.check_player_privs(placer, "protection_bypass") then
@ -129,7 +201,7 @@ function mcl_beds.register_bed(name, def)
return itemstack return itemstack
end end
local botdef = minetest.registered_nodes[minetest.get_node(botpos).name] local botdef = minetest.registered_nodes[minetest_get_node(botpos).name]
if not botdef or not botdef.buildable_to then if not botdef or not botdef.buildable_to then
return itemstack return itemstack
end end
@ -152,38 +224,7 @@ function mcl_beds.register_bed(name, def)
return itemstack return itemstack
end, end,
on_rotate = function(pos, node, user, mode, new_param2) on_rotate = rotate,
local dir = minetest.facedir_to_dir(node.param2)
local p = vector.add(pos, dir)
local node2 = minetest.get_node_or_nil(p)
if not node2 or not minetest.get_item_group(node2.name, "bed") == 2 or
not node.param2 == node2.param2 then
return false
end
if minetest.is_protected(p, user:get_player_name()) then
minetest.record_protection_violation(p, user:get_player_name())
return false
end
if mode ~= screwdriver.ROTATE_FACE then
return false
end
local newp = vector.add(pos, minetest.facedir_to_dir(new_param2))
local node3 = minetest.get_node_or_nil(newp)
local node_def = node3 and minetest.registered_nodes[node3.name]
if not node_def or not node_def.buildable_to then
return false
end
if minetest.is_protected(newp, user:get_player_name()) then
minetest.record_protection_violation(newp, user:get_player_name())
return false
end
node.param2 = new_param2
-- do not remove_node here - it will trigger destroy_bed()
minetest.set_node(p, {name = "air"})
minetest.set_node(pos, node)
minetest.set_node(newp, {name = name .. "_top", param2 = new_param2})
return true
end,
}) })
local node_box_top, selection_box_top, collision_box_top local node_box_top, selection_box_top, collision_box_top
@ -217,7 +258,7 @@ function mcl_beds.register_bed(name, def)
mcl_beds.on_rightclick(pos, clicker, true) mcl_beds.on_rightclick(pos, clicker, true)
return itemstack return itemstack
end, end,
on_rotate = false, on_rotate = rotate,
after_destruct = destruct_bed, after_destruct = destruct_bed,
}) })