Split liquid_viscosity to liquid_viscosity and move_resistance (#10810)

This commit is contained in:
Wuzzy 2021-10-01 14:21:24 +00:00 committed by GitHub
parent f5040707fe
commit 21113ad410
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 288 additions and 44 deletions

@ -1030,8 +1030,8 @@ Methods:
* returns true if player is in a liquid (This oscillates so that the player jumps a bit above the surface) * returns true if player is in a liquid (This oscillates so that the player jumps a bit above the surface)
* `is_in_liquid_stable()` * `is_in_liquid_stable()`
* returns true if player is in a stable liquid (This is more stable and defines the maximum speed of the player) * returns true if player is in a stable liquid (This is more stable and defines the maximum speed of the player)
* `get_liquid_viscosity()` * `get_move_resistance()`
* returns liquid viscosity (Gets the viscosity of liquid to calculate friction) * returns move resistance of current node, the higher the slower the player moves
* `is_climbing()` * `is_climbing()`
* returns true if player is climbing * returns true if player is climbing
* `swimming_vertical()` * `swimming_vertical()`
@ -1233,7 +1233,7 @@ It can be created via `Raycast(pos1, pos2, objects, liquids)` or
liquid_type = <string>, -- A string containing "none", "flowing", or "source" *May not exist* liquid_type = <string>, -- A string containing "none", "flowing", or "source" *May not exist*
liquid_alternative_flowing = <string>, -- Alternative node for liquid *May not exist* liquid_alternative_flowing = <string>, -- Alternative node for liquid *May not exist*
liquid_alternative_source = <string>, -- Alternative node for liquid *May not exist* liquid_alternative_source = <string>, -- Alternative node for liquid *May not exist*
liquid_viscosity = <number>, -- How fast the liquid flows *May not exist* liquid_viscosity = <number>, -- How slow the liquid flows *May not exist*
liquid_renewable = <boolean>, -- Whether the liquid makes an infinite source *May not exist* liquid_renewable = <boolean>, -- Whether the liquid makes an infinite source *May not exist*
liquid_range = <number>, -- How far the liquid flows *May not exist* liquid_range = <number>, -- How far the liquid flows *May not exist*
drowning = bool, -- Whether the player will drown in the node drowning = bool, -- Whether the player will drown in the node
@ -1248,6 +1248,7 @@ It can be created via `Raycast(pos1, pos2, objects, liquids)` or
}, },
legacy_facedir_simple = bool, -- Whether to use old facedir legacy_facedir_simple = bool, -- Whether to use old facedir
legacy_wallmounted = bool -- Whether to use old wallmounted legacy_wallmounted = bool -- Whether to use old wallmounted
move_resistance = <number>, -- How slow players can move through the node *May not exist*
} }
``` ```

@ -1804,7 +1804,7 @@ to games.
- (14) -- constant tolerance - (14) -- constant tolerance
Negative damage values are discarded as no damage. Negative damage values are discarded as no damage.
* `falling_node`: if there is no walkable block under the node it will fall * `falling_node`: if there is no walkable block under the node it will fall
* `float`: the node will not fall through liquids * `float`: the node will not fall through liquids (`liquidtype ~= "none"`)
* `level`: Can be used to give an additional sense of progression in the game. * `level`: Can be used to give an additional sense of progression in the game.
* A larger level will cause e.g. a weapon of a lower level make much less * A larger level will cause e.g. a weapon of a lower level make much less
damage, and get worn out much faster, or not be able to get drops damage, and get worn out much faster, or not be able to get drops
@ -4147,7 +4147,7 @@ differences:
### Other API functions operating on a VoxelManip ### Other API functions operating on a VoxelManip
If any VoxelManip contents were set to a liquid node, If any VoxelManip contents were set to a liquid node (`liquidtype ~= "none"`),
`VoxelManip:update_liquids()` must be called for these liquid nodes to begin `VoxelManip:update_liquids()` must be called for these liquid nodes to begin
flowing. It is recommended to call this function only after having written all flowing. It is recommended to call this function only after having written all
buffered data back to the VoxelManip object, save for special situations where buffered data back to the VoxelManip object, save for special situations where
@ -4958,8 +4958,8 @@ Call these functions only at load time!
* You should have joined some channels to receive events. * You should have joined some channels to receive events.
* If message comes from a server mod, `sender` field is an empty string. * If message comes from a server mod, `sender` field is an empty string.
* `minetest.register_on_liquid_transformed(function(pos_list, node_list))` * `minetest.register_on_liquid_transformed(function(pos_list, node_list))`
* Called after liquid nodes are modified by the engine's liquid transformation * Called after liquid nodes (`liquidtype ~= "none"`) are modified by the
process. engine's liquid transformation process.
* `pos_list` is an array of all modified positions. * `pos_list` is an array of all modified positions.
* `node_list` is an array of the old node that was previously at the position * `node_list` is an array of the old node that was previously at the position
with the corresponding index in pos_list. with the corresponding index in pos_list.
@ -5301,7 +5301,8 @@ Environment access
* `pos1`: start of the ray * `pos1`: start of the ray
* `pos2`: end of the ray * `pos2`: end of the ray
* `objects`: if false, only nodes will be returned. Default is `true`. * `objects`: if false, only nodes will be returned. Default is `true`.
* `liquids`: if false, liquid nodes won't be returned. Default is `false`. * `liquids`: if false, liquid nodes (`liquidtype ~= "none"`) won't be
returned. Default is `false`.
* `minetest.find_path(pos1,pos2,searchdistance,max_jump,max_drop,algorithm)` * `minetest.find_path(pos1,pos2,searchdistance,max_jump,max_drop,algorithm)`
* returns table containing path that can be walked on * returns table containing path that can be walked on
* returns a table of 3D points representing a path from `pos1` to `pos2` or * returns a table of 3D points representing a path from `pos1` to `pos2` or
@ -5325,7 +5326,7 @@ Environment access
* `minetest.spawn_tree (pos, {treedef})` * `minetest.spawn_tree (pos, {treedef})`
* spawns L-system tree at given `pos` with definition in `treedef` table * spawns L-system tree at given `pos` with definition in `treedef` table
* `minetest.transforming_liquid_add(pos)` * `minetest.transforming_liquid_add(pos)`
* add node to liquid update queue * add node to liquid flow update queue
* `minetest.get_node_max_level(pos)` * `minetest.get_node_max_level(pos)`
* get max available level for leveled node * get max available level for leveled node
* `minetest.get_node_level(pos)` * `minetest.get_node_level(pos)`
@ -6978,7 +6979,8 @@ It can be created via `Raycast(pos1, pos2, objects, liquids)` or
* `pos1`: start of the ray * `pos1`: start of the ray
* `pos2`: end of the ray * `pos2`: end of the ray
* `objects`: if false, only nodes will be returned. Default is true. * `objects`: if false, only nodes will be returned. Default is true.
* `liquids`: if false, liquid nodes won't be returned. Default is false. * `liquids`: if false, liquid nodes (`liquidtype ~= "none"`) won't be
returned. Default is false.
### Methods ### Methods
@ -7462,6 +7464,8 @@ Used by `minetest.register_node`, `minetest.register_craftitem`, and
range = 4.0, range = 4.0,
liquids_pointable = false, liquids_pointable = false,
-- If true, item points to all liquid nodes (`liquidtype ~= "none"`),
-- even those for which `pointable = false`
light_source = 0, light_source = 0,
-- When used for nodes: Defines amount of light emitted by node. -- When used for nodes: Defines amount of light emitted by node.
@ -7647,14 +7651,21 @@ Used by `minetest.register_node`.
climbable = false, -- If true, can be climbed on (ladder) climbable = false, -- If true, can be climbed on (ladder)
move_resistance = 0,
-- Slows down movement of players through this node (max. 7).
-- If this is nil, it will be equal to liquid_viscosity.
-- Note: If liquid movement physics apply to the node
-- (see `liquid_move_physics`), the movement speed will also be
-- affected by the `movement_liquid_*` settings.
buildable_to = false, -- If true, placed nodes can replace this node buildable_to = false, -- If true, placed nodes can replace this node
floodable = false, floodable = false,
-- If true, liquids flow into and replace this node. -- If true, liquids flow into and replace this node.
-- Warning: making a liquid node 'floodable' will cause problems. -- Warning: making a liquid node 'floodable' will cause problems.
liquidtype = "none", -- specifies liquid physics liquidtype = "none", -- specifies liquid flowing physics
-- * "none": no liquid physics -- * "none": no liquid flowing physics
-- * "source": spawns flowing liquid nodes at all 4 sides and below; -- * "source": spawns flowing liquid nodes at all 4 sides and below;
-- recommended drawtype: "liquid". -- recommended drawtype: "liquid".
-- * "flowing": spawned from source, spawns more flowing liquid nodes -- * "flowing": spawned from source, spawns more flowing liquid nodes
@ -7668,12 +7679,26 @@ Used by `minetest.register_node`.
liquid_alternative_source = "", -- Source version of flowing liquid liquid_alternative_source = "", -- Source version of flowing liquid
liquid_viscosity = 0, -- Higher viscosity = slower flow (max. 7) liquid_viscosity = 0,
-- Controls speed at which the liquid spreads/flows (max. 7).
-- 0 is fastest, 7 is slowest.
-- By default, this also slows down movement of players inside the node
-- (can be overridden using `move_resistance`)
liquid_renewable = true, liquid_renewable = true,
-- If true, a new liquid source can be created by placing two or more -- If true, a new liquid source can be created by placing two or more
-- sources nearby -- sources nearby
liquid_move_physics = nil, -- specifies movement physics if inside node
-- * false: No liquid movement physics apply.
-- * true: Enables liquid movement physics. Enables things like
-- ability to "swim" up/down, sinking slowly if not moving,
-- smoother speed change when falling into, etc. The `movement_liquid_*`
-- settings apply.
-- * nil: Will be treated as true if `liquidype ~= "none"`
-- and as false otherwise.
-- Default: nil
leveled = 0, leveled = 0,
-- Only valid for "nodebox" drawtype with 'type = "leveled"'. -- Only valid for "nodebox" drawtype with 'type = "leveled"'.
-- Allows defining the nodebox height without using param2. -- Allows defining the nodebox height without using param2.

@ -40,9 +40,11 @@ for d=0, 8 do
liquid_range = d, liquid_range = d,
}) })
if d <= 7 then
local mod = "^[colorize:#000000:127" local mod = "^[colorize:#000000:127"
minetest.register_node("testnodes:vliquid_"..d, { minetest.register_node("testnodes:vliquid_"..d, {
description = "Test Liquid Source, Viscosity "..d, description = "Test Liquid Source, Viscosity/Resistance "..d,
drawtype = "liquid", drawtype = "liquid",
tiles = {"testnodes_liquidsource_r"..d..".png"..mod}, tiles = {"testnodes_liquidsource_r"..d..".png"..mod},
special_tiles = { special_tiles = {
@ -61,7 +63,7 @@ for d=0, 8 do
}) })
minetest.register_node("testnodes:vliquid_flowing_"..d, { minetest.register_node("testnodes:vliquid_flowing_"..d, {
description = "Flowing Test Liquid, Viscosity "..d, description = "Flowing Test Liquid, Viscosity/Resistance "..d,
drawtype = "flowingliquid", drawtype = "flowingliquid",
tiles = {"testnodes_liquidflowing_r"..d..".png"..mod}, tiles = {"testnodes_liquidflowing_r"..d..".png"..mod},
special_tiles = { special_tiles = {
@ -80,4 +82,53 @@ for d=0, 8 do
liquid_viscosity = d, liquid_viscosity = d,
}) })
mod = "^[colorize:#000000:192"
local v = 4
minetest.register_node("testnodes:vrliquid_"..d, {
description = "Test Liquid Source, Viscosity "..v..", Resistance "..d,
drawtype = "liquid",
tiles = {"testnodes_liquidsource_r"..d..".png"..mod},
special_tiles = {
{name = "testnodes_liquidsource_r"..d..".png"..mod, backface_culling = false},
{name = "testnodes_liquidsource_r"..d..".png"..mod, backface_culling = true},
},
use_texture_alpha = "blend",
paramtype = "light",
walkable = false,
pointable = false,
diggable = false,
buildable_to = true,
is_ground_content = false,
liquidtype = "source",
liquid_alternative_flowing = "testnodes:vrliquid_flowing_"..d,
liquid_alternative_source = "testnodes:vrliquid_"..d,
liquid_viscosity = v,
move_resistance = d,
})
minetest.register_node("testnodes:vrliquid_flowing_"..d, {
description = "Flowing Test Liquid, Viscosity "..v..", Resistance "..d,
drawtype = "flowingliquid",
tiles = {"testnodes_liquidflowing_r"..d..".png"..mod},
special_tiles = {
{name = "testnodes_liquidflowing_r"..d..".png"..mod, backface_culling = false},
{name = "testnodes_liquidflowing_r"..d..".png"..mod, backface_culling = false},
},
use_texture_alpha = "blend",
paramtype = "light",
paramtype2 = "flowingliquid",
walkable = false,
pointable = false,
diggable = false,
buildable_to = true,
is_ground_content = false,
liquidtype = "flowing",
liquid_alternative_flowing = "testnodes:vrliquid_flowing_"..d,
liquid_alternative_source = "testnodes:vrliquid_"..d,
liquid_viscosity = v,
move_resistance = d,
})
end
end end

@ -152,6 +152,66 @@ minetest.register_node("testnodes:liquidflowing_nojump", {
post_effect_color = {a = 70, r = 255, g = 0, b = 200}, post_effect_color = {a = 70, r = 255, g = 0, b = 200},
}) })
-- A liquid which doesn't have liquid movement physics (source variant)
minetest.register_node("testnodes:liquid_noswim", {
description = S("No-swim Liquid Source Node"),
liquidtype = "source",
liquid_range = 1,
liquid_viscosity = 0,
liquid_alternative_flowing = "testnodes:liquidflowing_noswim",
liquid_alternative_source = "testnodes:liquid_noswim",
liquid_renewable = false,
liquid_move_physics = false,
groups = {dig_immediate=3},
walkable = false,
drawtype = "liquid",
tiles = {"testnodes_liquidsource.png^[colorize:#FF00FF:127"},
special_tiles = {
{name = "testnodes_liquidsource.png^[colorize:#FF00FF:127", backface_culling = false},
{name = "testnodes_liquidsource.png^[colorize:#FF00FF:127", backface_culling = true},
},
use_texture_alpha = "blend",
paramtype = "light",
pointable = false,
liquids_pointable = true,
buildable_to = true,
is_ground_content = false,
post_effect_color = {a = 70, r = 255, g = 200, b = 200},
})
-- A liquid which doen't have liquid movement physics (flowing variant)
minetest.register_node("testnodes:liquidflowing_noswim", {
description = S("No-swim Flowing Liquid Node"),
liquidtype = "flowing",
liquid_range = 1,
liquid_viscosity = 0,
liquid_alternative_flowing = "testnodes:liquidflowing_noswim",
liquid_alternative_source = "testnodes:liquid_noswim",
liquid_renewable = false,
liquid_move_physics = false,
groups = {dig_immediate=3},
walkable = false,
drawtype = "flowingliquid",
tiles = {"testnodes_liquidflowing.png^[colorize:#FF00FF:127"},
special_tiles = {
{name = "testnodes_liquidflowing.png^[colorize:#FF00FF:127", backface_culling = false},
{name = "testnodes_liquidflowing.png^[colorize:#FF00FF:127", backface_culling = false},
},
use_texture_alpha = "blend",
paramtype = "light",
paramtype2 = "flowingliquid",
pointable = false,
liquids_pointable = true,
buildable_to = true,
is_ground_content = false,
post_effect_color = {a = 70, r = 255, g = 200, b = 200},
})
-- Nodes that modify fall damage (various damage modifiers) -- Nodes that modify fall damage (various damage modifiers)
for i=-100, 100, 25 do for i=-100, 100, 25 do
if i ~= 0 then if i ~= 0 then
@ -216,6 +276,54 @@ for i=1, 5 do
}) })
end end
-- Move resistance nodes (various resistance levels)
for r=0, 7 do
if r > 0 then
minetest.register_node("testnodes:move_resistance"..r, {
description = S("Move-resistant Node (@1)", r),
walkable = false,
move_resistance = r,
drawtype = "glasslike",
paramtype = "light",
sunlight_propagates = true,
tiles = { "testnodes_move_resistance.png" },
is_ground_content = false,
groups = { dig_immediate = 3 },
color = { b = 0, g = 255, r = math.floor((r/7)*255), a = 255 },
})
end
minetest.register_node("testnodes:move_resistance_liquidlike"..r, {
description = S("Move-resistant Node, liquidlike (@1)", r),
walkable = false,
move_resistance = r,
liquid_move_physics = true,
drawtype = "glasslike",
paramtype = "light",
sunlight_propagates = true,
tiles = { "testnodes_move_resistance.png" },
is_ground_content = false,
groups = { dig_immediate = 3 },
color = { b = 255, g = 0, r = math.floor((r/7)*255), a = 255 },
})
end
minetest.register_node("testnodes:climbable_move_resistance_4", {
description = S("Climbable Move-resistant Node (4)"),
walkable = false,
climbable = true,
move_resistance = 4,
drawtype = "glasslike",
paramtype = "light",
sunlight_propagates = true,
tiles = {"testnodes_climbable_resistance_side.png"},
is_ground_content = false,
groups = { dig_immediate = 3 },
})
-- By placing something on the node, the node itself will be replaced -- By placing something on the node, the node itself will be replaced
minetest.register_node("testnodes:buildable_to", { minetest.register_node("testnodes:buildable_to", {
description = S("Replacable Node"), description = S("Replacable Node"),

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

@ -194,32 +194,41 @@ void ClientEnvironment::step(float dtime)
lplayer->applyControl(dtime_part, this); lplayer->applyControl(dtime_part, this);
// Apply physics // Apply physics
if (!free_move && !is_climbing) { if (!free_move) {
// Gravity // Gravity
v3f speed = lplayer->getSpeed(); v3f speed = lplayer->getSpeed();
if (!lplayer->in_liquid) if (!is_climbing && !lplayer->in_liquid)
speed.Y -= lplayer->movement_gravity * speed.Y -= lplayer->movement_gravity *
lplayer->physics_override_gravity * dtime_part * 2.0f; lplayer->physics_override_gravity * dtime_part * 2.0f;
// Liquid floating / sinking // Liquid floating / sinking
if (lplayer->in_liquid && !lplayer->swimming_vertical && if (!is_climbing && lplayer->in_liquid &&
!lplayer->swimming_vertical &&
!lplayer->swimming_pitch) !lplayer->swimming_pitch)
speed.Y -= lplayer->movement_liquid_sink * dtime_part * 2.0f; speed.Y -= lplayer->movement_liquid_sink * dtime_part * 2.0f;
// Liquid resistance // Movement resistance
if (lplayer->in_liquid_stable || lplayer->in_liquid) { if (lplayer->move_resistance > 0) {
// How much the node's viscosity blocks movement, ranges // How much the node's move_resistance blocks movement, ranges
// between 0 and 1. Should match the scale at which viscosity // between 0 and 1. Should match the scale at which liquid_viscosity
// increase affects other liquid attributes. // increase affects other liquid attributes.
static const f32 viscosity_factor = 0.3f; static const f32 resistance_factor = 0.3f;
v3f d_wanted = -speed / lplayer->movement_liquid_fluidity; v3f d_wanted;
bool in_liquid_stable = lplayer->in_liquid_stable || lplayer->in_liquid;
if (in_liquid_stable) {
d_wanted = -speed / lplayer->movement_liquid_fluidity;
} else {
d_wanted = -speed / BS;
}
f32 dl = d_wanted.getLength(); f32 dl = d_wanted.getLength();
if (dl > lplayer->movement_liquid_fluidity_smooth) if (in_liquid_stable) {
dl = lplayer->movement_liquid_fluidity_smooth; if (dl > lplayer->movement_liquid_fluidity_smooth)
dl = lplayer->movement_liquid_fluidity_smooth;
}
dl *= (lplayer->liquid_viscosity * viscosity_factor) + dl *= (lplayer->move_resistance * resistance_factor) +
(1 - viscosity_factor); (1 - resistance_factor);
v3f d = d_wanted.normalize() * (dl * dtime_part * 100.0f); v3f d = d_wanted.normalize() * (dl * dtime_part * 100.0f);
speed += d; speed += d;
} }

@ -227,8 +227,9 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
pp = floatToInt(position + v3f(0.0f, BS * 0.1f, 0.0f), BS); pp = floatToInt(position + v3f(0.0f, BS * 0.1f, 0.0f), BS);
node = map->getNode(pp, &is_valid_position); node = map->getNode(pp, &is_valid_position);
if (is_valid_position) { if (is_valid_position) {
in_liquid = nodemgr->get(node.getContent()).isLiquid(); const ContentFeatures &cf = nodemgr->get(node.getContent());
liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity; in_liquid = cf.liquid_move_physics;
move_resistance = cf.move_resistance;
} else { } else {
in_liquid = false; in_liquid = false;
} }
@ -238,8 +239,9 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
pp = floatToInt(position + v3f(0.0f, BS * 0.5f, 0.0f), BS); pp = floatToInt(position + v3f(0.0f, BS * 0.5f, 0.0f), BS);
node = map->getNode(pp, &is_valid_position); node = map->getNode(pp, &is_valid_position);
if (is_valid_position) { if (is_valid_position) {
in_liquid = nodemgr->get(node.getContent()).isLiquid(); const ContentFeatures &cf = nodemgr->get(node.getContent());
liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity; in_liquid = cf.liquid_move_physics;
move_resistance = cf.move_resistance;
} else { } else {
in_liquid = false; in_liquid = false;
} }
@ -252,7 +254,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
pp = floatToInt(position + v3f(0.0f), BS); pp = floatToInt(position + v3f(0.0f), BS);
node = map->getNode(pp, &is_valid_position); node = map->getNode(pp, &is_valid_position);
if (is_valid_position) { if (is_valid_position) {
in_liquid_stable = nodemgr->get(node.getContent()).isLiquid(); in_liquid_stable = nodemgr->get(node.getContent()).liquid_move_physics;
} else { } else {
in_liquid_stable = false; in_liquid_stable = false;
} }
@ -800,8 +802,9 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
pp = floatToInt(position + v3f(0.0f, BS * 0.1f, 0.0f), BS); pp = floatToInt(position + v3f(0.0f, BS * 0.1f, 0.0f), BS);
node = map->getNode(pp, &is_valid_position); node = map->getNode(pp, &is_valid_position);
if (is_valid_position) { if (is_valid_position) {
in_liquid = nodemgr->get(node.getContent()).isLiquid(); const ContentFeatures &cf = nodemgr->get(node.getContent());
liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity; in_liquid = cf.liquid_move_physics;
move_resistance = cf.move_resistance;
} else { } else {
in_liquid = false; in_liquid = false;
} }
@ -810,8 +813,9 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
pp = floatToInt(position + v3f(0.0f, BS * 0.5f, 0.0f), BS); pp = floatToInt(position + v3f(0.0f, BS * 0.5f, 0.0f), BS);
node = map->getNode(pp, &is_valid_position); node = map->getNode(pp, &is_valid_position);
if (is_valid_position) { if (is_valid_position) {
in_liquid = nodemgr->get(node.getContent()).isLiquid(); const ContentFeatures &cf = nodemgr->get(node.getContent());
liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity; in_liquid = cf.liquid_move_physics;
move_resistance = cf.move_resistance;
} else { } else {
in_liquid = false; in_liquid = false;
} }
@ -823,7 +827,7 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
pp = floatToInt(position + v3f(0.0f), BS); pp = floatToInt(position + v3f(0.0f), BS);
node = map->getNode(pp, &is_valid_position); node = map->getNode(pp, &is_valid_position);
if (is_valid_position) if (is_valid_position)
in_liquid_stable = nodemgr->get(node.getContent()).isLiquid(); in_liquid_stable = nodemgr->get(node.getContent()).liquid_move_physics;
else else
in_liquid_stable = false; in_liquid_stable = false;

@ -55,8 +55,8 @@ public:
bool in_liquid = false; bool in_liquid = false;
// This is more stable and defines the maximum speed of the player // This is more stable and defines the maximum speed of the player
bool in_liquid_stable = false; bool in_liquid_stable = false;
// Gets the viscosity of water to calculate friction // Slows down the player when moving through
u8 liquid_viscosity = 0; u8 move_resistance = 0;
bool is_climbing = false; bool is_climbing = false;
bool swimming_vertical = false; bool swimming_vertical = false;
bool swimming_pitch = false; bool swimming_pitch = false;

@ -403,6 +403,8 @@ void ContentFeatures::reset()
palette_name = ""; palette_name = "";
palette = NULL; palette = NULL;
node_dig_prediction = "air"; node_dig_prediction = "air";
move_resistance = 0;
liquid_move_physics = false;
} }
void ContentFeatures::setAlphaFromLegacy(u8 legacy_alpha) void ContentFeatures::setAlphaFromLegacy(u8 legacy_alpha)
@ -512,9 +514,12 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
writeU8(os, legacy_facedir_simple); writeU8(os, legacy_facedir_simple);
writeU8(os, legacy_wallmounted); writeU8(os, legacy_wallmounted);
// new attributes
os << serializeString16(node_dig_prediction); os << serializeString16(node_dig_prediction);
writeU8(os, leveled_max); writeU8(os, leveled_max);
writeU8(os, alpha); writeU8(os, alpha);
writeU8(os, move_resistance);
writeU8(os, liquid_move_physics);
} }
void ContentFeatures::deSerialize(std::istream &is) void ContentFeatures::deSerialize(std::istream &is)
@ -584,9 +589,11 @@ void ContentFeatures::deSerialize(std::istream &is)
// liquid // liquid
liquid_type = (enum LiquidType) readU8(is); liquid_type = (enum LiquidType) readU8(is);
liquid_move_physics = liquid_type != LIQUID_NONE;
liquid_alternative_flowing = deSerializeString16(is); liquid_alternative_flowing = deSerializeString16(is);
liquid_alternative_source = deSerializeString16(is); liquid_alternative_source = deSerializeString16(is);
liquid_viscosity = readU8(is); liquid_viscosity = readU8(is);
move_resistance = liquid_viscosity; // set default move_resistance
liquid_renewable = readU8(is); liquid_renewable = readU8(is);
liquid_range = readU8(is); liquid_range = readU8(is);
drowning = readU8(is); drowning = readU8(is);
@ -618,6 +625,16 @@ void ContentFeatures::deSerialize(std::istream &is)
if (is.eof()) if (is.eof())
throw SerializationError(""); throw SerializationError("");
alpha = static_cast<enum AlphaMode>(tmp); alpha = static_cast<enum AlphaMode>(tmp);
tmp = readU8(is);
if (is.eof())
throw SerializationError("");
move_resistance = tmp;
tmp = readU8(is);
if (is.eof())
throw SerializationError("");
liquid_move_physics = tmp;
} catch(SerializationError &e) {}; } catch(SerializationError &e) {};
} }

@ -376,11 +376,15 @@ struct ContentFeatures
u32 damage_per_second; u32 damage_per_second;
// client dig prediction // client dig prediction
std::string node_dig_prediction; std::string node_dig_prediction;
// how slow players move through
u8 move_resistance = 0;
// --- LIQUID PROPERTIES --- // --- LIQUID PROPERTIES ---
// Whether the node is non-liquid, source liquid or flowing liquid // Whether the node is non-liquid, source liquid or flowing liquid
enum LiquidType liquid_type; enum LiquidType liquid_type;
// If true, movement (e.g. of players) inside this node is liquid-like.
bool liquid_move_physics;
// If the content is liquid, this is the flowing version of the liquid. // If the content is liquid, this is the flowing version of the liquid.
std::string liquid_alternative_flowing; std::string liquid_alternative_flowing;
content_t liquid_alternative_flowing_id; content_t liquid_alternative_flowing_id;

@ -719,6 +719,9 @@ void read_content_features(lua_State *L, ContentFeatures &f, int index)
// the slowest possible // the slowest possible
f.liquid_viscosity = getintfield_default(L, index, f.liquid_viscosity = getintfield_default(L, index,
"liquid_viscosity", f.liquid_viscosity); "liquid_viscosity", f.liquid_viscosity);
// If move_resistance is not set explicitly,
// move_resistance is equal to liquid_viscosity
f.move_resistance = f.liquid_viscosity;
f.liquid_range = getintfield_default(L, index, f.liquid_range = getintfield_default(L, index,
"liquid_range", f.liquid_range); "liquid_range", f.liquid_range);
f.leveled = getintfield_default(L, index, "leveled", f.leveled); f.leveled = getintfield_default(L, index, "leveled", f.leveled);
@ -822,6 +825,21 @@ void read_content_features(lua_State *L, ContentFeatures &f, int index)
getstringfield(L, index, "node_dig_prediction", getstringfield(L, index, "node_dig_prediction",
f.node_dig_prediction); f.node_dig_prediction);
// How much the node slows down players, ranging from 1 to 7,
// the higher, the slower.
f.move_resistance = getintfield_default(L, index,
"move_resistance", f.move_resistance);
// Whether e.g. players in this node will have liquid movement physics
lua_getfield(L, index, "liquid_move_physics");
if(lua_isboolean(L, -1)) {
f.liquid_move_physics = lua_toboolean(L, -1);
} else if(lua_isnil(L, -1)) {
f.liquid_move_physics = f.liquid_type != LIQUID_NONE;
} else {
errorstream << "Field \"liquid_move_physics\": Invalid type!" << std::endl;
}
lua_pop(L, 1);
} }
void push_content_features(lua_State *L, const ContentFeatures &c) void push_content_features(lua_State *L, const ContentFeatures &c)
@ -949,6 +967,10 @@ void push_content_features(lua_State *L, const ContentFeatures &c)
lua_setfield(L, -2, "legacy_wallmounted"); lua_setfield(L, -2, "legacy_wallmounted");
lua_pushstring(L, c.node_dig_prediction.c_str()); lua_pushstring(L, c.node_dig_prediction.c_str());
lua_setfield(L, -2, "node_dig_prediction"); lua_setfield(L, -2, "node_dig_prediction");
lua_pushnumber(L, c.move_resistance);
lua_setfield(L, -2, "move_resistance");
lua_pushboolean(L, c.liquid_move_physics);
lua_setfield(L, -2, "liquid_move_physics");
} }
/******************************************************************************/ /******************************************************************************/

@ -53,6 +53,7 @@ public:
static struct EnumString es_ContentParamType[]; static struct EnumString es_ContentParamType[];
static struct EnumString es_ContentParamType2[]; static struct EnumString es_ContentParamType2[];
static struct EnumString es_LiquidType[]; static struct EnumString es_LiquidType[];
static struct EnumString es_LiquidMoveType[];
static struct EnumString es_NodeBoxType[]; static struct EnumString es_NodeBoxType[];
static struct EnumString es_TextureAlphaMode[]; static struct EnumString es_TextureAlphaMode[];
}; };

@ -128,11 +128,11 @@ int LuaLocalPlayer::l_is_in_liquid_stable(lua_State *L)
return 1; return 1;
} }
int LuaLocalPlayer::l_get_liquid_viscosity(lua_State *L) int LuaLocalPlayer::l_get_move_resistance(lua_State *L)
{ {
LocalPlayer *player = getobject(L, 1); LocalPlayer *player = getobject(L, 1);
lua_pushinteger(L, player->liquid_viscosity); lua_pushinteger(L, player->move_resistance);
return 1; return 1;
} }
@ -466,7 +466,6 @@ const luaL_Reg LuaLocalPlayer::methods[] = {
luamethod(LuaLocalPlayer, is_touching_ground), luamethod(LuaLocalPlayer, is_touching_ground),
luamethod(LuaLocalPlayer, is_in_liquid), luamethod(LuaLocalPlayer, is_in_liquid),
luamethod(LuaLocalPlayer, is_in_liquid_stable), luamethod(LuaLocalPlayer, is_in_liquid_stable),
luamethod(LuaLocalPlayer, get_liquid_viscosity),
luamethod(LuaLocalPlayer, is_climbing), luamethod(LuaLocalPlayer, is_climbing),
luamethod(LuaLocalPlayer, swimming_vertical), luamethod(LuaLocalPlayer, swimming_vertical),
luamethod(LuaLocalPlayer, get_physics_override), luamethod(LuaLocalPlayer, get_physics_override),
@ -488,5 +487,7 @@ const luaL_Reg LuaLocalPlayer::methods[] = {
luamethod(LuaLocalPlayer, hud_change), luamethod(LuaLocalPlayer, hud_change),
luamethod(LuaLocalPlayer, hud_get), luamethod(LuaLocalPlayer, hud_get),
luamethod(LuaLocalPlayer, get_move_resistance),
{0, 0} {0, 0}
}; };

@ -51,7 +51,6 @@ private:
static int l_is_touching_ground(lua_State *L); static int l_is_touching_ground(lua_State *L);
static int l_is_in_liquid(lua_State *L); static int l_is_in_liquid(lua_State *L);
static int l_is_in_liquid_stable(lua_State *L); static int l_is_in_liquid_stable(lua_State *L);
static int l_get_liquid_viscosity(lua_State *L);
static int l_is_climbing(lua_State *L); static int l_is_climbing(lua_State *L);
static int l_swimming_vertical(lua_State *L); static int l_swimming_vertical(lua_State *L);
@ -96,6 +95,8 @@ private:
// hud_get(self, id) // hud_get(self, id)
static int l_hud_get(lua_State *L); static int l_hud_get(lua_State *L);
static int l_get_move_resistance(lua_State *L);
LocalPlayer *m_localplayer = nullptr; LocalPlayer *m_localplayer = nullptr;
public: public: