]> git.lizzy.rs Git - dragonfireclient.git/blob - src/client/localplayer.cpp
Disable autoforward if player is dead
[dragonfireclient.git] / src / client / localplayer.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
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.
9
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.
14
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.
18 */
19
20 #include "localplayer.h"
21 #include <cmath>
22 #include "event.h"
23 #include "collision.h"
24 #include "nodedef.h"
25 #include "settings.h"
26 #include "environment.h"
27 #include "map.h"
28 #include "client.h"
29 #include "content_cao.h"
30
31 /*
32         LocalPlayer
33 */
34
35 LocalPlayer::LocalPlayer(Client *client, const char *name):
36         Player(name, client->idef()),
37         m_client(client)
38 {
39 }
40
41 static aabb3f getNodeBoundingBox(const std::vector<aabb3f> &nodeboxes)
42 {
43         if (nodeboxes.empty())
44                 return aabb3f(0, 0, 0, 0, 0, 0);
45
46         aabb3f b_max;
47
48         std::vector<aabb3f>::const_iterator it = nodeboxes.begin();
49         b_max = aabb3f(it->MinEdge, it->MaxEdge);
50
51         ++it;
52         for (; it != nodeboxes.end(); ++it)
53                 b_max.addInternalBox(*it);
54
55         return b_max;
56 }
57
58 bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
59                 const v3f &sneak_max)
60 {
61         static const v3s16 dir9_center[9] = {
62                 v3s16( 0, 0,  0),
63                 v3s16( 1, 0,  0),
64                 v3s16(-1, 0,  0),
65                 v3s16( 0, 0,  1),
66                 v3s16( 0, 0, -1),
67                 v3s16( 1, 0,  1),
68                 v3s16(-1, 0,  1),
69                 v3s16( 1, 0, -1),
70                 v3s16(-1, 0, -1)
71         };
72
73         const NodeDefManager *nodemgr = m_client->ndef();
74         MapNode node;
75         bool is_valid_position;
76         bool new_sneak_node_exists = m_sneak_node_exists;
77
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;
82
83         // Get position of current standing node
84         const v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
85
86         if (current_node != m_sneak_node) {
87                 new_sneak_node_exists = false;
88         } else {
89                 node = map->getNode(current_node, &is_valid_position);
90                 if (!is_valid_position || !nodemgr->get(node).walkable)
91                         new_sneak_node_exists = false;
92         }
93
94         // Keep old sneak node
95         if (new_sneak_node_exists)
96                 return true;
97
98         // Get new sneak node
99         m_sneak_ladder_detected = false;
100         f32 min_distance_f = 100000.0 * BS;
101
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();
107
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)
111                         continue;
112
113
114                 // The node to be sneaked on has to be walkable
115                 node = map->getNode(p, &is_valid_position);
116                 if (!is_valid_position || !nodemgr->get(node).walkable)
117                         continue;
118                 // And the node(s) above have to be nonwalkable
119                 bool ok = true;
120                 if (!physics_override_sneak_glitch) {
121                         u16 height = ceilf(
122                                         (m_collisionbox.MaxEdge.Y - m_collisionbox.MinEdge.Y) / BS
123                         );
124                         for (u16 y = 1; y <= height; y++) {
125                                 node = map->getNode(p + v3s16(0, y, 0), &is_valid_position);
126                                 if (!is_valid_position || nodemgr->get(node).walkable) {
127                                         ok = false;
128                                         break;
129                                 }
130                         }
131                 } else {
132                         // legacy behaviour: check just one node
133                         node = map->getNode(p + v3s16(0, 1, 0), &is_valid_position);
134                         ok = is_valid_position && !nodemgr->get(node).walkable;
135                 }
136                 if (!ok)
137                         continue;
138
139                 min_distance_f = distance_f;
140                 m_sneak_node = p;
141                 new_sneak_node_exists = true;
142         }
143
144         if (!new_sneak_node_exists)
145                 return false;
146
147         // Update saved top bounding box of sneak node
148         node = map->getNode(m_sneak_node);
149         std::vector<aabb3f> nodeboxes;
150         node.getCollisionBoxes(nodemgr, &nodeboxes);
151         m_sneak_node_bb_top = getNodeBoundingBox(nodeboxes);
152
153         if (physics_override_sneak_glitch) {
154                 // Detect sneak ladder:
155                 // Node two meters above sneak node must be solid
156                 node = map->getNode(m_sneak_node + v3s16(0, 2, 0),
157                         &is_valid_position);
158                 if (is_valid_position && nodemgr->get(node).walkable) {
159                         // Node three meters above: must be non-solid
160                         node = map->getNode(m_sneak_node + v3s16(0, 3, 0),
161                                 &is_valid_position);
162                         m_sneak_ladder_detected = is_valid_position &&
163                                 !nodemgr->get(node).walkable;
164                 }
165         }
166         return true;
167 }
168
169 void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
170                 std::vector<CollisionInfo> *collision_info)
171 {
172         if (!collision_info || collision_info->empty()) {
173                 // Node at feet position, update each ClientEnvironment::step()
174                 m_standing_node = floatToInt(m_position, BS);
175         }
176
177         // Temporary option for old move code
178         if (!physics_override_new_move) {
179                 old_move(dtime, env, pos_max_d, collision_info);
180                 return;
181         }
182
183         Map *map = &env->getMap();
184         const NodeDefManager *nodemgr = m_client->ndef();
185
186         v3f position = getPosition();
187
188         // Copy parent position if local player is attached
189         if (isAttached) {
190                 setPosition(overridePosition);
191                 added_velocity = v3f(); // ignored
192                 return;
193         }
194
195         PlayerSettings &player_settings = getPlayerSettings();
196
197         // Skip collision detection if noclip mode is used
198         bool fly_allowed = m_client->checkLocalPrivilege("fly");
199         bool noclip = m_client->checkLocalPrivilege("noclip") && player_settings.noclip;
200         bool free_move = player_settings.free_move && fly_allowed;
201
202         if (noclip && free_move) {
203                 position += m_speed * dtime;
204                 setPosition(position);
205                 added_velocity = v3f(); // ignored
206                 return;
207         }
208
209         m_speed += added_velocity;
210         added_velocity = v3f();
211
212         /*
213                 Collision detection
214         */
215
216         bool is_valid_position;
217         MapNode node;
218         v3s16 pp;
219
220         /*
221                 Check if player is in liquid (the oscillating value)
222         */
223
224         // If in liquid, the threshold of coming out is at higher y
225         if (in_liquid)
226         {
227                 pp = floatToInt(position + v3f(0,BS*0.1,0), BS);
228                 node = map->getNode(pp, &is_valid_position);
229                 if (is_valid_position) {
230                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
231                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
232                 } else {
233                         in_liquid = false;
234                 }
235         }
236         // If not in liquid, the threshold of going in is at lower y
237         else
238         {
239                 pp = floatToInt(position + v3f(0,BS*0.5,0), BS);
240                 node = map->getNode(pp, &is_valid_position);
241                 if (is_valid_position) {
242                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
243                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
244                 } else {
245                         in_liquid = false;
246                 }
247         }
248
249
250         /*
251                 Check if player is in liquid (the stable value)
252         */
253         pp = floatToInt(position + v3f(0,0,0), BS);
254         node = map->getNode(pp, &is_valid_position);
255         if (is_valid_position) {
256                 in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
257         } else {
258                 in_liquid_stable = false;
259         }
260
261         /*
262                         Check if player is climbing
263         */
264
265
266         pp = floatToInt(position + v3f(0,0.5*BS,0), BS);
267         v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS);
268         node = map->getNode(pp, &is_valid_position);
269         bool is_valid_position2;
270         MapNode node2 = map->getNode(pp2, &is_valid_position2);
271
272         if (!(is_valid_position && is_valid_position2)) {
273                 is_climbing = false;
274         } else {
275                 is_climbing = (nodemgr->get(node.getContent()).climbable
276                                 || nodemgr->get(node2.getContent()).climbable) && !free_move;
277         }
278
279         /*
280                 Collision uncertainty radius
281                 Make it a bit larger than the maximum distance of movement
282         */
283         //f32 d = pos_max_d * 1.1;
284         // A fairly large value in here makes moving smoother
285         f32 d = 0.15*BS;
286
287         // This should always apply, otherwise there are glitches
288         sanity_check(d > pos_max_d);
289
290         // Player object property step height is multiplied by BS in
291         // /src/script/common/c_content.cpp and /src/content_sao.cpp
292         float player_stepheight = (m_cao == nullptr) ? 0.0f :
293                 (touching_ground ? m_cao->getStepHeight() : (0.2f * BS));
294
295         v3f accel_f = v3f(0,0,0);
296         const v3f initial_position = position;
297         const v3f initial_speed = m_speed;
298
299         collisionMoveResult result = collisionMoveSimple(env, m_client,
300                 pos_max_d, m_collisionbox, player_stepheight, dtime,
301                 &position, &m_speed, accel_f);
302
303         bool could_sneak = control.sneak && !free_move && !in_liquid &&
304                 !is_climbing && physics_override_sneak;
305
306         // Add new collisions to the vector
307         if (collision_info && !free_move) {
308                 v3f diff = intToFloat(m_standing_node, BS) - position;
309                 f32 distance = diff.getLength();
310                 // Force update each ClientEnvironment::step()
311                 bool is_first = collision_info->empty();
312
313                 for (const auto &colinfo : result.collisions) {
314                         collision_info->push_back(colinfo);
315
316                         if (colinfo.type != COLLISION_NODE ||
317                                         colinfo.axis != COLLISION_AXIS_Y ||
318                                         (could_sneak && m_sneak_node_exists))
319                                 continue;
320
321                         diff = intToFloat(colinfo.node_p, BS) - position;
322
323                         // Find nearest colliding node
324                         f32 len = diff.getLength();
325                         if (is_first || len < distance) {
326                                 m_standing_node = colinfo.node_p;
327                                 distance = len;
328                                 is_first = false;
329                         }
330                 }
331         }
332
333         /*
334                 If the player's feet touch the topside of any node, this is
335                 set to true.
336
337                 Player is allowed to jump when this is true.
338         */
339         bool touching_ground_was = touching_ground;
340         touching_ground = result.touching_ground;
341         bool sneak_can_jump = false;
342
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;
346
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);
350         }
351
352         /*
353                 If sneaking, keep on top of last walked node and don't fall off
354         */
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;
363
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);
371
372                         if (position.X != old_pos.X)
373                                 m_speed.X = 0;
374                         if (position.Z != old_pos.Z)
375                                 m_speed.Z = 0;
376                 }
377
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.
382
383                         // Smoothen the movement (based on 'position.Y = bmax.Y')
384                         position.Y += y_diff * dtime * 22.0f + BS * 0.01f;
385                         position.Y = std::min(position.Y, bmax.Y);
386                         m_speed.Y = 0;
387                 }
388
389                 // Allow jumping on node edges while sneaking
390                 if (m_speed.Y == 0 || m_sneak_ladder_detected)
391                         sneak_can_jump = true;
392
393                 if (collision_info &&
394                                 m_speed.Y - old_speed.Y > BS) {
395                         // Collide with sneak node, report fall damage
396                         CollisionInfo sn_info;
397                         sn_info.node_p = m_sneak_node;
398                         sn_info.old_speed = old_speed;
399                         sn_info.new_speed = m_speed;
400                         collision_info->push_back(sn_info);
401                 }
402         }
403
404         /*
405                 Find the next sneak node if necessary
406         */
407         bool new_sneak_node_exists = false;
408
409         if (could_sneak)
410                 new_sneak_node_exists = updateSneakNode(map, position, sneak_max);
411
412         /*
413                 Set new position but keep sneak node set
414         */
415         setPosition(position);
416         m_sneak_node_exists = new_sneak_node_exists;
417
418         /*
419                 Report collisions
420         */
421
422         if(!result.standing_on_object && !touching_ground_was && touching_ground) {
423                 m_client->getEventManager()->put(new SimpleTriggerEvent(MtEvent::PLAYER_REGAIN_GROUND));
424
425                 // Set camera impact value to be used for view bobbing
426                 camera_impact = getSpeed().Y * -1;
427         }
428
429         {
430                 camera_barely_in_ceiling = false;
431                 v3s16 camera_np = floatToInt(getEyePosition(), BS);
432                 MapNode n = map->getNode(camera_np);
433                 if(n.getContent() != CONTENT_IGNORE){
434                         if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){
435                                 camera_barely_in_ceiling = true;
436                         }
437                 }
438         }
439
440         /*
441                 Check properties of the node on which the player is standing
442         */
443         const ContentFeatures &f = nodemgr->get(map->getNode(m_standing_node));
444
445         // Determine if jumping is possible
446         m_disable_jump = itemgroup_get(f.groups, "disable_jump");
447         m_can_jump = ((touching_ground && !is_climbing)
448                         || sneak_can_jump) && !m_disable_jump;
449
450         // Jump key pressed while jumping off from a bouncy block
451         if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
452                 m_speed.Y >= -0.5 * BS) {
453                 float jumpspeed = movement_speed_jump * physics_override_jump;
454                 if (m_speed.Y > 1) {
455                         // Reduce boost when speed already is high
456                         m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
457                 } else {
458                         m_speed.Y += jumpspeed;
459                 }
460                 setSpeed(m_speed);
461                 m_can_jump = false;
462         }
463
464         // Autojump
465         handleAutojump(dtime, env, result, initial_position, initial_speed, pos_max_d);
466 }
467
468 void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d)
469 {
470         move(dtime, env, pos_max_d, NULL);
471 }
472
473 void LocalPlayer::applyControl(float dtime, Environment *env)
474 {
475         // Clear stuff
476         swimming_vertical = false;
477         swimming_pitch = false;
478
479         setPitch(control.pitch);
480         setYaw(control.yaw);
481
482         // Nullify speed and don't run positioning code if the player is attached
483         if(isAttached)
484         {
485                 setSpeed(v3f(0,0,0));
486                 return;
487         }
488
489         PlayerSettings &player_settings = getPlayerSettings();
490
491         // All vectors are relative to the player's yaw,
492         // (and pitch if pitch move mode enabled),
493         // and will be rotated at the end
494         v3f speedH = v3f(0,0,0); // Horizontal (X, Z)
495         v3f speedV = v3f(0,0,0); // Vertical (Y)
496
497         bool fly_allowed = m_client->checkLocalPrivilege("fly");
498         bool fast_allowed = m_client->checkLocalPrivilege("fast");
499
500         bool free_move = fly_allowed && player_settings.free_move;
501         bool fast_move = fast_allowed && player_settings.fast_move;
502         bool pitch_move = (free_move || in_liquid) && player_settings.pitch_move;
503         // When aux1_descends is enabled the fast key is used to go down, so fast isn't possible
504         bool fast_climb = fast_move && control.aux1 && !player_settings.aux1_descends;
505         bool always_fly_fast = player_settings.always_fly_fast;
506
507         // Whether superspeed mode is used or not
508         bool superspeed = false;
509
510         if (always_fly_fast && free_move && fast_move)
511                 superspeed = true;
512
513         // Old descend control
514         if (player_settings.aux1_descends)
515         {
516                 // If free movement and fast movement, always move fast
517                 if(free_move && fast_move)
518                         superspeed = true;
519
520                 // Auxiliary button 1 (E)
521                 if(control.aux1)
522                 {
523                         if(free_move)
524                         {
525                                 // In free movement mode, aux1 descends
526                                 if(fast_move)
527                                         speedV.Y = -movement_speed_fast;
528                                 else
529                                         speedV.Y = -movement_speed_walk;
530                         }
531                         else if(in_liquid || in_liquid_stable)
532                         {
533                                 speedV.Y = -movement_speed_walk;
534                                 swimming_vertical = true;
535                         }
536                         else if(is_climbing)
537                         {
538                                 speedV.Y = -movement_speed_climb;
539                         }
540                         else
541                         {
542                                 // If not free movement but fast is allowed, aux1 is
543                                 // "Turbo button"
544                                 if(fast_move)
545                                         superspeed = true;
546                         }
547                 }
548         }
549         // New minecraft-like descend control
550         else
551         {
552                 // Auxiliary button 1 (E)
553                 if(control.aux1)
554                 {
555                         if(!is_climbing)
556                         {
557                                 // aux1 is "Turbo button"
558                                 if(fast_move)
559                                         superspeed = true;
560                         }
561                 }
562
563                 if(control.sneak)
564                 {
565                         if(free_move)
566                         {
567                                 // In free movement mode, sneak descends
568                                 if (fast_move && (control.aux1 || always_fly_fast))
569                                         speedV.Y = -movement_speed_fast;
570                                 else
571                                         speedV.Y = -movement_speed_walk;
572                         }
573                         else if(in_liquid || in_liquid_stable)
574                         {
575                                 if(fast_climb)
576                                         speedV.Y = -movement_speed_fast;
577                                 else
578                                         speedV.Y = -movement_speed_walk;
579                                 swimming_vertical = true;
580                         }
581                         else if(is_climbing)
582                         {
583                                 if(fast_climb)
584                                         speedV.Y = -movement_speed_fast;
585                                 else
586                                         speedV.Y = -movement_speed_climb;
587                         }
588                 }
589         }
590
591         if (control.up) {
592                 speedH += v3f(0,0,1);
593         }
594         if (control.down) {
595                 speedH -= v3f(0,0,1);
596         }
597         if (!control.up && !control.down) {
598                 speedH -= v3f(0,0,1) *
599                         (control.forw_move_joystick_axis / 32767.f);
600         }
601         if (control.left) {
602                 speedH += v3f(-1,0,0);
603         }
604         if (control.right) {
605                 speedH += v3f(1,0,0);
606         }
607         if (!control.left && !control.right) {
608                 speedH += v3f(1,0,0) *
609                         (control.sidew_move_joystick_axis / 32767.f);
610         }
611         if (m_autojump) {
612                 // release autojump after a given time
613                 m_autojump_time -= dtime;
614                 if (m_autojump_time <= 0.0f)
615                         m_autojump = false;
616         }
617         if(control.jump)
618         {
619                 if (free_move) {
620                         if (player_settings.aux1_descends || always_fly_fast) {
621                                 if (fast_move)
622                                         speedV.Y = movement_speed_fast;
623                                 else
624                                         speedV.Y = movement_speed_walk;
625                         } else {
626                                 if(fast_move && control.aux1)
627                                         speedV.Y = movement_speed_fast;
628                                 else
629                                         speedV.Y = movement_speed_walk;
630                         }
631                 }
632                 else if(m_can_jump)
633                 {
634                         /*
635                                 NOTE: The d value in move() affects jump height by
636                                 raising the height at which the jump speed is kept
637                                 at its starting value
638                         */
639                         v3f speedJ = getSpeed();
640                         if(speedJ.Y >= -0.5 * BS) {
641                                 speedJ.Y = movement_speed_jump * physics_override_jump;
642                                 setSpeed(speedJ);
643                                 m_client->getEventManager()->put(new SimpleTriggerEvent(MtEvent::PLAYER_JUMP));
644                         }
645                 } else if (in_liquid && !m_disable_jump) {
646                         if (fast_climb)
647                                 speedV.Y = movement_speed_fast;
648                         else
649                                 speedV.Y = movement_speed_walk;
650                         swimming_vertical = true;
651                 } else if (is_climbing && !m_disable_jump) {
652                         if (fast_climb)
653                                 speedV.Y = movement_speed_fast;
654                         else
655                                 speedV.Y = movement_speed_climb;
656                 }
657         }
658
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;
664         else
665                 speedH = speedH.normalize() * movement_speed_walk;
666
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))
671         {
672                 // Jumping and falling
673                 if(superspeed || (fast_move && control.aux1))
674                         incH = movement_acceleration_fast * BS * dtime;
675                 else
676                         incH = movement_acceleration_air * BS * dtime;
677                 incV = 0; // No vertical acceleration in air
678         }
679         else if (superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
680                 incH = incV = movement_acceleration_fast * BS * dtime;
681         else
682                 incH = incV = movement_acceleration_default * BS * dtime;
683
684         float slip_factor = 1.0f;
685         if (!free_move && !in_liquid && !in_liquid_stable)
686                 slip_factor = getSlipFactor(env, speedH);
687
688         // Don't sink when swimming in pitch mode
689         if (pitch_move && in_liquid) {
690                 v3f controlSpeed = speedH + speedV;
691                 if (controlSpeed.getLength() > 0.01f)
692                         swimming_pitch = true;
693         }
694
695         // Accelerate to target speed with maximum increment
696         accelerate((speedH + speedV) * physics_override_speed,
697                         incH * physics_override_speed * slip_factor, incV * physics_override_speed,
698                         pitch_move);
699 }
700
701 v3s16 LocalPlayer::getStandingNodePos()
702 {
703         if(m_sneak_node_exists)
704                 return m_sneak_node;
705         return m_standing_node;
706 }
707
708 v3s16 LocalPlayer::getFootstepNodePos()
709 {
710         if (in_liquid_stable)
711                 // Emit swimming sound if the player is in liquid
712                 return floatToInt(getPosition(), BS);
713         if (touching_ground)
714                 // BS * 0.05 below the player's feet ensures a 1/16th height
715                 // nodebox is detected instead of the node below it.
716                 return floatToInt(getPosition() - v3f(0, BS * 0.05f, 0), BS);
717         // A larger distance below is necessary for a footstep sound
718         // when landing after a jump or fall. BS * 0.5 ensures water
719         // sounds when swimming in 1 node deep water.
720         return floatToInt(getPosition() - v3f(0, BS * 0.5f, 0), BS);
721 }
722
723 v3s16 LocalPlayer::getLightPosition() const
724 {
725         return floatToInt(m_position + v3f(0,BS+BS/2,0), BS);
726 }
727
728 v3f LocalPlayer::getEyeOffset() const
729 {
730         float eye_height = camera_barely_in_ceiling ?
731                 m_eye_height - 0.125f : m_eye_height;
732         return v3f(0, BS * eye_height, 0);
733 }
734
735 // 3D acceleration
736 void LocalPlayer::accelerate(const v3f &target_speed, const f32 max_increase_H,
737                 const f32 max_increase_V, const bool use_pitch)
738 {
739         const f32 yaw = getYaw();
740         const f32 pitch = getPitch();
741         v3f flat_speed = m_speed;
742         // Rotate speed vector by -yaw and -pitch to make it relative to the player's yaw and pitch
743         flat_speed.rotateXZBy(-yaw);
744         if (use_pitch)
745                 flat_speed.rotateYZBy(-pitch);
746
747         v3f d_wanted = target_speed - flat_speed;
748         v3f d = v3f(0,0,0);
749
750         // Then compare the horizontal and vertical components with the wanted speed
751         if (max_increase_H > 0) {
752                 v3f d_wanted_H = d_wanted * v3f(1,0,1);
753                 if (d_wanted_H.getLength() > max_increase_H)
754                         d += d_wanted_H.normalize() * max_increase_H;
755                 else
756                         d += d_wanted_H;
757         }
758
759         if (max_increase_V > 0) {
760                 f32 d_wanted_V = d_wanted.Y;
761                 if (d_wanted_V > max_increase_V)
762                         d.Y += max_increase_V;
763                 else if (d_wanted_V < -max_increase_V)
764                         d.Y -= max_increase_V;
765                 else
766                         d.Y += d_wanted_V;
767         }
768
769         // Finally rotate it again
770         if (use_pitch)
771                 d.rotateYZBy(pitch);
772         d.rotateXZBy(yaw);
773
774         m_speed += d;
775 }
776
777 // Temporary option for old move code
778 void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
779                 std::vector<CollisionInfo> *collision_info)
780 {
781         Map *map = &env->getMap();
782         const NodeDefManager *nodemgr = m_client->ndef();
783
784         v3f position = getPosition();
785
786         // Copy parent position if local player is attached
787         if (isAttached) {
788                 setPosition(overridePosition);
789                 m_sneak_node_exists = false;
790                 added_velocity = v3f();
791                 return;
792         }
793
794         PlayerSettings &player_settings = getPlayerSettings();
795
796         // Skip collision detection if noclip mode is used
797         bool fly_allowed = m_client->checkLocalPrivilege("fly");
798         bool noclip = m_client->checkLocalPrivilege("noclip") && player_settings.noclip;
799         bool free_move = noclip && fly_allowed && player_settings.free_move;
800         if (free_move) {
801                 position += m_speed * dtime;
802                 setPosition(position);
803                 m_sneak_node_exists = false;
804                 added_velocity = v3f();
805                 return;
806         }
807
808         m_speed += added_velocity;
809         added_velocity = v3f();
810
811         /*
812                 Collision detection
813         */
814         bool is_valid_position;
815         MapNode node;
816         v3s16 pp;
817
818         /*
819                 Check if player is in liquid (the oscillating value)
820         */
821         if (in_liquid) {
822                 // If in liquid, the threshold of coming out is at higher y
823                 pp = floatToInt(position + v3f(0, BS * 0.1, 0), BS);
824                 node = map->getNode(pp, &is_valid_position);
825                 if (is_valid_position) {
826                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
827                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
828                 } else {
829                         in_liquid = false;
830                 }
831         } else {
832                 // If not in liquid, the threshold of going in is at lower y
833                 pp = floatToInt(position + v3f(0, BS * 0.5, 0), BS);
834                 node = map->getNode(pp, &is_valid_position);
835                 if (is_valid_position) {
836                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
837                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
838                 } else {
839                         in_liquid = false;
840                 }
841         }
842
843         /*
844                 Check if player is in liquid (the stable value)
845         */
846         pp = floatToInt(position + v3f(0, 0, 0), BS);
847         node = map->getNode(pp, &is_valid_position);
848         if (is_valid_position)
849                 in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
850         else
851                 in_liquid_stable = false;
852
853         /*
854                 Check if player is climbing
855         */
856         pp = floatToInt(position + v3f(0, 0.5 * BS, 0), BS);
857         v3s16 pp2 = floatToInt(position + v3f(0, -0.2 * BS, 0), BS);
858         node = map->getNode(pp, &is_valid_position);
859         bool is_valid_position2;
860         MapNode node2 = map->getNode(pp2, &is_valid_position2);
861
862         if (!(is_valid_position && is_valid_position2))
863                 is_climbing = false;
864         else
865                 is_climbing = (nodemgr->get(node.getContent()).climbable ||
866                                 nodemgr->get(node2.getContent()).climbable) && !free_move;
867
868         /*
869                 Collision uncertainty radius
870                 Make it a bit larger than the maximum distance of movement
871         */
872         //f32 d = pos_max_d * 1.1;
873         // A fairly large value in here makes moving smoother
874         f32 d = 0.15 * BS;
875         // This should always apply, otherwise there are glitches
876         sanity_check(d > pos_max_d);
877         // Maximum distance over border for sneaking
878         f32 sneak_max = BS * 0.4;
879
880         /*
881                 If sneaking, keep in range from the last walked node and don't
882                 fall off from it
883         */
884         if (control.sneak && m_sneak_node_exists &&
885                         !(fly_allowed && player_settings.free_move) && !in_liquid &&
886                         physics_override_sneak) {
887                 f32 maxd = 0.5 * BS + sneak_max;
888                 v3f lwn_f = intToFloat(m_sneak_node, BS);
889                 position.X = rangelim(position.X, lwn_f.X - maxd, lwn_f.X + maxd);
890                 position.Z = rangelim(position.Z, lwn_f.Z - maxd, lwn_f.Z + maxd);
891
892                 if (!is_climbing) {
893                         // Move up if necessary
894                         f32 new_y = (lwn_f.Y - 0.5 * BS) + m_sneak_node_bb_ymax;
895                         if (position.Y < new_y)
896                                 position.Y = new_y;
897                         /*
898                                 Collision seems broken, since player is sinking when
899                                 sneaking over the edges of current sneaking_node.
900                                 TODO (when fixed): Set Y-speed only to 0 when position.Y < new_y.
901                         */
902                         if (m_speed.Y < 0)
903                                 m_speed.Y = 0;
904                 }
905         }
906
907         // this shouldn't be hardcoded but transmitted from server
908         float player_stepheight = touching_ground ? (BS * 0.6) : (BS * 0.2);
909
910         v3f accel_f = v3f(0, 0, 0);
911         const v3f initial_position = position;
912         const v3f initial_speed = m_speed;
913
914         collisionMoveResult result = collisionMoveSimple(env, m_client,
915                 pos_max_d, m_collisionbox, player_stepheight, dtime,
916                 &position, &m_speed, accel_f);
917
918         // Positition was slightly changed; update standing node pos
919         if (touching_ground)
920                 m_standing_node = floatToInt(m_position - v3f(0, 0.1f * BS, 0), BS);
921         else
922                 m_standing_node = floatToInt(m_position, BS);
923
924         /*
925                 If the player's feet touch the topside of any node, this is
926                 set to true.
927
928                 Player is allowed to jump when this is true.
929         */
930         bool touching_ground_was = touching_ground;
931         touching_ground = result.touching_ground;
932
933         //bool standing_on_unloaded = result.standing_on_unloaded;
934
935         /*
936                 Check the nodes under the player to see from which node the
937                 player is sneaking from, if any. If the node from under
938                 the player has been removed, the player falls.
939         */
940         f32 position_y_mod = 0.05 * BS;
941         if (m_sneak_node_bb_ymax > 0)
942                 position_y_mod = m_sneak_node_bb_ymax - position_y_mod;
943         v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
944         if (m_sneak_node_exists &&
945                         nodemgr->get(map->getNode(m_old_node_below)).name == "air" &&
946                         m_old_node_below_type != "air") {
947                 // Old node appears to have been removed; that is,
948                 // it wasn't air before but now it is
949                 m_need_to_get_new_sneak_node = false;
950                 m_sneak_node_exists = false;
951         } else if (nodemgr->get(map->getNode(current_node)).name != "air") {
952                 // We are on something, so make sure to recalculate the sneak
953                 // node.
954                 m_need_to_get_new_sneak_node = true;
955         }
956
957         if (m_need_to_get_new_sneak_node && physics_override_sneak) {
958                 m_sneak_node_bb_ymax = 0;
959                 v3s16 pos_i_bottom = floatToInt(position - v3f(0, position_y_mod, 0), BS);
960                 v2f player_p2df(position.X, position.Z);
961                 f32 min_distance_f = 100000.0 * BS;
962                 // If already seeking from some node, compare to it.
963                 v3s16 new_sneak_node = m_sneak_node;
964                 for (s16 x= -1; x <= 1; x++)
965                 for (s16 z= -1; z <= 1; z++) {
966                         v3s16 p = pos_i_bottom + v3s16(x, 0, z);
967                         v3f pf = intToFloat(p, BS);
968                         v2f node_p2df(pf.X, pf.Z);
969                         f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
970                         f32 max_axis_distance_f = MYMAX(
971                                         std::fabs(player_p2df.X - node_p2df.X),
972                                         std::fabs(player_p2df.Y - node_p2df.Y));
973
974                         if (distance_f > min_distance_f ||
975                                         max_axis_distance_f > 0.5 * BS + sneak_max + 0.1 * BS)
976                                 continue;
977
978                         // The node to be sneaked on has to be walkable
979                         node = map->getNode(p, &is_valid_position);
980                         if (!is_valid_position || !nodemgr->get(node).walkable)
981                                 continue;
982                         // And the node above it has to be nonwalkable
983                         node = map->getNode(p + v3s16(0, 1, 0), &is_valid_position);
984                         if (!is_valid_position || nodemgr->get(node).walkable)
985                                 continue;
986                         // If not 'sneak_glitch' the node 2 nodes above it has to be nonwalkable
987                         if (!physics_override_sneak_glitch) {
988                                 node =map->getNode(p + v3s16(0, 2, 0), &is_valid_position);
989                                 if (!is_valid_position || nodemgr->get(node).walkable)
990                                         continue;
991                         }
992
993                         min_distance_f = distance_f;
994                         new_sneak_node = p;
995                 }
996
997                 bool sneak_node_found = (min_distance_f < 100000.0 * BS * 0.9);
998
999                 m_sneak_node = new_sneak_node;
1000                 m_sneak_node_exists = sneak_node_found;
1001
1002                 if (sneak_node_found) {
1003                         f32 cb_max = 0;
1004                         MapNode n = map->getNode(m_sneak_node);
1005                         std::vector<aabb3f> nodeboxes;
1006                         n.getCollisionBoxes(nodemgr, &nodeboxes);
1007                         for (const auto &box : nodeboxes) {
1008                                 if (box.MaxEdge.Y > cb_max)
1009                                         cb_max = box.MaxEdge.Y;
1010                         }
1011                         m_sneak_node_bb_ymax = cb_max;
1012                 }
1013
1014                 /*
1015                         If sneaking, the player's collision box can be in air, so
1016                         this has to be set explicitly
1017                 */
1018                 if (sneak_node_found && control.sneak)
1019                         touching_ground = true;
1020         }
1021
1022         /*
1023                 Set new position but keep sneak node set
1024         */
1025         bool sneak_node_exists = m_sneak_node_exists;
1026         setPosition(position);
1027         m_sneak_node_exists = sneak_node_exists;
1028
1029         /*
1030                 Report collisions
1031         */
1032         // Dont report if flying
1033         if (collision_info && !(player_settings.free_move && fly_allowed)) {
1034                 for (const auto &info : result.collisions) {
1035                         collision_info->push_back(info);
1036                 }
1037         }
1038
1039         if (!result.standing_on_object && !touching_ground_was && touching_ground) {
1040                 m_client->getEventManager()->put(new SimpleTriggerEvent(MtEvent::PLAYER_REGAIN_GROUND));
1041                 // Set camera impact value to be used for view bobbing
1042                 camera_impact = getSpeed().Y * -1;
1043         }
1044
1045         {
1046                 camera_barely_in_ceiling = false;
1047                 v3s16 camera_np = floatToInt(getEyePosition(), BS);
1048                 MapNode n = map->getNode(camera_np);
1049                 if (n.getContent() != CONTENT_IGNORE) {
1050                         if (nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2)
1051                                 camera_barely_in_ceiling = true;
1052                 }
1053         }
1054
1055         /*
1056                 Update the node last under the player
1057         */
1058         m_old_node_below = floatToInt(position - v3f(0, BS / 2, 0), BS);
1059         m_old_node_below_type = nodemgr->get(map->getNode(m_old_node_below)).name;
1060
1061         /*
1062                 Check properties of the node on which the player is standing
1063         */
1064         const ContentFeatures &f = nodemgr->get(map->getNode(
1065                 getStandingNodePos()));
1066
1067         // Determine if jumping is possible
1068         m_disable_jump = itemgroup_get(f.groups, "disable_jump");
1069         m_can_jump = touching_ground && !m_disable_jump;
1070
1071         // Jump key pressed while jumping off from a bouncy block
1072         if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
1073                         m_speed.Y >= -0.5 * BS) {
1074                 float jumpspeed = movement_speed_jump * physics_override_jump;
1075                 if (m_speed.Y > 1) {
1076                         // Reduce boost when speed already is high
1077                         m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
1078                 } else {
1079                         m_speed.Y += jumpspeed;
1080                 }
1081                 setSpeed(m_speed);
1082                 m_can_jump = false;
1083         }
1084
1085         // Autojump
1086         handleAutojump(dtime, env, result, initial_position, initial_speed, pos_max_d);
1087 }
1088
1089 float LocalPlayer::getSlipFactor(Environment *env, const v3f &speedH)
1090 {
1091         // Slip on slippery nodes
1092         const NodeDefManager *nodemgr = env->getGameDef()->ndef();
1093         Map *map = &env->getMap();
1094         const ContentFeatures &f = nodemgr->get(map->getNode(
1095                         getStandingNodePos()));
1096         int slippery = 0;
1097         if (f.walkable)
1098                 slippery = itemgroup_get(f.groups, "slippery");
1099
1100         if (slippery >= 1) {
1101                 if (speedH == v3f(0.0f)) {
1102                         slippery = slippery * 2;
1103                 }
1104                 return core::clamp(1.0f / (slippery + 1), 0.001f, 1.0f);
1105         }
1106         return 1.0f;
1107 }
1108
1109 void LocalPlayer::handleAutojump(f32 dtime, Environment *env,
1110                 const collisionMoveResult &result, const v3f &initial_position,
1111                 const v3f &initial_speed, f32 pos_max_d)
1112 {
1113         PlayerSettings &player_settings = getPlayerSettings();
1114         if (!player_settings.autojump)
1115                 return;
1116
1117         if (m_autojump)
1118                 return;
1119
1120         bool control_forward = control.up ||
1121                         (!control.up && !control.down &&
1122                         control.forw_move_joystick_axis < -0.05);
1123         bool could_autojump =
1124                         m_can_jump && !control.jump && !control.sneak && control_forward;
1125         if (!could_autojump)
1126                 return;
1127
1128         bool horizontal_collision = false;
1129         for (const auto &colinfo : result.collisions) {
1130                 if (colinfo.type == COLLISION_NODE && colinfo.plane != 1) {
1131                         horizontal_collision = true;
1132                         break; // one is enough
1133                 }
1134         }
1135
1136         // must be running against something to trigger autojumping
1137         if (!horizontal_collision)
1138                 return;
1139
1140         // check for nodes above
1141         v3f headpos_min = m_position + m_collisionbox.MinEdge * 0.99f;
1142         v3f headpos_max = m_position + m_collisionbox.MaxEdge * 0.99f;
1143         headpos_min.Y = headpos_max.Y; // top face of collision box
1144         v3s16 ceilpos_min = floatToInt(headpos_min, BS) + v3s16(0, 1, 0);
1145         v3s16 ceilpos_max = floatToInt(headpos_max, BS) + v3s16(0, 1, 0);
1146         const NodeDefManager *ndef = env->getGameDef()->ndef();
1147         bool is_position_valid;
1148         for (s16 z = ceilpos_min.Z; z <= ceilpos_max.Z; z++) {
1149                 for (s16 x = ceilpos_min.X; x <= ceilpos_max.X; x++) {
1150                         MapNode n = env->getMap().getNode(v3s16(x, ceilpos_max.Y, z), &is_position_valid);
1151
1152                         if (!is_position_valid)
1153                                 break;  // won't collide with the void outside
1154                         if (n.getContent() == CONTENT_IGNORE)
1155                                 return; // players collide with ignore blocks -> same as walkable
1156                         const ContentFeatures &f = ndef->get(n);
1157                         if (f.walkable)
1158                                 return; // would bump head, don't jump
1159                 }
1160         }
1161
1162         float jump_height = 1.1f; // TODO: better than a magic number
1163         v3f jump_pos = initial_position + v3f(0.0f, jump_height * BS, 0.0f);
1164         v3f jump_speed = initial_speed;
1165
1166         // try at peak of jump, zero step height
1167         collisionMoveResult jump_result = collisionMoveSimple(env, m_client, pos_max_d,
1168                         m_collisionbox, 0.0f, dtime, &jump_pos, &jump_speed,
1169                         v3f(0, 0, 0));
1170
1171         // see if we can get a little bit farther horizontally if we had
1172         // jumped
1173         v3f run_delta = m_position - initial_position;
1174         run_delta.Y = 0.0f;
1175         v3f jump_delta = jump_pos - initial_position;
1176         jump_delta.Y = 0.0f;
1177         if (jump_delta.getLengthSQ() > run_delta.getLengthSQ() * 1.01f) {
1178                 m_autojump = true;
1179                 m_autojump_time = 0.1f;
1180         }
1181 }