From 8ebaf753d3c6b50028d097db924a887d98602c18 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 15 Sep 2023 20:10:08 +0200 Subject: [PATCH] New physics overrides (#11465) --- doc/lua_api.md | 30 +++++++++++++++++++++++++- src/client/clientenvironment.cpp | 22 ++++++++++--------- src/client/content_cao.cpp | 24 +++++++++++++++++++++ src/client/localplayer.cpp | 12 +++++------ src/player.h | 8 +++++++ src/script/lua_api/l_localplayer.cpp | 21 ++++++++++++++++++ src/script/lua_api/l_object.cpp | 21 ++++++++++++++++++ src/server/player_sao.cpp | 32 +++++++++++++++++++++++----- 8 files changed, 148 insertions(+), 22 deletions(-) diff --git a/doc/lua_api.md b/doc/lua_api.md index be187bbd7..e93cddba9 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -7693,16 +7693,44 @@ child will follow movement and rotation of that bone. * 9 - zoom * Returns `0` (no bits set) if the object is not a player. * `set_physics_override(override_table)` + * Overrides the physics attributes of the player * `override_table` is a table with the following fields: - * `speed`: multiplier to default walking speed value (default: `1`) + * `speed`: multiplier to default movement speed and acceleration values (default: `1`) * `jump`: multiplier to default jump value (default: `1`) * `gravity`: multiplier to default gravity value (default: `1`) + * `speed_climb`: multiplier to default climb speed value (default: `1`) + * Note: The actual climb speed is the product of `speed` and `speed_climb` + * `speed_crouch`: multiplier to default sneak speed value (default: `1`) + * Note: The actual sneak speed is the product of `speed` and `speed_crouch` + * `liquid_fluidity`: multiplier to liquid movement resistance value + (for nodes with `liquid_move_physics`); the higher this value, the lower the + resistance to movement. At `math.huge`, the resistance is zero and you can + move through any liquid like air. (default: `1`) + * Warning: Values below 1 are currently unsupported. + * `liquid_fluidity_smooth`: multiplier to default maximum liquid resistance value + (for nodes with `liquid_move_physics`); controls deceleration when entering + node at high speed. At higher values you come to a halt more quickly + (default: `1`) + * `liquid_sink`: multiplier to default liquid sinking speed value; + (for nodes with `liquid_move_physics`) (default: `1`) + * `acceleration_default`: multiplier to horizontal and vertical acceleration + on ground or when climbing (default: `1`) + * Note: The actual acceleration is the product of `speed` and `acceleration_default` + * `acceleration_air`: multiplier to acceleration + when jumping or falling (default: `1`) + * Note: The actual acceleration is the product of `speed` and `acceleration_air` * `sneak`: whether player can sneak (default: `true`) * `sneak_glitch`: whether player can use the new move code replications of the old sneak side-effects: sneak ladders and 2 node sneak jump (default: `false`) * `new_move`: use new move/sneak code. When `false` the exact old code is used for the specific old sneak behavior (default: `true`) + * Note: All numeric fields above modify a corresponding `movement_*` setting. + * For games, we recommend for simpler code to first modify the `movement_*` + settings (e.g. via the game's `minetest.conf`) to set a global base value + for all players and only use `set_physics_override` when you need to change + from the base value on a per-player basis + * `get_physics_override()`: returns the table given to `set_physics_override` * `hud_add(hud definition)`: add a HUD element described by HUD def, returns ID number on success diff --git a/src/client/clientenvironment.cpp b/src/client/clientenvironment.cpp index d71b0ec33..633a2896c 100644 --- a/src/client/clientenvironment.cpp +++ b/src/client/clientenvironment.cpp @@ -208,7 +208,7 @@ void ClientEnvironment::step(float dtime) !lplayer->swimming_vertical && !lplayer->swimming_pitch) // HACK the factor 2 for gravity is arbitrary and should be removed eventually - lplayer->gravity = 2 * lplayer->movement_liquid_sink; + lplayer->gravity = 2 * lplayer->movement_liquid_sink * lplayer->physics_override.liquid_sink; // Movement resistance if (lplayer->move_resistance > 0) { @@ -218,20 +218,22 @@ void ClientEnvironment::step(float dtime) // between 0 and 1. Should match the scale at which liquid_viscosity // increase affects other liquid attributes. static const f32 resistance_factor = 0.3f; + float fluidity = lplayer->movement_liquid_fluidity; + fluidity *= MYMAX(1.0f, lplayer->physics_override.liquid_fluidity); + fluidity = MYMAX(0.001f, fluidity); // prevent division by 0 + float fluidity_smooth = lplayer->movement_liquid_fluidity_smooth; + fluidity_smooth *= lplayer->physics_override.liquid_fluidity_smooth; + fluidity_smooth = MYMAX(0.0f, fluidity_smooth); 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 { + if (in_liquid_stable) + d_wanted = -speed / fluidity; + else d_wanted = -speed / BS; - } f32 dl = d_wanted.getLength(); - if (in_liquid_stable) { - if (dl > lplayer->movement_liquid_fluidity_smooth) - dl = lplayer->movement_liquid_fluidity_smooth; - } - + if (in_liquid_stable) + dl = MYMIN(dl, fluidity_smooth); dl *= (lplayer->move_resistance * resistance_factor) + (1 - resistance_factor); v3f d = d_wanted.normalize() * (dl * dtime_part * 100.0f); diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index eb166806b..a38445dc4 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -1775,6 +1775,23 @@ void GenericCAO::processMessage(const std::string &data) bool sneak_glitch = !readU8(is); bool new_move = !readU8(is); + float override_speed_climb = readF32(is); + float override_speed_crouch = readF32(is); + float override_liquid_fluidity = readF32(is); + float override_liquid_fluidity_smooth = readF32(is); + float override_liquid_sink = readF32(is); + float override_acceleration_default = readF32(is); + float override_acceleration_air = readF32(is); + // fallback for new overrides (since 5.8.0) + if (is.eof()) { + override_speed_climb = 1.0f; + override_speed_crouch = 1.0f; + override_liquid_fluidity = 1.0f; + override_liquid_fluidity_smooth = 1.0f; + override_liquid_sink = 1.0f; + override_acceleration_default = 1.0f; + override_acceleration_air = 1.0f; + } if (m_is_local_player) { auto &phys = m_env->getLocalPlayer()->physics_override; @@ -1784,6 +1801,13 @@ void GenericCAO::processMessage(const std::string &data) phys.sneak = sneak; phys.sneak_glitch = sneak_glitch; phys.new_move = new_move; + phys.speed_climb = override_speed_climb; + phys.speed_crouch = override_speed_crouch; + phys.liquid_fluidity = override_liquid_fluidity; + phys.liquid_fluidity_smooth = override_liquid_fluidity_smooth; + phys.liquid_sink = override_liquid_sink; + phys.acceleration_default = override_acceleration_default; + phys.acceleration_air = override_acceleration_air; } } else if (cmd == AO_CMD_SET_ANIMATION) { // TODO: change frames send as v2s32 value diff --git a/src/client/localplayer.cpp b/src/client/localplayer.cpp index a7bcc9689..6e5458c8a 100644 --- a/src/client/localplayer.cpp +++ b/src/client/localplayer.cpp @@ -557,7 +557,7 @@ void LocalPlayer::applyControl(float dtime, Environment *env) speedV.Y = -movement_speed_walk; swimming_vertical = true; } else if (is_climbing && !m_disable_descend) { - speedV.Y = -movement_speed_climb; + speedV.Y = -movement_speed_climb * physics_override.speed_climb; } else { // If not free movement but fast is allowed, aux1 is // "Turbo button" @@ -595,7 +595,7 @@ void LocalPlayer::applyControl(float dtime, Environment *env) if (fast_climb) speedV.Y = -movement_speed_fast; else - speedV.Y = -movement_speed_climb; + speedV.Y = -movement_speed_climb * physics_override.speed_climb; } } } @@ -647,7 +647,7 @@ void LocalPlayer::applyControl(float dtime, Environment *env) if (fast_climb) speedV.Y = movement_speed_fast; else - speedV.Y = movement_speed_climb; + speedV.Y = movement_speed_climb * physics_override.speed_climb; } } @@ -656,7 +656,7 @@ void LocalPlayer::applyControl(float dtime, Environment *env) ((in_liquid || in_liquid_stable) && fast_climb)) speedH = speedH.normalize() * movement_speed_fast; else if (control.sneak && !free_move && !in_liquid && !in_liquid_stable) - speedH = speedH.normalize() * movement_speed_crouch; + speedH = speedH.normalize() * movement_speed_crouch * physics_override.speed_crouch; else speedH = speedH.normalize() * movement_speed_walk; @@ -671,13 +671,13 @@ void LocalPlayer::applyControl(float dtime, Environment *env) if (superspeed || (fast_move && control.aux1)) incH = movement_acceleration_fast * BS * dtime; else - incH = movement_acceleration_air * BS * dtime; + incH = movement_acceleration_air * physics_override.acceleration_air * BS * dtime; incV = 0.0f; // No vertical acceleration in air } else if (superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb)) { incH = incV = movement_acceleration_fast * BS * dtime; } else { - incH = incV = movement_acceleration_default * BS * dtime; + incH = incV = movement_acceleration_default * physics_override.acceleration_default * BS * dtime; } float slip_factor = 1.0f; diff --git a/src/player.h b/src/player.h index 9fdaf6ff5..1a59a17ce 100644 --- a/src/player.h +++ b/src/player.h @@ -106,6 +106,14 @@ struct PlayerPhysicsOverride bool sneak_glitch = false; // "Temporary" option for old move code bool new_move = true; + + float speed_climb = 1.f; + float speed_crouch = 1.f; + float liquid_fluidity = 1.f; + float liquid_fluidity_smooth = 1.f; + float liquid_sink = 1.f; + float acceleration_default = 1.f; + float acceleration_air = 1.f; }; struct PlayerSettings diff --git a/src/script/lua_api/l_localplayer.cpp b/src/script/lua_api/l_localplayer.cpp index ff9c61f53..42ca2e0c2 100644 --- a/src/script/lua_api/l_localplayer.cpp +++ b/src/script/lua_api/l_localplayer.cpp @@ -177,6 +177,27 @@ int LuaLocalPlayer::l_get_physics_override(lua_State *L) lua_pushboolean(L, phys.new_move); lua_setfield(L, -2, "new_move"); + lua_pushnumber(L, phys.speed_climb); + lua_setfield(L, -2, "speed_climb"); + + lua_pushnumber(L, phys.speed_crouch); + lua_setfield(L, -2, "speed_crouch"); + + lua_pushnumber(L, phys.liquid_fluidity); + lua_setfield(L, -2, "liquid_fluidity"); + + lua_pushnumber(L, phys.liquid_fluidity_smooth); + lua_setfield(L, -2, "liquid_fluidity_smooth"); + + lua_pushnumber(L, phys.liquid_sink); + lua_setfield(L, -2, "liquid_sink"); + + lua_pushnumber(L, phys.acceleration_default); + lua_setfield(L, -2, "acceleration_default"); + + lua_pushnumber(L, phys.acceleration_air); + lua_setfield(L, -2, "acceleration_air"); + return 1; } diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 08140f3bc..684a55dc4 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -1435,6 +1435,13 @@ int ObjectRef::l_set_physics_override(lua_State *L) modified |= getboolfield(L, 2, "sneak", phys.sneak); modified |= getboolfield(L, 2, "sneak_glitch", phys.sneak_glitch); modified |= getboolfield(L, 2, "new_move", phys.new_move); + modified |= getfloatfield(L, 2, "speed_climb", phys.speed_climb); + modified |= getfloatfield(L, 2, "speed_crouch", phys.speed_crouch); + modified |= getfloatfield(L, 2, "liquid_fluidity", phys.liquid_fluidity); + modified |= getfloatfield(L, 2, "liquid_fluidity_smooth", phys.liquid_fluidity_smooth); + modified |= getfloatfield(L, 2, "liquid_sink", phys.liquid_sink); + modified |= getfloatfield(L, 2, "acceleration_default", phys.acceleration_default); + modified |= getfloatfield(L, 2, "acceleration_air", phys.acceleration_air); if (modified) playersao->m_physics_override_sent = false; } else { @@ -1481,6 +1488,20 @@ int ObjectRef::l_get_physics_override(lua_State *L) lua_setfield(L, -2, "sneak_glitch"); lua_pushboolean(L, phys.new_move); lua_setfield(L, -2, "new_move"); + lua_pushnumber(L, phys.speed_climb); + lua_setfield(L, -2, "speed_climb"); + lua_pushnumber(L, phys.speed_crouch); + lua_setfield(L, -2, "speed_crouch"); + lua_pushnumber(L, phys.liquid_fluidity); + lua_setfield(L, -2, "liquid_fluidity"); + lua_pushnumber(L, phys.liquid_fluidity_smooth); + lua_setfield(L, -2, "liquid_fluidity_smooth"); + lua_pushnumber(L, phys.liquid_sink); + lua_setfield(L, -2, "liquid_sink"); + lua_pushnumber(L, phys.acceleration_default); + lua_setfield(L, -2, "acceleration_default"); + lua_pushnumber(L, phys.acceleration_air); + lua_setfield(L, -2, "acceleration_air"); return 1; } diff --git a/src/server/player_sao.cpp b/src/server/player_sao.cpp index ca56d3667..0b8113c01 100644 --- a/src/server/player_sao.cpp +++ b/src/server/player_sao.cpp @@ -325,6 +325,14 @@ std::string PlayerSAO::generateUpdatePhysicsOverrideCommand() const writeU8(os, !phys.sneak); writeU8(os, !phys.sneak_glitch); writeU8(os, !phys.new_move); + // new physics overrides since 5.8.0 + writeF32(os, phys.speed_climb); + writeF32(os, phys.speed_crouch); + writeF32(os, phys.liquid_fluidity); + writeF32(os, phys.liquid_fluidity_smooth); + writeF32(os, phys.liquid_sink); + writeF32(os, phys.acceleration_default); + writeF32(os, phys.acceleration_air); return os.str(); } @@ -609,17 +617,31 @@ bool PlayerSAO::checkMovementCheat() float player_max_walk = 0; // horizontal movement float player_max_jump = 0; // vertical upwards movement - if (m_privs.count("fast") != 0) - player_max_walk = m_player->movement_speed_fast; // Fast speed - else - player_max_walk = m_player->movement_speed_walk; // Normal speed - player_max_walk *= m_player->physics_override.speed; + float speed_walk = m_player->movement_speed_walk * m_player->physics_override.speed; + float speed_fast = m_player->movement_speed_fast; + float speed_crouch = m_player->movement_speed_crouch * m_player->physics_override.speed_crouch; + + // Get permissible max. speed + if (m_privs.count("fast") != 0) { + // Fast priv: Get the highest speed of fast, walk or crouch + // (it is not forbidden the 'fast' speed is + // not actually the fastest) + player_max_walk = MYMAX(speed_crouch, speed_fast); + player_max_walk = MYMAX(player_max_walk, speed_walk); + } else { + // Get the highest speed of walk or crouch + // (it is not forbidden the 'walk' speed is + // lower than the crouch speed) + player_max_walk = MYMAX(speed_crouch, speed_walk); + } + player_max_walk = MYMAX(player_max_walk, override_max_H); player_max_jump = m_player->movement_speed_jump * m_player->physics_override.jump; // FIXME: Bouncy nodes cause practically unbound increase in Y speed, // until this can be verified correctly, tolerate higher jumping speeds player_max_jump *= 2.0; + player_max_jump = MYMAX(player_max_jump, m_player->movement_speed_climb * m_player->physics_override.speed_climb); player_max_jump = MYMAX(player_max_jump, override_max_V); // Don't divide by zero!