From 93bccb349080b0b184cdda9e7ab4a364664efe70 Mon Sep 17 00:00:00 2001 From: Ben Deutsch Date: Thu, 22 Nov 2018 22:47:15 +0100 Subject: Client-side autojump. Remove Android-only stepheight autojump (#7228) Works by detecting a collision while moving forward and then simulating a jump. If the simulated jump is more successful, an artificial jump key press is injected in the client. Includes setting and key change GUI element for enabling and disabling this feature. --- src/localplayer.cpp | 102 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 89 insertions(+), 13 deletions(-) (limited to 'src/localplayer.cpp') diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 4bf689428..1c65d3b4d 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -287,16 +287,9 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d, float player_stepheight = (m_cao == nullptr) ? 0.0f : (touching_ground ? m_cao->getStepHeight() : (0.2f * BS)); - // TODO this is a problematic hack. - // Use a better implementation for autojump, or apply a custom stepheight - // to all players, as this currently creates unintended special movement - // abilities and advantages for Android players on a server. -#ifdef __ANDROID__ - if (touching_ground) - player_stepheight += (0.6f * BS); -#endif - v3f accel_f = v3f(0,0,0); + const v3f initial_position = position; + const v3f initial_speed = m_speed; collisionMoveResult result = collisionMoveSimple(env, m_client, pos_max_d, m_collisionbox, player_stepheight, dtime, @@ -461,6 +454,9 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d, setSpeed(m_speed); m_can_jump = false; } + + // Autojump + handleAutojump(dtime, env, result, initial_position, initial_speed, pos_max_d); } void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d) @@ -891,11 +887,9 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d, // this shouldn't be hardcoded but transmitted from server float player_stepheight = touching_ground ? (BS * 0.6) : (BS * 0.2); -#ifdef __ANDROID__ - player_stepheight += (0.6 * BS); -#endif - v3f accel_f = v3f(0, 0, 0); + const v3f initial_position = position; + const v3f initial_speed = m_speed; collisionMoveResult result = collisionMoveSimple(env, m_client, pos_max_d, m_collisionbox, player_stepheight, dtime, @@ -1059,6 +1053,9 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d, setSpeed(m_speed); m_can_jump = false; } + + // Autojump + handleAutojump(dtime, env, result, initial_position, initial_speed, pos_max_d); } float LocalPlayer::getSlipFactor(Environment *env, const v3f &speedH) @@ -1080,3 +1077,82 @@ float LocalPlayer::getSlipFactor(Environment *env, const v3f &speedH) } return 1.0f; } + +void LocalPlayer::handleAutojump(f32 dtime, Environment *env, + const collisionMoveResult &result, const v3f &initial_position, + const v3f &initial_speed, f32 pos_max_d) +{ + PlayerSettings &player_settings = getPlayerSettings(); + if (!player_settings.autojump) + return; + + if (m_autojump) { + // release autojump after a given time + m_autojump_time -= dtime; + if (m_autojump_time <= 0.0f) + m_autojump = false; + return; + } + + bool control_forward = control.up || + (!control.up && !control.down && + control.forw_move_joystick_axis < -0.05); + bool could_autojump = + m_can_jump && !control.jump && !control.sneak && control_forward; + if (!could_autojump) + return; + + bool horizontal_collision = false; + for (const auto &colinfo : result.collisions) { + if (colinfo.type == COLLISION_NODE && colinfo.plane != 1) { + horizontal_collision = true; + break; // one is enough + } + } + + // must be running against something to trigger autojumping + if (!horizontal_collision) + return; + + // check for nodes above + v3f headpos_min = m_position + m_collisionbox.MinEdge * 0.99f; + v3f headpos_max = m_position + m_collisionbox.MaxEdge * 0.99f; + headpos_min.Y = headpos_max.Y; // top face of collision box + v3s16 ceilpos_min = floatToInt(headpos_min, BS) + v3s16(0, 1, 0); + v3s16 ceilpos_max = floatToInt(headpos_max, BS) + v3s16(0, 1, 0); + const NodeDefManager *ndef = env->getGameDef()->ndef(); + bool is_position_valid; + for (s16 z = ceilpos_min.Z; z <= ceilpos_max.Z; z++) { + for (s16 x = ceilpos_min.X; x <= ceilpos_max.X; x++) { + MapNode n = env->getMap().getNodeNoEx(v3s16(x, ceilpos_max.Y, z), &is_position_valid); + + if (!is_position_valid) + break; // won't collide with the void outside + if (n.getContent() == CONTENT_IGNORE) + return; // players collide with ignore blocks -> same as walkable + const ContentFeatures &f = ndef->get(n); + if (f.walkable) + return; // would bump head, don't jump + } + } + + float jump_height = 1.1f; // TODO: better than a magic number + v3f jump_pos = initial_position + v3f(0.0f, jump_height * BS, 0.0f); + v3f jump_speed = initial_speed; + + // try at peak of jump, zero step height + collisionMoveResult jump_result = collisionMoveSimple(env, m_client, pos_max_d, + m_collisionbox, 0.0f, dtime, &jump_pos, &jump_speed, + v3f(0, 0, 0)); + + // see if we can get a little bit farther horizontally if we had + // jumped + v3f run_delta = m_position - initial_position; + run_delta.Y = 0.0f; + v3f jump_delta = jump_pos - initial_position; + jump_delta.Y = 0.0f; + if (jump_delta.getLengthSQ() > run_delta.getLengthSQ() * 1.01f) { + m_autojump = true; + m_autojump_time = 0.1f; + } +} -- cgit v1.2.3