From d8322fccc81f9802a1feb76dea734272ab7d6ca3 Mon Sep 17 00:00:00 2001 From: Jude Melton-Houghton Date: Sat, 26 Feb 2022 12:15:56 -0500 Subject: [PATCH 1/4] Move objects even when sticky blocks are involved --- mesecons_mvps/init.lua | 101 ++++++++++++++++++++++++++++++++--------- 1 file changed, 80 insertions(+), 21 deletions(-) diff --git a/mesecons_mvps/init.lua b/mesecons_mvps/init.lua index 31f103c8..cdcdfdaa 100644 --- a/mesecons_mvps/init.lua +++ b/mesecons_mvps/init.lua @@ -253,6 +253,44 @@ function mesecon.mvps_push_or_pull(pos, stackdir, movedir, maximum, all_pull_sti return true, nodes, oldstack end +-- Returns whether the given area intersects any nodes in the given set of position hashes. +local function area_intersects_nodes(min_pos, max_pos, positions) + min_pos = vector.round(min_pos) + max_pos = vector.round(max_pos) + local pos = vector.new(min_pos) + while pos.x <= max_pos.x do + while pos.y <= max_pos.y do + while pos.z <= max_pos.z do + if positions[minetest.hash_node_position(pos)] then + return true + end + pos.z = pos.z + 1 + end + pos.z = min_pos.z + pos.y = pos.y + 1 + end + pos.y = min_pos.y + pos.x = pos.x + 1 + end + return false +end + +-- Returns whether the given area intersects the node face with the given normal axis and center point. +local function area_intersects_face(min_pos, max_pos, normal_axis, center) + for k, v in pairs(center) do + if k == normal_axis then + if min_pos[k] >= v or max_pos[k] <= v then + return false + end + else + if min_pos[k] >= v + 0.5 or max_pos[k] <= v - 0.5 then + return false + end + end + end + return true +end + function mesecon.mvps_move_objects(pos, dir, nodestack, movefactor) local dir_k local dir_l @@ -265,29 +303,50 @@ function mesecon.mvps_move_objects(pos, dir, nodestack, movefactor) end movefactor = movefactor or 1 dir = vector.multiply(dir, movefactor) - for id, obj in pairs(minetest.get_objects_inside_radius(pos, #nodestack + 1)) do + -- The collision box min and max positions will be extended by these values. + -- These small scalars are so that objects next to the moved stack are also moved. + local extension_min = vector.new(-0.01, -0.01, -0.01) + local extension_max = vector.new(0.01, 0.01, 0.01) + -- The collision box is extended in one direction to account for node displacement, + -- except in the special case where no nodes are moved. + local extension = nodestack[1] ~= nil and -dir[dir_k] or 0 + if extension < 0 then + extension_min[dir_k] = extension + extension_max[dir_k] = 0 + else + extension_min[dir_k] = 0 + extension_max[dir_k] = extension + end + + local max_distance = 0 + local moved_positions, face_center + if movefactor == 1 or nodestack[1] ~= nil then + -- Usually, objects are moved if they intersect with moved node positions. + moved_positions = {} + if nodestack[1] == nil then + -- Push objects intersecting the mvps position. + moved_positions[minetest.hash_node_position(pos)] = true + end + for _, n in ipairs(nodestack) do + moved_positions[minetest.hash_node_position(n.pos)] = true + max_distance = math.max(max_distance, vector.distance(pos, n.pos)) + end + else + -- When zero nodes are retracted, objects are moved if they intersect with the retracting face. + face_center = vector.new(pos) + face_center[dir_k] = face_center[dir_k] - 0.5 * dir_l + end + + for id, obj in pairs(minetest.get_objects_inside_radius(pos, max_distance + 2)) do local obj_pos = obj:get_pos() local cbox = obj:get_properties().collisionbox - local min_pos = vector.add(obj_pos, vector.new(cbox[1], cbox[2], cbox[3])) - local max_pos = vector.add(obj_pos, vector.new(cbox[4], cbox[5], cbox[6])) - local ok = true - for k, v in pairs(pos) do - local edge1, edge2 - if k ~= dir_k then - edge1 = v - 0.51 -- More than 0.5 to move objects near to the stack. - edge2 = v + 0.51 - else - edge1 = v - 0.5 * dir_l - edge2 = v + (#nodestack + 0.5 * movefactor) * dir_l - -- Make sure, edge1 is bigger than edge2: - if edge1 > edge2 then - edge1, edge2 = edge2, edge1 - end - end - if min_pos[k] > edge2 or max_pos[k] < edge1 then - ok = false - break - end + local min_pos = vector.add(obj_pos, vector.offset(extension_min, cbox[1], cbox[2], cbox[3])) + local max_pos = vector.add(obj_pos, vector.offset(extension_max, cbox[4], cbox[5], cbox[6])) + local ok + if moved_positions then + ok = area_intersects_nodes(min_pos, max_pos, moved_positions) + else + ok = area_intersects_face(min_pos, max_pos, dir_k, face_center) end if ok then local ent = obj:get_luaentity() From 807e6d5f0b17f7ce91c9686c6718894b1bb489c4 Mon Sep 17 00:00:00 2001 From: Jude Melton-Houghton Date: Sun, 27 Feb 2022 17:14:13 -0500 Subject: [PATCH 2/4] Fix blockage in mvps object movement --- mesecons_mvps/init.lua | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/mesecons_mvps/init.lua b/mesecons_mvps/init.lua index cdcdfdaa..36897751 100644 --- a/mesecons_mvps/init.lua +++ b/mesecons_mvps/init.lua @@ -253,7 +253,8 @@ function mesecon.mvps_push_or_pull(pos, stackdir, movedir, maximum, all_pull_sti return true, nodes, oldstack end --- Returns whether the given area intersects any nodes in the given set of position hashes. +-- Returns whether the given area intersects any nodes in the given set of position hashes, +-- or any walkable nodes in the map if no set is given. local function area_intersects_nodes(min_pos, max_pos, positions) min_pos = vector.round(min_pos) max_pos = vector.round(max_pos) @@ -261,8 +262,15 @@ local function area_intersects_nodes(min_pos, max_pos, positions) while pos.x <= max_pos.x do while pos.y <= max_pos.y do while pos.z <= max_pos.z do - if positions[minetest.hash_node_position(pos)] then - return true + if positions then + if positions[minetest.hash_node_position(pos)] then + return true + end + else + local def = minetest.registered_nodes[minetest.get_node(pos).name] + if def.walkable then + return true + end end pos.z = pos.z + 1 end @@ -351,15 +359,13 @@ function mesecon.mvps_move_objects(pos, dir, nodestack, movefactor) if ok then local ent = obj:get_luaentity() if obj:is_player() or (ent and not mesecon.is_mvps_unmov(ent.name)) then - local np = vector.add(obj_pos, dir) -- Move only if destination is not solid or object is inside stack: - local nn = minetest.get_node(np) - local node_def = minetest.registered_nodes[nn.name] - local obj_offset = dir_l * (obj_pos[dir_k] - pos[dir_k]) - if (node_def and not node_def.walkable) or - (obj_offset >= 0 and - obj_offset <= #nodestack - 0.5) then - obj:move_to(np) + -- (A small bias is added to prevent rounding issues.) + local min_pos = vector.offset(obj_pos, cbox[1] + 0.01, cbox[2] + 0.01, cbox[3] + 0.01) + local max_pos = vector.offset(obj_pos, cbox[4] - 0.01, cbox[5] - 0.01, cbox[6] - 0.01) + if not area_intersects_nodes(vector.add(min_pos, dir), vector.add(max_pos, dir)) or + area_intersects_nodes(min_pos, max_pos, moved_positions) then + obj:move_to(vector.add(obj_pos, dir)) end end end From fe649e8d6825445a0007123b4da8745d02101c3c Mon Sep 17 00:00:00 2001 From: Jude Melton-Houghton Date: Mon, 28 Feb 2022 10:50:18 -0500 Subject: [PATCH 3/4] Ensafen intersection function --- mesecons_mvps/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesecons_mvps/init.lua b/mesecons_mvps/init.lua index 36897751..b8be404d 100644 --- a/mesecons_mvps/init.lua +++ b/mesecons_mvps/init.lua @@ -268,7 +268,7 @@ local function area_intersects_nodes(min_pos, max_pos, positions) end else local def = minetest.registered_nodes[minetest.get_node(pos).name] - if def.walkable then + if not def or def.walkable then return true end end From 8e87671c3944f20de594ba263e83836e813bacb5 Mon Sep 17 00:00:00 2001 From: Jude Melton-Houghton Date: Mon, 28 Feb 2022 13:42:34 -0500 Subject: [PATCH 4/4] Fix bare pistons pushing objects into walls --- mesecons_mvps/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesecons_mvps/init.lua b/mesecons_mvps/init.lua index b8be404d..0f89d68b 100644 --- a/mesecons_mvps/init.lua +++ b/mesecons_mvps/init.lua @@ -364,7 +364,7 @@ function mesecon.mvps_move_objects(pos, dir, nodestack, movefactor) local min_pos = vector.offset(obj_pos, cbox[1] + 0.01, cbox[2] + 0.01, cbox[3] + 0.01) local max_pos = vector.offset(obj_pos, cbox[4] - 0.01, cbox[5] - 0.01, cbox[6] - 0.01) if not area_intersects_nodes(vector.add(min_pos, dir), vector.add(max_pos, dir)) or - area_intersects_nodes(min_pos, max_pos, moved_positions) then + (nodestack[1] ~= nil and area_intersects_nodes(min_pos, max_pos, moved_positions)) then obj:move_to(vector.add(obj_pos, dir)) end end