Skip to content

Commit 723926a

Browse files
committedMay 6, 2020
Rewrite falling entity to make use of collision info
fixes #4781, fixes #9293
1 parent b6b80f5 commit 723926a

File tree

1 file changed

+128
-66
lines changed

1 file changed

+128
-66
lines changed
 

Diff for: ‎builtin/game/falling.lua

+128-66
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ local facedir_to_euler = {
3030
{y = math.pi/2, x = math.pi, z = 0}
3131
}
3232

33+
local gravity = tonumber(core.settings:get("movement_gravity")) or 9.81
34+
3335
--
3436
-- Falling stuff
3537
--
@@ -47,6 +49,7 @@ core.register_entity(":__builtin:falling_node", {
4749

4850
node = {},
4951
meta = {},
52+
floats = false,
5053

5154
set_node = function(self, node, meta)
5255
self.node = node
@@ -71,6 +74,11 @@ core.register_entity(":__builtin:falling_node", {
7174
return
7275
end
7376
self.meta = meta
77+
78+
-- Cache whether we're supposed to float on water
79+
self.floats = core.get_item_group(node.name, "float") ~= 0
80+
81+
-- Set entity visuals
7482
if def.drawtype == "torchlike" or def.drawtype == "signlike" then
7583
local textures
7684
if def.tiles and def.tiles[1] then
@@ -113,6 +121,7 @@ core.register_entity(":__builtin:falling_node", {
113121
glow = def.light_source,
114122
})
115123
end
124+
116125
-- Rotate entity
117126
if def.drawtype == "torchlike" then
118127
self.object:set_yaw(math.pi*0.25)
@@ -172,6 +181,7 @@ core.register_entity(":__builtin:falling_node", {
172181

173182
on_activate = function(self, staticdata)
174183
self.object:set_armor_groups({immortal = 1})
184+
self.object:set_acceleration({x = 0, y = -gravity, z = 0})
175185

176186
local ds = core.deserialize(staticdata)
177187
if ds and ds.node then
@@ -183,85 +193,137 @@ core.register_entity(":__builtin:falling_node", {
183193
end
184194
end,
185195

186-
on_step = function(self, dtime)
187-
-- Set gravity
188-
local acceleration = self.object:get_acceleration()
189-
if not vector.equals(acceleration, {x = 0, y = -10, z = 0}) then
190-
self.object:set_acceleration({x = 0, y = -10, z = 0})
196+
try_place = function(self, bcp, bcn)
197+
local bcd = core.registered_nodes[bcn.name]
198+
-- Add levels if dropped on same leveled node
199+
if bcd and bcd.leveled and
200+
bcn.name == self.node.name then
201+
local addlevel = self.node.level
202+
if not addlevel or addlevel <= 0 then
203+
addlevel = bcd.leveled
204+
end
205+
if core.add_node_level(bcp, addlevel) == 0 then
206+
return true
207+
end
191208
end
192-
-- Turn to actual node when colliding with ground, or continue to move
193-
local pos = self.object:get_pos()
194-
-- Position of bottom center point
195-
local bcp = {x = pos.x, y = pos.y - 0.7, z = pos.z}
196-
-- 'bcn' is nil for unloaded nodes
197-
local bcn = core.get_node_or_nil(bcp)
198-
-- Delete on contact with ignore at world edges
199-
if bcn and bcn.name == "ignore" then
200-
self.object:remove()
201-
return
209+
210+
-- Decide if we're replacing the node or placing on top
211+
local np = vector.new(bcp)
212+
if bcd and bcd.buildable_to and
213+
(not self.floats or bcd.liquidtype == "none") then
214+
core.remove_node(bcp)
215+
else
216+
np.y = np.y + 1
202217
end
203-
local bcd = bcn and core.registered_nodes[bcn.name]
204-
if bcn and
205-
(not bcd or bcd.walkable or
206-
(core.get_item_group(self.node.name, "float") ~= 0 and
207-
bcd.liquidtype ~= "none")) then
208-
if bcd and bcd.leveled and
209-
bcn.name == self.node.name then
210-
local addlevel = self.node.level
211-
if not addlevel or addlevel <= 0 then
212-
addlevel = bcd.leveled
218+
219+
-- Check what's here
220+
local n2 = core.get_node(np)
221+
local nd = core.registered_nodes[n2.name]
222+
-- If it's not air or liquid, remove node and replace it with
223+
-- it's drops
224+
if n2.name ~= "air" and (not nd or nd.liquidtype == "none") then
225+
if nd and nd.buildable_to == false then
226+
nd.on_dig(np, n2, nil)
227+
-- If it's still there, it might be protected
228+
if core.get_node(np).name == n2.name then
229+
return false
213230
end
214-
if core.add_node_level(bcp, addlevel) == 0 then
231+
else
232+
core.remove_node(np)
233+
end
234+
end
235+
236+
-- Create node
237+
local def = core.registered_nodes[self.node.name]
238+
if def then
239+
core.add_node(np, self.node)
240+
if self.meta then
241+
core.get_meta(np):from_table(self.meta)
242+
end
243+
if def.sounds and def.sounds.place then
244+
core.sound_play(def.sounds.place, {pos = np}, true)
245+
end
246+
end
247+
core.check_for_falling(np)
248+
return true
249+
end,
250+
251+
on_step = function(self, dtime, moveresult)
252+
-- Fallback code since collision detection can't tell us
253+
-- about liquids (which do not collide)
254+
if self.floats then
255+
local pos = self.object:get_pos()
256+
257+
local bcp = vector.round({x = pos.x, y = pos.y - 0.7, z = pos.z})
258+
local bcn = core.get_node(bcp)
259+
260+
local bcd = core.registered_nodes[bcn.name]
261+
if bcd and bcd.liquidtype ~= "none" then
262+
if self:try_place(bcp, bcn) then
215263
self.object:remove()
216264
return
217265
end
218-
elseif bcd and bcd.buildable_to and
219-
(core.get_item_group(self.node.name, "float") == 0 or
220-
bcd.liquidtype == "none") then
221-
core.remove_node(bcp)
222-
return
223266
end
224-
local np = {x = bcp.x, y = bcp.y + 1, z = bcp.z}
225-
-- Check what's here
226-
local n2 = core.get_node(np)
227-
local nd = core.registered_nodes[n2.name]
228-
-- If it's not air or liquid, remove node and replace it with
229-
-- it's drops
230-
if n2.name ~= "air" and (not nd or nd.liquidtype == "none") then
231-
core.remove_node(np)
232-
if nd and nd.buildable_to == false then
233-
-- Add dropped items
234-
local drops = core.get_node_drops(n2, "")
235-
for _, dropped_item in pairs(drops) do
236-
core.add_item(np, dropped_item)
237-
end
238-
end
239-
-- Run script hook
240-
for _, callback in pairs(core.registered_on_dignodes) do
241-
callback(np, n2)
242-
end
243-
end
244-
-- Create node and remove entity
245-
local def = core.registered_nodes[self.node.name]
246-
if def then
247-
core.add_node(np, self.node)
248-
if self.meta then
249-
local meta = core.get_meta(np)
250-
meta:from_table(self.meta)
251-
end
252-
if def.sounds and def.sounds.place then
253-
core.sound_play(def.sounds.place, {pos = np}, true)
267+
end
268+
269+
assert(moveresult)
270+
if not moveresult.collides then
271+
return -- Nothing to do :)
272+
end
273+
274+
local bcp, bcn
275+
if moveresult.touching_ground then
276+
for _, info in ipairs(moveresult.collisions) do
277+
if info.axis == "y" then
278+
bcp = info.node_pos
279+
bcn = core.get_node(bcp)
280+
break
254281
end
255282
end
283+
end
284+
285+
if not bcp then
286+
-- We're colliding with something, but not the ground. Irrelevant to us.
287+
return
288+
elseif bcn.name == "ignore" then
289+
-- Delete on contact with ignore at world edges
256290
self.object:remove()
257-
core.check_for_falling(np)
258291
return
259292
end
260-
local vel = self.object:get_velocity()
261-
if vector.equals(vel, {x = 0, y = 0, z = 0}) then
262-
local npos = self.object:get_pos()
263-
self.object:set_pos(vector.round(npos))
293+
294+
local failure = false
295+
296+
local pos = self.object:get_pos()
297+
local distance = vector.apply(vector.subtract(pos, bcp), math.abs)
298+
if distance.x >= 1 or distance.z >= 1 then
299+
-- We're colliding with some part of a node that's sticking out
300+
-- Since we don't want to visually teleport, drop as item
301+
failure = true
302+
elseif distance.y >= 2 then
303+
-- Doors consist of a hidden top node and a bottom node that is
304+
-- the actual door. Despite the top node being solid, the moveresult
305+
-- almost always indicates collision with the bottom node.
306+
-- Compensate for this by checking the top node
307+
bcp.y = bcp.y + 1
308+
bcn = core.get_node(bcp)
309+
local def = core.registered_nodes[bcn.name]
310+
if not (def and def.walkable) then
311+
failure = true -- This is unexpected, fail
312+
end
313+
end
314+
315+
-- Try to actually place ourselves
316+
if not failure then
317+
failure = not self:try_place(bcp, bcn)
318+
end
319+
320+
if failure then
321+
local drops = core.get_node_drops(self.node, "")
322+
for _, item in pairs(drops) do
323+
core.add_item(pos, item)
324+
end
264325
end
326+
self.object:remove()
265327
end
266328
})
267329

0 commit comments

Comments
 (0)
Please sign in to comment.