Add core.remove_detached_inventory (#7684)
[oweals/minetest.git] / src / localplayer.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "localplayer.h"
21 #include <cmath>
22 #include "event.h"
23 #include "collision.h"
24 #include "nodedef.h"
25 #include "settings.h"
26 #include "environment.h"
27 #include "map.h"
28 #include "client.h"
29 #include "content_cao.h"
30
31 /*
32         LocalPlayer
33 */
34
35 LocalPlayer::LocalPlayer(Client *client, const char *name):
36         Player(name, client->idef()),
37         m_client(client)
38 {
39 }
40
41 static aabb3f getNodeBoundingBox(const std::vector<aabb3f> &nodeboxes)
42 {
43         if (nodeboxes.empty())
44                 return aabb3f(0, 0, 0, 0, 0, 0);
45
46         aabb3f b_max;
47
48         std::vector<aabb3f>::const_iterator it = nodeboxes.begin();
49         b_max = aabb3f(it->MinEdge, it->MaxEdge);
50
51         ++it;
52         for (; it != nodeboxes.end(); ++it)
53                 b_max.addInternalBox(*it);
54
55         return b_max;
56 }
57
58 bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
59                 const v3f &sneak_max)
60 {
61         static const v3s16 dir9_center[9] = {
62                 v3s16( 0, 0,  0),
63                 v3s16( 1, 0,  0),
64                 v3s16(-1, 0,  0),
65                 v3s16( 0, 0,  1),
66                 v3s16( 0, 0, -1),
67                 v3s16( 1, 0,  1),
68                 v3s16(-1, 0,  1),
69                 v3s16( 1, 0, -1),
70                 v3s16(-1, 0, -1)
71         };
72
73         const NodeDefManager *nodemgr = m_client->ndef();
74         MapNode node;
75         bool is_valid_position;
76         bool new_sneak_node_exists = m_sneak_node_exists;
77
78         // We want the top of the sneak node to be below the players feet
79         f32 position_y_mod = 0.05 * BS;
80         if (m_sneak_node_exists)
81                 position_y_mod = m_sneak_node_bb_top.MaxEdge.Y - position_y_mod;
82
83         // Get position of current standing node
84         const v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
85
86         if (current_node != m_sneak_node) {
87                 new_sneak_node_exists = false;
88         } else {
89                 node = map->getNodeNoEx(current_node, &is_valid_position);
90                 if (!is_valid_position || !nodemgr->get(node).walkable)
91                         new_sneak_node_exists = false;
92         }
93
94         // Keep old sneak node
95         if (new_sneak_node_exists)
96                 return true;
97
98         // Get new sneak node
99         m_sneak_ladder_detected = false;
100         f32 min_distance_f = 100000.0 * BS;
101
102         for (const auto &d : dir9_center) {
103                 const v3s16 p = current_node + d;
104                 const v3f pf = intToFloat(p, BS);
105                 const v2f diff(position.X - pf.X, position.Z - pf.Z);
106                 f32 distance_f = diff.getLength();
107
108                 if (distance_f > min_distance_f ||
109                                 fabs(diff.X) > (.5 + .1) * BS + sneak_max.X ||
110                                 fabs(diff.Y) > (.5 + .1) * BS + sneak_max.Z)
111                         continue;
112
113
114                 // The node to be sneaked on has to be walkable
115                 node = map->getNodeNoEx(p, &is_valid_position);
116                 if (!is_valid_position || !nodemgr->get(node).walkable)
117                         continue;
118                 // And the node(s) above have to be nonwalkable
119                 bool ok = true;
120                 if (!physics_override_sneak_glitch) {
121                         u16 height = ceilf(
122                                         (m_collisionbox.MaxEdge.Y - m_collisionbox.MinEdge.Y) / BS
123                         );
124                         for (u16 y = 1; y <= height; y++) {
125                                 node = map->getNodeNoEx(p + v3s16(0, y, 0), &is_valid_position);
126                                 if (!is_valid_position || nodemgr->get(node).walkable) {
127                                         ok = false;
128                                         break;
129                                 }
130                         }
131                 } else {
132                         // legacy behaviour: check just one node
133                         node = map->getNodeNoEx(p + v3s16(0, 1, 0), &is_valid_position);
134                         ok = is_valid_position && !nodemgr->get(node).walkable;
135                 }
136                 if (!ok)
137                         continue;
138
139                 min_distance_f = distance_f;
140                 m_sneak_node = p;
141                 new_sneak_node_exists = true;
142         }
143
144         if (!new_sneak_node_exists)
145                 return false;
146
147         // Update saved top bounding box of sneak node
148         node = map->getNodeNoEx(m_sneak_node);
149         std::vector<aabb3f> nodeboxes;
150         node.getCollisionBoxes(nodemgr, &nodeboxes);
151         m_sneak_node_bb_top = getNodeBoundingBox(nodeboxes);
152
153         if (physics_override_sneak_glitch) {
154                 // Detect sneak ladder:
155                 // Node two meters above sneak node must be solid
156                 node = map->getNodeNoEx(m_sneak_node + v3s16(0, 2, 0),
157                         &is_valid_position);
158                 if (is_valid_position && nodemgr->get(node).walkable) {
159                         // Node three meters above: must be non-solid
160                         node = map->getNodeNoEx(m_sneak_node + v3s16(0, 3, 0),
161                                 &is_valid_position);
162                         m_sneak_ladder_detected = is_valid_position &&
163                                 !nodemgr->get(node).walkable;
164                 }
165         }
166         return true;
167 }
168
169 void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
170                 std::vector<CollisionInfo> *collision_info)
171 {
172         if (!collision_info || collision_info->empty()) {
173                 // Node below the feet, update each ClientEnvironment::step()
174                 m_standing_node = floatToInt(m_position, BS) - v3s16(0, 1, 0);
175         }
176
177         // Temporary option for old move code
178         if (!physics_override_new_move) {
179                 old_move(dtime, env, pos_max_d, collision_info);
180                 return;
181         }
182
183         Map *map = &env->getMap();
184         const NodeDefManager *nodemgr = m_client->ndef();
185
186         v3f position = getPosition();
187
188         // Copy parent position if local player is attached
189         if (isAttached) {
190                 setPosition(overridePosition);
191                 return;
192         }
193
194         PlayerSettings &player_settings = getPlayerSettings();
195
196         // Skip collision detection if noclip mode is used
197         bool fly_allowed = m_client->checkLocalPrivilege("fly");
198         bool noclip = m_client->checkLocalPrivilege("noclip") && player_settings.noclip;
199         bool free_move = player_settings.free_move && fly_allowed;
200
201         if (noclip && free_move) {
202                 position += m_speed * dtime;
203                 setPosition(position);
204                 return;
205         }
206
207         /*
208                 Collision detection
209         */
210
211         bool is_valid_position;
212         MapNode node;
213         v3s16 pp;
214
215         /*
216                 Check if player is in liquid (the oscillating value)
217         */
218
219         // If in liquid, the threshold of coming out is at higher y
220         if (in_liquid)
221         {
222                 pp = floatToInt(position + v3f(0,BS*0.1,0), BS);
223                 node = map->getNodeNoEx(pp, &is_valid_position);
224                 if (is_valid_position) {
225                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
226                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
227                 } else {
228                         in_liquid = false;
229                 }
230         }
231         // If not in liquid, the threshold of going in is at lower y
232         else
233         {
234                 pp = floatToInt(position + v3f(0,BS*0.5,0), BS);
235                 node = map->getNodeNoEx(pp, &is_valid_position);
236                 if (is_valid_position) {
237                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
238                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
239                 } else {
240                         in_liquid = false;
241                 }
242         }
243
244
245         /*
246                 Check if player is in liquid (the stable value)
247         */
248         pp = floatToInt(position + v3f(0,0,0), BS);
249         node = map->getNodeNoEx(pp, &is_valid_position);
250         if (is_valid_position) {
251                 in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
252         } else {
253                 in_liquid_stable = false;
254         }
255
256         /*
257                 Check if player is climbing
258         */
259
260
261         pp = floatToInt(position + v3f(0,0.5*BS,0), BS);
262         v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS);
263         node = map->getNodeNoEx(pp, &is_valid_position);
264         bool is_valid_position2;
265         MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
266
267         if (!(is_valid_position && is_valid_position2)) {
268                 is_climbing = false;
269         } else {
270                 is_climbing = (nodemgr->get(node.getContent()).climbable
271                                 || nodemgr->get(node2.getContent()).climbable) && !free_move;
272         }
273
274         /*
275                 Collision uncertainty radius
276                 Make it a bit larger than the maximum distance of movement
277         */
278         //f32 d = pos_max_d * 1.1;
279         // A fairly large value in here makes moving smoother
280         f32 d = 0.15*BS;
281
282         // This should always apply, otherwise there are glitches
283         sanity_check(d > pos_max_d);
284
285         // Player object property step height is multiplied by BS in
286         // /src/script/common/c_content.cpp and /src/content_sao.cpp
287         float player_stepheight = (m_cao == nullptr) ? 0.0f :
288                 (touching_ground ? m_cao->getStepHeight() : (0.2f * BS));
289
290         // TODO this is a problematic hack.
291         // Use a better implementation for autojump, or apply a custom stepheight
292         // to all players, as this currently creates unintended special movement
293         // abilities and advantages for Android players on a server.
294 #ifdef __ANDROID__
295         if (touching_ground)
296                 player_stepheight += (0.6f * BS);
297 #endif
298
299         v3f accel_f = v3f(0,0,0);
300
301         collisionMoveResult result = collisionMoveSimple(env, m_client,
302                 pos_max_d, m_collisionbox, player_stepheight, dtime,
303                 &position, &m_speed, accel_f);
304
305         bool could_sneak = control.sneak && !free_move && !in_liquid &&
306                 !is_climbing && physics_override_sneak;
307
308         // Add new collisions to the vector
309         if (collision_info && !free_move) {
310                 v3f diff = intToFloat(m_standing_node, BS) - position;
311                 f32 distance = diff.getLength();
312                 // Force update each ClientEnvironment::step()
313                 bool is_first = collision_info->empty();
314
315                 for (const auto &colinfo : result.collisions) {
316                         collision_info->push_back(colinfo);
317
318                         if (colinfo.type != COLLISION_NODE ||
319                                         colinfo.new_speed.Y != 0 ||
320                                         (could_sneak && m_sneak_node_exists))
321                                 continue;
322
323                         diff = intToFloat(colinfo.node_p, BS) - position;
324
325                         // Find nearest colliding node
326                         f32 len = diff.getLength();
327                         if (is_first || len < distance) {
328                                 m_standing_node = colinfo.node_p;
329                                 distance = len;
330                         }
331                 }
332         }
333
334         /*
335                 If the player's feet touch the topside of any node, this is
336                 set to true.
337
338                 Player is allowed to jump when this is true.
339         */
340         bool touching_ground_was = touching_ground;
341         touching_ground = result.touching_ground;
342         bool sneak_can_jump = false;
343
344         // Max. distance (X, Z) over border for sneaking determined by collision box
345         // * 0.49 to keep the center just barely on the node
346         v3f sneak_max = m_collisionbox.getExtent() * 0.49;
347
348         if (m_sneak_ladder_detected) {
349                 // restore legacy behaviour (this makes the m_speed.Y hack necessary)
350                 sneak_max = v3f(0.4 * BS, 0, 0.4 * BS);
351         }
352
353         /*
354                 If sneaking, keep on top of last walked node and don't fall off
355         */
356         if (could_sneak && m_sneak_node_exists) {
357                 const v3f sn_f = intToFloat(m_sneak_node, BS);
358                 const v3f bmin = sn_f + m_sneak_node_bb_top.MinEdge;
359                 const v3f bmax = sn_f + m_sneak_node_bb_top.MaxEdge;
360                 const v3f old_pos = position;
361                 const v3f old_speed = m_speed;
362                 f32 y_diff = bmax.Y - position.Y;
363                 m_standing_node = m_sneak_node;
364
365                 // (BS * 0.6f) is the basic stepheight while standing on ground
366                 if (y_diff < BS * 0.6f) {
367                         // Only center player when they're on the node
368                         position.X = rangelim(position.X,
369                                 bmin.X - sneak_max.X, bmax.X + sneak_max.X);
370                         position.Z = rangelim(position.Z,
371                                 bmin.Z - sneak_max.Z, bmax.Z + sneak_max.Z);
372
373                         if (position.X != old_pos.X)
374                                 m_speed.X = 0;
375                         if (position.Z != old_pos.Z)
376                                 m_speed.Z = 0;
377                 }
378
379                 if (y_diff > 0 && m_speed.Y < 0 &&
380                                 (physics_override_sneak_glitch || y_diff < BS * 0.6f)) {
381                         // Move player to the maximal height when falling or when
382                         // the ledge is climbed on the next step.
383                         position.Y = bmax.Y;
384                         m_speed.Y = 0;
385                 }
386
387                 // Allow jumping on node edges while sneaking
388                 if (m_speed.Y == 0 || 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->getNodeNoEx(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         /*
439                 Check properties of the node on which the player is standing
440         */
441         const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(m_standing_node));
442         // Determine if jumping is possible
443         m_can_jump = (touching_ground && !in_liquid && !is_climbing)
444                         || sneak_can_jump;
445         if (itemgroup_get(f.groups, "disable_jump"))
446                 m_can_jump = false;
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.5 * BS) {
451                 float jumpspeed = movement_speed_jump * physics_override_jump;
452                 if (m_speed.Y > 1) {
453                         // Reduce boost when speed already is high
454                         m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
455                 } else {
456                         m_speed.Y += jumpspeed;
457                 }
458                 setSpeed(m_speed);
459                 m_can_jump = false;
460         }
461 }
462
463 void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d)
464 {
465         move(dtime, env, pos_max_d, NULL);
466 }
467
468 void LocalPlayer::applyControl(float dtime, Environment *env)
469 {
470         // Clear stuff
471         swimming_vertical = false;
472
473         setPitch(control.pitch);
474         setYaw(control.yaw);
475
476         // Nullify speed and don't run positioning code if the player is attached
477         if(isAttached)
478         {
479                 setSpeed(v3f(0,0,0));
480                 return;
481         }
482
483         PlayerSettings &player_settings = getPlayerSettings();
484
485         v3f move_direction = v3f(0,0,1);
486         move_direction.rotateXZBy(getYaw());
487
488         v3f speedH = v3f(0,0,0); // Horizontal (X, Z)
489         v3f speedV = v3f(0,0,0); // Vertical (Y)
490
491         bool fly_allowed = m_client->checkLocalPrivilege("fly");
492         bool fast_allowed = m_client->checkLocalPrivilege("fast");
493
494         bool free_move = fly_allowed && player_settings.free_move;
495         bool fast_move = fast_allowed && player_settings.fast_move;
496         // When aux1_descends is enabled the fast key is used to go down, so fast isn't possible
497         bool fast_climb = fast_move && control.aux1 && !player_settings.aux1_descends;
498         bool continuous_forward = player_settings.continuous_forward;
499         bool always_fly_fast = player_settings.always_fly_fast;
500
501         // Whether superspeed mode is used or not
502         bool superspeed = false;
503
504         if (always_fly_fast && free_move && fast_move)
505                 superspeed = true;
506
507         // Old descend control
508         if (player_settings.aux1_descends)
509         {
510                 // If free movement and fast movement, always move fast
511                 if(free_move && fast_move)
512                         superspeed = true;
513
514                 // Auxiliary button 1 (E)
515                 if(control.aux1)
516                 {
517                         if(free_move)
518                         {
519                                 // In free movement mode, aux1 descends
520                                 if(fast_move)
521                                         speedV.Y = -movement_speed_fast;
522                                 else
523                                         speedV.Y = -movement_speed_walk;
524                         }
525                         else if(in_liquid || in_liquid_stable)
526                         {
527                                 speedV.Y = -movement_speed_walk;
528                                 swimming_vertical = true;
529                         }
530                         else if(is_climbing)
531                         {
532                                 speedV.Y = -movement_speed_climb;
533                         }
534                         else
535                         {
536                                 // If not free movement but fast is allowed, aux1 is
537                                 // "Turbo button"
538                                 if(fast_move)
539                                         superspeed = true;
540                         }
541                 }
542         }
543         // New minecraft-like descend control
544         else
545         {
546                 // Auxiliary button 1 (E)
547                 if(control.aux1)
548                 {
549                         if(!is_climbing)
550                         {
551                                 // aux1 is "Turbo button"
552                                 if(fast_move)
553                                         superspeed = true;
554                         }
555                 }
556
557                 if(control.sneak)
558                 {
559                         if(free_move)
560                         {
561                                 // In free movement mode, sneak descends
562                                 if (fast_move && (control.aux1 || always_fly_fast))
563                                         speedV.Y = -movement_speed_fast;
564                                 else
565                                         speedV.Y = -movement_speed_walk;
566                         }
567                         else if(in_liquid || in_liquid_stable)
568                         {
569                                 if(fast_climb)
570                                         speedV.Y = -movement_speed_fast;
571                                 else
572                                         speedV.Y = -movement_speed_walk;
573                                 swimming_vertical = true;
574                         }
575                         else if(is_climbing)
576                         {
577                                 if(fast_climb)
578                                         speedV.Y = -movement_speed_fast;
579                                 else
580                                         speedV.Y = -movement_speed_climb;
581                         }
582                 }
583         }
584
585         if (continuous_forward)
586                 speedH += move_direction;
587
588         if (control.up) {
589                 if (continuous_forward) {
590                         if (fast_move)
591                                 superspeed = true;
592                 } else {
593                         speedH += move_direction;
594                 }
595         }
596         if (control.down) {
597                 speedH -= move_direction;
598         }
599         if (!control.up && !control.down) {
600                 speedH -= move_direction *
601                         (control.forw_move_joystick_axis / 32767.f);
602         }
603         if (control.left) {
604                 speedH += move_direction.crossProduct(v3f(0,1,0));
605         }
606         if (control.right) {
607                 speedH += move_direction.crossProduct(v3f(0,-1,0));
608         }
609         if (!control.left && !control.right) {
610                 speedH -= move_direction.crossProduct(v3f(0,1,0)) *
611                         (control.sidew_move_joystick_axis / 32767.f);
612         }
613         if(control.jump)
614         {
615                 if (free_move) {
616                         if (player_settings.aux1_descends || always_fly_fast) {
617                                 if (fast_move)
618                                         speedV.Y = movement_speed_fast;
619                                 else
620                                         speedV.Y = movement_speed_walk;
621                         } else {
622                                 if(fast_move && control.aux1)
623                                         speedV.Y = movement_speed_fast;
624                                 else
625                                         speedV.Y = movement_speed_walk;
626                         }
627                 }
628                 else if(m_can_jump)
629                 {
630                         /*
631                                 NOTE: The d value in move() affects jump height by
632                                 raising the height at which the jump speed is kept
633                                 at its starting value
634                         */
635                         v3f speedJ = getSpeed();
636                         if(speedJ.Y >= -0.5 * BS) {
637                                 speedJ.Y = movement_speed_jump * physics_override_jump;
638                                 setSpeed(speedJ);
639                                 m_client->getEventManager()->put(new SimpleTriggerEvent(MtEvent::PLAYER_JUMP));
640                         }
641                 }
642                 else if(in_liquid)
643                 {
644                         if(fast_climb)
645                                 speedV.Y = movement_speed_fast;
646                         else
647                                 speedV.Y = movement_speed_walk;
648                         swimming_vertical = true;
649                 }
650                 else if(is_climbing)
651                 {
652                         if(fast_climb)
653                                 speedV.Y = movement_speed_fast;
654                         else
655                                 speedV.Y = movement_speed_climb;
656                 }
657         }
658
659         // The speed of the player (Y is ignored)
660         if(superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
661                 speedH = speedH.normalize() * movement_speed_fast;
662         else if(control.sneak && !free_move && !in_liquid && !in_liquid_stable)
663                 speedH = speedH.normalize() * movement_speed_crouch;
664         else
665                 speedH = speedH.normalize() * movement_speed_walk;
666
667         // Acceleration increase
668         f32 incH = 0; // Horizontal (X, Z)
669         f32 incV = 0; // Vertical (Y)
670         if((!touching_ground && !free_move && !is_climbing && !in_liquid) || (!free_move && m_can_jump && control.jump))
671         {
672                 // Jumping and falling
673                 if(superspeed || (fast_move && control.aux1))
674                         incH = movement_acceleration_fast * BS * dtime;
675                 else
676                         incH = movement_acceleration_air * BS * dtime;
677                 incV = 0; // No vertical acceleration in air
678         }
679         else if (superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
680                 incH = incV = movement_acceleration_fast * BS * dtime;
681         else
682                 incH = incV = movement_acceleration_default * BS * dtime;
683
684         float slip_factor = 1.0f;
685         if (!free_move)
686                 slip_factor = getSlipFactor(env, speedH);
687
688         // Accelerate to target speed with maximum increment
689         accelerateHorizontal(speedH * physics_override_speed,
690                         incH * physics_override_speed * slip_factor);
691         accelerateVertical(speedV * physics_override_speed,
692                         incV * physics_override_speed);
693 }
694
695 v3s16 LocalPlayer::getStandingNodePos()
696 {
697         if(m_sneak_node_exists)
698                 return m_sneak_node;
699         return m_standing_node;
700 }
701
702 v3s16 LocalPlayer::getFootstepNodePos()
703 {
704         if (in_liquid_stable)
705                 // Emit swimming sound if the player is in liquid
706                 return floatToInt(getPosition(), BS);
707         if (touching_ground)
708                 // BS * 0.05 below the player's feet ensures a 1/16th height
709                 // nodebox is detected instead of the node below it.
710                 return floatToInt(getPosition() - v3f(0, BS * 0.05f, 0), BS);
711         // A larger distance below is necessary for a footstep sound
712         // when landing after a jump or fall. BS * 0.5 ensures water
713         // sounds when swimming in 1 node deep water.
714         return floatToInt(getPosition() - v3f(0, BS * 0.5f, 0), BS);
715 }
716
717 v3s16 LocalPlayer::getLightPosition() const
718 {
719         return floatToInt(m_position + v3f(0,BS+BS/2,0), BS);
720 }
721
722 v3f LocalPlayer::getEyeOffset() const
723 {
724         float eye_height = camera_barely_in_ceiling ?
725                 m_eye_height - 0.125f : m_eye_height;
726         return v3f(0, BS * eye_height, 0);
727 }
728
729 // Horizontal acceleration (X and Z), Y direction is ignored
730 void LocalPlayer::accelerateHorizontal(const v3f &target_speed,
731         const f32 max_increase)
732 {
733         if (max_increase == 0)
734                 return;
735
736         v3f d_wanted = target_speed - m_speed;
737         d_wanted.Y = 0.0f;
738         f32 dl = d_wanted.getLength();
739         if (dl > max_increase)
740                 dl = max_increase;
741
742         v3f d = d_wanted.normalize() * dl;
743
744         m_speed.X += d.X;
745         m_speed.Z += d.Z;
746 }
747
748 // Vertical acceleration (Y), X and Z directions are ignored
749 void LocalPlayer::accelerateVertical(const v3f &target_speed, const f32 max_increase)
750 {
751         if (max_increase == 0)
752                 return;
753
754         f32 d_wanted = target_speed.Y - m_speed.Y;
755         if (d_wanted > max_increase)
756                 d_wanted = max_increase;
757         else if (d_wanted < -max_increase)
758                 d_wanted = -max_increase;
759
760         m_speed.Y += d_wanted;
761 }
762
763 // Temporary option for old move code
764 void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
765                 std::vector<CollisionInfo> *collision_info)
766 {
767         Map *map = &env->getMap();
768         const NodeDefManager *nodemgr = m_client->ndef();
769
770         v3f position = getPosition();
771
772         // Copy parent position if local player is attached
773         if (isAttached) {
774                 setPosition(overridePosition);
775                 m_sneak_node_exists = false;
776                 return;
777         }
778
779         PlayerSettings &player_settings = getPlayerSettings();
780
781         // Skip collision detection if noclip mode is used
782         bool fly_allowed = m_client->checkLocalPrivilege("fly");
783         bool noclip = m_client->checkLocalPrivilege("noclip") && player_settings.noclip;
784         bool free_move = noclip && fly_allowed && player_settings.free_move;
785         if (free_move) {
786                 position += m_speed * dtime;
787                 setPosition(position);
788                 m_sneak_node_exists = false;
789                 return;
790         }
791
792         /*
793                 Collision detection
794         */
795         bool is_valid_position;
796         MapNode node;
797         v3s16 pp;
798
799         /*
800                 Check if player is in liquid (the oscillating value)
801         */
802         if (in_liquid) {
803                 // If in liquid, the threshold of coming out is at higher y
804                 pp = floatToInt(position + v3f(0, BS * 0.1, 0), BS);
805                 node = map->getNodeNoEx(pp, &is_valid_position);
806                 if (is_valid_position) {
807                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
808                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
809                 } else {
810                         in_liquid = false;
811                 }
812         } else {
813                 // If not in liquid, the threshold of going in is at lower y
814                 pp = floatToInt(position + v3f(0, BS * 0.5, 0), BS);
815                 node = map->getNodeNoEx(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         }
823
824         /*
825                 Check if player is in liquid (the stable value)
826         */
827         pp = floatToInt(position + v3f(0, 0, 0), BS);
828         node = map->getNodeNoEx(pp, &is_valid_position);
829         if (is_valid_position)
830                 in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
831         else
832                 in_liquid_stable = false;
833
834         /*
835                 Check if player is climbing
836         */
837         pp = floatToInt(position + v3f(0, 0.5 * BS, 0), BS);
838         v3s16 pp2 = floatToInt(position + v3f(0, -0.2 * BS, 0), BS);
839         node = map->getNodeNoEx(pp, &is_valid_position);
840         bool is_valid_position2;
841         MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
842
843         if (!(is_valid_position && is_valid_position2))
844                 is_climbing = false;
845         else
846                 is_climbing = (nodemgr->get(node.getContent()).climbable ||
847                                 nodemgr->get(node2.getContent()).climbable) && !free_move;
848
849         /*
850                 Collision uncertainty radius
851                 Make it a bit larger than the maximum distance of movement
852         */
853         //f32 d = pos_max_d * 1.1;
854         // A fairly large value in here makes moving smoother
855         f32 d = 0.15 * BS;
856         // This should always apply, otherwise there are glitches
857         sanity_check(d > pos_max_d);
858         // Maximum distance over border for sneaking
859         f32 sneak_max = BS * 0.4;
860
861         /*
862                 If sneaking, keep in range from the last walked node and don't
863                 fall off from it
864         */
865         if (control.sneak && m_sneak_node_exists &&
866                         !(fly_allowed && player_settings.free_move) && !in_liquid &&
867                         physics_override_sneak) {
868                 f32 maxd = 0.5 * BS + sneak_max;
869                 v3f lwn_f = intToFloat(m_sneak_node, BS);
870                 position.X = rangelim(position.X, lwn_f.X - maxd, lwn_f.X + maxd);
871                 position.Z = rangelim(position.Z, lwn_f.Z - maxd, lwn_f.Z + maxd);
872
873                 if (!is_climbing) {
874                         // Move up if necessary
875                         f32 new_y = (lwn_f.Y - 0.5 * BS) + m_sneak_node_bb_ymax;
876                         if (position.Y < new_y)
877                                 position.Y = new_y;
878                         /*
879                                 Collision seems broken, since player is sinking when
880                                 sneaking over the edges of current sneaking_node.
881                                 TODO (when fixed): Set Y-speed only to 0 when position.Y < new_y.
882                         */
883                         if (m_speed.Y < 0)
884                                 m_speed.Y = 0;
885                 }
886         }
887
888         // this shouldn't be hardcoded but transmitted from server
889         float player_stepheight = touching_ground ? (BS * 0.6) : (BS * 0.2);
890
891 #ifdef __ANDROID__
892         player_stepheight += (0.6 * BS);
893 #endif
894
895         v3f accel_f = v3f(0, 0, 0);
896
897         collisionMoveResult result = collisionMoveSimple(env, m_client,
898                 pos_max_d, m_collisionbox, player_stepheight, dtime,
899                 &position, &m_speed, accel_f);
900
901         /*
902                 If the player's feet touch the topside of any node, this is
903                 set to true.
904
905                 Player is allowed to jump when this is true.
906         */
907         bool touching_ground_was = touching_ground;
908         touching_ground = result.touching_ground;
909
910     //bool standing_on_unloaded = result.standing_on_unloaded;
911
912         /*
913                 Check the nodes under the player to see from which node the
914                 player is sneaking from, if any.  If the node from under
915                 the player has been removed, the player falls.
916         */
917         f32 position_y_mod = 0.05 * BS;
918         if (m_sneak_node_bb_ymax > 0)
919                 position_y_mod = m_sneak_node_bb_ymax - position_y_mod;
920         v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
921         if (m_sneak_node_exists &&
922                         nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
923                         m_old_node_below_type != "air") {
924                 // Old node appears to have been removed; that is,
925                 // it wasn't air before but now it is
926                 m_need_to_get_new_sneak_node = false;
927                 m_sneak_node_exists = false;
928         } else if (nodemgr->get(map->getNodeNoEx(current_node)).name != "air") {
929                 // We are on something, so make sure to recalculate the sneak
930                 // node.
931                 m_need_to_get_new_sneak_node = true;
932         }
933
934         if (m_need_to_get_new_sneak_node && physics_override_sneak) {
935                 m_sneak_node_bb_ymax = 0;
936                 v3s16 pos_i_bottom = floatToInt(position - v3f(0, position_y_mod, 0), BS);
937                 v2f player_p2df(position.X, position.Z);
938                 f32 min_distance_f = 100000.0 * BS;
939                 // If already seeking from some node, compare to it.
940                 v3s16 new_sneak_node = m_sneak_node;
941                 for (s16 x= -1; x <= 1; x++)
942                 for (s16 z= -1; z <= 1; z++) {
943                         v3s16 p = pos_i_bottom + v3s16(x, 0, z);
944                         v3f pf = intToFloat(p, BS);
945                         v2f node_p2df(pf.X, pf.Z);
946                         f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
947                         f32 max_axis_distance_f = MYMAX(
948                                         std::fabs(player_p2df.X - node_p2df.X),
949                                         std::fabs(player_p2df.Y - node_p2df.Y));
950
951                         if (distance_f > min_distance_f ||
952                                         max_axis_distance_f > 0.5 * BS + sneak_max + 0.1 * BS)
953                                 continue;
954
955                         // The node to be sneaked on has to be walkable
956                         node = map->getNodeNoEx(p, &is_valid_position);
957                         if (!is_valid_position || !nodemgr->get(node).walkable)
958                                 continue;
959                         // And the node above it has to be nonwalkable
960                         node = map->getNodeNoEx(p + v3s16(0, 1, 0), &is_valid_position);
961                         if (!is_valid_position || nodemgr->get(node).walkable)
962                                 continue;
963                         // If not 'sneak_glitch' the node 2 nodes above it has to be nonwalkable
964                         if (!physics_override_sneak_glitch) {
965                                 node =map->getNodeNoEx(p + v3s16(0, 2, 0), &is_valid_position);
966                                 if (!is_valid_position || nodemgr->get(node).walkable)
967                                         continue;
968                         }
969
970                         min_distance_f = distance_f;
971                         new_sneak_node = p;
972                 }
973
974                 bool sneak_node_found = (min_distance_f < 100000.0 * BS * 0.9);
975
976                 m_sneak_node = new_sneak_node;
977                 m_sneak_node_exists = sneak_node_found;
978
979                 if (sneak_node_found) {
980                         f32 cb_max = 0;
981                         MapNode n = map->getNodeNoEx(m_sneak_node);
982                         std::vector<aabb3f> nodeboxes;
983                         n.getCollisionBoxes(nodemgr, &nodeboxes);
984                         for (const auto &box : nodeboxes) {
985                                 if (box.MaxEdge.Y > cb_max)
986                                         cb_max = box.MaxEdge.Y;
987                         }
988                         m_sneak_node_bb_ymax = cb_max;
989                 }
990
991                 /*
992                         If sneaking, the player's collision box can be in air, so
993                         this has to be set explicitly
994                 */
995                 if (sneak_node_found && control.sneak)
996                         touching_ground = true;
997         }
998
999         /*
1000                 Set new position but keep sneak node set
1001         */
1002         bool sneak_node_exists = m_sneak_node_exists;
1003         setPosition(position);
1004         m_sneak_node_exists = sneak_node_exists;
1005
1006         /*
1007                 Report collisions
1008         */
1009         // Dont report if flying
1010         if (collision_info && !(player_settings.free_move && fly_allowed)) {
1011                 for (const auto &info : result.collisions) {
1012                         collision_info->push_back(info);
1013                 }
1014         }
1015
1016         if (!result.standing_on_object && !touching_ground_was && touching_ground) {
1017                 m_client->getEventManager()->put(new SimpleTriggerEvent(MtEvent::PLAYER_REGAIN_GROUND));
1018                 // Set camera impact value to be used for view bobbing
1019                 camera_impact = getSpeed().Y * -1;
1020         }
1021
1022         {
1023                 camera_barely_in_ceiling = false;
1024                 v3s16 camera_np = floatToInt(getEyePosition(), BS);
1025                 MapNode n = map->getNodeNoEx(camera_np);
1026                 if (n.getContent() != CONTENT_IGNORE) {
1027                         if (nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2)
1028                                 camera_barely_in_ceiling = true;
1029                 }
1030         }
1031
1032         /*
1033                 Update the node last under the player
1034         */
1035         m_old_node_below = floatToInt(position - v3f(0, BS / 2, 0), BS);
1036         m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
1037
1038         /*
1039                 Check properties of the node on which the player is standing
1040         */
1041         const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
1042         // Determine if jumping is possible
1043         m_can_jump = touching_ground && !in_liquid;
1044         if (itemgroup_get(f.groups, "disable_jump"))
1045                 m_can_jump = false;
1046         // Jump key pressed while jumping off from a bouncy block
1047         if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
1048                         m_speed.Y >= -0.5 * BS) {
1049                 float jumpspeed = movement_speed_jump * physics_override_jump;
1050                 if (m_speed.Y > 1) {
1051                         // Reduce boost when speed already is high
1052                         m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
1053                 } else {
1054                         m_speed.Y += jumpspeed;
1055                 }
1056                 setSpeed(m_speed);
1057                 m_can_jump = false;
1058         }
1059 }
1060
1061 float LocalPlayer::getSlipFactor(Environment *env, const v3f &speedH)
1062 {
1063         // Slip on slippery nodes
1064         const NodeDefManager *nodemgr = env->getGameDef()->ndef();
1065         Map *map = &env->getMap();
1066         const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(
1067                         getStandingNodePos()));
1068         int slippery = 0;
1069         if (f.walkable)
1070                 slippery = itemgroup_get(f.groups, "slippery");
1071
1072         if (slippery >= 1) {
1073                 if (speedH == v3f(0.0f)) {
1074                         slippery = slippery * 2;
1075                 }
1076                 return core::clamp(1.0f / (slippery + 1), 0.001f, 1.0f);
1077         }
1078         return 1.0f;
1079 }