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 LocalPlayer::~LocalPlayer()
45 static aabb3f getNodeBoundingBox(const std::vector<aabb3f> &nodeboxes)
47 if (nodeboxes.size() == 0)
48 return aabb3f(0, 0, 0, 0, 0, 0);
52 std::vector<aabb3f>::const_iterator it = nodeboxes.begin();
53 b_max = aabb3f(it->MinEdge, it->MaxEdge);
56 for (; it != nodeboxes.end(); ++it)
57 b_max.addInternalBox(*it);
62 bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
65 static const v3s16 dir9_center[9] = {
77 INodeDefManager *nodemgr = m_client->ndef();
79 bool is_valid_position;
80 bool new_sneak_node_exists = m_sneak_node_exists;
82 // We want the top of the sneak node to be below the players feet
83 f32 position_y_mod = 0.05 * BS;
84 if (m_sneak_node_exists)
85 position_y_mod = m_sneak_node_bb_top.MaxEdge.Y - position_y_mod;
87 // Get position of current standing node
88 const v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
90 if (current_node != m_sneak_node) {
91 new_sneak_node_exists = false;
93 node = map->getNodeNoEx(current_node, &is_valid_position);
94 if (!is_valid_position || !nodemgr->get(node).walkable)
95 new_sneak_node_exists = false;
98 // Keep old sneak node
99 if (new_sneak_node_exists)
102 // Get new sneak node
103 m_sneak_ladder_detected = false;
104 f32 min_distance_f = 100000.0 * BS;
106 for (s16 d = 0; d < 9; d++) {
107 const v3s16 p = current_node + dir9_center[d];
108 const v3f pf = intToFloat(p, BS);
109 const v2f diff(position.X - pf.X, position.Z - pf.Z);
110 f32 distance_f = diff.getLength();
112 if (distance_f > min_distance_f ||
113 fabs(diff.X) > (.5 + .1) * BS + sneak_max.X ||
114 fabs(diff.Y) > (.5 + .1) * BS + sneak_max.Z)
118 // The node to be sneaked on has to be walkable
119 node = map->getNodeNoEx(p, &is_valid_position);
120 if (!is_valid_position || !nodemgr->get(node).walkable)
122 // And the node(s) above have to be nonwalkable
124 if (!physics_override_sneak_glitch) {
126 (m_collisionbox.MaxEdge.Y - m_collisionbox.MinEdge.Y) / BS
128 for (u16 y = 1; y <= height; y++) {
129 node = map->getNodeNoEx(p + v3s16(0, y, 0), &is_valid_position);
130 if (!is_valid_position || nodemgr->get(node).walkable) {
136 // legacy behaviour: check just one node
137 node = map->getNodeNoEx(p + v3s16(0, 1, 0), &is_valid_position);
138 ok = is_valid_position && !nodemgr->get(node).walkable;
143 min_distance_f = distance_f;
145 new_sneak_node_exists = true;
148 if (!new_sneak_node_exists)
151 // Update saved top bounding box of sneak node
152 node = map->getNodeNoEx(m_sneak_node);
153 std::vector<aabb3f> nodeboxes;
154 node.getCollisionBoxes(nodemgr, &nodeboxes);
155 m_sneak_node_bb_top = getNodeBoundingBox(nodeboxes);
157 if (physics_override_sneak_glitch) {
158 // Detect sneak ladder:
159 // Node two meters above sneak node must be solid
160 node = map->getNodeNoEx(m_sneak_node + v3s16(0, 2, 0),
162 if (is_valid_position && nodemgr->get(node).walkable) {
163 // Node three meters above: must be non-solid
164 node = map->getNodeNoEx(m_sneak_node + v3s16(0, 3, 0),
166 m_sneak_ladder_detected = is_valid_position &&
167 !nodemgr->get(node).walkable;
173 void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
174 std::vector<CollisionInfo> *collision_info)
176 // Temporary option for old move code
177 if (!physics_override_new_move) {
178 old_move(dtime, env, pos_max_d, collision_info);
182 Map *map = &env->getMap();
183 INodeDefManager *nodemgr = m_client->ndef();
185 v3f position = getPosition();
187 // Copy parent position if local player is attached
189 setPosition(overridePosition);
193 // Skip collision detection if noclip mode is used
194 bool fly_allowed = m_client->checkLocalPrivilege("fly");
195 bool noclip = m_client->checkLocalPrivilege("noclip") &&
196 g_settings->getBool("noclip");
197 bool free_move = noclip && fly_allowed && g_settings->getBool("free_move");
199 position += m_speed * dtime;
200 setPosition(position);
208 bool is_valid_position;
213 Check if player is in liquid (the oscillating value)
216 // If in liquid, the threshold of coming out is at higher y
219 pp = floatToInt(position + v3f(0,BS*0.1,0), BS);
220 node = map->getNodeNoEx(pp, &is_valid_position);
221 if (is_valid_position) {
222 in_liquid = nodemgr->get(node.getContent()).isLiquid();
223 liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
228 // If not in liquid, the threshold of going in is at lower y
231 pp = floatToInt(position + v3f(0,BS*0.5,0), BS);
232 node = map->getNodeNoEx(pp, &is_valid_position);
233 if (is_valid_position) {
234 in_liquid = nodemgr->get(node.getContent()).isLiquid();
235 liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
243 Check if player is in liquid (the stable value)
245 pp = floatToInt(position + v3f(0,0,0), BS);
246 node = map->getNodeNoEx(pp, &is_valid_position);
247 if (is_valid_position) {
248 in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
250 in_liquid_stable = false;
254 Check if player is climbing
258 pp = floatToInt(position + v3f(0,0.5*BS,0), BS);
259 v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS);
260 node = map->getNodeNoEx(pp, &is_valid_position);
261 bool is_valid_position2;
262 MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
264 if (!(is_valid_position && is_valid_position2)) {
267 is_climbing = (nodemgr->get(node.getContent()).climbable
268 || nodemgr->get(node2.getContent()).climbable) && !free_move;
272 Collision uncertainty radius
273 Make it a bit larger than the maximum distance of movement
275 //f32 d = pos_max_d * 1.1;
276 // A fairly large value in here makes moving smoother
279 // This should always apply, otherwise there are glitches
280 sanity_check(d > pos_max_d);
282 // TODO: this shouldn't be hardcoded but transmitted from server
283 float player_stepheight = (touching_ground) ? (BS * 0.6f) : (BS * 0.2f);
286 player_stepheight += (0.6f * BS);
289 v3f accel_f = v3f(0,0,0);
291 collisionMoveResult result = collisionMoveSimple(env, m_client,
292 pos_max_d, m_collisionbox, player_stepheight, dtime,
293 &position, &m_speed, accel_f);
295 bool could_sneak = control.sneak &&
296 !(fly_allowed && g_settings->getBool("free_move")) &&
297 !in_liquid && !is_climbing &&
298 physics_override_sneak;
300 If the player's feet touch the topside of any node, this is
303 Player is allowed to jump when this is true.
305 bool touching_ground_was = touching_ground;
306 touching_ground = result.touching_ground;
307 bool sneak_can_jump = false;
309 // Max. distance (X, Z) over border for sneaking determined by collision box
310 // * 0.49 to keep the center just barely on the node
311 v3f sneak_max = m_collisionbox.getExtent() * 0.49;
313 if (m_sneak_ladder_detected) {
314 // restore legacy behaviour (this makes the m_speed.Y hack necessary)
315 sneak_max = v3f(0.4 * BS, 0, 0.4 * BS);
319 If sneaking, keep on top of last walked node and don't fall off
321 if (could_sneak && m_sneak_node_exists) {
322 const v3f sn_f = intToFloat(m_sneak_node, BS);
323 const v3f bmin = sn_f + m_sneak_node_bb_top.MinEdge;
324 const v3f bmax = sn_f + m_sneak_node_bb_top.MaxEdge;
325 const v3f old_pos = position;
326 const v3f old_speed = m_speed;
327 f32 y_diff = bmax.Y - position.Y;
329 // (BS * 0.6f) is the basic stepheight while standing on ground
330 if (y_diff < BS * 0.6f) {
331 // Only center player when they're on the node
332 position.X = rangelim(position.X,
333 bmin.X - sneak_max.X, bmax.X + sneak_max.X);
334 position.Z = rangelim(position.Z,
335 bmin.Z - sneak_max.Z, bmax.Z + sneak_max.Z);
337 if (position.X != old_pos.X)
339 if (position.Z != old_pos.Z)
343 if (y_diff > 0 && m_speed.Y < 0 &&
344 (physics_override_sneak_glitch || y_diff < BS * 0.6f)) {
345 // Move player to the maximal height when falling or when
346 // the ledge is climbed on the next step.
351 // Allow jumping on node edges while sneaking
352 if (m_speed.Y == 0 || m_sneak_ladder_detected)
353 sneak_can_jump = true;
355 if (collision_info != NULL &&
356 m_speed.Y - old_speed.Y > BS) {
357 // Collide with sneak node, report fall damage
358 CollisionInfo sn_info;
359 sn_info.node_p = m_sneak_node;
360 sn_info.old_speed = old_speed;
361 sn_info.new_speed = m_speed;
362 collision_info->push_back(sn_info);
367 Find the next sneak node if necessary
369 bool new_sneak_node_exists = false;
372 new_sneak_node_exists = updateSneakNode(map, position, sneak_max);
375 Set new position but keep sneak node set
377 setPosition(position);
378 m_sneak_node_exists = new_sneak_node_exists;
384 // Dont report if flying
385 if(collision_info && !(g_settings->getBool("free_move") && fly_allowed)) {
386 for(size_t i=0; i<result.collisions.size(); i++) {
387 const CollisionInfo &info = result.collisions[i];
388 collision_info->push_back(info);
392 if(!result.standing_on_object && !touching_ground_was && touching_ground) {
393 MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
394 m_client->event()->put(e);
396 // Set camera impact value to be used for view bobbing
397 camera_impact = getSpeed().Y * -1;
401 camera_barely_in_ceiling = false;
402 v3s16 camera_np = floatToInt(getEyePosition(), BS);
403 MapNode n = map->getNodeNoEx(camera_np);
404 if(n.getContent() != CONTENT_IGNORE){
405 if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){
406 camera_barely_in_ceiling = true;
412 Check properties of the node on which the player is standing
414 const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
415 // Determine if jumping is possible
416 m_can_jump = (touching_ground && !in_liquid && !is_climbing)
418 if (itemgroup_get(f.groups, "disable_jump"))
421 // Jump key pressed while jumping off from a bouncy block
422 if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
423 m_speed.Y >= -0.5 * BS) {
424 float jumpspeed = movement_speed_jump * physics_override_jump;
426 // Reduce boost when speed already is high
427 m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
429 m_speed.Y += jumpspeed;
436 void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d)
438 move(dtime, env, pos_max_d, NULL);
441 void LocalPlayer::applyControl(float dtime)
444 swimming_vertical = false;
446 setPitch(control.pitch);
449 // Nullify speed and don't run positioning code if the player is attached
452 setSpeed(v3f(0,0,0));
456 v3f move_direction = v3f(0,0,1);
457 move_direction.rotateXZBy(getYaw());
459 v3f speedH = v3f(0,0,0); // Horizontal (X, Z)
460 v3f speedV = v3f(0,0,0); // Vertical (Y)
462 bool fly_allowed = m_client->checkLocalPrivilege("fly");
463 bool fast_allowed = m_client->checkLocalPrivilege("fast");
465 bool free_move = fly_allowed && g_settings->getBool("free_move");
466 bool fast_move = fast_allowed && g_settings->getBool("fast_move");
467 // When aux1_descends is enabled the fast key is used to go down, so fast isn't possible
468 bool fast_climb = fast_move && control.aux1 && !g_settings->getBool("aux1_descends");
469 bool continuous_forward = g_settings->getBool("continuous_forward");
470 bool always_fly_fast = g_settings->getBool("always_fly_fast");
472 // Whether superspeed mode is used or not
473 bool superspeed = false;
475 if (always_fly_fast && free_move && fast_move)
478 // Old descend control
479 if(g_settings->getBool("aux1_descends"))
481 // If free movement and fast movement, always move fast
482 if(free_move && fast_move)
485 // Auxiliary button 1 (E)
490 // In free movement mode, aux1 descends
492 speedV.Y = -movement_speed_fast;
494 speedV.Y = -movement_speed_walk;
496 else if(in_liquid || in_liquid_stable)
498 speedV.Y = -movement_speed_walk;
499 swimming_vertical = true;
503 speedV.Y = -movement_speed_climb;
507 // If not free movement but fast is allowed, aux1 is
514 // New minecraft-like descend control
517 // Auxiliary button 1 (E)
522 // aux1 is "Turbo button"
532 // In free movement mode, sneak descends
533 if (fast_move && (control.aux1 || always_fly_fast))
534 speedV.Y = -movement_speed_fast;
536 speedV.Y = -movement_speed_walk;
538 else if(in_liquid || in_liquid_stable)
541 speedV.Y = -movement_speed_fast;
543 speedV.Y = -movement_speed_walk;
544 swimming_vertical = true;
549 speedV.Y = -movement_speed_fast;
551 speedV.Y = -movement_speed_climb;
556 if (continuous_forward)
557 speedH += move_direction;
560 if (continuous_forward) {
564 speedH += move_direction;
568 speedH -= move_direction;
570 if (!control.up && !control.down) {
571 speedH -= move_direction *
572 (control.forw_move_joystick_axis / 32767.f);
575 speedH += move_direction.crossProduct(v3f(0,1,0));
578 speedH += move_direction.crossProduct(v3f(0,-1,0));
580 if (!control.left && !control.right) {
581 speedH -= move_direction.crossProduct(v3f(0,1,0)) *
582 (control.sidew_move_joystick_axis / 32767.f);
587 if (g_settings->getBool("aux1_descends") || always_fly_fast) {
589 speedV.Y = movement_speed_fast;
591 speedV.Y = movement_speed_walk;
593 if(fast_move && control.aux1)
594 speedV.Y = movement_speed_fast;
596 speedV.Y = movement_speed_walk;
602 NOTE: The d value in move() affects jump height by
603 raising the height at which the jump speed is kept
604 at its starting value
606 v3f speedJ = getSpeed();
607 if(speedJ.Y >= -0.5 * BS) {
608 speedJ.Y = movement_speed_jump * physics_override_jump;
611 MtEvent *e = new SimpleTriggerEvent("PlayerJump");
612 m_client->event()->put(e);
618 speedV.Y = movement_speed_fast;
620 speedV.Y = movement_speed_walk;
621 swimming_vertical = true;
626 speedV.Y = movement_speed_fast;
628 speedV.Y = movement_speed_climb;
632 // The speed of the player (Y is ignored)
633 if(superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
634 speedH = speedH.normalize() * movement_speed_fast;
635 else if(control.sneak && !free_move && !in_liquid && !in_liquid_stable)
636 speedH = speedH.normalize() * movement_speed_crouch;
638 speedH = speedH.normalize() * movement_speed_walk;
640 // Acceleration increase
641 f32 incH = 0; // Horizontal (X, Z)
642 f32 incV = 0; // Vertical (Y)
643 if((!touching_ground && !free_move && !is_climbing && !in_liquid) || (!free_move && m_can_jump && control.jump))
645 // Jumping and falling
646 if(superspeed || (fast_move && control.aux1))
647 incH = movement_acceleration_fast * BS * dtime;
649 incH = movement_acceleration_air * BS * dtime;
650 incV = 0; // No vertical acceleration in air
652 else if (superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
653 incH = incV = movement_acceleration_fast * BS * dtime;
655 incH = incV = movement_acceleration_default * BS * dtime;
657 // Accelerate to target speed with maximum increment
658 accelerateHorizontal(speedH * physics_override_speed, incH * physics_override_speed);
659 accelerateVertical(speedV * physics_override_speed, incV * physics_override_speed);
662 v3s16 LocalPlayer::getStandingNodePos()
664 if(m_sneak_node_exists)
666 return floatToInt(getPosition() - v3f(0, BS, 0), BS);
669 v3s16 LocalPlayer::getFootstepNodePos()
671 if (in_liquid_stable)
672 // Emit swimming sound if the player is in liquid
673 return floatToInt(getPosition(), BS);
675 // BS * 0.05 below the player's feet ensures a 1/16th height
676 // nodebox is detected instead of the node below it.
677 return floatToInt(getPosition() - v3f(0, BS * 0.05f, 0), BS);
678 // A larger distance below is necessary for a footstep sound
679 // when landing after a jump or fall. BS * 0.5 ensures water
680 // sounds when swimming in 1 node deep water.
681 return floatToInt(getPosition() - v3f(0, BS * 0.5f, 0), BS);
684 v3s16 LocalPlayer::getLightPosition() const
686 return floatToInt(m_position + v3f(0,BS+BS/2,0), BS);
689 v3f LocalPlayer::getEyeOffset() const
691 float eye_height = camera_barely_in_ceiling ? 1.5f : 1.625f;
692 return v3f(0, BS * eye_height, 0);
695 // Horizontal acceleration (X and Z), Y direction is ignored
696 void LocalPlayer::accelerateHorizontal(const v3f &target_speed, const f32 max_increase)
698 if (max_increase == 0)
701 v3f d_wanted = target_speed - m_speed;
703 f32 dl = d_wanted.getLength();
704 if (dl > max_increase)
707 v3f d = d_wanted.normalize() * dl;
713 // Vertical acceleration (Y), X and Z directions are ignored
714 void LocalPlayer::accelerateVertical(const v3f &target_speed, const f32 max_increase)
716 if (max_increase == 0)
719 f32 d_wanted = target_speed.Y - m_speed.Y;
720 if (d_wanted > max_increase)
721 d_wanted = max_increase;
722 else if (d_wanted < -max_increase)
723 d_wanted = -max_increase;
725 m_speed.Y += d_wanted;
728 // Temporary option for old move code
729 void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
730 std::vector<CollisionInfo> *collision_info)
732 Map *map = &env->getMap();
733 INodeDefManager *nodemgr = m_client->ndef();
735 v3f position = getPosition();
737 // Copy parent position if local player is attached
739 setPosition(overridePosition);
740 m_sneak_node_exists = false;
744 // Skip collision detection if noclip mode is used
745 bool fly_allowed = m_client->checkLocalPrivilege("fly");
746 bool noclip = m_client->checkLocalPrivilege("noclip") &&
747 g_settings->getBool("noclip");
748 bool free_move = noclip && fly_allowed && g_settings->getBool("free_move");
750 position += m_speed * dtime;
751 setPosition(position);
752 m_sneak_node_exists = false;
759 bool is_valid_position;
764 Check if player is in liquid (the oscillating value)
767 // If in liquid, the threshold of coming out is at higher y
768 pp = floatToInt(position + v3f(0, BS * 0.1, 0), BS);
769 node = map->getNodeNoEx(pp, &is_valid_position);
770 if (is_valid_position) {
771 in_liquid = nodemgr->get(node.getContent()).isLiquid();
772 liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
777 // If not in liquid, the threshold of going in is at lower y
778 pp = floatToInt(position + v3f(0, BS * 0.5, 0), BS);
779 node = map->getNodeNoEx(pp, &is_valid_position);
780 if (is_valid_position) {
781 in_liquid = nodemgr->get(node.getContent()).isLiquid();
782 liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
789 Check if player is in liquid (the stable value)
791 pp = floatToInt(position + v3f(0, 0, 0), BS);
792 node = map->getNodeNoEx(pp, &is_valid_position);
793 if (is_valid_position)
794 in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
796 in_liquid_stable = false;
799 Check if player is climbing
801 pp = floatToInt(position + v3f(0, 0.5 * BS, 0), BS);
802 v3s16 pp2 = floatToInt(position + v3f(0, -0.2 * BS, 0), BS);
803 node = map->getNodeNoEx(pp, &is_valid_position);
804 bool is_valid_position2;
805 MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
807 if (!(is_valid_position && is_valid_position2))
810 is_climbing = (nodemgr->get(node.getContent()).climbable ||
811 nodemgr->get(node2.getContent()).climbable) && !free_move;
814 Collision uncertainty radius
815 Make it a bit larger than the maximum distance of movement
817 //f32 d = pos_max_d * 1.1;
818 // A fairly large value in here makes moving smoother
820 // This should always apply, otherwise there are glitches
821 sanity_check(d > pos_max_d);
822 // Maximum distance over border for sneaking
823 f32 sneak_max = BS * 0.4;
826 If sneaking, keep in range from the last walked node and don't
829 if (control.sneak && m_sneak_node_exists &&
830 !(fly_allowed && g_settings->getBool("free_move")) && !in_liquid &&
831 physics_override_sneak) {
832 f32 maxd = 0.5 * BS + sneak_max;
833 v3f lwn_f = intToFloat(m_sneak_node, BS);
834 position.X = rangelim(position.X, lwn_f.X - maxd, lwn_f.X + maxd);
835 position.Z = rangelim(position.Z, lwn_f.Z - maxd, lwn_f.Z + maxd);
838 // Move up if necessary
839 f32 new_y = (lwn_f.Y - 0.5 * BS) + m_sneak_node_bb_ymax;
840 if (position.Y < new_y)
843 Collision seems broken, since player is sinking when
844 sneaking over the edges of current sneaking_node.
845 TODO (when fixed): Set Y-speed only to 0 when position.Y < new_y.
852 // this shouldn't be hardcoded but transmitted from server
853 float player_stepheight = touching_ground ? (BS * 0.6) : (BS * 0.2);
856 player_stepheight += (0.6 * BS);
859 v3f accel_f = v3f(0, 0, 0);
861 collisionMoveResult result = collisionMoveSimple(env, m_client,
862 pos_max_d, m_collisionbox, player_stepheight, dtime,
863 &position, &m_speed, accel_f);
866 If the player's feet touch the topside of any node, this is
869 Player is allowed to jump when this is true.
871 bool touching_ground_was = touching_ground;
872 touching_ground = result.touching_ground;
874 //bool standing_on_unloaded = result.standing_on_unloaded;
877 Check the nodes under the player to see from which node the
878 player is sneaking from, if any. If the node from under
879 the player has been removed, the player falls.
881 f32 position_y_mod = 0.05 * BS;
882 if (m_sneak_node_bb_ymax > 0)
883 position_y_mod = m_sneak_node_bb_ymax - position_y_mod;
884 v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
885 if (m_sneak_node_exists &&
886 nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
887 m_old_node_below_type != "air") {
888 // Old node appears to have been removed; that is,
889 // it wasn't air before but now it is
890 m_need_to_get_new_sneak_node = false;
891 m_sneak_node_exists = false;
892 } else if (nodemgr->get(map->getNodeNoEx(current_node)).name != "air") {
893 // We are on something, so make sure to recalculate the sneak
895 m_need_to_get_new_sneak_node = true;
898 if (m_need_to_get_new_sneak_node && physics_override_sneak) {
899 m_sneak_node_bb_ymax = 0;
900 v3s16 pos_i_bottom = floatToInt(position - v3f(0, position_y_mod, 0), BS);
901 v2f player_p2df(position.X, position.Z);
902 f32 min_distance_f = 100000.0 * BS;
903 // If already seeking from some node, compare to it.
904 v3s16 new_sneak_node = m_sneak_node;
905 for (s16 x= -1; x <= 1; x++)
906 for (s16 z= -1; z <= 1; z++) {
907 v3s16 p = pos_i_bottom + v3s16(x, 0, z);
908 v3f pf = intToFloat(p, BS);
909 v2f node_p2df(pf.X, pf.Z);
910 f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
911 f32 max_axis_distance_f = MYMAX(
912 fabs(player_p2df.X - node_p2df.X),
913 fabs(player_p2df.Y - node_p2df.Y));
915 if (distance_f > min_distance_f ||
916 max_axis_distance_f > 0.5 * BS + sneak_max + 0.1 * BS)
919 // The node to be sneaked on has to be walkable
920 node = map->getNodeNoEx(p, &is_valid_position);
921 if (!is_valid_position || nodemgr->get(node).walkable == false)
923 // And the node above it has to be nonwalkable
924 node = map->getNodeNoEx(p + v3s16(0, 1, 0), &is_valid_position);
925 if (!is_valid_position || nodemgr->get(node).walkable)
927 // If not 'sneak_glitch' the node 2 nodes above it has to be nonwalkable
928 if (!physics_override_sneak_glitch) {
929 node =map->getNodeNoEx(p + v3s16(0, 2, 0), &is_valid_position);
930 if (!is_valid_position || nodemgr->get(node).walkable)
934 min_distance_f = distance_f;
938 bool sneak_node_found = (min_distance_f < 100000.0 * BS * 0.9);
940 m_sneak_node = new_sneak_node;
941 m_sneak_node_exists = sneak_node_found;
943 if (sneak_node_found) {
945 MapNode n = map->getNodeNoEx(m_sneak_node);
946 std::vector<aabb3f> nodeboxes;
947 n.getCollisionBoxes(nodemgr, &nodeboxes);
948 for (std::vector<aabb3f>::iterator it = nodeboxes.begin();
949 it != nodeboxes.end(); ++it) {
951 if (box.MaxEdge.Y > cb_max)
952 cb_max = box.MaxEdge.Y;
954 m_sneak_node_bb_ymax = cb_max;
958 If sneaking, the player's collision box can be in air, so
959 this has to be set explicitly
961 if (sneak_node_found && control.sneak)
962 touching_ground = true;
966 Set new position but keep sneak node set
968 bool sneak_node_exists = m_sneak_node_exists;
969 setPosition(position);
970 m_sneak_node_exists = sneak_node_exists;
975 // Dont report if flying
976 if (collision_info && !(g_settings->getBool("free_move") && fly_allowed)) {
977 for (size_t i = 0; i < result.collisions.size(); i++) {
978 const CollisionInfo &info = result.collisions[i];
979 collision_info->push_back(info);
983 if (!result.standing_on_object && !touching_ground_was && touching_ground) {
984 MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
985 m_client->event()->put(e);
986 // Set camera impact value to be used for view bobbing
987 camera_impact = getSpeed().Y * -1;
991 camera_barely_in_ceiling = false;
992 v3s16 camera_np = floatToInt(getEyePosition(), BS);
993 MapNode n = map->getNodeNoEx(camera_np);
994 if (n.getContent() != CONTENT_IGNORE) {
995 if (nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2)
996 camera_barely_in_ceiling = true;
1001 Update the node last under the player
1003 m_old_node_below = floatToInt(position - v3f(0, BS / 2, 0), BS);
1004 m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
1007 Check properties of the node on which the player is standing
1009 const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
1010 // Determine if jumping is possible
1011 m_can_jump = touching_ground && !in_liquid;
1012 if (itemgroup_get(f.groups, "disable_jump"))
1014 // Jump key pressed while jumping off from a bouncy block
1015 if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
1016 m_speed.Y >= -0.5 * BS) {
1017 float jumpspeed = movement_speed_jump * physics_override_jump;
1018 if (m_speed.Y > 1) {
1019 // Reduce boost when speed already is high
1020 m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
1022 m_speed.Y += jumpspeed;