2023-10-18 21:30:00 +00:00
|
|
|
local entity = minetest.registered_entities["__builtin:falling_node"]
|
|
|
|
|
2023-10-19 09:19:32 +00:00
|
|
|
|
|
|
|
|
2023-10-19 12:07:47 +00:00
|
|
|
local old_try_place = entity.try_place
|
2023-10-18 21:30:00 +00:00
|
|
|
local after_land_callbacks = {}
|
|
|
|
|
|
|
|
entity.try_place = function (self, bcp, bcn)
|
2023-10-19 12:07:47 +00:00
|
|
|
local result = old_try_place(self, bcp, bcn)
|
2023-10-18 21:30:00 +00:00
|
|
|
-- `result` will be true if the falling node landed successfully (afaict from reading `/builtin/game/falling.lua` in the minetest source).
|
|
|
|
if result then
|
2023-10-19 09:25:12 +00:00
|
|
|
-- `bcp` is actually the node 0.7 nodes (rounded) below the falling_node entity.
|
|
|
|
-- the vector addition here makes it be the position where the entity itself landed.
|
|
|
|
-- if it landed on something layered, this new position might be air when the callbacks are called.
|
|
|
|
local pos = bcp + vector.new(0, 1, 0)
|
2023-10-18 21:30:00 +00:00
|
|
|
for _, callback in pairs(after_land_callbacks) do
|
2023-10-19 09:25:12 +00:00
|
|
|
callback(pos, bcn, self)
|
2023-10-18 21:30:00 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
return result
|
|
|
|
end
|
|
|
|
|
|
|
|
function blockgame.register_after_falling_node_lands (callback)
|
|
|
|
table.insert(after_land_callbacks, callback)
|
|
|
|
end
|
|
|
|
|
|
|
|
blockgame.register_after_falling_node_lands(function (pos, node)
|
|
|
|
local def = minetest.registered_nodes[node.name]
|
|
|
|
|
2023-10-19 10:46:38 +00:00
|
|
|
if type(def.after_land) == "function" then
|
|
|
|
def.after_land(pos, node)
|
2023-10-18 21:30:00 +00:00
|
|
|
end
|
|
|
|
end)
|
2023-10-19 09:20:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2023-10-19 12:07:47 +00:00
|
|
|
local old_on_step = entity.on_step
|
2023-10-19 09:20:23 +00:00
|
|
|
local on_step_callbacks = {}
|
|
|
|
|
|
|
|
entity.on_step = function (self, dtime, moveresult)
|
2023-10-19 12:07:47 +00:00
|
|
|
local result = old_on_step(self, dtime, moveresult)
|
2023-10-19 09:20:23 +00:00
|
|
|
for _, callback in pairs(on_step_callbacks) do
|
|
|
|
callback(self, dtime, moveresult)
|
|
|
|
end
|
|
|
|
return result
|
|
|
|
end
|
|
|
|
|
|
|
|
function blockgame.register_on_falling_node_step (callback)
|
|
|
|
table.insert(on_step_callbacks, callback)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- keep track of velocity a falling_node had before landing
|
|
|
|
-- so that code hooked into the landing can check "how fast was this moving?"
|
|
|
|
blockgame.register_on_falling_node_step(function (entity, delta_time, move_result)
|
|
|
|
local velocity = entity.object:get_velocity()
|
|
|
|
|
|
|
|
-- let `previous_velocity` be (0, 0, 0) at the very first step
|
|
|
|
if not entity.fall_velocity then
|
|
|
|
entity.fall_velocity = vector.new(0, 0, 0)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- keep track of moving velocity, not still velocity
|
|
|
|
if velocity and (vector.length(velocity) ~= 0) then
|
|
|
|
entity.fall_velocity = vector.copy(velocity)
|
|
|
|
end
|
|
|
|
|
|
|
|
end)
|
2023-10-19 12:07:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- make falling nodes collide with `walkable = false` nodes if they are also `supports_falling = true`.
|
|
|
|
blockgame.register_on_falling_node_step(function (entity, delta_time, move_result)
|
|
|
|
local pos = entity.object:get_pos()
|
|
|
|
if not pos then return end
|
|
|
|
|
|
|
|
local below = pos:offset(0, -0.7, 0) -- same offset as in `/builtin/game/falling.lua`
|
|
|
|
|
|
|
|
local node = minetest.get_node(below)
|
|
|
|
if node == "air" then return end
|
|
|
|
|
|
|
|
local def = minetest.registered_nodes[node.name]
|
|
|
|
if not def then return end
|
|
|
|
|
|
|
|
if def.walkable or not def.supports_falling then return end
|
|
|
|
|
|
|
|
local success = entity:try_place(below, node)
|
|
|
|
|
|
|
|
if not success then
|
|
|
|
local drops = minetest.get_node_drops(entity.node, "")
|
|
|
|
for _, item in pairs(drops) do
|
|
|
|
minetest.add_item(pos, item)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
entity.object:remove()
|
|
|
|
end)
|
|
|
|
|
|
|
|
local old_check = minetest.check_single_for_falling
|
|
|
|
function minetest.check_single_for_falling (pos, ...)
|
|
|
|
local node = minetest.get_node(pos:offset(0, -1, 0))
|
|
|
|
local def = minetest.registered_nodes[node.name]
|
|
|
|
if def and def.supports_falling then return false end
|
|
|
|
return old_check(pos, ...)
|
|
|
|
end
|