Skip to content
2 changes: 2 additions & 0 deletions doc/client_lua_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,8 @@ Methods:
liquid_sink = float,
sneak = boolean,
sneak_glitch = boolean,
upward_rejump = boolean,
loose_lips = boolean,
new_move = boolean,
}
```
Expand Down
3 changes: 3 additions & 0 deletions doc/lua_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -8825,6 +8825,9 @@ child will follow movement and rotation of that bone.
* `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`)
* `upward_rejump`: legacy ability to jump again while contacting a jumpable surface mid-jump
(default: `false`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

based on the code, isn't the default true (which it should be for backwards compatibility)? same for loose_lips

i'd also just remove the word "legacy" here. it suggests some sort of deprecation which is not the case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure author intends deprecation, that's why I (and others) dislike this PR so much.

In other words, before we ask ourselves whether or not we could, we should ask ourselves whether or not we should. Because this PR looks like cargoculting MC physics to me.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well, there are two ways this PR can go:

  1. add a new option. not terribly much friction. games that want very MC-like physics (@ryvnf would you like this?) can have it. other games stay as they are. nothing breaks.
  2. try to force everyone into the new option by default. users will notice (and might avoid upgrading to not suffer annoyance in PvP), modders will notice (and be forced to update their mods), maybe some parkours and such will suffer if not break. i doubt that there is a compelling argument that this disruption must be and that MC's arbitrary decisions for "less floaty" movement physics are the way they "must" be.

so simply put, i agree with you that (2) is not really an option.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@appgurueu regarding Mineclonia we have gotten one bug report about being able to jump over fences. There could be another one but that is what I could find. My impression is that people do not mind it that much. They mostly think it is weird and some find it convenient. Currently we have a policy of not trying to replicate MC physics because that is not feasible to do consistently.

One of our collaborators also created the mcl_localplayer clientmod which replicates MC physics among other things (requires special engine support). It feels like the long term solution for player physics is to make it customizable like that using SSCSM.

I am personally indifferent to this PR. I would mostly like a future SSCSM API were we could incorporate logic like the player physics from mcl_localplayer into the base game.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Thank you for your feedback. I will look at that clientmod.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not want this to feel like Minecraft. I just want jumping over ledges to feel intentional and not like there's some glitch that rapidly snaps you to the top. I like the physics for the most part, which is why I left the step-up when going down or sideways completely intact. Being able to cross over gaps is awesome.

I would very much like for this to be the default. I know changes get on people's nerves and I have no sway in this community though. My making this PR without asking if "most people" like it was rude on my part, and I deserve the flack I'm getting for that. But I think "most people" at best is the people that stick around after experiencing the jump jank.

Luanti has a lot to offer with regards to the tons of creative content and games that I very much enjoy. That's what makes it worth sticking around. And I am trying my best to make sure these games aren't unplayable and actually feel better. But if I'm just digging myself a grave over it, I'd rather just leave it up to a vote or something. To me, this is sneak glitch territory: not intended, not good, but some people like it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd also like people to try the physics before making assumptions. I know that's a lot, but I've been accused in bad faith of cargo culting for Minecraft, which makes me think people aren't reading or trying it out in-game. I've been playing on parkour maps where the physics very much DO make a difference (like Glitch), and the changes don't break anything so far. I think the fear of disruption and pushback is getting in the way of making any progress.

Copy link
Author

@AbbyRead AbbyRead Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@appgurueu regarding Mineclonia we have gotten one bug report about being able to jump over fences.

I just want to be clear, with or without this modification, fences remain jumpable. I don't want Luanti to be Minecraft. I just want it to not feel broken, unpolished, and unloved. Minecraft went down a road of useless additions, piling on bloat and breaking pretty much every mod with every new version.

I'm trying to say that I'm with you guys on not wanting to upset the community and break games. At the same time though, many games on ContentDB start out broken and remain unfinished. If this is only ever going to be an optional improvement, most creators won't even be aware it's an available improvement.

* `loose_lips`: legacy step-up while jumping into the corner of a node (default: `false`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think loose_lips is very unclear. I would prefer calling it ledge_stepup or ledge_step_up if this PR is to be merged.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't figure out a good name, but thanks for that. That's much better.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'm gonna go with upward_step since that's the only thing changing about it.

* `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.
Expand Down
8 changes: 5 additions & 3 deletions src/client/content_cao.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1581,9 +1581,11 @@ void GenericCAO::processMessage(const std::string &data)
phys.gravity = readF32(is);

// MT 0.4.10 legacy: send inverted for detault `true` if the server sends nothing
phys.sneak = !readU8(is);
phys.sneak_glitch = !readU8(is);
phys.new_move = !readU8(is);
phys.sneak = !readU8(is);
phys.sneak_glitch = !readU8(is);
phys.upward_rejump = !readU8(is);
phys.loose_lips = !readU8(is);
phys.new_move = !readU8(is);

// new overrides since 5.8.0
if (canRead(is)) {
Expand Down
17 changes: 14 additions & 3 deletions src/client/localplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,19 @@ void LocalPlayer::move(f32 dtime, Environment *env,

// Player object property step height is multiplied by BS in
// /src/script/common/c_content.cpp and /src/content_sao.cpp
float player_stepheight = (m_cao == nullptr) ? 0.0f :
(touching_ground ? m_cao->getStepHeight() : (0.2f * BS));
float player_stepheight = 0.0f;
if (m_cao != nullptr) {

const bool rising = m_speed.Y > 0.01f * BS;
const bool loose = physics_override.loose_lips;

const float snap_height =
(rising && !loose ? 0.05f : 0.2f) * BS;

player_stepheight = touching_ground
? m_cao->getStepHeight()
: snap_height;
}

v3f accel_f(0, -gravity, 0);
const v3f initial_position = position;
Expand Down Expand Up @@ -658,7 +669,7 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
at its starting value
*/
v3f speedJ = getSpeed();
if (speedJ.Y >= -0.5f * BS) {
if (speedJ.Y >= -0.5f * BS && (physics_override.upward_rejump || speedJ.Y <= 0.0f * BS)) {
speedJ.Y = movement_speed_jump * physics_override.jump;
setSpeed(speedJ);
m_client->getEventManager()->put(new SimpleTriggerEvent(MtEvent::PLAYER_JUMP));
Expand Down
2 changes: 1 addition & 1 deletion src/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ static auto tie(const PlayerPhysicsOverride &o)
{
// Make sure to add new members to this list!
return std::tie(
o.speed, o.jump, o.gravity, o.sneak, o.sneak_glitch, o.new_move, o.speed_climb,
o.speed, o.jump, o.gravity, o.sneak, o.sneak_glitch, o.upward_rejump, o.loose_lips, o.new_move, o.speed_climb,
o.speed_crouch, o.liquid_fluidity, o.liquid_fluidity_smooth, o.liquid_sink,
o.acceleration_default, o.acceleration_air, o.speed_fast, o.acceleration_fast,
o.speed_walk
Expand Down
2 changes: 2 additions & 0 deletions src/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ struct PlayerPhysicsOverride

bool sneak = true;
bool sneak_glitch = false;
bool upward_rejump = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be true too?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thoughts on upward rejump is that you end up accidentally jumping again just by trying to hold jump the first time. Seems like a bug to me.

bool loose_lips = false;
// "Temporary" option for old move code
bool new_move = true;

Expand Down
6 changes: 6 additions & 0 deletions src/script/lua_api/l_localplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@ int LuaLocalPlayer::l_get_physics_override(lua_State *L)
lua_pushboolean(L, phys.sneak_glitch);
lua_setfield(L, -2, "sneak_glitch");

lua_pushboolean(L, phys.upward_rejump);
lua_setfield(L, -2, "upward_rejump");

lua_pushboolean(L, phys.loose_lips);
lua_setfield(L, -2, "loose_lips");

lua_pushboolean(L, phys.new_move);
lua_setfield(L, -2, "new_move");

Expand Down
2 changes: 2 additions & 0 deletions src/script/lua_api/l_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1744,6 +1744,8 @@ int ObjectRef::l_set_physics_override(lua_State *L)
getfloatfield(L, 2, "gravity", phys.gravity);
getboolfield(L, 2, "sneak", phys.sneak);
getboolfield(L, 2, "sneak_glitch", phys.sneak_glitch);
getboolfield(L, 2, "upward_rejump", phys.upward_rejump);
getboolfield(L, 2, "loose_lips", phys.loose_lips);
getboolfield(L, 2, "new_move", phys.new_move);
getfloatfield(L, 2, "speed_climb", phys.speed_climb);
getfloatfield(L, 2, "speed_crouch", phys.speed_crouch);
Expand Down
2 changes: 2 additions & 0 deletions src/server/player_sao.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,8 @@ std::string PlayerSAO::generateUpdatePhysicsOverrideCommand() const
// MT 0.4.10 legacy: send inverted for detault `true` if the server sends nothing
writeU8(os, !phys.sneak);
writeU8(os, !phys.sneak_glitch);
writeU8(os, !phys.upward_rejump);
writeU8(os, !phys.loose_lips);
writeU8(os, !phys.new_move);
// new physics overrides since 5.8.0
writeF32(os, phys.speed_climb);
Expand Down
Loading