Compare commits
10 Commits
0.2
...
feature-re
| Author | SHA1 | Date | |
|---|---|---|---|
| 8cc342e199 | |||
| c60873e80f | |||
| 1e606df0b4 | |||
| 6a021676b9 | |||
| 606a215f77 | |||
| b6b2ba4672 | |||
| ed7e26fb8a | |||
| 2d6c43e69f | |||
| 6c74c3de5c | |||
| fa60ac48a2 |
15
README.md
15
README.md
@@ -6,23 +6,23 @@ This mod is in early alpha.
|
||||
|
||||
## What NOT to expect
|
||||
|
||||
- Proper water equalization and water pressure
|
||||
- Removing weeds and other wall mounted items
|
||||
- Interaction of different liquid types, e.g. lava and water
|
||||
- Ability to scoop up liquids with a level below 8
|
||||
- Proper water equalization and water pressure *
|
||||
- Removing weeds and other wall mounted items *
|
||||
- Interaction of different liquid types, e.g. lava and water *
|
||||
- Interaction with pistons or pipes
|
||||
- Perfect performance
|
||||
- Integration with any other mods
|
||||
- Integration with any other mods *
|
||||
- A smooth liquid surface
|
||||
- Viscosity for different liquid types
|
||||
|
||||
* to an extend
|
||||
|
||||
## What to expect
|
||||
|
||||
- Water leveling for flat surfaces
|
||||
- Settling water
|
||||
- Multi-level liquids from 1 to 8
|
||||
- Draining all oceans in a jiffy
|
||||
- Water duplication due to a [bug](https://github.com/minetest/minetest/issues/15647) in the Luanti Engine
|
||||
|
||||
## API
|
||||
|
||||
@@ -31,6 +31,9 @@ This mod is in early alpha.
|
||||
--Example: Register default:water_source
|
||||
liquid_physics.register_liquid("default", "water_source", "water_flowing")
|
||||
|
||||
--Example: Register bucket:bucket_water to scoop up liquids
|
||||
liquid_physics.register_bucket("bucket:bucket_water")
|
||||
|
||||
--Example: Check if block underneath is liquid and then proceed to reduce its level
|
||||
local id_water = liquid_physics.get_liquid_id("default:water_source")
|
||||
local liquid = liquid_physics.get_liquid_at(pos)
|
||||
|
||||
45
api.lua
45
api.lua
@@ -15,6 +15,7 @@
|
||||
|
||||
local modpath = core.get_modpath(core.get_current_modname())
|
||||
local internal = dofile(modpath .. "/internal.lua")
|
||||
local internal_bucket = dofile(modpath .. "/bucket.lua")
|
||||
|
||||
-- Returns liquid_id of the node or
|
||||
-- nil when the node is not a liquid
|
||||
@@ -40,6 +41,18 @@ function liquid_physics.get_liquid_at(pos)
|
||||
return { liquid_id = lpn.liquid_id, liquid_level = lpn.liquid_level }
|
||||
end
|
||||
|
||||
-- Returns the node names for a liquid ordered by the corresponding liquid level
|
||||
-- Useful if you want to register an ABM or LBM
|
||||
-- @param liquid_id number ID of the liquid
|
||||
-- @return table Table of liquid node names for that id
|
||||
function liquid_physics.get_liquid_node_names(liquid_id)
|
||||
local nodes = {}
|
||||
for i = 2, 9 do
|
||||
table.insert(nodes, liquid_physics._registered_liquids[liquid_id][i])
|
||||
end
|
||||
return nodes
|
||||
end
|
||||
|
||||
-- Sets the liquid at the position specified
|
||||
-- Returns true if the operation was successful
|
||||
-- @param pos table Position of the Node
|
||||
@@ -52,10 +65,18 @@ function liquid_physics.set_liquid_at(pos, liquid_id, liquid_level)
|
||||
end
|
||||
local lpn = internal.new_lpn(core.hash_node_position(pos), pos)
|
||||
internal.set_lpn(liquid_id, lpn, liquid_level)
|
||||
internal.set_node(lpn)
|
||||
internal.add_node_to_check(pos)
|
||||
return true
|
||||
end
|
||||
|
||||
-- This function will override the bucket provided to add the capapability
|
||||
-- of transporting liquids of factional size
|
||||
-- @param name string Name of the bucket, e.g. "bucket:bucket:water"
|
||||
function liquid_physics.register_bucket(name)
|
||||
internal_bucket.register_filled_bucket(name)
|
||||
end
|
||||
|
||||
-- Executing this function will override the nodes specified.
|
||||
-- New liquid sources will be "liquid_physics:namespace_name_level_1" through 7
|
||||
-- @param namespace string Name of mod e.g. "default"
|
||||
@@ -80,14 +101,12 @@ function liquid_physics.register_liquid(namespace, source_name, flowing_name)
|
||||
|
||||
if flowing_liquid_def.liquidtype ~= "flowing" then
|
||||
error("Liquid Physics: " ..
|
||||
source_liquid_name .. " is of type " .. source_liquid_def.drawtype .. " and not of type source")
|
||||
source_liquid_name .. " is of type " .. source_liquid_def.drawtype .. " and not of type flowing")
|
||||
end
|
||||
|
||||
--Overwrite source
|
||||
source_liquid_def.liquid_range = 0
|
||||
source_liquid_def.liquid_renewable = false
|
||||
source_liquid_def.liquid_alternative_flowing = source_liquid_name
|
||||
source_liquid_def.liquid_alternative_source = source_liquid_name
|
||||
source_liquid_def.groups.liquid_physics = 1
|
||||
|
||||
core.register_node(":" .. source_liquid_name, source_liquid_def)
|
||||
liquid_physics._liquid_ids[source_liquid_name] = id
|
||||
@@ -99,6 +118,7 @@ function liquid_physics.register_liquid(namespace, source_name, flowing_name)
|
||||
local node_name = "liquid_physics:" .. namespace .. "_" .. source_name .. "_level_" .. i
|
||||
|
||||
local level_def = {
|
||||
name = node_name,
|
||||
description = source_liquid_def.description .. " Level " .. i,
|
||||
tiles = source_liquid_def.tiles,
|
||||
use_texture_alpha = source_liquid_def.use_texture_alpha,
|
||||
@@ -134,7 +154,7 @@ function liquid_physics.register_liquid(namespace, source_name, flowing_name)
|
||||
sounds = source_liquid_def.sounds,
|
||||
}
|
||||
|
||||
core.register_node(node_name, level_def)
|
||||
core.register_node(":" .. node_name, level_def)
|
||||
liquid_physics._liquid_ids[node_name] = id
|
||||
|
||||
table.insert(liquids, node_name)
|
||||
@@ -142,14 +162,13 @@ function liquid_physics.register_liquid(namespace, source_name, flowing_name)
|
||||
|
||||
table.insert(liquids, source_liquid_name)
|
||||
|
||||
--Finally, replace flowing, such that it behaves like a source
|
||||
flowing_liquid_def.liquidtype = "source"
|
||||
flowing_liquid_def.liquid_range = 0
|
||||
flowing_liquid_def.liquid_renewable = false
|
||||
flowing_liquid_def.liquid_alternative_flowing = source_liquid_name
|
||||
flowing_liquid_def.liquid_alternative_source = source_liquid_name
|
||||
|
||||
core.register_node(":" .. flowing_liquid_name, flowing_liquid_def)
|
||||
-- Finally, stop flowing
|
||||
flowing_liquid_def.groups.liquid_physics = 1
|
||||
core.override_item(flowing_liquid_name, {
|
||||
liquid_range = 0,
|
||||
liquid_renewable = false,
|
||||
groups = flowing_liquid_def.groups
|
||||
}, nil)
|
||||
liquid_physics._liquid_ids[flowing_liquid_name] = id
|
||||
|
||||
liquid_physics._registered_liquids[id] = liquids
|
||||
|
||||
362
bucket.lua
Normal file
362
bucket.lua
Normal file
@@ -0,0 +1,362 @@
|
||||
-- Copyright (C) 2025 snoutie
|
||||
-- Authors: snoutie (copyright@achtarmig.org)
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU Affero General Public License as published
|
||||
-- by the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU Affero General Public License for more details.
|
||||
|
||||
-- You should have received a copy of the GNU Affero General Public License
|
||||
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
local internal_bucket = {}
|
||||
|
||||
local wear_levels = {}
|
||||
wear_levels[1] = 65535
|
||||
wear_levels[2] = 57337
|
||||
wear_levels[3] = 49146
|
||||
wear_levels[4] = 40955
|
||||
wear_levels[5] = 32764
|
||||
wear_levels[6] = 24573
|
||||
wear_levels[7] = 16382
|
||||
wear_levels[8] = 8191
|
||||
wear_levels[9] = 0
|
||||
|
||||
local base_mcl_buckets = core.get_modpath("mcl_buckets")
|
||||
local base_default = core.get_modpath("default")
|
||||
|
||||
local function check_protection(pos, name, text)
|
||||
if core.is_protected(pos, name) then
|
||||
core.log("action", (name ~= "" and name or "A mod")
|
||||
.. " tried to " .. text
|
||||
.. " at protected position "
|
||||
.. core.pos_to_string(pos)
|
||||
.. " with a bucket")
|
||||
core.record_protection_violation(pos, name)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function internal_bucket.get_wear(liquid_level)
|
||||
return wear_levels[liquid_level + 1]
|
||||
end
|
||||
|
||||
function internal_bucket.get_liquid_level(wear)
|
||||
for i = 1, 9 do
|
||||
if wear_levels[i] == wear then
|
||||
return i - 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function set_bucket_item_liquid_level(item, liquid_level)
|
||||
local meta = item:get_meta()
|
||||
|
||||
meta:set_string("description",
|
||||
ItemStack(item:get_name()):get_description() .. " " .. liquid_level .. "/8")
|
||||
|
||||
item:set_wear(internal_bucket.get_wear(liquid_level))
|
||||
end
|
||||
|
||||
local function mcl_get_pointed_thing(usr)
|
||||
local start = usr:get_pos()
|
||||
start.y = start.y + usr:get_properties().eye_height
|
||||
local look_dir = usr:get_look_dir()
|
||||
local _end = vector.add(start, vector.multiply(look_dir, 5))
|
||||
|
||||
local ray = core.raycast(start, _end, false, true)
|
||||
for pointed_thing in ray do
|
||||
local name = core.get_node(pointed_thing.under).name
|
||||
local def = core.registered_nodes[name]
|
||||
if not def or def.drawtype ~= "flowingliquid" then
|
||||
return pointed_thing
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function get_bucket_name_empty()
|
||||
if base_default then
|
||||
return "bucket:bucket_empty"
|
||||
elseif base_mcl_buckets then
|
||||
return "mcl_buckets:bucket_empty"
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function get_bucket_name_filled(source_name)
|
||||
if base_default then
|
||||
return bucket.liquids[source_name].itemname
|
||||
elseif base_mcl_buckets then
|
||||
return mcl_buckets.liquids[source_name].bucketname
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function get_liquid_name(bucket_name)
|
||||
if base_default then
|
||||
for source, b in pairs(bucket.liquids) do
|
||||
if b.itemname and b.itemname == bucket_name then
|
||||
return b.source
|
||||
end
|
||||
end
|
||||
elseif base_mcl_buckets then
|
||||
-- TODO: How Should I handle this then...
|
||||
return mcl_buckets.buckets[bucket_name].source_take[1]
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function bucket_on_use(on_use_fallback, itemstack, user, pointed_thing)
|
||||
if pointed_thing.type == "object" then
|
||||
pointed_thing.ref:punch(user, 1.0, { full_punch_interval = 1.0 }, nil)
|
||||
return user:get_wielded_item()
|
||||
elseif pointed_thing.type ~= "node" then
|
||||
return
|
||||
end
|
||||
|
||||
local held_bucket_name = itemstack:get_name()
|
||||
|
||||
local is_bucket_filled = held_bucket_name ~= get_bucket_name_empty()
|
||||
local bucket_contents = is_bucket_filled and get_liquid_name(held_bucket_name)
|
||||
local bucket_fill_level = internal_bucket.get_liquid_level(itemstack:get_wear())
|
||||
|
||||
local liquid = liquid_physics.get_liquid_at(pointed_thing.under)
|
||||
|
||||
-- Bucket is filled and pointed at liquid is not registered
|
||||
-- -> Don't scoop
|
||||
if bucket_contents and liquid == nil then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
-- Pointed at liquid is not registered
|
||||
-- -> Scoop via fallback
|
||||
if liquid == nil then
|
||||
return on_use_fallback(itemstack, user, pointed_thing)
|
||||
end
|
||||
|
||||
-- Bucket is filled and pointed at liquid is of different kind
|
||||
-- -> Don't scoop
|
||||
local liquid_source_name = liquid_physics.get_liquid_node_names(liquid.liquid_id)[8]
|
||||
if bucket_contents and bucket_contents ~= liquid_source_name then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local node = core.get_node(pointed_thing.under)
|
||||
|
||||
if check_protection(pointed_thing.under,
|
||||
user:get_player_name(),
|
||||
"take " .. node.name) then
|
||||
return
|
||||
end
|
||||
|
||||
local bucket_name_filled = get_bucket_name_filled(liquid_source_name)
|
||||
|
||||
-- Don't know how to handle
|
||||
-- -> Fallback
|
||||
if bucket_name_filled == nil then
|
||||
return on_use_fallback(itemstack, user, pointed_thing)
|
||||
end
|
||||
|
||||
local item_bucket = ItemStack(bucket_name_filled)
|
||||
if not is_bucket_filled then
|
||||
set_bucket_item_liquid_level(item_bucket, liquid.liquid_level)
|
||||
|
||||
local item_count = user:get_wielded_item():get_count()
|
||||
if item_count > 1 then
|
||||
local inv = user:get_inventory()
|
||||
if inv:room_for_item("main", { name = bucket_name_filled }) then
|
||||
inv:add_item("main", item_bucket)
|
||||
else
|
||||
local pos = user:getpos()
|
||||
pos.y = math.floor(pos.y + 0.5)
|
||||
core.add_item(pos, item_bucket)
|
||||
end
|
||||
|
||||
-- set to return empty buckets minus 1
|
||||
item_bucket = ItemStack(get_bucket_name_empty() .. tostring(item_count - 1))
|
||||
end
|
||||
|
||||
liquid_physics.set_liquid_at(pointed_thing.under, 0, 0)
|
||||
return item_bucket
|
||||
else
|
||||
local give_amount = math.min(8 - bucket_fill_level, liquid.liquid_level)
|
||||
|
||||
set_bucket_item_liquid_level(item_bucket, bucket_fill_level + give_amount)
|
||||
liquid_physics.set_liquid_at(pointed_thing.under, liquid.liquid_id, liquid.liquid_level - give_amount)
|
||||
|
||||
return item_bucket
|
||||
end
|
||||
end
|
||||
|
||||
local function bucket_on_place(on_place_fallback, bucket_liquid_id, source_name, itemstack, user, pointed_thing)
|
||||
-- Must be pointing to node
|
||||
if pointed_thing.type ~= "node" then
|
||||
return
|
||||
end
|
||||
|
||||
local node = core.get_node(pointed_thing.under)
|
||||
local node_def = core.registered_nodes[node.name]
|
||||
|
||||
if not node_def then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
-- Call on_rightclick if the pointed node defines it
|
||||
if node_def.on_rightclick and
|
||||
not (user and user:is_player() and
|
||||
user:get_player_control().sneak) then
|
||||
return node_def.on_rightclick(
|
||||
pointed_thing.under,
|
||||
node, user,
|
||||
itemstack)
|
||||
end
|
||||
|
||||
-- Where to place the liquid at
|
||||
local place_at_pos
|
||||
|
||||
if node_def.buildable_to then
|
||||
place_at_pos = pointed_thing.under
|
||||
else
|
||||
place_at_pos = pointed_thing.above
|
||||
|
||||
node = core.get_node(place_at_pos)
|
||||
|
||||
local node_above_def = core.registered_nodes[node.name]
|
||||
|
||||
if not node_above_def or not node_above_def.buildable_to then
|
||||
return itemstack
|
||||
end
|
||||
end
|
||||
|
||||
if check_protection(place_at_pos, user
|
||||
and user:get_player_name()
|
||||
or "", "place " .. source_name) then
|
||||
return
|
||||
end
|
||||
|
||||
local liquid_level = internal_bucket.get_liquid_level(itemstack:get_wear())
|
||||
local liquid = liquid_physics.get_liquid_at(place_at_pos)
|
||||
|
||||
if liquid == nil then
|
||||
if liquid_physics.set_liquid_at(place_at_pos, bucket_liquid_id, liquid_level) then
|
||||
return ItemStack(get_bucket_name_empty())
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
|
||||
if liquid.liquid_id == bucket_liquid_id then
|
||||
local give_amount = math.min(8 - liquid.liquid_level, liquid_level)
|
||||
if liquid_physics.set_liquid_at(place_at_pos, bucket_liquid_id, liquid.liquid_level + give_amount) then
|
||||
if give_amount == liquid_level then
|
||||
return ItemStack(get_bucket_name_empty())
|
||||
end
|
||||
set_bucket_item_liquid_level(itemstack, liquid_level - give_amount)
|
||||
return itemstack
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
end
|
||||
|
||||
function internal_bucket.register_empty_bucket(bucket_name)
|
||||
local bucket_tool = core.registered_items[bucket_name]
|
||||
|
||||
if base_default then
|
||||
local on_use_fallback = bucket_tool.on_use
|
||||
core.override_item(bucket_name, {
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
return bucket_on_use(on_use_fallback, itemstack, user, pointed_thing)
|
||||
end
|
||||
}, nil)
|
||||
elseif base_mcl_buckets then
|
||||
local on_use_fallback = bucket_tool.on_place
|
||||
if core.settings:get_bool("liquid_physics_voxelibre_enable_scooping_via_use", true) then
|
||||
core.override_item(bucket_name, {
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
return bucket_on_use(on_use_fallback, itemstack, user, pointed_thing)
|
||||
end
|
||||
}, nil)
|
||||
end
|
||||
core.override_item(bucket_name, {
|
||||
on_place = function(itemstack, user, pointed_thing)
|
||||
local use_select_box = core.settings:get_bool("mcl_buckets_use_select_box", false)
|
||||
if use_select_box == false then
|
||||
-- TODO: Understand why this is nil
|
||||
if user.get_pos == nil then
|
||||
return itemstack
|
||||
end
|
||||
pointed_thing = mcl_get_pointed_thing(user)
|
||||
end
|
||||
return bucket_on_use(on_use_fallback, itemstack, user, pointed_thing)
|
||||
end
|
||||
}, nil)
|
||||
end
|
||||
end
|
||||
|
||||
function internal_bucket.register_filled_bucket(name)
|
||||
local bucket_tool = core.registered_items[name]
|
||||
|
||||
local source_name = get_liquid_name(name)
|
||||
if source_name == nil then
|
||||
error("Liquid Physics: Could not register bucket. Liquid for bucket " .. name .. " was not found")
|
||||
end
|
||||
local bucket_liquid_id = liquid_physics.get_liquid_id(source_name)
|
||||
if bucket_liquid_id == nil then
|
||||
error("Liquid Physics: Could not register bucket. Liquid " ..
|
||||
source_name .. " was not registered with liquid physics.")
|
||||
end
|
||||
|
||||
if base_default then
|
||||
local on_place_fallback = bucket_tool.on_place
|
||||
local on_use_fallback = bucket_tool.on_place
|
||||
core.override_item(name, {
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
return bucket_on_use(on_use_fallback, itemstack, user, pointed_thing)
|
||||
end,
|
||||
on_place = function(itemstack, user, pointed_thing)
|
||||
return bucket_on_place(on_place_fallback, bucket_liquid_id, source_name, itemstack, user, pointed_thing)
|
||||
end,
|
||||
wear_color = {
|
||||
blend = "linear",
|
||||
color_stops = {
|
||||
[0.0] = "#ff0000",
|
||||
[0.5] = "slateblue",
|
||||
[1.0] = { r = 0, g = 255, b = 0, a = 150 },
|
||||
}
|
||||
},
|
||||
}, nil)
|
||||
|
||||
core.register_tool(":" .. name, core.registered_items[name])
|
||||
elseif base_mcl_buckets then
|
||||
local on_place_fallback = bucket_tool.on_place
|
||||
if core.settings:get_bool("liquid_physics_voxelibre_enable_scooping_via_use", true) then
|
||||
local on_use_fallback = bucket_tool.on_use
|
||||
core.override_item(name, {
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
return bucket_on_use(on_use_fallback, itemstack, user, pointed_thing)
|
||||
end
|
||||
}, nil)
|
||||
end
|
||||
core.override_item(name, {
|
||||
on_place = function(itemstack, user, pointed_thing)
|
||||
return bucket_on_place(on_place_fallback, bucket_liquid_id, source_name, itemstack, user, pointed_thing)
|
||||
end,
|
||||
wear_color = {
|
||||
blend = "linear",
|
||||
color_stops = {
|
||||
[0.0] = "#ff0000",
|
||||
[0.5] = "slateblue",
|
||||
[1.0] = { r = 0, g = 255, b = 0, a = 150 },
|
||||
}
|
||||
},
|
||||
}, nil)
|
||||
|
||||
core.register_tool(":" .. name, core.registered_items[name])
|
||||
end
|
||||
end
|
||||
|
||||
return internal_bucket
|
||||
30
game/default.lua
Normal file
30
game/default.lua
Normal file
@@ -0,0 +1,30 @@
|
||||
-- Copyright (C) 2025 snoutie
|
||||
-- Authors: snoutie (copyright@achtarmig.org)
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU Affero General Public License as published
|
||||
-- by the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU Affero General Public License for more details.
|
||||
|
||||
-- You should have received a copy of the GNU Affero General Public License
|
||||
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
local modpath = core.get_modpath(core.get_current_modname())
|
||||
local internal_bucket = dofile(modpath .. "/bucket.lua")
|
||||
|
||||
internal_bucket.register_empty_bucket("bucket:bucket_empty")
|
||||
|
||||
-- Settings
|
||||
|
||||
if core.settings:get_bool("liquid_physics_enable_water_physics", true) then
|
||||
liquid_physics.register_liquid("default", "water_source", "water_flowing")
|
||||
internal_bucket.register_filled_bucket("bucket:bucket_water")
|
||||
end
|
||||
if core.settings:get_bool("liquid_physics_enable_lava_physics", true) then
|
||||
liquid_physics.register_liquid("default", "lava_source", "lava_flowing")
|
||||
internal_bucket.register_filled_bucket("bucket:bucket_lava")
|
||||
end
|
||||
30
game/voxelibre.lua
Normal file
30
game/voxelibre.lua
Normal file
@@ -0,0 +1,30 @@
|
||||
-- Copyright (C) 2025 snoutie
|
||||
-- Authors: snoutie (copyright@achtarmig.org)
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU Affero General Public License as published
|
||||
-- by the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU Affero General Public License for more details.
|
||||
|
||||
-- You should have received a copy of the GNU Affero General Public License
|
||||
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
local modpath = core.get_modpath(core.get_current_modname())
|
||||
local internal_bucket = dofile(modpath .. "/bucket.lua")
|
||||
|
||||
internal_bucket.register_empty_bucket("mcl_buckets:bucket_empty")
|
||||
|
||||
-- Settings
|
||||
|
||||
if core.settings:get_bool("liquid_physics_enable_water_physics", true) then
|
||||
liquid_physics.register_liquid("mcl_core", "water_source", "water_flowing")
|
||||
internal_bucket.register_filled_bucket("mcl_buckets:bucket_water")
|
||||
end
|
||||
if core.settings:get_bool("liquid_physics_enable_lava_physics", true) then
|
||||
liquid_physics.register_liquid("mcl_core", "lava_source", "lava_flowing")
|
||||
internal_bucket.register_filled_bucket("mcl_buckets:bucket_lava")
|
||||
end
|
||||
79
init.lua
79
init.lua
@@ -17,57 +17,60 @@ local modpath = core.get_modpath(core.get_current_modname())
|
||||
|
||||
liquid_physics = {}
|
||||
|
||||
--INTERNAL USE ONLY - Stores all nodes which need to checked
|
||||
-- INTERNAL USE ONLY - Stores all nodes which need to checked
|
||||
liquid_physics._nodes_to_check = {}
|
||||
--INTERNAL USE ONLY - Stores liquid_id and the corresponding liquid node names
|
||||
-- INTERNAL USE ONLY - Stores liquid_id and the corresponding liquid node names
|
||||
liquid_physics._registered_liquids = {}
|
||||
--INTERNAL USE ONLY - Stores all liquid node names and their corresponding liquid_id
|
||||
-- INTERNAL USE ONLY - Stores all liquid node names and their corresponding liquid_id
|
||||
liquid_physics._liquid_ids = {}
|
||||
|
||||
local internal = dofile(modpath .. "/internal.lua")
|
||||
|
||||
dofile(modpath .. "/api.lua")
|
||||
|
||||
if core.get_modpath("default") then
|
||||
liquid_physics.register_liquid("default", "water_source", "water_flowing")
|
||||
liquid_physics.register_liquid("default", "lava_source", "lava_flowing")
|
||||
end
|
||||
|
||||
if core.get_modpath("mcl_core") then
|
||||
liquid_physics.register_liquid("mcl_core", "water_source", "water_flowing")
|
||||
liquid_physics.register_liquid("mcl_core", "lava_source", "lava_flowing")
|
||||
end
|
||||
|
||||
-- Remove "air" from registered_liquids for lbm and abm
|
||||
local source_names = {}
|
||||
for key, value in pairs(liquid_physics._registered_liquids) do
|
||||
for i = 2, table.getn(value) do
|
||||
table.insert(source_names, value[i])
|
||||
end
|
||||
dofile(modpath .. "/game/default.lua")
|
||||
elseif core.get_modpath("mcl_core") then
|
||||
dofile(modpath .. "/game/voxelibre.lua")
|
||||
else
|
||||
error("Liquid Physics only supports VoxeLibre or Minetest")
|
||||
end
|
||||
|
||||
core.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing)
|
||||
if internal.get_liquid_id(core.get_node(pos).name) ~= nil then
|
||||
internal.add_node_to_check(pos)
|
||||
end
|
||||
--core.chat_send_all("Placed AT: " .. dump(pos) .. "___")
|
||||
-- if internal.get_liquid_id(core.get_node(pos).name) ~= nil then
|
||||
-- internal.add_node_to_check(pos)
|
||||
-- end
|
||||
end)
|
||||
|
||||
core.register_lbm {
|
||||
name = "liquid_physics:update",
|
||||
nodenames = source_names,
|
||||
run_at_every_load = true,
|
||||
action = function(pos, node, dtime_s)
|
||||
internal.add_node_to_check(pos)
|
||||
end,
|
||||
}
|
||||
-- core.register_lbm {
|
||||
-- name = "liquid_physics:update",
|
||||
-- nodenames = "group:liquid_physics",
|
||||
-- run_at_every_load = true,
|
||||
-- action = function(pos, node, dtime_s)
|
||||
-- --internal.add_node_to_check(pos)
|
||||
-- core.set_node(pos, { name = "air" })
|
||||
-- end,
|
||||
-- }
|
||||
|
||||
core.register_abm({
|
||||
nodenames = source_names,
|
||||
neighbors = { "air" },
|
||||
interval = 0.2,
|
||||
chance = 0,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
internal.add_node_to_check(pos)
|
||||
end
|
||||
})
|
||||
-- core.register_lbm {
|
||||
-- name = "liquid_physics:update",
|
||||
-- nodenames = "group:liquid_physics",
|
||||
-- run_at_every_load = true,
|
||||
-- action = function(pos, node, dtime_s)
|
||||
-- --internal.add_node_to_check(pos)
|
||||
-- core.set_node(pos, { name = "air" })
|
||||
-- end,
|
||||
-- }
|
||||
|
||||
-- core.register_abm({
|
||||
-- nodenames = "group:liquid_physics",
|
||||
-- neighbors = { "air" },
|
||||
-- interval = 0.2,
|
||||
-- chance = 0,
|
||||
-- action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
-- --internal.add_node_to_check(pos)
|
||||
-- end
|
||||
-- })
|
||||
|
||||
dofile(modpath .. "/physics.lua")
|
||||
|
||||
12
internal.lua
12
internal.lua
@@ -83,6 +83,9 @@ function internal.new_lpn(hash, pos)
|
||||
liquid_id = liquid_id,
|
||||
init_liquid_level = liquid_level,
|
||||
liquid_level = liquid_level,
|
||||
density = 0,
|
||||
gradient = { x = 0, y = 0, z = 0 },
|
||||
neighbors = {},
|
||||
}
|
||||
end
|
||||
|
||||
@@ -96,11 +99,18 @@ function internal.set_lpn(liquid_id, lpn, liquid_level)
|
||||
lpn.liquid_id = liquid_id
|
||||
end
|
||||
|
||||
-- Sets liquid node from LPN
|
||||
-- @param lpn table Liquid Physics Node
|
||||
function internal.set_node(lpn)
|
||||
core.set_node(lpn.pos, { name = internal.get_liquid_node_name(lpn.liquid_id, lpn.liquid_level) })
|
||||
end
|
||||
|
||||
-- This node will be checked in the next cycle
|
||||
-- @param pos table Position of the node
|
||||
function internal.add_node_to_check(pos)
|
||||
local h = core.hash_node_position(pos)
|
||||
liquid_physics._nodes_to_check[h] = pos
|
||||
local lpn = internal.new_lpn(h, pos)
|
||||
liquid_physics._nodes_to_check[h] = lpn
|
||||
end
|
||||
|
||||
-- This node will no longer be checked
|
||||
|
||||
2
mod.conf
2
mod.conf
@@ -1,6 +1,6 @@
|
||||
name = liquid_physics
|
||||
depends =
|
||||
optional_depends = default, mcl_core
|
||||
optional_depends = default, mcl_core, bucket, mcl_buckets
|
||||
author = snoutie
|
||||
description = Adds physics to liquids
|
||||
title = Liquid Physics
|
||||
|
||||
422
physics.lua
422
physics.lua
@@ -17,12 +17,30 @@ local modpath = core.get_modpath(core.get_current_modname())
|
||||
local internal = dofile(modpath .. "/internal.lua")
|
||||
|
||||
-- A table of offsets for ease of use
|
||||
local offsets = {
|
||||
{ x = 0, z = 1, },
|
||||
{ x = 0, z = -1, },
|
||||
{ x = 1, z = 0, },
|
||||
{ x = -1, z = 0, }
|
||||
}
|
||||
local offsets = {}
|
||||
-- local offsets = {
|
||||
-- { x = 0, z = 0, y = 0, d = 0 },
|
||||
|
||||
-- { x = 0, z = 1, y = 0, d = 1 },
|
||||
-- { x = 0, z = -1, y = 0, d = 1 },
|
||||
|
||||
-- { x = 1, z = 0, y = 0, d = 1 },
|
||||
-- { x = -1, z = 0, y = 0, d = 1 },
|
||||
-- }
|
||||
for x = -1, 1 do
|
||||
for y = -1, 1 do
|
||||
for z = -1, 1 do
|
||||
local d = math.abs(x) + math.abs(y) + math.abs(z)
|
||||
table.insert(offsets, {
|
||||
x = x, -- X Offset
|
||||
y = y, -- Y Offset
|
||||
z = z, -- Z Offset
|
||||
d = d -- Distance to 0 / 0 / 0
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Store number of offsets for less calculations
|
||||
local number_of_offsets = table.getn(offsets)
|
||||
|
||||
@@ -33,8 +51,8 @@ local number_of_offsets = table.getn(offsets)
|
||||
local function add_offset_to_pos(pos, offset)
|
||||
return {
|
||||
x = pos.x + offset.x,
|
||||
y = pos.y + offset.y,
|
||||
z = pos.z + offset.z,
|
||||
y = pos.y
|
||||
}
|
||||
end
|
||||
|
||||
@@ -52,6 +70,16 @@ local function get_lpn_buffered(b, pos)
|
||||
return b[h]
|
||||
end
|
||||
|
||||
local function round_away_from_zero(value)
|
||||
if value == 0 then
|
||||
return 0
|
||||
end
|
||||
if value > 0 then
|
||||
return math.ceil(value)
|
||||
end
|
||||
return math.floor(value) -- Let's hope math floor is optimized for zero
|
||||
end
|
||||
|
||||
-- Checks if liquid_id of curr and lpn are the same.
|
||||
-- Checks if the liquid_level is above -1
|
||||
-- @param curr table The current LPN
|
||||
@@ -61,25 +89,203 @@ local function is_lpn_relevant(curr, lpn)
|
||||
return lpn.liquid_level >= 0 and (lpn.liquid_level == 0 or curr.liquid_id == lpn.liquid_id)
|
||||
end
|
||||
|
||||
-- local function get_gradient(base, compare, opp)
|
||||
-- local compare_copy = compare
|
||||
-- if compare_copy < 0 then compare_copy = 0 end
|
||||
-- return math.ceil(((opp + base) - compare_copy * 2) / 8)
|
||||
-- end
|
||||
|
||||
-- Gets all adjacent liquid nodes with the same liquid_id as curr
|
||||
-- Gets all adjacent air nodes
|
||||
-- @param b table Buffered LPN
|
||||
-- @param curr table The current LPN
|
||||
-- @return table Table of neighboring LPN
|
||||
-- @return number Number of neighbors
|
||||
local function get_valid_neighbors(b, curr)
|
||||
local function get_all_neighbors_pressure(b, curr)
|
||||
local neighbors = {}
|
||||
local number_of_neighbors = 0
|
||||
local no_of_h_neighbors = 0
|
||||
local no_of_v_neighbors = 0
|
||||
for i = 1, number_of_offsets do
|
||||
local pos = add_offset_to_pos(curr.pos, offsets[i])
|
||||
local current_offset = offsets[i]
|
||||
local pos = add_offset_to_pos(curr.pos, current_offset)
|
||||
local lpn = get_lpn_buffered(b, pos)
|
||||
|
||||
if is_lpn_relevant(curr, lpn) then
|
||||
number_of_neighbors = number_of_neighbors + 1
|
||||
table.insert(neighbors, math.random(number_of_neighbors, 1), lpn)
|
||||
--if is_lpn_relevant(curr, lpn) then
|
||||
|
||||
local o_off = {}
|
||||
if i % 2 == 0 then
|
||||
o_off = offsets[i - 1]
|
||||
else
|
||||
o_off = offsets[i + 1]
|
||||
end
|
||||
|
||||
local o_pos = add_offset_to_pos(curr.pos, o_off)
|
||||
local o_lpn = get_lpn_buffered(b, o_pos)
|
||||
|
||||
local g = current_offset.g + get_gradient(curr.liquid_level, lpn.liquid_level, o_lpn.liquid_level)
|
||||
|
||||
if g ~= 0 then
|
||||
if i < 5 then
|
||||
no_of_h_neighbors = no_of_h_neighbors + 1
|
||||
else
|
||||
no_of_v_neighbors = no_of_v_neighbors + 1
|
||||
end
|
||||
end
|
||||
table.insert(neighbors, { lpn = lpn, g = g })
|
||||
--end
|
||||
end
|
||||
return neighbors, no_of_h_neighbors, no_of_v_neighbors
|
||||
end
|
||||
|
||||
|
||||
local function get_pressure_gradient(b, lpn)
|
||||
local number_of_directions = 0
|
||||
|
||||
lpn.neighbors = get_all_neighbors_pressure(b, lpn)
|
||||
|
||||
lpn.pressure_gradient = internal.get_inital_pressure_gradient()
|
||||
|
||||
local i = 1
|
||||
for _, g in pairs(lpn.pressure_gradient) do
|
||||
g = g + get_gradient(lpn.liquid_level, lpn.neighbors[i].liquid_level)
|
||||
i = i + 1
|
||||
if g ~= 0 then
|
||||
number_of_directions = number_of_directions + 1
|
||||
end
|
||||
end
|
||||
return neighbors, number_of_neighbors
|
||||
|
||||
return number_of_directions
|
||||
end
|
||||
|
||||
local function get_density_influence(r, d)
|
||||
local vol = math.pi * (r ^ 8) / 4
|
||||
local v = math.max(0, r - d)
|
||||
return v + v * v / vol
|
||||
end
|
||||
|
||||
local function get_density_influence_derivative(r, d)
|
||||
if (d >= r) then return 0 end
|
||||
local f = r * r - d * d
|
||||
local scale = -24 / (math.pi * (r ^ 8))
|
||||
return scale * d * f * f
|
||||
end
|
||||
|
||||
local function get_density(b, lpn)
|
||||
local radius = 3 -- 3 is max
|
||||
for i = 1, number_of_offsets do
|
||||
local offset = offsets[i]
|
||||
local o_pos = add_offset_to_pos(lpn.pos, offset)
|
||||
local o_lpn = get_lpn_buffered(b, o_pos)
|
||||
|
||||
local liquid_level = o_lpn.liquid_level
|
||||
if liquid_level < 0 then
|
||||
liquid_level = lpn.liquid_level
|
||||
elseif liquid_level == 0 then
|
||||
liquid_level = 0
|
||||
end
|
||||
|
||||
-- if offset.d == 0 then
|
||||
-- liquid_level = 0
|
||||
-- end
|
||||
|
||||
local influence = liquid_level * get_density_influence(radius, offset.d)
|
||||
|
||||
table.insert(lpn.neighbors, { lpn = o_lpn, prs = 0 })
|
||||
|
||||
lpn.density = lpn.density + influence
|
||||
end
|
||||
lpn.density = math.floor(lpn.density)
|
||||
end
|
||||
|
||||
|
||||
local function get_pressure_from_density(density)
|
||||
local multiplier = 1
|
||||
local target_pressure = 11
|
||||
--core.chat_send_all(density)
|
||||
return (density - target_pressure) * multiplier
|
||||
end
|
||||
|
||||
local function get_gradient(b, lpn)
|
||||
-- local gradient = {
|
||||
-- x = 0,
|
||||
-- y = 0,
|
||||
-- z = 0,
|
||||
-- }
|
||||
local radius = 3 -- 3 is max
|
||||
|
||||
for i = 1, number_of_offsets do
|
||||
local offset = offsets[i]
|
||||
|
||||
if offset.d == 0 then
|
||||
goto continue
|
||||
end
|
||||
|
||||
local neighbor = lpn.neighbors[i].lpn
|
||||
|
||||
local density = neighbor.density
|
||||
|
||||
-- if density < 0 then
|
||||
-- density = neighbor.density
|
||||
-- else
|
||||
if density == 0 then
|
||||
density = 1
|
||||
end
|
||||
|
||||
local slope = get_density_influence_derivative(radius, offset.d)
|
||||
local pressure = get_pressure_from_density(density)
|
||||
|
||||
--if offset.y == 0 then
|
||||
lpn.neighbors[i].prs = math.ceil(math.abs(
|
||||
(pressure * slope * lpn.liquid_level / density)))
|
||||
|
||||
lpn.neighbors[i].is_down = false
|
||||
|
||||
if offset.y == 1 then
|
||||
lpn.neighbors[i].prs = lpn.neighbors[i].prs - 6
|
||||
end
|
||||
|
||||
if offset.y == -1 then
|
||||
lpn.neighbors[i].prs = 1
|
||||
lpn.neighbors[i].is_down = true
|
||||
end
|
||||
|
||||
-- lpn.gradient = {
|
||||
-- x = lpn.gradient.x + (pressure * offset.x * slope * neighbor.liquid_level / density),
|
||||
-- y = lpn.gradient.y + (pressure * offset.y * slope * neighbor.liquid_level / density),
|
||||
-- z = lpn.gradient.z + (pressure * offset.z * slope * neighbor.liquid_level / density),
|
||||
-- }
|
||||
::continue::
|
||||
end
|
||||
|
||||
--core.chat_send_all("Pressure: " .. dump(lpn.gradient))
|
||||
|
||||
-- lpn.gradient = {
|
||||
-- x = round_away_from_zero(lpn.gradient.x),
|
||||
-- y = round_away_from_zero(lpn.gradient.y),
|
||||
-- z = round_away_from_zero(lpn.gradient.z),
|
||||
-- }
|
||||
-- if lpn.gradient.x > 0 then
|
||||
-- lpn.gradient.x = 1
|
||||
-- elseif lpn.gradient.x < 0 then
|
||||
-- lpn.gradient.x = -1
|
||||
-- end
|
||||
|
||||
-- if lpn.gradient.y > 0 then
|
||||
-- lpn.gradient.y = 1
|
||||
-- elseif lpn.gradient.y < 0 then
|
||||
-- lpn.gradient.y = -1
|
||||
-- end
|
||||
|
||||
-- if lpn.gradient.z > 0 then
|
||||
-- lpn.gradient.z = 1
|
||||
-- elseif lpn.gradient.z < 0 then
|
||||
-- lpn.gradient.z = -1
|
||||
-- end
|
||||
end
|
||||
|
||||
|
||||
local function get_pressure_force(lpn)
|
||||
|
||||
end
|
||||
|
||||
-- Gets neighbors of curr and calculates the pressure
|
||||
@@ -127,6 +333,9 @@ local function try_move(from, to, amount)
|
||||
if to.liquid_level >= 8 then
|
||||
return 0
|
||||
end
|
||||
if amount <= 0 then
|
||||
return 0
|
||||
end
|
||||
local max_allowed = amount + 8 - (to.liquid_level + amount)
|
||||
local max_allowed_clamped = math.min(max_allowed, amount, from.liquid_level)
|
||||
|
||||
@@ -212,20 +421,179 @@ local function move(b, curr_pos)
|
||||
end
|
||||
end
|
||||
|
||||
core.register_on_mapblocks_changed(function(modified_blocks, modified_blocks_count)
|
||||
-- Buffered LPN
|
||||
local b = {}
|
||||
for hpos, pos in pairs(liquid_physics._nodes_to_check) do
|
||||
if core.compare_block_status(pos, "active") then
|
||||
move(b, pos)
|
||||
else
|
||||
internal.remove_node_to_check(pos)
|
||||
end
|
||||
local function try_spread(buffer, from, to, is_down)
|
||||
if is_lpn_relevant(from, to) and ((from.liquid_level > 1 and from.liquid_level >= to.liquid_level + 1) or is_down) then
|
||||
return try_move(from, to, 1)
|
||||
end
|
||||
-- Update only changed nodes from buffer
|
||||
for _, lpn in pairs(b) do
|
||||
if lpn.init_liquid_level ~= lpn.liquid_level then
|
||||
core.set_node(lpn.pos, { name = internal.get_liquid_node_name(lpn.liquid_id, lpn.liquid_level) })
|
||||
return 0
|
||||
end
|
||||
|
||||
local function shuffle(array)
|
||||
math.randomseed(os.time()) -- Seed the random number generator
|
||||
for i = #array, 2, -1 do
|
||||
local j = math.random(i) -- Pick a random index from 1 to i
|
||||
array[i], array[j] = array[j], array[i] -- Swap elements
|
||||
end
|
||||
end
|
||||
|
||||
local last_finish = 0
|
||||
local active_blocks = {}
|
||||
|
||||
core.register_on_liquid_transformed(function(pos_list, node_list)
|
||||
for hash, block_start in pairs(active_blocks) do
|
||||
if core.compare_block_status(block_start, "active") then
|
||||
else
|
||||
active_blocks[hash] = nil
|
||||
goto continue
|
||||
end
|
||||
|
||||
--core.chat_send_all(dump(block_start) .. "----" .. modified_blocks_count)
|
||||
local buffer = {}
|
||||
local block_end = {
|
||||
x = block_start.x + 15,
|
||||
y = block_start.y + 15,
|
||||
z = block_start.z + 15,
|
||||
}
|
||||
local node_pos_list = core.find_nodes_in_area(block_start, block_end, { "group:liquid_physics" })
|
||||
|
||||
local lpn_list = {}
|
||||
local number_of_lpn = 0
|
||||
for _, pos in pairs(node_pos_list) do
|
||||
local lpn = get_lpn_buffered(buffer, pos)
|
||||
get_density(buffer, lpn)
|
||||
|
||||
table.insert(lpn_list, lpn)
|
||||
number_of_lpn = number_of_lpn + 1
|
||||
end
|
||||
|
||||
for i = 1, number_of_lpn do
|
||||
local g_lpn = lpn_list[i]
|
||||
get_gradient(buffer, g_lpn)
|
||||
|
||||
--g_lpn.gradient.y = 0
|
||||
|
||||
--core.chat_send_all("Grad: " .. dump(g_lpn.gradient))
|
||||
|
||||
-- local spread_to_pos = add_offset_to_pos(g_lpn.pos, g_lpn.gradient)
|
||||
-- local spread_to = get_lpn_buffered(buffer, spread_to_pos)
|
||||
|
||||
-- try_spread(buffer, g_lpn, spread_to)
|
||||
|
||||
|
||||
|
||||
-- local gs = 0
|
||||
-- for g = 1, number_of_offsets do
|
||||
-- if g_lpn.neighbors[g].prs > 0 then
|
||||
-- gs = gs + 1
|
||||
-- end
|
||||
-- end
|
||||
local number_of_targets = 0
|
||||
for g = 1, number_of_offsets do
|
||||
if g_lpn.neighbors[g].prs > 0 and not g_lpn.neighbors[g].is_down then
|
||||
number_of_targets = number_of_targets + 1
|
||||
end
|
||||
end
|
||||
|
||||
if number_of_targets >= g_lpn.liquid_level then
|
||||
shuffle(g_lpn.neighbors)
|
||||
end
|
||||
|
||||
for g = 1, number_of_offsets do
|
||||
if g_lpn.neighbors[g].prs > 0 then
|
||||
try_spread(buffer, g_lpn, g_lpn.neighbors[g].lpn, g_lpn.neighbors[g].is_down)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- if g_lpn.gradient.x ~= 0 then
|
||||
-- local spread_to_pos = add_offset_to_pos(g_lpn.pos, { x = g_lpn.gradient.x, y = 0, z = 0 })
|
||||
-- local spread_to = get_lpn_buffered(buffer, spread_to_pos)
|
||||
|
||||
-- try_spread(buffer, g_lpn, spread_to)
|
||||
-- -- if try_spread(buffer, g_lpn, spread_to, gs) == 0 then
|
||||
-- -- spread_to_pos = add_offset_to_pos(g_lpn.pos, { x = g_lpn.gradient.x * -1, y = 0, z = 0 })
|
||||
-- -- spread_to = get_lpn_buffered(buffer, spread_to_pos)
|
||||
-- -- try_spread(buffer, g_lpn, spread_to, gs)
|
||||
-- -- end
|
||||
-- end
|
||||
-- if g_lpn.gradient.z ~= 0 then
|
||||
-- local spread_to_pos = add_offset_to_pos(g_lpn.pos, { x = 0, y = 0, z = g_lpn.gradient.z })
|
||||
-- local spread_to = get_lpn_buffered(buffer, spread_to_pos)
|
||||
|
||||
-- try_spread(buffer, g_lpn, spread_to)
|
||||
-- -- if try_spread(buffer, g_lpn, spread_to, gs) == 0 then
|
||||
-- -- spread_to_pos = add_offset_to_pos(g_lpn.pos, { x = 0, y = 0, z = g_lpn.gradient.z * -1 })
|
||||
-- -- spread_to = get_lpn_buffered(buffer, spread_to_pos)
|
||||
-- -- try_spread(buffer, g_lpn, spread_to, gs)
|
||||
-- -- end
|
||||
-- end
|
||||
end
|
||||
|
||||
if lpn_list[1] ~= nil then
|
||||
end
|
||||
|
||||
-- for _, pos in pairs(node_pos_list) do
|
||||
-- local lpn = get_lpn_buffered(buffer, pos)
|
||||
|
||||
-- local neighbors, h, v = get_all_neighbors_pressure(buffer, lpn)
|
||||
|
||||
-- local n = 0
|
||||
-- for i = 1, number_of_offsets do
|
||||
-- if neighbors[i].g == 0 then
|
||||
-- goto continue
|
||||
-- end
|
||||
-- if i < 5 then
|
||||
-- n = h
|
||||
-- else
|
||||
-- n = v - 1
|
||||
-- end
|
||||
-- try_spread(buffer, lpn, neighbors[i].lpn, n, neighbors[i].g)
|
||||
-- ::continue::
|
||||
-- end
|
||||
-- end
|
||||
|
||||
-- ::continue::
|
||||
--
|
||||
for _, lpn in pairs(buffer) do
|
||||
if lpn.init_liquid_level ~= lpn.liquid_level then
|
||||
if lpn.liquid_id then
|
||||
internal.set_node(lpn)
|
||||
end
|
||||
end
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
end)
|
||||
|
||||
core.register_on_mapblocks_changed(function(modified_blocks, modified_blocks_count)
|
||||
for hash, _ in pairs(modified_blocks) do
|
||||
local block_start = core.get_position_from_hash(hash)
|
||||
|
||||
block_start = {
|
||||
x = block_start.x * 16,
|
||||
y = block_start.y * 16,
|
||||
z = block_start.z * 16,
|
||||
}
|
||||
|
||||
if core.compare_block_status(block_start, "active") then
|
||||
active_blocks[hash] = block_start
|
||||
else
|
||||
active_blocks[hash] = nil
|
||||
end
|
||||
end
|
||||
-- -- Buffered LPN
|
||||
-- local b = {}
|
||||
-- for hpos, pos in pairs(liquid_physics._nodes_to_check) do
|
||||
-- if core.compare_block_status(pos, "active") then
|
||||
-- move(b, pos)
|
||||
-- else
|
||||
-- internal.remove_node_to_check(pos)
|
||||
-- end
|
||||
-- end
|
||||
-- -- Update only changed nodes from buffer
|
||||
-- for _, lpn in pairs(b) do
|
||||
-- if lpn.init_liquid_level ~= lpn.liquid_level then
|
||||
-- internal.set_node(lpn)
|
||||
-- end
|
||||
-- end
|
||||
end)
|
||||
|
||||
3
settingtypes.txt
Normal file
3
settingtypes.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
liquid_physics_enable_water_physics (Enable Physics For Water) bool true
|
||||
liquid_physics_enable_lava_physics (Enable Physics For Lava) bool true
|
||||
liquid_physics_voxelibre_enable_scooping_via_use (VoxeLibre: Enable Scooping Via Use/Punch) bool true
|
||||
Reference in New Issue
Block a user