Rewrite builtin item entity to use collision info

fixes #8967
This commit is contained in:
sfan5 2020-04-14 16:55:16 +02:00
parent 3475759d1a
commit b9377f26a1

@ -34,7 +34,6 @@ core.register_entity(":__builtin:item", {
itemstring = "", itemstring = "",
moving_state = true, moving_state = true,
slippery_state = false,
physical_state = true, physical_state = true,
-- Item expiry -- Item expiry
age = 0, age = 0,
@ -157,7 +156,7 @@ core.register_entity(":__builtin:item", {
end end
end, end,
on_step = function(self, dtime) on_step = function(self, dtime, moveresult)
self.age = self.age + dtime self.age = self.age + dtime
if time_to_live > 0 and self.age > time_to_live then if time_to_live > 0 and self.age > time_to_live then
self.itemstring = "" self.itemstring = ""
@ -178,6 +177,36 @@ core.register_entity(":__builtin:item", {
return return
end end
if self.force_out then
-- This code runs after the entity got a push from the is_stuck code.
-- It makes sure the entity is entirely outside the solid node
local c = self.object:get_properties().collisionbox
local s = self.force_out_start
local f = self.force_out
local ok = (f.x > 0 and pos.x + c[1] > s.x + 0.5) or
(f.y > 0 and pos.y + c[2] > s.y + 0.5) or
(f.z > 0 and pos.z + c[3] > s.z + 0.5) or
(f.x < 0 and pos.x + c[4] < s.x - 0.5) or
(f.z < 0 and pos.z + c[6] < s.z - 0.5)
if ok then
-- Item was successfully forced out
self.force_out = nil
self:enable_physics()
return
end
end
if not self.physical_state then
return -- Don't do anything
end
assert(moveresult)
if not moveresult.collides then
-- future TODO: items should probably decelerate in air
return
end
-- Push item out when stuck inside solid node
local is_stuck = false local is_stuck = false
local snode = core.get_node_or_nil(pos) local snode = core.get_node_or_nil(pos)
if snode then if snode then
@ -187,7 +216,6 @@ core.register_entity(":__builtin:item", {
and (sdef.node_box == nil or sdef.node_box.type == "regular") and (sdef.node_box == nil or sdef.node_box.type == "regular")
end end
-- Push item out when stuck inside solid node
if is_stuck then if is_stuck then
local shootdir local shootdir
local order = { local order = {
@ -223,69 +251,49 @@ core.register_entity(":__builtin:item", {
self.force_out_start = vector.round(pos) self.force_out_start = vector.round(pos)
return return
end end
elseif self.force_out then
-- This code runs after the entity got a push from the above code.
-- It makes sure the entity is entirely outside the solid node
local c = self.object:get_properties().collisionbox
local s = self.force_out_start
local f = self.force_out
local ok = (f.x > 0 and pos.x + c[1] > s.x + 0.5) or
(f.y > 0 and pos.y + c[2] > s.y + 0.5) or
(f.z > 0 and pos.z + c[3] > s.z + 0.5) or
(f.x < 0 and pos.x + c[4] < s.x - 0.5) or
(f.z < 0 and pos.z + c[6] < s.z - 0.5)
if ok then
-- Item was successfully forced out
self.force_out = nil
self:enable_physics()
end
end end
if not self.physical_state then node = nil -- ground node we're colliding with
return -- Don't do anything if moveresult.touching_ground then
for _, info in ipairs(moveresult.collisions) do
if info.axis == "y" then
node = core.get_node(info.node_pos)
break
end
end
end end
-- Slide on slippery nodes -- Slide on slippery nodes
local vel = self.object:get_velocity()
local def = node and core.registered_nodes[node.name] local def = node and core.registered_nodes[node.name]
local is_moving = (def and not def.walkable) or local keep_movement = false
vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0
local is_slippery = false
if def and def.walkable then if def then
local slippery = core.get_item_group(node.name, "slippery") local slippery = core.get_item_group(node.name, "slippery")
is_slippery = slippery ~= 0 local vel = self.object:get_velocity()
if is_slippery and (math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2) then if slippery ~= 0 and (math.abs(vel.x) > 0.1 or math.abs(vel.z) > 0.1) then
-- Horizontal deceleration -- Horizontal deceleration
local slip_factor = 4.0 / (slippery + 4) local factor = math.min(4 / (slippery + 4) * dtime, 1)
self.object:set_acceleration({ self.object:set_velocity({
x = -vel.x * slip_factor, x = vel.x * (1 - factor),
y = 0, y = 0,
z = -vel.z * slip_factor z = vel.z * (1 - factor)
}) })
elseif vel.y == 0 then keep_movement = true
is_moving = false
end end
end end
if self.moving_state == is_moving and if not keep_movement then
self.slippery_state == is_slippery then
-- Do not update anything until the moving state changes
return
end
self.moving_state = is_moving
self.slippery_state = is_slippery
if is_moving then
self.object:set_acceleration({x = 0, y = -gravity, z = 0})
else
self.object:set_acceleration({x = 0, y = 0, z = 0})
self.object:set_velocity({x=0, y=0, z=0}) self.object:set_velocity({x=0, y=0, z=0})
end end
if self.moving_state == keep_movement then
-- Do not update anything until the moving state changes
return
end
self.moving_state = keep_movement
-- Only collect items if not moving -- Only collect items if not moving
if is_moving then if self.moving_state then
return return
end end
-- Collect the items around to merge with -- Collect the items around to merge with