3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "localplayer.h"
23 #include "collision.h"
26 #include "environment.h"
29 #include "content_cao.h"
35 LocalPlayer::LocalPlayer(Client *client, const char *name):
36 Player(name, client->idef()),
41 static aabb3f getNodeBoundingBox(const std::vector<aabb3f> &nodeboxes)
43 if (nodeboxes.empty())
44 return aabb3f(0, 0, 0, 0, 0, 0);
48 std::vector<aabb3f>::const_iterator it = nodeboxes.begin();
49 b_max = aabb3f(it->MinEdge, it->MaxEdge);
52 for (; it != nodeboxes.end(); ++it)
53 b_max.addInternalBox(*it);
58 bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
61 static const v3s16 dir9_center[9] = {
73 const NodeDefManager *nodemgr = m_client->ndef();
75 bool is_valid_position;
76 bool new_sneak_node_exists = m_sneak_node_exists;
78 // We want the top of the sneak node to be below the players feet
79 f32 position_y_mod = 0.05 * BS;
80 if (m_sneak_node_exists)
81 position_y_mod = m_sneak_node_bb_top.MaxEdge.Y - position_y_mod;
83 // Get position of current standing node
84 const v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
86 if (current_node != m_sneak_node) {
87 new_sneak_node_exists = false;
89 node = map->getNodeNoEx(current_node, &is_valid_position);
90 if (!is_valid_position || !nodemgr->get(node).walkable)
91 new_sneak_node_exists = false;
94 // Keep old sneak node
95 if (new_sneak_node_exists)
99 m_sneak_ladder_detected = false;
100 f32 min_distance_f = 100000.0 * BS;
102 for (const auto &d : dir9_center) {
103 const v3s16 p = current_node + d;
104 const v3f pf = intToFloat(p, BS);
105 const v2f diff(position.X - pf.X, position.Z - pf.Z);
106 f32 distance_f = diff.getLength();
108 if (distance_f > min_distance_f ||
109 fabs(diff.X) > (.5 + .1) * BS + sneak_max.X ||
110 fabs(diff.Y) > (.5 + .1) * BS + sneak_max.Z)
114 // The node to be sneaked on has to be walkable
115 node = map->getNodeNoEx(p, &is_valid_position);
116 if (!is_valid_position || !nodemgr->get(node).walkable)
118 // And the node(s) above have to be nonwalkable
120 if (!physics_override_sneak_glitch) {
122 (m_collisionbox.MaxEdge.Y - m_collisionbox.MinEdge.Y) / BS
124 for (u16 y = 1; y <= height; y++) {
125 node = map->getNodeNoEx(p + v3s16(0, y, 0), &is_valid_position);
126 if (!is_valid_position || nodemgr->get(node).walkable) {
132 // legacy behaviour: check just one node
133 node = map->getNodeNoEx(p + v3s16(0, 1, 0), &is_valid_position);
134 ok = is_valid_position && !nodemgr->get(node).walkable;
139 min_distance_f = distance_f;
141 new_sneak_node_exists = true;
144 if (!new_sneak_node_exists)
147 // Update saved top bounding box of sneak node
148 node = map->getNodeNoEx(m_sneak_node);
149 std::vector<aabb3f> nodeboxes;
150 node.getCollisionBoxes(nodemgr, &nodeboxes);
151 m_sneak_node_bb_top = getNodeBoundingBox(nodeboxes);
153 if (physics_override_sneak_glitch) {
154 // Detect sneak ladder:
155 // Node two meters above sneak node must be solid
156 node = map->getNodeNoEx(m_sneak_node + v3s16(0, 2, 0),
158 if (is_valid_position && nodemgr->get(node).walkable) {
159 // Node three meters above: must be non-solid
160 node = map->getNodeNoEx(m_sneak_node + v3s16(0, 3, 0),
162 m_sneak_ladder_detected = is_valid_position &&
163 !nodemgr->get(node).walkable;
169 void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
170 std::vector<CollisionInfo> *collision_info)
172 if (!collision_info || collision_info->empty()) {
173 // Node below the feet, update each ClientEnvironment::step()
174 m_standing_node = floatToInt(m_position, BS) - v3s16(0, 1, 0);
177 // Temporary option for old move code
178 if (!physics_override_new_move) {
179 old_move(dtime, env, pos_max_d, collision_info);
183 Map *map = &env->getMap();
184 const NodeDefManager *nodemgr = m_client->ndef();
186 v3f position = getPosition();
188 // Copy parent position if local player is attached
190 setPosition(overridePosition);
194 // Skip collision detection if noclip mode is used
195 bool fly_allowed = m_client->checkLocalPrivilege("fly");
196 bool noclip = m_client->checkLocalPrivilege("noclip") &&
197 g_settings->getBool("noclip");
198 bool free_move = g_settings->getBool("free_move") && fly_allowed;
200 if (noclip && free_move) {
201 position += m_speed * dtime;
202 setPosition(position);
210 bool is_valid_position;
215 Check if player is in liquid (the oscillating value)
218 // If in liquid, the threshold of coming out is at higher y
221 pp = floatToInt(position + v3f(0,BS*0.1,0), BS);
222 node = map->getNodeNoEx(pp, &is_valid_position);
223 if (is_valid_position) {
224 in_liquid = nodemgr->get(node.getContent()).isLiquid();
225 liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
230 // If not in liquid, the threshold of going in is at lower y
233 pp = floatToInt(position + v3f(0,BS*0.5,0), BS);
234 node = map->getNodeNoEx(pp, &is_valid_position);
235 if (is_valid_position) {
236 in_liquid = nodemgr->get(node.getContent()).isLiquid();
237 liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
245 Check if player is in liquid (the stable value)
247 pp = floatToInt(position + v3f(0,0,0), BS);
248 node = map->getNodeNoEx(pp, &is_valid_position);
249 if (is_valid_position) {
250 in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
252 in_liquid_stable = false;
256 Check if player is climbing
260 pp = floatToInt(position + v3f(0,0.5*BS,0), BS);
261 v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS);
262 node = map->getNodeNoEx(pp, &is_valid_position);
263 bool is_valid_position2;
264 MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
266 if (!(is_valid_position && is_valid_position2)) {
269 is_climbing = (nodemgr->get(node.getContent()).climbable
270 || nodemgr->get(node2.getContent()).climbable) && !free_move;
274 Collision uncertainty radius
275 Make it a bit larger than the maximum distance of movement
277 //f32 d = pos_max_d * 1.1;
278 // A fairly large value in here makes moving smoother
281 // This should always apply, otherwise there are glitches
282 sanity_check(d > pos_max_d);
284 // Player object property step height is multiplied by BS in
285 // /src/script/common/c_content.cpp and /src/content_sao.cpp
286 float player_stepheight = (m_cao == nullptr) ? 0.0f :
287 (touching_ground ? m_cao->getStepHeight() : (0.2f * BS));
289 // TODO this is a problematic hack.
290 // Use a better implementation for autojump, or apply a custom stepheight
291 // to all players, as this currently creates unintended special movement
292 // abilities and advantages for Android players on a server.
295 player_stepheight += (0.6f * BS);
298 v3f accel_f = v3f(0,0,0);
300 collisionMoveResult result = collisionMoveSimple(env, m_client,
301 pos_max_d, m_collisionbox, player_stepheight, dtime,
302 &position, &m_speed, accel_f);
304 bool could_sneak = control.sneak && !free_move && !in_liquid &&
305 !is_climbing && physics_override_sneak;
307 // Add new collisions to the vector
308 if (collision_info && !free_move) {
309 v3f diff = intToFloat(m_standing_node, BS) - position;
310 f32 distance = diff.getLength();
311 // Force update each ClientEnvironment::step()
312 bool is_first = collision_info->empty();
314 for (const auto &colinfo : result.collisions) {
315 collision_info->push_back(colinfo);
317 if (colinfo.type != COLLISION_NODE ||
318 colinfo.new_speed.Y != 0 ||
319 (could_sneak && m_sneak_node_exists))
322 diff = intToFloat(colinfo.node_p, BS) - position;
324 // Find nearest colliding node
325 f32 len = diff.getLength();
326 if (is_first || len < distance) {
327 m_standing_node = colinfo.node_p;
334 If the player's feet touch the topside of any node, this is
337 Player is allowed to jump when this is true.
339 bool touching_ground_was = touching_ground;
340 touching_ground = result.touching_ground;
341 bool sneak_can_jump = false;
343 // Max. distance (X, Z) over border for sneaking determined by collision box
344 // * 0.49 to keep the center just barely on the node
345 v3f sneak_max = m_collisionbox.getExtent() * 0.49;
347 if (m_sneak_ladder_detected) {
348 // restore legacy behaviour (this makes the m_speed.Y hack necessary)
349 sneak_max = v3f(0.4 * BS, 0, 0.4 * BS);
353 If sneaking, keep on top of last walked node and don't fall off
355 if (could_sneak && m_sneak_node_exists) {
356 const v3f sn_f = intToFloat(m_sneak_node, BS);
357 const v3f bmin = sn_f + m_sneak_node_bb_top.MinEdge;
358 const v3f bmax = sn_f + m_sneak_node_bb_top.MaxEdge;
359 const v3f old_pos = position;
360 const v3f old_speed = m_speed;
361 f32 y_diff = bmax.Y - position.Y;
362 m_standing_node = m_sneak_node;
364 // (BS * 0.6f) is the basic stepheight while standing on ground
365 if (y_diff < BS * 0.6f) {
366 // Only center player when they're on the node
367 position.X = rangelim(position.X,
368 bmin.X - sneak_max.X, bmax.X + sneak_max.X);
369 position.Z = rangelim(position.Z,
370 bmin.Z - sneak_max.Z, bmax.Z + sneak_max.Z);
372 if (position.X != old_pos.X)
374 if (position.Z != old_pos.Z)
378 if (y_diff > 0 && m_speed.Y < 0 &&
379 (physics_override_sneak_glitch || y_diff < BS * 0.6f)) {
380 // Move player to the maximal height when falling or when
381 // the ledge is climbed on the next step.
386 // Allow jumping on node edges while sneaking
387 if (m_speed.Y == 0 || m_sneak_ladder_detected)
388 sneak_can_jump = true;
390 if (collision_info &&
391 m_speed.Y - old_speed.Y > BS) {
392 // Collide with sneak node, report fall damage
393 CollisionInfo sn_info;
394 sn_info.node_p = m_sneak_node;
395 sn_info.old_speed = old_speed;
396 sn_info.new_speed = m_speed;
397 collision_info->push_back(sn_info);
402 Find the next sneak node if necessary
404 bool new_sneak_node_exists = false;
407 new_sneak_node_exists = updateSneakNode(map, position, sneak_max);
410 Set new position but keep sneak node set
412 setPosition(position);
413 m_sneak_node_exists = new_sneak_node_exists;
419 if(!result.standing_on_object && !touching_ground_was && touching_ground) {
420 MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
421 m_client->event()->put(e);
423 // Set camera impact value to be used for view bobbing
424 camera_impact = getSpeed().Y * -1;
428 camera_barely_in_ceiling = false;
429 v3s16 camera_np = floatToInt(getEyePosition(), BS);
430 MapNode n = map->getNodeNoEx(camera_np);
431 if(n.getContent() != CONTENT_IGNORE){
432 if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){
433 camera_barely_in_ceiling = true;
439 Check properties of the node on which the player is standing
441 const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(m_standing_node));
442 // Determine if jumping is possible
443 m_can_jump = (touching_ground && !in_liquid && !is_climbing)
445 if (itemgroup_get(f.groups, "disable_jump"))
448 // Jump key pressed while jumping off from a bouncy block
449 if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
450 m_speed.Y >= -0.5 * BS) {
451 float jumpspeed = movement_speed_jump * physics_override_jump;
453 // Reduce boost when speed already is high
454 m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
456 m_speed.Y += jumpspeed;
463 void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d)
465 move(dtime, env, pos_max_d, NULL);
468 void LocalPlayer::applyControl(float dtime, Environment *env)
471 swimming_vertical = false;
473 setPitch(control.pitch);
476 // Nullify speed and don't run positioning code if the player is attached
479 setSpeed(v3f(0,0,0));
483 v3f move_direction = v3f(0,0,1);
484 move_direction.rotateXZBy(getYaw());
486 v3f speedH = v3f(0,0,0); // Horizontal (X, Z)
487 v3f speedV = v3f(0,0,0); // Vertical (Y)
489 bool fly_allowed = m_client->checkLocalPrivilege("fly");
490 bool fast_allowed = m_client->checkLocalPrivilege("fast");
492 bool free_move = fly_allowed && g_settings->getBool("free_move");
493 bool fast_move = fast_allowed && g_settings->getBool("fast_move");
494 // When aux1_descends is enabled the fast key is used to go down, so fast isn't possible
495 bool fast_climb = fast_move && control.aux1 && !g_settings->getBool("aux1_descends");
496 bool continuous_forward = g_settings->getBool("continuous_forward");
497 bool always_fly_fast = g_settings->getBool("always_fly_fast");
499 // Whether superspeed mode is used or not
500 bool superspeed = false;
502 if (always_fly_fast && free_move && fast_move)
505 // Old descend control
506 if(g_settings->getBool("aux1_descends"))
508 // If free movement and fast movement, always move fast
509 if(free_move && fast_move)
512 // Auxiliary button 1 (E)
517 // In free movement mode, aux1 descends
519 speedV.Y = -movement_speed_fast;
521 speedV.Y = -movement_speed_walk;
523 else if(in_liquid || in_liquid_stable)
525 speedV.Y = -movement_speed_walk;
526 swimming_vertical = true;
530 speedV.Y = -movement_speed_climb;
534 // If not free movement but fast is allowed, aux1 is
541 // New minecraft-like descend control
544 // Auxiliary button 1 (E)
549 // aux1 is "Turbo button"
559 // In free movement mode, sneak descends
560 if (fast_move && (control.aux1 || always_fly_fast))
561 speedV.Y = -movement_speed_fast;
563 speedV.Y = -movement_speed_walk;
565 else if(in_liquid || in_liquid_stable)
568 speedV.Y = -movement_speed_fast;
570 speedV.Y = -movement_speed_walk;
571 swimming_vertical = true;
576 speedV.Y = -movement_speed_fast;
578 speedV.Y = -movement_speed_climb;
583 if (continuous_forward)
584 speedH += move_direction;
587 if (continuous_forward) {
591 speedH += move_direction;
595 speedH -= move_direction;
597 if (!control.up && !control.down) {
598 speedH -= move_direction *
599 (control.forw_move_joystick_axis / 32767.f);
602 speedH += move_direction.crossProduct(v3f(0,1,0));
605 speedH += move_direction.crossProduct(v3f(0,-1,0));
607 if (!control.left && !control.right) {
608 speedH -= move_direction.crossProduct(v3f(0,1,0)) *
609 (control.sidew_move_joystick_axis / 32767.f);
614 if (g_settings->getBool("aux1_descends") || always_fly_fast) {
616 speedV.Y = movement_speed_fast;
618 speedV.Y = movement_speed_walk;
620 if(fast_move && control.aux1)
621 speedV.Y = movement_speed_fast;
623 speedV.Y = movement_speed_walk;
629 NOTE: The d value in move() affects jump height by
630 raising the height at which the jump speed is kept
631 at its starting value
633 v3f speedJ = getSpeed();
634 if(speedJ.Y >= -0.5 * BS) {
635 speedJ.Y = movement_speed_jump * physics_override_jump;
638 MtEvent *e = new SimpleTriggerEvent("PlayerJump");
639 m_client->event()->put(e);
645 speedV.Y = movement_speed_fast;
647 speedV.Y = movement_speed_walk;
648 swimming_vertical = true;
653 speedV.Y = movement_speed_fast;
655 speedV.Y = movement_speed_climb;
659 // The speed of the player (Y is ignored)
660 if(superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
661 speedH = speedH.normalize() * movement_speed_fast;
662 else if(control.sneak && !free_move && !in_liquid && !in_liquid_stable)
663 speedH = speedH.normalize() * movement_speed_crouch;
665 speedH = speedH.normalize() * movement_speed_walk;
667 // Acceleration increase
668 f32 incH = 0; // Horizontal (X, Z)
669 f32 incV = 0; // Vertical (Y)
670 if((!touching_ground && !free_move && !is_climbing && !in_liquid) || (!free_move && m_can_jump && control.jump))
672 // Jumping and falling
673 if(superspeed || (fast_move && control.aux1))
674 incH = movement_acceleration_fast * BS * dtime;
676 incH = movement_acceleration_air * BS * dtime;
677 incV = 0; // No vertical acceleration in air
679 else if (superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
680 incH = incV = movement_acceleration_fast * BS * dtime;
682 incH = incV = movement_acceleration_default * BS * dtime;
684 float slip_factor = 1.0f;
686 slip_factor = getSlipFactor(env, speedH);
688 // Accelerate to target speed with maximum increment
689 accelerateHorizontal(speedH * physics_override_speed,
690 incH * physics_override_speed * slip_factor);
691 accelerateVertical(speedV * physics_override_speed,
692 incV * physics_override_speed);
695 v3s16 LocalPlayer::getStandingNodePos()
697 if(m_sneak_node_exists)
699 return m_standing_node;
702 v3s16 LocalPlayer::getFootstepNodePos()
704 if (in_liquid_stable)
705 // Emit swimming sound if the player is in liquid
706 return floatToInt(getPosition(), BS);
708 // BS * 0.05 below the player's feet ensures a 1/16th height
709 // nodebox is detected instead of the node below it.
710 return floatToInt(getPosition() - v3f(0, BS * 0.05f, 0), BS);
711 // A larger distance below is necessary for a footstep sound
712 // when landing after a jump or fall. BS * 0.5 ensures water
713 // sounds when swimming in 1 node deep water.
714 return floatToInt(getPosition() - v3f(0, BS * 0.5f, 0), BS);
717 v3s16 LocalPlayer::getLightPosition() const
719 return floatToInt(m_position + v3f(0,BS+BS/2,0), BS);
722 v3f LocalPlayer::getEyeOffset() const
724 float eye_height = camera_barely_in_ceiling ?
725 m_eye_height - 0.125f : m_eye_height;
726 return v3f(0, BS * eye_height, 0);
729 // Horizontal acceleration (X and Z), Y direction is ignored
730 void LocalPlayer::accelerateHorizontal(const v3f &target_speed,
731 const f32 max_increase)
733 if (max_increase == 0)
736 v3f d_wanted = target_speed - m_speed;
738 f32 dl = d_wanted.getLength();
739 if (dl > max_increase)
742 v3f d = d_wanted.normalize() * dl;
748 // Vertical acceleration (Y), X and Z directions are ignored
749 void LocalPlayer::accelerateVertical(const v3f &target_speed, const f32 max_increase)
751 if (max_increase == 0)
754 f32 d_wanted = target_speed.Y - m_speed.Y;
755 if (d_wanted > max_increase)
756 d_wanted = max_increase;
757 else if (d_wanted < -max_increase)
758 d_wanted = -max_increase;
760 m_speed.Y += d_wanted;
763 // Temporary option for old move code
764 void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
765 std::vector<CollisionInfo> *collision_info)
767 Map *map = &env->getMap();
768 const NodeDefManager *nodemgr = m_client->ndef();
770 v3f position = getPosition();
772 // Copy parent position if local player is attached
774 setPosition(overridePosition);
775 m_sneak_node_exists = false;
779 // Skip collision detection if noclip mode is used
780 bool fly_allowed = m_client->checkLocalPrivilege("fly");
781 bool noclip = m_client->checkLocalPrivilege("noclip") &&
782 g_settings->getBool("noclip");
783 bool free_move = noclip && fly_allowed && g_settings->getBool("free_move");
785 position += m_speed * dtime;
786 setPosition(position);
787 m_sneak_node_exists = false;
794 bool is_valid_position;
799 Check if player is in liquid (the oscillating value)
802 // If in liquid, the threshold of coming out is at higher y
803 pp = floatToInt(position + v3f(0, BS * 0.1, 0), BS);
804 node = map->getNodeNoEx(pp, &is_valid_position);
805 if (is_valid_position) {
806 in_liquid = nodemgr->get(node.getContent()).isLiquid();
807 liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
812 // If not in liquid, the threshold of going in is at lower y
813 pp = floatToInt(position + v3f(0, BS * 0.5, 0), BS);
814 node = map->getNodeNoEx(pp, &is_valid_position);
815 if (is_valid_position) {
816 in_liquid = nodemgr->get(node.getContent()).isLiquid();
817 liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
824 Check if player is in liquid (the stable value)
826 pp = floatToInt(position + v3f(0, 0, 0), BS);
827 node = map->getNodeNoEx(pp, &is_valid_position);
828 if (is_valid_position)
829 in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
831 in_liquid_stable = false;
834 Check if player is climbing
836 pp = floatToInt(position + v3f(0, 0.5 * BS, 0), BS);
837 v3s16 pp2 = floatToInt(position + v3f(0, -0.2 * BS, 0), BS);
838 node = map->getNodeNoEx(pp, &is_valid_position);
839 bool is_valid_position2;
840 MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
842 if (!(is_valid_position && is_valid_position2))
845 is_climbing = (nodemgr->get(node.getContent()).climbable ||
846 nodemgr->get(node2.getContent()).climbable) && !free_move;
849 Collision uncertainty radius
850 Make it a bit larger than the maximum distance of movement
852 //f32 d = pos_max_d * 1.1;
853 // A fairly large value in here makes moving smoother
855 // This should always apply, otherwise there are glitches
856 sanity_check(d > pos_max_d);
857 // Maximum distance over border for sneaking
858 f32 sneak_max = BS * 0.4;
861 If sneaking, keep in range from the last walked node and don't
864 if (control.sneak && m_sneak_node_exists &&
865 !(fly_allowed && g_settings->getBool("free_move")) && !in_liquid &&
866 physics_override_sneak) {
867 f32 maxd = 0.5 * BS + sneak_max;
868 v3f lwn_f = intToFloat(m_sneak_node, BS);
869 position.X = rangelim(position.X, lwn_f.X - maxd, lwn_f.X + maxd);
870 position.Z = rangelim(position.Z, lwn_f.Z - maxd, lwn_f.Z + maxd);
873 // Move up if necessary
874 f32 new_y = (lwn_f.Y - 0.5 * BS) + m_sneak_node_bb_ymax;
875 if (position.Y < new_y)
878 Collision seems broken, since player is sinking when
879 sneaking over the edges of current sneaking_node.
880 TODO (when fixed): Set Y-speed only to 0 when position.Y < new_y.
887 // this shouldn't be hardcoded but transmitted from server
888 float player_stepheight = touching_ground ? (BS * 0.6) : (BS * 0.2);
891 player_stepheight += (0.6 * BS);
894 v3f accel_f = v3f(0, 0, 0);
896 collisionMoveResult result = collisionMoveSimple(env, m_client,
897 pos_max_d, m_collisionbox, player_stepheight, dtime,
898 &position, &m_speed, accel_f);
901 If the player's feet touch the topside of any node, this is
904 Player is allowed to jump when this is true.
906 bool touching_ground_was = touching_ground;
907 touching_ground = result.touching_ground;
909 //bool standing_on_unloaded = result.standing_on_unloaded;
912 Check the nodes under the player to see from which node the
913 player is sneaking from, if any. If the node from under
914 the player has been removed, the player falls.
916 f32 position_y_mod = 0.05 * BS;
917 if (m_sneak_node_bb_ymax > 0)
918 position_y_mod = m_sneak_node_bb_ymax - position_y_mod;
919 v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
920 if (m_sneak_node_exists &&
921 nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
922 m_old_node_below_type != "air") {
923 // Old node appears to have been removed; that is,
924 // it wasn't air before but now it is
925 m_need_to_get_new_sneak_node = false;
926 m_sneak_node_exists = false;
927 } else if (nodemgr->get(map->getNodeNoEx(current_node)).name != "air") {
928 // We are on something, so make sure to recalculate the sneak
930 m_need_to_get_new_sneak_node = true;
933 if (m_need_to_get_new_sneak_node && physics_override_sneak) {
934 m_sneak_node_bb_ymax = 0;
935 v3s16 pos_i_bottom = floatToInt(position - v3f(0, position_y_mod, 0), BS);
936 v2f player_p2df(position.X, position.Z);
937 f32 min_distance_f = 100000.0 * BS;
938 // If already seeking from some node, compare to it.
939 v3s16 new_sneak_node = m_sneak_node;
940 for (s16 x= -1; x <= 1; x++)
941 for (s16 z= -1; z <= 1; z++) {
942 v3s16 p = pos_i_bottom + v3s16(x, 0, z);
943 v3f pf = intToFloat(p, BS);
944 v2f node_p2df(pf.X, pf.Z);
945 f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
946 f32 max_axis_distance_f = MYMAX(
947 fabs(player_p2df.X - node_p2df.X),
948 fabs(player_p2df.Y - node_p2df.Y));
950 if (distance_f > min_distance_f ||
951 max_axis_distance_f > 0.5 * BS + sneak_max + 0.1 * BS)
954 // The node to be sneaked on has to be walkable
955 node = map->getNodeNoEx(p, &is_valid_position);
956 if (!is_valid_position || !nodemgr->get(node).walkable)
958 // And the node above it has to be nonwalkable
959 node = map->getNodeNoEx(p + v3s16(0, 1, 0), &is_valid_position);
960 if (!is_valid_position || nodemgr->get(node).walkable)
962 // If not 'sneak_glitch' the node 2 nodes above it has to be nonwalkable
963 if (!physics_override_sneak_glitch) {
964 node =map->getNodeNoEx(p + v3s16(0, 2, 0), &is_valid_position);
965 if (!is_valid_position || nodemgr->get(node).walkable)
969 min_distance_f = distance_f;
973 bool sneak_node_found = (min_distance_f < 100000.0 * BS * 0.9);
975 m_sneak_node = new_sneak_node;
976 m_sneak_node_exists = sneak_node_found;
978 if (sneak_node_found) {
980 MapNode n = map->getNodeNoEx(m_sneak_node);
981 std::vector<aabb3f> nodeboxes;
982 n.getCollisionBoxes(nodemgr, &nodeboxes);
983 for (const auto &box : nodeboxes) {
984 if (box.MaxEdge.Y > cb_max)
985 cb_max = box.MaxEdge.Y;
987 m_sneak_node_bb_ymax = cb_max;
991 If sneaking, the player's collision box can be in air, so
992 this has to be set explicitly
994 if (sneak_node_found && control.sneak)
995 touching_ground = true;
999 Set new position but keep sneak node set
1001 bool sneak_node_exists = m_sneak_node_exists;
1002 setPosition(position);
1003 m_sneak_node_exists = sneak_node_exists;
1008 // Dont report if flying
1009 if (collision_info && !(g_settings->getBool("free_move") && fly_allowed)) {
1010 for (const auto &info : result.collisions) {
1011 collision_info->push_back(info);
1015 if (!result.standing_on_object && !touching_ground_was && touching_ground) {
1016 MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
1017 m_client->event()->put(e);
1018 // Set camera impact value to be used for view bobbing
1019 camera_impact = getSpeed().Y * -1;
1023 camera_barely_in_ceiling = false;
1024 v3s16 camera_np = floatToInt(getEyePosition(), BS);
1025 MapNode n = map->getNodeNoEx(camera_np);
1026 if (n.getContent() != CONTENT_IGNORE) {
1027 if (nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2)
1028 camera_barely_in_ceiling = true;
1033 Update the node last under the player
1035 m_old_node_below = floatToInt(position - v3f(0, BS / 2, 0), BS);
1036 m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
1039 Check properties of the node on which the player is standing
1041 const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
1042 // Determine if jumping is possible
1043 m_can_jump = touching_ground && !in_liquid;
1044 if (itemgroup_get(f.groups, "disable_jump"))
1046 // Jump key pressed while jumping off from a bouncy block
1047 if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
1048 m_speed.Y >= -0.5 * BS) {
1049 float jumpspeed = movement_speed_jump * physics_override_jump;
1050 if (m_speed.Y > 1) {
1051 // Reduce boost when speed already is high
1052 m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
1054 m_speed.Y += jumpspeed;
1061 float LocalPlayer::getSlipFactor(Environment *env, const v3f &speedH)
1063 // Slip on slippery nodes
1064 const NodeDefManager *nodemgr = env->getGameDef()->ndef();
1065 Map *map = &env->getMap();
1066 const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(
1067 getStandingNodePos()));
1070 slippery = itemgroup_get(f.groups, "slippery");
1072 if (slippery >= 1) {
1073 if (speedH == v3f(0.0f)) {
1074 slippery = slippery * 2;
1076 return core::clamp(1.0f / (slippery + 1), 0.001f, 1.0f);