mirror of
https://github.com/HybridDog/builtin_item.git
synced 2024-12-22 17:00:27 +01:00
Fix liquid flowing down ledges
This commit is contained in:
parent
5636a2bb94
commit
66c222e93b
@ -1,5 +1,2 @@
|
|||||||
For a description of this Minetest mod, see
|
For a description of this Minetest mod, see
|
||||||
https://forum.minetest.net/viewtopic.php?f=9&t=10271.
|
https://forum.minetest.net/viewtopic.php?f=9&t=10271.
|
||||||
|
|
||||||
TODO:
|
|
||||||
* Support more fluids which push items, e.g. river water
|
|
||||||
|
113
init.lua
113
init.lua
@ -2,68 +2,85 @@
|
|||||||
-- The setting may change in-game but for simplicity we don't support this.
|
-- The setting may change in-game but for simplicity we don't support this.
|
||||||
local movement_gravity = tonumber(core.settings:get("movement_gravity")) or 9.81
|
local movement_gravity = tonumber(core.settings:get("movement_gravity")) or 9.81
|
||||||
|
|
||||||
-- get_flow_target_raw determines position to which the water flows, or returns
|
local function is_flowing_liquid(nodename)
|
||||||
-- nothing if no target position was found
|
local def = minetest.registered_nodes[nodename]
|
||||||
|
return def and def.liquidtype == "flowing"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- get_flow_raw determines the fluid flow vector, or returns nothing if
|
||||||
|
-- the flow is zero
|
||||||
local neighbour_offsets = {
|
local neighbour_offsets = {
|
||||||
{x=-1, y=0, z=0},
|
{x=-1, y=0, z=0},
|
||||||
{x=1, y=0, z=0},
|
{x=1, y=0, z=0},
|
||||||
{x=0, y=0, z=-1},
|
{x=0, y=0, z=-1},
|
||||||
{x=0, y=0, z=1}
|
{x=0, y=0, z=1}
|
||||||
}
|
}
|
||||||
local function get_flow_target_raw(pos)
|
local function get_flow_raw(pos)
|
||||||
|
-- FIXME: Do we need to treat nodes with special liquid_range differently?
|
||||||
local param2 = minetest.get_node(pos).param2
|
local param2 = minetest.get_node(pos).param2
|
||||||
if param2 > 7 then
|
if param2 == 15 then
|
||||||
-- The liquid flows downwards
|
-- The liquid has full height and flows downwards
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local neighbours = {}
|
local neighbours = {}
|
||||||
for n = 1, 4 do
|
for n = 1, 4 do
|
||||||
local p = vector.add(pos, neighbour_offsets[n])
|
local p = vector.add(pos, neighbour_offsets[n])
|
||||||
neighbours[n] = p
|
neighbours[n] = minetest.get_node(p)
|
||||||
neighbours[n + 4] = minetest.get_node(p)
|
|
||||||
end
|
end
|
||||||
for i = 1, 4 do
|
if param2 < 8 then
|
||||||
-- If a neighbour has a lower height, flow to it
|
-- The liquid does not flow downwards
|
||||||
local node = neighbours[i + 4]
|
for i = 1, 4 do
|
||||||
if node.name == "default:water_flowing"
|
-- Flow to a neighbouring free space if possible
|
||||||
and node.param2 < param2 then
|
local node = neighbours[i]
|
||||||
return neighbours[i]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i = 1, 4 do
|
|
||||||
-- Flow to a downwards-flowing neighbour if its height is not too small
|
|
||||||
local node = neighbours[i + 4]
|
|
||||||
if node.name == "default:water_flowing"
|
|
||||||
and node.param2 >= 11 then
|
|
||||||
return neighbours[i]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i = 1, 4 do
|
|
||||||
-- Flow to a neighbouring unsolid node
|
|
||||||
local node = neighbours[i + 4]
|
|
||||||
if node.name ~= "default:water_flowing" then
|
|
||||||
local def = minetest.registered_nodes[node.name]
|
local def = minetest.registered_nodes[node.name]
|
||||||
if def and not def.walkable then
|
if def and not def.walkable and def.liquidtype == "none" then
|
||||||
return neighbours[i]
|
return neighbour_offsets[i]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
-- Find a liquid neighbour with lowest height
|
||||||
|
local min_height_neig = param2
|
||||||
|
local min_neighbour
|
||||||
|
for i = 1, 4 do
|
||||||
|
local node = neighbours[i]
|
||||||
|
local height_neigh = node.param2 % 8
|
||||||
|
if height_neigh < min_height_neig
|
||||||
|
and is_flowing_liquid(node.name) then
|
||||||
|
min_height_neig = height_neigh
|
||||||
|
min_neighbour = neighbour_offsets[i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if min_neighbour then
|
||||||
|
return min_neighbour
|
||||||
|
end
|
||||||
|
-- No free neighbour and no flowing liquid neighbour
|
||||||
end
|
end
|
||||||
-- No neighbour found
|
-- The flowing liquid ends here in the XZ plane, so determine the
|
||||||
|
-- flow from higher neighbour nodes
|
||||||
|
local flow = {x = 0, y = 0, z = 0}
|
||||||
|
for i = 1, 4 do
|
||||||
|
local node = neighbours[i]
|
||||||
|
local height_neigh = node.param2 % 8
|
||||||
|
if is_flowing_liquid(node.name) then
|
||||||
|
-- A higher liquid is coming from there
|
||||||
|
flow = vector.subtract(flow, neighbour_offsets[i])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return not vector.equals(flow, {x = 0, y = 0, z = 0}) and flow or nil
|
||||||
end
|
end
|
||||||
|
|
||||||
-- get_flow_target caches the results from get_flow_target_raw for 10 s
|
-- get_flow caches the results from get_flow_raw for 10 s
|
||||||
local flow_target_cache = {}
|
local flow_cache = {}
|
||||||
setmetatable(flow_target_cache, {__mode = "kv"})
|
setmetatable(flow_cache, {__mode = "kv"})
|
||||||
local function get_flow_target(pos)
|
local function get_flow(pos)
|
||||||
local vi = minetest.hash_node_position(pos)
|
local vi = minetest.hash_node_position(pos)
|
||||||
local t = minetest.get_us_time()
|
local t = minetest.get_us_time()
|
||||||
if flow_target_cache[vi]
|
if flow_cache[vi]
|
||||||
and t - flow_target_cache[vi][1] < 10 * 1000000 then
|
and t - flow_cache[vi][1] < 10 * 1000000 then
|
||||||
return flow_target_cache[vi][2]
|
return flow_cache[vi][2]
|
||||||
end
|
end
|
||||||
local flow_target = get_flow_target_raw(pos)
|
local flow = get_flow_raw(pos)
|
||||||
flow_target_cache[vi] = {t, flow_target}
|
flow_cache[vi] = {t, flow}
|
||||||
return flow_target
|
return flow
|
||||||
end
|
end
|
||||||
|
|
||||||
local item_entity = minetest.registered_entities["__builtin:item"]
|
local item_entity = minetest.registered_entities["__builtin:item"]
|
||||||
@ -112,17 +129,17 @@ item_entity.on_step = function(self, dtime, ...)
|
|||||||
if not def or not def.liquidtype or def.liquidtype ~= "flowing" then
|
if not def or not def.liquidtype or def.liquidtype ~= "flowing" then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local pos_next = get_flow_target(pos)
|
local flow = get_flow(pos)
|
||||||
if not pos_next then
|
if not flow then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local vel_current = vel_desired or self.object:get_velocity()
|
local vel_current = vel_desired or self.object:get_velocity()
|
||||||
local acc = vector.multiply(vector.subtract(pos_next, pos), 2.0)
|
local acc
|
||||||
if math.abs(vel_current.x) > 1.0 then
|
if vector.dot(vel_current, flow) < 1.0 then
|
||||||
acc.x = 0
|
acc = vector.multiply(flow, 2.0)
|
||||||
end
|
else
|
||||||
if math.abs(vel_current.z) > 1.0 then
|
-- The item is already accelerated by the fluids
|
||||||
acc.z = 0
|
acc = {x = 0, y = 0, z = 0}
|
||||||
end
|
end
|
||||||
acc.y = -movement_gravity
|
acc.y = -movement_gravity
|
||||||
self.object:set_acceleration(acc)
|
self.object:set_acceleration(acc)
|
||||||
|
Loading…
Reference in New Issue
Block a user