local entity = minetest.registered_entities["__builtin:falling_node"] local old_try_place = entity.try_place local after_land_callbacks = {} entity.try_place = function (self, bcp, bcn) local result = old_try_place(self, bcp, bcn) -- `result` will be true if the falling node landed successfully (afaict from reading `/builtin/game/falling.lua` in the minetest source). if result then -- `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) for _, callback in pairs(after_land_callbacks) do callback(pos, bcn, self) 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] if type(def.after_land) == "function" then def.after_land(pos, node) end end) local old_on_step = entity.on_step local on_step_callbacks = {} entity.on_step = function (self, dtime, moveresult) local result = old_on_step(self, dtime, moveresult) 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) -- 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