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 m_client->getEventManager()->put(new SimpleTriggerEvent(MtEvent::PLAYER_REGAIN_GROUND));
422 // Set camera impact value to be used for view bobbing
423 camera_impact = getSpeed().Y * -1;
427 camera_barely_in_ceiling = false;
428 v3s16 camera_np = floatToInt(getEyePosition(), BS);
429 MapNode n = map->getNodeNoEx(camera_np);
430 if(n.getContent() != CONTENT_IGNORE){
431 if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){
432 camera_barely_in_ceiling = true;
438 Check properties of the node on which the player is standing
440 const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(m_standing_node));
441 // Determine if jumping is possible
442 m_can_jump = (touching_ground && !in_liquid && !is_climbing)
444 if (itemgroup_get(f.groups, "disable_jump"))
447 // Jump key pressed while jumping off from a bouncy block
448 if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
449 m_speed.Y >= -0.5 * BS) {
450 float jumpspeed = movement_speed_jump * physics_override_jump;
452 // Reduce boost when speed already is high
453 m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
455 m_speed.Y += jumpspeed;
462 void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d)
464 move(dtime, env, pos_max_d, NULL);
467 void LocalPlayer::applyControl(float dtime, Environment *env)
470 swimming_vertical = false;
472 setPitch(control.pitch);
475 // Nullify speed and don't run positioning code if the player is attached
478 setSpeed(v3f(0,0,0));
482 v3f move_direction = v3f(0,0,1);
483 move_direction.rotateXZBy(getYaw());
485 v3f speedH = v3f(0,0,0); // Horizontal (X, Z)
486 v3f speedV = v3f(0,0,0); // Vertical (Y)
488 bool fly_allowed = m_client->checkLocalPrivilege("fly");
489 bool fast_allowed = m_client->checkLocalPrivilege("fast");
491 bool free_move = fly_allowed && g_settings->getBool("free_move");
492 bool fast_move = fast_allowed && g_settings->getBool("fast_move");
493 // When aux1_descends is enabled the fast key is used to go down, so fast isn't possible
494 bool fast_climb = fast_move && control.aux1 && !g_settings->getBool("aux1_descends");
495 bool continuous_forward = g_settings->getBool("continuous_forward");
496 bool always_fly_fast = g_settings->getBool("always_fly_fast");
498 // Whether superspeed mode is used or not
499 bool superspeed = false;
501 if (always_fly_fast && free_move && fast_move)
504 // Old descend control
505 if(g_settings->getBool("aux1_descends"))
507 // If free movement and fast movement, always move fast
508 if(free_move && fast_move)
511 // Auxiliary button 1 (E)
516 // In free movement mode, aux1 descends
518 speedV.Y = -movement_speed_fast;
520 speedV.Y = -movement_speed_walk;
522 else if(in_liquid || in_liquid_stable)
524 speedV.Y = -movement_speed_walk;
525 swimming_vertical = true;
529 speedV.Y = -movement_speed_climb;
533 // If not free movement but fast is allowed, aux1 is
540 // New minecraft-like descend control
543 // Auxiliary button 1 (E)
548 // aux1 is "Turbo button"
558 // In free movement mode, sneak descends
559 if (fast_move && (control.aux1 || always_fly_fast))
560 speedV.Y = -movement_speed_fast;
562 speedV.Y = -movement_speed_walk;
564 else if(in_liquid || in_liquid_stable)
567 speedV.Y = -movement_speed_fast;
569 speedV.Y = -movement_speed_walk;
570 swimming_vertical = true;
575 speedV.Y = -movement_speed_fast;
577 speedV.Y = -movement_speed_climb;
582 if (continuous_forward)
583 speedH += move_direction;
586 if (continuous_forward) {
590 speedH += move_direction;
594 speedH -= move_direction;
596 if (!control.up && !control.down) {
597 speedH -= move_direction *
598 (control.forw_move_joystick_axis / 32767.f);
601 speedH += move_direction.crossProduct(v3f(0,1,0));
604 speedH += move_direction.crossProduct(v3f(0,-1,0));
606 if (!control.left && !control.right) {
607 speedH -= move_direction.crossProduct(v3f(0,1,0)) *
608 (control.sidew_move_joystick_axis / 32767.f);
613 if (g_settings->getBool("aux1_descends") || always_fly_fast) {
615 speedV.Y = movement_speed_fast;
617 speedV.Y = movement_speed_walk;
619 if(fast_move && control.aux1)
620 speedV.Y = movement_speed_fast;
622 speedV.Y = movement_speed_walk;
628 NOTE: The d value in move() affects jump height by
629 raising the height at which the jump speed is kept
630 at its starting value
632 v3f speedJ = getSpeed();
633 if(speedJ.Y >= -0.5 * BS) {
634 speedJ.Y = movement_speed_jump * physics_override_jump;
636 m_client->getEventManager()->put(new SimpleTriggerEvent(MtEvent::PLAYER_JUMP));
642 speedV.Y = movement_speed_fast;
644 speedV.Y = movement_speed_walk;
645 swimming_vertical = true;
650 speedV.Y = movement_speed_fast;
652 speedV.Y = movement_speed_climb;
656 // The speed of the player (Y is ignored)
657 if(superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
658 speedH = speedH.normalize() * movement_speed_fast;
659 else if(control.sneak && !free_move && !in_liquid && !in_liquid_stable)
660 speedH = speedH.normalize() * movement_speed_crouch;
662 speedH = speedH.normalize() * movement_speed_walk;
664 // Acceleration increase
665 f32 incH = 0; // Horizontal (X, Z)
666 f32 incV = 0; // Vertical (Y)
667 if((!touching_ground && !free_move && !is_climbing && !in_liquid) || (!free_move && m_can_jump && control.jump))
669 // Jumping and falling
670 if(superspeed || (fast_move && control.aux1))
671 incH = movement_acceleration_fast * BS * dtime;
673 incH = movement_acceleration_air * BS * dtime;
674 incV = 0; // No vertical acceleration in air
676 else if (superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
677 incH = incV = movement_acceleration_fast * BS * dtime;
679 incH = incV = movement_acceleration_default * BS * dtime;
681 float slip_factor = 1.0f;
683 slip_factor = getSlipFactor(env, speedH);
685 // Accelerate to target speed with maximum increment
686 accelerateHorizontal(speedH * physics_override_speed,
687 incH * physics_override_speed * slip_factor);
688 accelerateVertical(speedV * physics_override_speed,
689 incV * physics_override_speed);
692 v3s16 LocalPlayer::getStandingNodePos()
694 if(m_sneak_node_exists)
696 return m_standing_node;
699 v3s16 LocalPlayer::getFootstepNodePos()
701 if (in_liquid_stable)
702 // Emit swimming sound if the player is in liquid
703 return floatToInt(getPosition(), BS);
705 // BS * 0.05 below the player's feet ensures a 1/16th height
706 // nodebox is detected instead of the node below it.
707 return floatToInt(getPosition() - v3f(0, BS * 0.05f, 0), BS);
708 // A larger distance below is necessary for a footstep sound
709 // when landing after a jump or fall. BS * 0.5 ensures water
710 // sounds when swimming in 1 node deep water.
711 return floatToInt(getPosition() - v3f(0, BS * 0.5f, 0), BS);
714 v3s16 LocalPlayer::getLightPosition() const
716 return floatToInt(m_position + v3f(0,BS+BS/2,0), BS);
719 v3f LocalPlayer::getEyeOffset() const
721 float eye_height = camera_barely_in_ceiling ?
722 m_eye_height - 0.125f : m_eye_height;
723 return v3f(0, BS * eye_height, 0);
726 // Horizontal acceleration (X and Z), Y direction is ignored
727 void LocalPlayer::accelerateHorizontal(const v3f &target_speed,
728 const f32 max_increase)
730 if (max_increase == 0)
733 v3f d_wanted = target_speed - m_speed;
735 f32 dl = d_wanted.getLength();
736 if (dl > max_increase)
739 v3f d = d_wanted.normalize() * dl;
745 // Vertical acceleration (Y), X and Z directions are ignored
746 void LocalPlayer::accelerateVertical(const v3f &target_speed, const f32 max_increase)
748 if (max_increase == 0)
751 f32 d_wanted = target_speed.Y - m_speed.Y;
752 if (d_wanted > max_increase)
753 d_wanted = max_increase;
754 else if (d_wanted < -max_increase)
755 d_wanted = -max_increase;
757 m_speed.Y += d_wanted;
760 // Temporary option for old move code
761 void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
762 std::vector<CollisionInfo> *collision_info)
764 Map *map = &env->getMap();
765 const NodeDefManager *nodemgr = m_client->ndef();
767 v3f position = getPosition();
769 // Copy parent position if local player is attached
771 setPosition(overridePosition);
772 m_sneak_node_exists = false;
776 // Skip collision detection if noclip mode is used
777 bool fly_allowed = m_client->checkLocalPrivilege("fly");
778 bool noclip = m_client->checkLocalPrivilege("noclip") &&
779 g_settings->getBool("noclip");
780 bool free_move = noclip && fly_allowed && g_settings->getBool("free_move");
782 position += m_speed * dtime;
783 setPosition(position);
784 m_sneak_node_exists = false;
791 bool is_valid_position;
796 Check if player is in liquid (the oscillating value)
799 // If in liquid, the threshold of coming out is at higher y
800 pp = floatToInt(position + v3f(0, BS * 0.1, 0), BS);
801 node = map->getNodeNoEx(pp, &is_valid_position);
802 if (is_valid_position) {
803 in_liquid = nodemgr->get(node.getContent()).isLiquid();
804 liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
809 // If not in liquid, the threshold of going in is at lower y
810 pp = floatToInt(position + v3f(0, BS * 0.5, 0), BS);
811 node = map->getNodeNoEx(pp, &is_valid_position);
812 if (is_valid_position) {
813 in_liquid = nodemgr->get(node.getContent()).isLiquid();
814 liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
821 Check if player is in liquid (the stable value)
823 pp = floatToInt(position + v3f(0, 0, 0), BS);
824 node = map->getNodeNoEx(pp, &is_valid_position);
825 if (is_valid_position)
826 in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
828 in_liquid_stable = false;
831 Check if player is climbing
833 pp = floatToInt(position + v3f(0, 0.5 * BS, 0), BS);
834 v3s16 pp2 = floatToInt(position + v3f(0, -0.2 * BS, 0), BS);
835 node = map->getNodeNoEx(pp, &is_valid_position);
836 bool is_valid_position2;
837 MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
839 if (!(is_valid_position && is_valid_position2))
842 is_climbing = (nodemgr->get(node.getContent()).climbable ||
843 nodemgr->get(node2.getContent()).climbable) && !free_move;
846 Collision uncertainty radius
847 Make it a bit larger than the maximum distance of movement
849 //f32 d = pos_max_d * 1.1;
850 // A fairly large value in here makes moving smoother
852 // This should always apply, otherwise there are glitches
853 sanity_check(d > pos_max_d);
854 // Maximum distance over border for sneaking
855 f32 sneak_max = BS * 0.4;
858 If sneaking, keep in range from the last walked node and don't
861 if (control.sneak && m_sneak_node_exists &&
862 !(fly_allowed && g_settings->getBool("free_move")) && !in_liquid &&
863 physics_override_sneak) {
864 f32 maxd = 0.5 * BS + sneak_max;
865 v3f lwn_f = intToFloat(m_sneak_node, BS);
866 position.X = rangelim(position.X, lwn_f.X - maxd, lwn_f.X + maxd);
867 position.Z = rangelim(position.Z, lwn_f.Z - maxd, lwn_f.Z + maxd);
870 // Move up if necessary
871 f32 new_y = (lwn_f.Y - 0.5 * BS) + m_sneak_node_bb_ymax;
872 if (position.Y < new_y)
875 Collision seems broken, since player is sinking when
876 sneaking over the edges of current sneaking_node.
877 TODO (when fixed): Set Y-speed only to 0 when position.Y < new_y.
884 // this shouldn't be hardcoded but transmitted from server
885 float player_stepheight = touching_ground ? (BS * 0.6) : (BS * 0.2);
888 player_stepheight += (0.6 * BS);
891 v3f accel_f = v3f(0, 0, 0);
893 collisionMoveResult result = collisionMoveSimple(env, m_client,
894 pos_max_d, m_collisionbox, player_stepheight, dtime,
895 &position, &m_speed, accel_f);
898 If the player's feet touch the topside of any node, this is
901 Player is allowed to jump when this is true.
903 bool touching_ground_was = touching_ground;
904 touching_ground = result.touching_ground;
906 //bool standing_on_unloaded = result.standing_on_unloaded;
909 Check the nodes under the player to see from which node the
910 player is sneaking from, if any. If the node from under
911 the player has been removed, the player falls.
913 f32 position_y_mod = 0.05 * BS;
914 if (m_sneak_node_bb_ymax > 0)
915 position_y_mod = m_sneak_node_bb_ymax - position_y_mod;
916 v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
917 if (m_sneak_node_exists &&
918 nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
919 m_old_node_below_type != "air") {
920 // Old node appears to have been removed; that is,
921 // it wasn't air before but now it is
922 m_need_to_get_new_sneak_node = false;
923 m_sneak_node_exists = false;
924 } else if (nodemgr->get(map->getNodeNoEx(current_node)).name != "air") {
925 // We are on something, so make sure to recalculate the sneak
927 m_need_to_get_new_sneak_node = true;
930 if (m_need_to_get_new_sneak_node && physics_override_sneak) {
931 m_sneak_node_bb_ymax = 0;
932 v3s16 pos_i_bottom = floatToInt(position - v3f(0, position_y_mod, 0), BS);
933 v2f player_p2df(position.X, position.Z);
934 f32 min_distance_f = 100000.0 * BS;
935 // If already seeking from some node, compare to it.
936 v3s16 new_sneak_node = m_sneak_node;
937 for (s16 x= -1; x <= 1; x++)
938 for (s16 z= -1; z <= 1; z++) {
939 v3s16 p = pos_i_bottom + v3s16(x, 0, z);
940 v3f pf = intToFloat(p, BS);
941 v2f node_p2df(pf.X, pf.Z);
942 f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
943 f32 max_axis_distance_f = MYMAX(
944 std::fabs(player_p2df.X - node_p2df.X),
945 std::fabs(player_p2df.Y - node_p2df.Y));
947 if (distance_f > min_distance_f ||
948 max_axis_distance_f > 0.5 * BS + sneak_max + 0.1 * BS)
951 // The node to be sneaked on has to be walkable
952 node = map->getNodeNoEx(p, &is_valid_position);
953 if (!is_valid_position || !nodemgr->get(node).walkable)
955 // And the node above it has to be nonwalkable
956 node = map->getNodeNoEx(p + v3s16(0, 1, 0), &is_valid_position);
957 if (!is_valid_position || nodemgr->get(node).walkable)
959 // If not 'sneak_glitch' the node 2 nodes above it has to be nonwalkable
960 if (!physics_override_sneak_glitch) {
961 node =map->getNodeNoEx(p + v3s16(0, 2, 0), &is_valid_position);
962 if (!is_valid_position || nodemgr->get(node).walkable)
966 min_distance_f = distance_f;
970 bool sneak_node_found = (min_distance_f < 100000.0 * BS * 0.9);
972 m_sneak_node = new_sneak_node;
973 m_sneak_node_exists = sneak_node_found;
975 if (sneak_node_found) {
977 MapNode n = map->getNodeNoEx(m_sneak_node);
978 std::vector<aabb3f> nodeboxes;
979 n.getCollisionBoxes(nodemgr, &nodeboxes);
980 for (const auto &box : nodeboxes) {
981 if (box.MaxEdge.Y > cb_max)
982 cb_max = box.MaxEdge.Y;
984 m_sneak_node_bb_ymax = cb_max;
988 If sneaking, the player's collision box can be in air, so
989 this has to be set explicitly
991 if (sneak_node_found && control.sneak)
992 touching_ground = true;
996 Set new position but keep sneak node set
998 bool sneak_node_exists = m_sneak_node_exists;
999 setPosition(position);
1000 m_sneak_node_exists = sneak_node_exists;
1005 // Dont report if flying
1006 if (collision_info && !(g_settings->getBool("free_move") && fly_allowed)) {
1007 for (const auto &info : result.collisions) {
1008 collision_info->push_back(info);
1012 if (!result.standing_on_object && !touching_ground_was && touching_ground) {
1013 m_client->getEventManager()->put(new SimpleTriggerEvent(MtEvent::PLAYER_REGAIN_GROUND));
1014 // Set camera impact value to be used for view bobbing
1015 camera_impact = getSpeed().Y * -1;
1019 camera_barely_in_ceiling = false;
1020 v3s16 camera_np = floatToInt(getEyePosition(), BS);
1021 MapNode n = map->getNodeNoEx(camera_np);
1022 if (n.getContent() != CONTENT_IGNORE) {
1023 if (nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2)
1024 camera_barely_in_ceiling = true;
1029 Update the node last under the player
1031 m_old_node_below = floatToInt(position - v3f(0, BS / 2, 0), BS);
1032 m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
1035 Check properties of the node on which the player is standing
1037 const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
1038 // Determine if jumping is possible
1039 m_can_jump = touching_ground && !in_liquid;
1040 if (itemgroup_get(f.groups, "disable_jump"))
1042 // Jump key pressed while jumping off from a bouncy block
1043 if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
1044 m_speed.Y >= -0.5 * BS) {
1045 float jumpspeed = movement_speed_jump * physics_override_jump;
1046 if (m_speed.Y > 1) {
1047 // Reduce boost when speed already is high
1048 m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
1050 m_speed.Y += jumpspeed;
1057 float LocalPlayer::getSlipFactor(Environment *env, const v3f &speedH)
1059 // Slip on slippery nodes
1060 const NodeDefManager *nodemgr = env->getGameDef()->ndef();
1061 Map *map = &env->getMap();
1062 const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(
1063 getStandingNodePos()));
1066 slippery = itemgroup_get(f.groups, "slippery");
1068 if (slippery >= 1) {
1069 if (speedH == v3f(0.0f)) {
1070 slippery = slippery * 2;
1072 return core::clamp(1.0f / (slippery + 1), 0.001f, 1.0f);