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