summaryrefslogtreecommitdiff
path: root/src/localplayer.cpp
diff options
context:
space:
mode:
authorparamat <mat.gregory@virginmedia.com>2017-04-05 12:18:22 +0100
committerparamat <mat.gregory@virginmedia.com>2017-04-17 10:13:05 +0100
commitf6da7b3fda5bbb793c7795a228ea6f2602b93fbe (patch)
treeca2bd50fdf29414cbee58576786170928676b8a5 /src/localplayer.cpp
parent907be0ab918a99c30c37c4abfe3e11722691f3bc (diff)
downloadminetest-f6da7b3fda5bbb793c7795a228ea6f2602b93fbe.tar.gz
minetest-f6da7b3fda5bbb793c7795a228ea6f2602b93fbe.tar.bz2
minetest-f6da7b3fda5bbb793c7795a228ea6f2602b93fbe.zip
Sneak: Add option for old move code
Temporary option for the old move code for specific old sneak behaviour. Enabled by setting the added 'new move' physics override to false. By default 'new move' is true.
Diffstat (limited to 'src/localplayer.cpp')
-rw-r--r--src/localplayer.cpp309
1 files changed, 309 insertions, 0 deletions
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index 9dc3bf5aa..ea4347207 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -49,6 +49,7 @@ LocalPlayer::LocalPlayer(Client *client, const char *name):
physics_override_gravity(1.0f),
physics_override_sneak(true),
physics_override_sneak_glitch(true),
+ physics_override_new_move(true), // Temporary option for old move code
overridePosition(v3f(0,0,0)),
last_position(v3f(0,0,0)),
last_speed(v3f(0,0,0)),
@@ -66,6 +67,7 @@ LocalPlayer::LocalPlayer(Client *client, const char *name):
hurt_tilt_strength(0.0f),
m_position(0,0,0),
m_sneak_node(32767,32767,32767),
+ m_sneak_node_bb_ymax(0), // To support temporary option for old move code
m_sneak_node_bb_top(0,0,0,0,0,0),
m_sneak_node_exists(false),
m_need_to_get_new_sneak_node(true),
@@ -178,6 +180,12 @@ static bool detectLedge(Map *map, INodeDefManager *nodemgr, v3s16 pos)
void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
std::vector<CollisionInfo> *collision_info)
{
+ // Temporary option for old move code
+ if (!physics_override_new_move) {
+ old_move(dtime, env, pos_max_d, collision_info);
+ return;
+ }
+
Map *map = &env->getMap();
INodeDefManager *nodemgr = m_client->ndef();
@@ -806,3 +814,304 @@ void LocalPlayer::accelerateVertical(const v3f &target_speed, const f32 max_incr
m_speed.Y += d_wanted;
}
+// Temporary option for old move code
+void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
+ std::vector<CollisionInfo> *collision_info)
+{
+ Map *map = &env->getMap();
+ INodeDefManager *nodemgr = m_client->ndef();
+
+ v3f position = getPosition();
+
+ // Copy parent position if local player is attached
+ if (isAttached) {
+ setPosition(overridePosition);
+ m_sneak_node_exists = false;
+ return;
+ }
+
+ // Skip collision detection if noclip mode is used
+ bool fly_allowed = m_client->checkLocalPrivilege("fly");
+ bool noclip = m_client->checkLocalPrivilege("noclip") &&
+ g_settings->getBool("noclip");
+ bool free_move = noclip && fly_allowed && g_settings->getBool("free_move");
+ if (free_move) {
+ position += m_speed * dtime;
+ setPosition(position);
+ m_sneak_node_exists = false;
+ return;
+ }
+
+ /*
+ Collision detection
+ */
+ bool is_valid_position;
+ MapNode node;
+ v3s16 pp;
+
+ /*
+ Check if player is in liquid (the oscillating value)
+ */
+ if (in_liquid) {
+ // If in liquid, the threshold of coming out is at higher y
+ pp = floatToInt(position + v3f(0, BS * 0.1, 0), BS);
+ node = map->getNodeNoEx(pp, &is_valid_position);
+ if (is_valid_position) {
+ in_liquid = nodemgr->get(node.getContent()).isLiquid();
+ liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
+ } else {
+ in_liquid = false;
+ }
+ } else {
+ // If not in liquid, the threshold of going in is at lower y
+ pp = floatToInt(position + v3f(0, BS * 0.5, 0), BS);
+ node = map->getNodeNoEx(pp, &is_valid_position);
+ if (is_valid_position) {
+ in_liquid = nodemgr->get(node.getContent()).isLiquid();
+ liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
+ } else {
+ in_liquid = false;
+ }
+ }
+
+ /*
+ Check if player is in liquid (the stable value)
+ */
+ pp = floatToInt(position + v3f(0, 0, 0), BS);
+ node = map->getNodeNoEx(pp, &is_valid_position);
+ if (is_valid_position)
+ in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
+ else
+ in_liquid_stable = false;
+
+ /*
+ Check if player is climbing
+ */
+ pp = floatToInt(position + v3f(0, 0.5 * BS, 0), BS);
+ v3s16 pp2 = floatToInt(position + v3f(0, -0.2 * BS, 0), BS);
+ node = map->getNodeNoEx(pp, &is_valid_position);
+ bool is_valid_position2;
+ MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
+
+ if (!(is_valid_position && is_valid_position2))
+ is_climbing = false;
+ else
+ is_climbing = (nodemgr->get(node.getContent()).climbable ||
+ nodemgr->get(node2.getContent()).climbable) && !free_move;
+
+ /*
+ Collision uncertainty radius
+ Make it a bit larger than the maximum distance of movement
+ */
+ //f32 d = pos_max_d * 1.1;
+ // A fairly large value in here makes moving smoother
+ f32 d = 0.15 * BS;
+ // This should always apply, otherwise there are glitches
+ sanity_check(d > pos_max_d);
+ // Maximum distance over border for sneaking
+ f32 sneak_max = BS * 0.4;
+
+ /*
+ If sneaking, keep in range from the last walked node and don't
+ fall off from it
+ */
+ if (control.sneak && m_sneak_node_exists &&
+ !(fly_allowed && g_settings->getBool("free_move")) && !in_liquid &&
+ physics_override_sneak && !got_teleported) {
+ f32 maxd = 0.5 * BS + sneak_max;
+ v3f lwn_f = intToFloat(m_sneak_node, BS);
+ position.X = rangelim(position.X, lwn_f.X - maxd, lwn_f.X + maxd);
+ position.Z = rangelim(position.Z, lwn_f.Z - maxd, lwn_f.Z + maxd);
+
+ if (!is_climbing) {
+ // Move up if necessary
+ f32 new_y = (lwn_f.Y - 0.5 * BS) + m_sneak_node_bb_ymax;
+ if (position.Y < new_y)
+ position.Y = new_y;
+ /*
+ Collision seems broken, since player is sinking when
+ sneaking over the edges of current sneaking_node.
+ TODO (when fixed): Set Y-speed only to 0 when position.Y < new_y.
+ */
+ if (m_speed.Y < 0)
+ m_speed.Y = 0;
+ }
+ }
+
+ if (got_teleported)
+ got_teleported = false;
+
+ // 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);
+
+ collisionMoveResult result = collisionMoveSimple(env, m_client,
+ pos_max_d, m_collisionbox, player_stepheight, dtime,
+ &position, &m_speed, accel_f);
+
+ /*
+ If the player's feet touch the topside of any node, this is
+ set to true.
+
+ Player is allowed to jump when this is true.
+ */
+ bool touching_ground_was = touching_ground;
+ touching_ground = result.touching_ground;
+
+ //bool standing_on_unloaded = result.standing_on_unloaded;
+
+ /*
+ Check the nodes under the player to see from which node the
+ player is sneaking from, if any. If the node from under
+ the player has been removed, the player falls.
+ */
+ f32 position_y_mod = 0.05 * BS;
+ if (m_sneak_node_bb_ymax > 0)
+ position_y_mod = m_sneak_node_bb_ymax - position_y_mod;
+ v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
+ if (m_sneak_node_exists &&
+ nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
+ m_old_node_below_type != "air") {
+ // Old node appears to have been removed; that is,
+ // it wasn't air before but now it is
+ m_need_to_get_new_sneak_node = false;
+ m_sneak_node_exists = false;
+ } else if (nodemgr->get(map->getNodeNoEx(current_node)).name != "air") {
+ // We are on something, so make sure to recalculate the sneak
+ // node.
+ m_need_to_get_new_sneak_node = true;
+ }
+
+ if (m_need_to_get_new_sneak_node && physics_override_sneak) {
+ m_sneak_node_bb_ymax = 0;
+ v3s16 pos_i_bottom = floatToInt(position - v3f(0, position_y_mod, 0), BS);
+ v2f player_p2df(position.X, position.Z);
+ f32 min_distance_f = 100000.0 * BS;
+ // If already seeking from some node, compare to it.
+ v3s16 new_sneak_node = m_sneak_node;
+ for (s16 x= -1; x <= 1; x++)
+ for (s16 z= -1; z <= 1; z++) {
+ v3s16 p = pos_i_bottom + v3s16(x, 0, z);
+ v3f pf = intToFloat(p, BS);
+ v2f node_p2df(pf.X, pf.Z);
+ f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
+ f32 max_axis_distance_f = MYMAX(
+ fabs(player_p2df.X - node_p2df.X),
+ fabs(player_p2df.Y - node_p2df.Y));
+
+ if (distance_f > min_distance_f ||
+ max_axis_distance_f > 0.5 * BS + sneak_max + 0.1 * BS)
+ continue;
+
+ // The node to be sneaked on has to be walkable
+ node = map->getNodeNoEx(p, &is_valid_position);
+ if (!is_valid_position || nodemgr->get(node).walkable == false)
+ continue;
+ // And the node above it has to be nonwalkable
+ node = map->getNodeNoEx(p + v3s16(0, 1, 0), &is_valid_position);
+ if (!is_valid_position || nodemgr->get(node).walkable)
+ continue;
+ // If not 'sneak_glitch' the node 2 nodes above it has to be nonwalkable
+ if (!physics_override_sneak_glitch) {
+ node =map->getNodeNoEx(p + v3s16(0, 2, 0), &is_valid_position);
+ if (!is_valid_position || nodemgr->get(node).walkable)
+ continue;
+ }
+
+ min_distance_f = distance_f;
+ new_sneak_node = p;
+ }
+
+ bool sneak_node_found = (min_distance_f < 100000.0 * BS * 0.9);
+
+ m_sneak_node = new_sneak_node;
+ m_sneak_node_exists = sneak_node_found;
+
+ if (sneak_node_found) {
+ f32 cb_max = 0;
+ MapNode n = map->getNodeNoEx(m_sneak_node);
+ std::vector<aabb3f> nodeboxes;
+ n.getCollisionBoxes(nodemgr, &nodeboxes);
+ for (std::vector<aabb3f>::iterator it = nodeboxes.begin();
+ it != nodeboxes.end(); ++it) {
+ aabb3f box = *it;
+ if (box.MaxEdge.Y > cb_max)
+ cb_max = box.MaxEdge.Y;
+ }
+ m_sneak_node_bb_ymax = cb_max;
+ }
+
+ /*
+ If sneaking, the player's collision box can be in air, so
+ this has to be set explicitly
+ */
+ if (sneak_node_found && control.sneak)
+ touching_ground = true;
+ }
+
+ /*
+ Set new position
+ */
+ setPosition(position);
+
+ /*
+ Report collisions
+ */
+ // Dont report if flying
+ if (collision_info && !(g_settings->getBool("free_move") && fly_allowed)) {
+ for (size_t i = 0; i < result.collisions.size(); i++) {
+ const CollisionInfo &info = result.collisions[i];
+ collision_info->push_back(info);
+ }
+ }
+
+ if (!result.standing_on_object && !touching_ground_was && touching_ground) {
+ MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
+ m_client->event()->put(e);
+ // Set camera impact value to be used for view bobbing
+ camera_impact = getSpeed().Y * -1;
+ }
+
+ {
+ camera_barely_in_ceiling = false;
+ v3s16 camera_np = floatToInt(getEyePosition(), BS);
+ MapNode n = map->getNodeNoEx(camera_np);
+ if (n.getContent() != CONTENT_IGNORE) {
+ if (nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2)
+ camera_barely_in_ceiling = true;
+ }
+ }
+
+ /*
+ Update the node last under the player
+ */
+ m_old_node_below = floatToInt(position - v3f(0, BS / 2, 0), BS);
+ m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
+
+ /*
+ Check properties of the node on which the player is standing
+ */
+ const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
+ // Determine if jumping is possible
+ m_can_jump = touching_ground && !in_liquid;
+ if (itemgroup_get(f.groups, "disable_jump"))
+ m_can_jump = false;
+ // Jump key pressed while jumping off from a bouncy block
+ if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
+ m_speed.Y >= -0.5 * BS) {
+ float jumpspeed = movement_speed_jump * physics_override_jump;
+ if (m_speed.Y > 1) {
+ // Reduce boost when speed already is high
+ m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
+ } else {
+ m_speed.Y += jumpspeed;
+ }
+ setSpeed(m_speed);
+ m_can_jump = false;
+ }
+}