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