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