summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin/settingtypes.txt4
-rw-r--r--minetest.conf.example4
-rw-r--r--src/collision.cpp1
-rw-r--r--src/collision.h1
-rw-r--r--src/defaultsettings.cpp5
-rw-r--r--src/game.cpp9
-rw-r--r--src/gui/guiKeyChangeMenu.cpp25
-rw-r--r--src/localplayer.cpp102
-rw-r--r--src/localplayer.h9
-rw-r--r--src/player.cpp1
-rw-r--r--src/player.h5
-rw-r--r--src/settings_translation_file.cpp1
12 files changed, 149 insertions, 18 deletions
diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt
index 7566be594..950de5d1c 100644
--- a/builtin/settingtypes.txt
+++ b/builtin/settingtypes.txt
@@ -111,6 +111,10 @@ always_fly_fast (Always fly and fast) bool true
# mouse button.
repeat_rightclick_time (Rightclick repetition interval) float 0.25
+# Automatically jump up single-node obstacles.
+# type: bool
+autojump (Automatic jumping) bool false
+
# Prevent digging and placing from repeating when holding the mouse buttons.
# Enable this when you dig or place too often by accident.
safe_dig_and_place (Safe digging and placing) bool false
diff --git a/minetest.conf.example b/minetest.conf.example
index 8d69733a1..ccb57520c 100644
--- a/minetest.conf.example
+++ b/minetest.conf.example
@@ -69,6 +69,10 @@
# type: bool
# always_fly_fast = true
+# Automatically jump up single-node obstacles.
+# type: bool
+# autojump = false
+
# The time in seconds it takes between repeated right clicks when holding the right mouse button.
# type: float
# repeat_rightclick_time = 0.25
diff --git a/src/collision.cpp b/src/collision.cpp
index 48a681dca..9626221a0 100644
--- a/src/collision.cpp
+++ b/src/collision.cpp
@@ -515,6 +515,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
info.node_p = nearest_info.position;
info.old_speed = *speed_f;
+ info.plane = nearest_collided;
// Set the speed component that caused the collision to zero
if (step_up) {
diff --git a/src/collision.h b/src/collision.h
index 4d47171ea..4c5594528 100644
--- a/src/collision.h
+++ b/src/collision.h
@@ -41,6 +41,7 @@ struct CollisionInfo
v3s16 node_p = v3s16(-32768,-32768,-32768); // COLLISION_NODE
v3f old_speed;
v3f new_speed;
+ int plane = -1;
};
struct collisionMoveResult
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index 6a0474e74..2408bffeb 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -247,6 +247,11 @@ void set_default_settings(Settings *settings)
settings->setDefault("aux1_descends", "false");
settings->setDefault("doubletap_jump", "false");
settings->setDefault("always_fly_fast", "true");
+#ifdef __ANDROID__
+ settings->setDefault("autojump", "true");
+#else
+ settings->setDefault("autojump", "false");
+#endif
settings->setDefault("continuous_forward", "false");
settings->setDefault("enable_joysticks", "false");
settings->setDefault("joystick_id", "0");
diff --git a/src/game.cpp b/src/game.cpp
index 227b21db5..1cb9a1650 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -2449,8 +2449,15 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
}
#endif
- client->setPlayerControl(control);
LocalPlayer *player = client->getEnv().getLocalPlayer();
+
+ // autojump if set: simulate "jump" key
+ if (player->getAutojump()) {
+ control.jump = true;
+ keypress_bits |= 1U << 4;
+ }
+
+ client->setPlayerControl(control);
player->keyPressed = keypress_bits;
//tt.stop();
diff --git a/src/gui/guiKeyChangeMenu.cpp b/src/gui/guiKeyChangeMenu.cpp
index ca97e0b9e..f3d8e8eef 100644
--- a/src/gui/guiKeyChangeMenu.cpp
+++ b/src/gui/guiKeyChangeMenu.cpp
@@ -77,6 +77,7 @@ enum
// other
GUI_ID_CB_AUX1_DESCENDS,
GUI_ID_CB_DOUBLETAP_JUMP,
+ GUI_ID_CB_AUTOJUMP,
};
GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
@@ -196,6 +197,21 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
}
{
+ s32 option_x = offset.X;
+ s32 option_y = offset.Y + 5;
+ u32 option_w = 280;
+ {
+ core::rect<s32> rect(0, 0, option_w, 30);
+ rect += topleft + v2s32(option_x, option_y);
+ const wchar_t *text = wgettext("Automatic jumping");
+ Environment->addCheckBox(g_settings->getBool("autojump"), rect, this,
+ GUI_ID_CB_AUTOJUMP, text);
+ delete[] text;
+ }
+ offset += v2s32(0, 25);
+ }
+
+ {
core::rect < s32 > rect(0, 0, 100, 30);
rect += topleft + v2s32(size.X / 2 - 105, size.Y - 40);
const wchar_t *text = wgettext("Save");
@@ -239,14 +255,19 @@ bool GUIKeyChangeMenu::acceptInput()
{
gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUX1_DESCENDS);
- if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
+ if(e && e->getType() == gui::EGUIET_CHECK_BOX)
g_settings->setBool("aux1_descends", ((gui::IGUICheckBox*)e)->isChecked());
}
{
gui::IGUIElement *e = getElementFromId(GUI_ID_CB_DOUBLETAP_JUMP);
- if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
+ if(e && e->getType() == gui::EGUIET_CHECK_BOX)
g_settings->setBool("doubletap_jump", ((gui::IGUICheckBox*)e)->isChecked());
}
+ {
+ gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUTOJUMP);
+ if(e && e->getType() == gui::EGUIET_CHECK_BOX)
+ g_settings->setBool("autojump", ((gui::IGUICheckBox*)e)->isChecked());
+ }
clearKeyCache();
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;
+ }
+}
diff --git a/src/localplayer.h b/src/localplayer.h
index dc59c4179..7148bc4de 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -31,6 +31,7 @@ class GenericCAO;
class ClientActiveObject;
class ClientEnvironment;
class IGameDef;
+struct collisionMoveResult;
enum LocalPlayerAnimations
{
@@ -145,11 +146,17 @@ public:
float getZoomFOV() const { return m_zoom_fov; }
void setZoomFOV(float zoom_fov) { m_zoom_fov = zoom_fov; }
+ bool getAutojump() const { return m_autojump; }
+
private:
void accelerateHorizontal(const v3f &target_speed, const f32 max_increase);
void accelerateVertical(const v3f &target_speed, const f32 max_increase);
bool updateSneakNode(Map *map, const v3f &position, const v3f &sneak_max);
float getSlipFactor(Environment *env, const v3f &speedH);
+ void handleAutojump(f32 dtime, Environment *env,
+ const collisionMoveResult &result,
+ const v3f &position_before_move, const v3f &speed_before_move,
+ f32 pos_max_d);
v3f m_position;
v3s16 m_standing_node;
@@ -183,6 +190,8 @@ private:
BS * 1.75f, BS * 0.30f);
float m_eye_height = 1.625f;
float m_zoom_fov = 0.0f;
+ bool m_autojump = false;
+ float m_autojump_time = 0.0f;
GenericCAO *m_cao = nullptr;
Client *m_client;
diff --git a/src/player.cpp b/src/player.cpp
index ccc753834..4b104a71b 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -144,6 +144,7 @@ void PlayerSettings::readGlobalSettings()
always_fly_fast = g_settings->getBool("always_fly_fast");
aux1_descends = g_settings->getBool("aux1_descends");
noclip = g_settings->getBool("noclip");
+ autojump = g_settings->getBool("autojump");
}
void Player::settingsChangedCallback(const std::string &name, void *data)
diff --git a/src/player.h b/src/player.h
index 66cd0f5cf..674491546 100644
--- a/src/player.h
+++ b/src/player.h
@@ -92,10 +92,11 @@ struct PlayerSettings
bool always_fly_fast = false;
bool aux1_descends = false;
bool noclip = false;
+ bool autojump = false;
- const std::string setting_names[6] = {
+ const std::string setting_names[7] = {
"free_move", "fast_move", "continuous_forward", "always_fly_fast",
- "aux1_descends", "noclip"
+ "aux1_descends", "noclip", "autojump"
};
void readGlobalSettings();
};
diff --git a/src/settings_translation_file.cpp b/src/settings_translation_file.cpp
index c2390c189..2b56115df 100644
--- a/src/settings_translation_file.cpp
+++ b/src/settings_translation_file.cpp
@@ -27,6 +27,7 @@ fake_function() {
gettext("Double tap jump for fly");
gettext("Double-tapping the jump key toggles fly mode.");
gettext("Always fly and fast");
+ gettext("Automatic jumping");
gettext("If disabled, \"special\" key is used to fly fast if both fly and fast mode are enabled.");
gettext("Rightclick repetition interval");
gettext("The time in seconds it takes between repeated right clicks when holding the right mouse button.");