]> git.lizzy.rs Git - minetest.git/blob - src/localplayer.cpp
Fix naming conventions of noise userdata
[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
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         INodeDefManager *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         INodeDefManager *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         // Skip collision detection if noclip mode is used
195         bool fly_allowed = m_client->checkLocalPrivilege("fly");
196         bool noclip = m_client->checkLocalPrivilege("noclip") &&
197                 g_settings->getBool("noclip");
198         bool free_move = g_settings->getBool("free_move") && fly_allowed;
199
200         if (noclip && free_move) {
201                 position += m_speed * dtime;
202                 setPosition(position);
203                 return;
204         }
205
206         /*
207                 Collision detection
208         */
209
210         bool is_valid_position;
211         MapNode node;
212         v3s16 pp;
213
214         /*
215                 Check if player is in liquid (the oscillating value)
216         */
217
218         // If in liquid, the threshold of coming out is at higher y
219         if (in_liquid)
220         {
221                 pp = floatToInt(position + v3f(0,BS*0.1,0), BS);
222                 node = map->getNodeNoEx(pp, &is_valid_position);
223                 if (is_valid_position) {
224                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
225                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
226                 } else {
227                         in_liquid = false;
228                 }
229         }
230         // If not in liquid, the threshold of going in is at lower y
231         else
232         {
233                 pp = floatToInt(position + v3f(0,BS*0.5,0), BS);
234                 node = map->getNodeNoEx(pp, &is_valid_position);
235                 if (is_valid_position) {
236                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
237                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
238                 } else {
239                         in_liquid = false;
240                 }
241         }
242
243
244         /*
245                 Check if player is in liquid (the stable value)
246         */
247         pp = floatToInt(position + v3f(0,0,0), BS);
248         node = map->getNodeNoEx(pp, &is_valid_position);
249         if (is_valid_position) {
250                 in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
251         } else {
252                 in_liquid_stable = false;
253         }
254
255         /*
256                 Check if player is climbing
257         */
258
259
260         pp = floatToInt(position + v3f(0,0.5*BS,0), BS);
261         v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS);
262         node = map->getNodeNoEx(pp, &is_valid_position);
263         bool is_valid_position2;
264         MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
265
266         if (!(is_valid_position && is_valid_position2)) {
267                 is_climbing = false;
268         } else {
269                 is_climbing = (nodemgr->get(node.getContent()).climbable
270                                 || nodemgr->get(node2.getContent()).climbable) && !free_move;
271         }
272
273         /*
274                 Collision uncertainty radius
275                 Make it a bit larger than the maximum distance of movement
276         */
277         //f32 d = pos_max_d * 1.1;
278         // A fairly large value in here makes moving smoother
279         f32 d = 0.15*BS;
280
281         // This should always apply, otherwise there are glitches
282         sanity_check(d > pos_max_d);
283
284         // Player object property step height is multiplied by BS in
285         // /src/script/common/c_content.cpp and /src/content_sao.cpp
286         float player_stepheight = (m_cao == nullptr) ? 0.0f :
287                 (touching_ground ? m_cao->getStepHeight() : (0.2f * BS));
288
289         // TODO this is a problematic hack.
290         // Use a better implementation for autojump, or apply a custom stepheight
291         // to all players, as this currently creates unintended special movement
292         // abilities and advantages for Android players on a server.
293 #ifdef __ANDROID__
294         if (touching_ground)
295                 player_stepheight += (0.6f * BS);
296 #endif
297
298         v3f accel_f = v3f(0,0,0);
299
300         collisionMoveResult result = collisionMoveSimple(env, m_client,
301                 pos_max_d, m_collisionbox, player_stepheight, dtime,
302                 &position, &m_speed, accel_f);
303
304         bool could_sneak = control.sneak && !free_move && !in_liquid &&
305                 !is_climbing && physics_override_sneak;
306
307         // Add new collisions to the vector
308         if (collision_info && !free_move) {
309                 v3f diff = intToFloat(m_standing_node, BS) - position;
310                 f32 distance = diff.getLength();
311                 // Force update each ClientEnvironment::step()
312                 bool is_first = collision_info->empty();
313
314                 for (const auto &colinfo : result.collisions) {
315                         collision_info->push_back(colinfo);
316
317                         if (colinfo.type != COLLISION_NODE ||
318                                         colinfo.new_speed.Y != 0 ||
319                                         (could_sneak && m_sneak_node_exists))
320                                 continue;
321
322                         diff = intToFloat(colinfo.node_p, BS) - position;
323
324                         // Find nearest colliding node
325                         f32 len = diff.getLength();
326                         if (is_first || len < distance) {
327                                 m_standing_node = colinfo.node_p;
328                                 distance = len;
329                         }
330                 }
331         }
332
333         /*
334                 If the player's feet touch the topside of any node, this is
335                 set to true.
336
337                 Player is allowed to jump when this is true.
338         */
339         bool touching_ground_was = touching_ground;
340         touching_ground = result.touching_ground;
341         bool sneak_can_jump = false;
342
343         // Max. distance (X, Z) over border for sneaking determined by collision box
344         // * 0.49 to keep the center just barely on the node
345         v3f sneak_max = m_collisionbox.getExtent() * 0.49;
346
347         if (m_sneak_ladder_detected) {
348                 // restore legacy behaviour (this makes the m_speed.Y hack necessary)
349                 sneak_max = v3f(0.4 * BS, 0, 0.4 * BS);
350         }
351
352         /*
353                 If sneaking, keep on top of last walked node and don't fall off
354         */
355         if (could_sneak && m_sneak_node_exists) {
356                 const v3f sn_f = intToFloat(m_sneak_node, BS);
357                 const v3f bmin = sn_f + m_sneak_node_bb_top.MinEdge;
358                 const v3f bmax = sn_f + m_sneak_node_bb_top.MaxEdge;
359                 const v3f old_pos = position;
360                 const v3f old_speed = m_speed;
361                 f32 y_diff = bmax.Y - position.Y;
362                 m_standing_node = m_sneak_node;
363
364                 // (BS * 0.6f) is the basic stepheight while standing on ground
365                 if (y_diff < BS * 0.6f) {
366                         // Only center player when they're on the node
367                         position.X = rangelim(position.X,
368                                 bmin.X - sneak_max.X, bmax.X + sneak_max.X);
369                         position.Z = rangelim(position.Z,
370                                 bmin.Z - sneak_max.Z, bmax.Z + sneak_max.Z);
371
372                         if (position.X != old_pos.X)
373                                 m_speed.X = 0;
374                         if (position.Z != old_pos.Z)
375                                 m_speed.Z = 0;
376                 }
377
378                 if (y_diff > 0 && m_speed.Y < 0 &&
379                                 (physics_override_sneak_glitch || y_diff < BS * 0.6f)) {
380                         // Move player to the maximal height when falling or when
381                         // the ledge is climbed on the next step.
382                         position.Y = bmax.Y;
383                         m_speed.Y = 0;
384                 }
385
386                 // Allow jumping on node edges while sneaking
387                 if (m_speed.Y == 0 || m_sneak_ladder_detected)
388                         sneak_can_jump = true;
389
390                 if (collision_info &&
391                                 m_speed.Y - old_speed.Y > BS) {
392                         // Collide with sneak node, report fall damage
393                         CollisionInfo sn_info;
394                         sn_info.node_p = m_sneak_node;
395                         sn_info.old_speed = old_speed;
396                         sn_info.new_speed = m_speed;
397                         collision_info->push_back(sn_info);
398                 }
399         }
400
401         /*
402                 Find the next sneak node if necessary
403         */
404         bool new_sneak_node_exists = false;
405
406         if (could_sneak)
407                 new_sneak_node_exists = updateSneakNode(map, position, sneak_max);
408
409         /*
410                 Set new position but keep sneak node set
411         */
412         setPosition(position);
413         m_sneak_node_exists = new_sneak_node_exists;
414
415         /*
416                 Report collisions
417         */
418
419         if(!result.standing_on_object && !touching_ground_was && touching_ground) {
420                 MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
421                 m_client->event()->put(e);
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         v3f move_direction = v3f(0,0,1);
484         move_direction.rotateXZBy(getYaw());
485
486         v3f speedH = v3f(0,0,0); // Horizontal (X, Z)
487         v3f speedV = v3f(0,0,0); // Vertical (Y)
488
489         bool fly_allowed = m_client->checkLocalPrivilege("fly");
490         bool fast_allowed = m_client->checkLocalPrivilege("fast");
491
492         bool free_move = fly_allowed && g_settings->getBool("free_move");
493         bool fast_move = fast_allowed && g_settings->getBool("fast_move");
494         // When aux1_descends is enabled the fast key is used to go down, so fast isn't possible
495         bool fast_climb = fast_move && control.aux1 && !g_settings->getBool("aux1_descends");
496         bool continuous_forward = g_settings->getBool("continuous_forward");
497         bool always_fly_fast = g_settings->getBool("always_fly_fast");
498
499         // Whether superspeed mode is used or not
500         bool superspeed = false;
501
502         if (always_fly_fast && free_move && fast_move)
503                 superspeed = true;
504
505         // Old descend control
506         if(g_settings->getBool("aux1_descends"))
507         {
508                 // If free movement and fast movement, always move fast
509                 if(free_move && fast_move)
510                         superspeed = true;
511
512                 // Auxiliary button 1 (E)
513                 if(control.aux1)
514                 {
515                         if(free_move)
516                         {
517                                 // In free movement mode, aux1 descends
518                                 if(fast_move)
519                                         speedV.Y = -movement_speed_fast;
520                                 else
521                                         speedV.Y = -movement_speed_walk;
522                         }
523                         else if(in_liquid || in_liquid_stable)
524                         {
525                                 speedV.Y = -movement_speed_walk;
526                                 swimming_vertical = true;
527                         }
528                         else if(is_climbing)
529                         {
530                                 speedV.Y = -movement_speed_climb;
531                         }
532                         else
533                         {
534                                 // If not free movement but fast is allowed, aux1 is
535                                 // "Turbo button"
536                                 if(fast_move)
537                                         superspeed = true;
538                         }
539                 }
540         }
541         // New minecraft-like descend control
542         else
543         {
544                 // Auxiliary button 1 (E)
545                 if(control.aux1)
546                 {
547                         if(!is_climbing)
548                         {
549                                 // aux1 is "Turbo button"
550                                 if(fast_move)
551                                         superspeed = true;
552                         }
553                 }
554
555                 if(control.sneak)
556                 {
557                         if(free_move)
558                         {
559                                 // In free movement mode, sneak descends
560                                 if (fast_move && (control.aux1 || always_fly_fast))
561                                         speedV.Y = -movement_speed_fast;
562                                 else
563                                         speedV.Y = -movement_speed_walk;
564                         }
565                         else if(in_liquid || in_liquid_stable)
566                         {
567                                 if(fast_climb)
568                                         speedV.Y = -movement_speed_fast;
569                                 else
570                                         speedV.Y = -movement_speed_walk;
571                                 swimming_vertical = true;
572                         }
573                         else if(is_climbing)
574                         {
575                                 if(fast_climb)
576                                         speedV.Y = -movement_speed_fast;
577                                 else
578                                         speedV.Y = -movement_speed_climb;
579                         }
580                 }
581         }
582
583         if (continuous_forward)
584                 speedH += move_direction;
585
586         if (control.up) {
587                 if (continuous_forward) {
588                         if (fast_move)
589                                 superspeed = true;
590                 } else {
591                         speedH += move_direction;
592                 }
593         }
594         if (control.down) {
595                 speedH -= move_direction;
596         }
597         if (!control.up && !control.down) {
598                 speedH -= move_direction *
599                         (control.forw_move_joystick_axis / 32767.f);
600         }
601         if (control.left) {
602                 speedH += move_direction.crossProduct(v3f(0,1,0));
603         }
604         if (control.right) {
605                 speedH += move_direction.crossProduct(v3f(0,-1,0));
606         }
607         if (!control.left && !control.right) {
608                 speedH -= move_direction.crossProduct(v3f(0,1,0)) *
609                         (control.sidew_move_joystick_axis / 32767.f);
610         }
611         if(control.jump)
612         {
613                 if (free_move) {
614                         if (g_settings->getBool("aux1_descends") || always_fly_fast) {
615                                 if (fast_move)
616                                         speedV.Y = movement_speed_fast;
617                                 else
618                                         speedV.Y = movement_speed_walk;
619                         } else {
620                                 if(fast_move && control.aux1)
621                                         speedV.Y = movement_speed_fast;
622                                 else
623                                         speedV.Y = movement_speed_walk;
624                         }
625                 }
626                 else if(m_can_jump)
627                 {
628                         /*
629                                 NOTE: The d value in move() affects jump height by
630                                 raising the height at which the jump speed is kept
631                                 at its starting value
632                         */
633                         v3f speedJ = getSpeed();
634                         if(speedJ.Y >= -0.5 * BS) {
635                                 speedJ.Y = movement_speed_jump * physics_override_jump;
636                                 setSpeed(speedJ);
637
638                                 MtEvent *e = new SimpleTriggerEvent("PlayerJump");
639                                 m_client->event()->put(e);
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 = getSlipFactor(env, speedH);
685         // Accelerate to target speed with maximum increment
686         accelerateHorizontal(speedH * physics_override_speed,
687                         incH * physics_override_speed * slip_factor);
688         accelerateVertical(speedV * physics_override_speed,
689                         incV * physics_override_speed);
690 }
691
692 v3s16 LocalPlayer::getStandingNodePos()
693 {
694         if(m_sneak_node_exists)
695                 return m_sneak_node;
696         return m_standing_node;
697 }
698
699 v3s16 LocalPlayer::getFootstepNodePos()
700 {
701         if (in_liquid_stable)
702                 // Emit swimming sound if the player is in liquid
703                 return floatToInt(getPosition(), BS);
704         if (touching_ground)
705                 // BS * 0.05 below the player's feet ensures a 1/16th height
706                 // nodebox is detected instead of the node below it.
707                 return floatToInt(getPosition() - v3f(0, BS * 0.05f, 0), BS);
708         // A larger distance below is necessary for a footstep sound
709         // when landing after a jump or fall. BS * 0.5 ensures water
710         // sounds when swimming in 1 node deep water.
711         return floatToInt(getPosition() - v3f(0, BS * 0.5f, 0), BS);
712 }
713
714 v3s16 LocalPlayer::getLightPosition() const
715 {
716         return floatToInt(m_position + v3f(0,BS+BS/2,0), BS);
717 }
718
719 v3f LocalPlayer::getEyeOffset() const
720 {
721         float eye_height = camera_barely_in_ceiling ?
722                 m_eye_height - 0.125f : m_eye_height;
723         return v3f(0, BS * eye_height, 0);
724 }
725
726 // Horizontal acceleration (X and Z), Y direction is ignored
727 void LocalPlayer::accelerateHorizontal(const v3f &target_speed,
728         const f32 max_increase)
729 {
730         if (max_increase == 0)
731                 return;
732
733         v3f d_wanted = target_speed - m_speed;
734         d_wanted.Y = 0.0f;
735         f32 dl = d_wanted.getLength();
736         if (dl > max_increase)
737                 dl = max_increase;
738
739         v3f d = d_wanted.normalize() * dl;
740
741         m_speed.X += d.X;
742         m_speed.Z += d.Z;
743 }
744
745 // Vertical acceleration (Y), X and Z directions are ignored
746 void LocalPlayer::accelerateVertical(const v3f &target_speed, const f32 max_increase)
747 {
748         if (max_increase == 0)
749                 return;
750
751         f32 d_wanted = target_speed.Y - m_speed.Y;
752         if (d_wanted > max_increase)
753                 d_wanted = max_increase;
754         else if (d_wanted < -max_increase)
755                 d_wanted = -max_increase;
756
757         m_speed.Y += d_wanted;
758 }
759
760 // Temporary option for old move code
761 void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
762                 std::vector<CollisionInfo> *collision_info)
763 {
764         Map *map = &env->getMap();
765         INodeDefManager *nodemgr = m_client->ndef();
766
767         v3f position = getPosition();
768
769         // Copy parent position if local player is attached
770         if (isAttached) {
771                 setPosition(overridePosition);
772                 m_sneak_node_exists = false;
773                 return;
774         }
775
776         // Skip collision detection if noclip mode is used
777         bool fly_allowed = m_client->checkLocalPrivilege("fly");
778         bool noclip = m_client->checkLocalPrivilege("noclip") &&
779                 g_settings->getBool("noclip");
780         bool free_move = noclip && fly_allowed && g_settings->getBool("free_move");
781         if (free_move) {
782                 position += m_speed * dtime;
783                 setPosition(position);
784                 m_sneak_node_exists = false;
785                 return;
786         }
787
788         /*
789                 Collision detection
790         */
791         bool is_valid_position;
792         MapNode node;
793         v3s16 pp;
794
795         /*
796                 Check if player is in liquid (the oscillating value)
797         */
798         if (in_liquid) {
799                 // If in liquid, the threshold of coming out is at higher y
800                 pp = floatToInt(position + v3f(0, BS * 0.1, 0), BS);
801                 node = map->getNodeNoEx(pp, &is_valid_position);
802                 if (is_valid_position) {
803                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
804                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
805                 } else {
806                         in_liquid = false;
807                 }
808         } else {
809                 // If not in liquid, the threshold of going in is at lower y
810                 pp = floatToInt(position + v3f(0, BS * 0.5, 0), BS);
811                 node = map->getNodeNoEx(pp, &is_valid_position);
812                 if (is_valid_position) {
813                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
814                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
815                 } else {
816                         in_liquid = false;
817                 }
818         }
819
820         /*
821                 Check if player is in liquid (the stable value)
822         */
823         pp = floatToInt(position + v3f(0, 0, 0), BS);
824         node = map->getNodeNoEx(pp, &is_valid_position);
825         if (is_valid_position)
826                 in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
827         else
828                 in_liquid_stable = false;
829
830         /*
831                 Check if player is climbing
832         */
833         pp = floatToInt(position + v3f(0, 0.5 * BS, 0), BS);
834         v3s16 pp2 = floatToInt(position + v3f(0, -0.2 * BS, 0), BS);
835         node = map->getNodeNoEx(pp, &is_valid_position);
836         bool is_valid_position2;
837         MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
838
839         if (!(is_valid_position && is_valid_position2))
840                 is_climbing = false;
841         else
842                 is_climbing = (nodemgr->get(node.getContent()).climbable ||
843                                 nodemgr->get(node2.getContent()).climbable) && !free_move;
844
845         /*
846                 Collision uncertainty radius
847                 Make it a bit larger than the maximum distance of movement
848         */
849         //f32 d = pos_max_d * 1.1;
850         // A fairly large value in here makes moving smoother
851         f32 d = 0.15 * BS;
852         // This should always apply, otherwise there are glitches
853         sanity_check(d > pos_max_d);
854         // Maximum distance over border for sneaking
855         f32 sneak_max = BS * 0.4;
856
857         /*
858                 If sneaking, keep in range from the last walked node and don't
859                 fall off from it
860         */
861         if (control.sneak && m_sneak_node_exists &&
862                         !(fly_allowed && g_settings->getBool("free_move")) && !in_liquid &&
863                         physics_override_sneak) {
864                 f32 maxd = 0.5 * BS + sneak_max;
865                 v3f lwn_f = intToFloat(m_sneak_node, BS);
866                 position.X = rangelim(position.X, lwn_f.X - maxd, lwn_f.X + maxd);
867                 position.Z = rangelim(position.Z, lwn_f.Z - maxd, lwn_f.Z + maxd);
868
869                 if (!is_climbing) {
870                         // Move up if necessary
871                         f32 new_y = (lwn_f.Y - 0.5 * BS) + m_sneak_node_bb_ymax;
872                         if (position.Y < new_y)
873                                 position.Y = new_y;
874                         /*
875                                 Collision seems broken, since player is sinking when
876                                 sneaking over the edges of current sneaking_node.
877                                 TODO (when fixed): Set Y-speed only to 0 when position.Y < new_y.
878                         */
879                         if (m_speed.Y < 0)
880                                 m_speed.Y = 0;
881                 }
882         }
883
884         // this shouldn't be hardcoded but transmitted from server
885         float player_stepheight = touching_ground ? (BS * 0.6) : (BS * 0.2);
886
887 #ifdef __ANDROID__
888         player_stepheight += (0.6 * BS);
889 #endif
890
891         v3f accel_f = v3f(0, 0, 0);
892
893         collisionMoveResult result = collisionMoveSimple(env, m_client,
894                 pos_max_d, m_collisionbox, player_stepheight, dtime,
895                 &position, &m_speed, accel_f);
896
897         /*
898                 If the player's feet touch the topside of any node, this is
899                 set to true.
900
901                 Player is allowed to jump when this is true.
902         */
903         bool touching_ground_was = touching_ground;
904         touching_ground = result.touching_ground;
905
906     //bool standing_on_unloaded = result.standing_on_unloaded;
907
908         /*
909                 Check the nodes under the player to see from which node the
910                 player is sneaking from, if any.  If the node from under
911                 the player has been removed, the player falls.
912         */
913         f32 position_y_mod = 0.05 * BS;
914         if (m_sneak_node_bb_ymax > 0)
915                 position_y_mod = m_sneak_node_bb_ymax - position_y_mod;
916         v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
917         if (m_sneak_node_exists &&
918                         nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
919                         m_old_node_below_type != "air") {
920                 // Old node appears to have been removed; that is,
921                 // it wasn't air before but now it is
922                 m_need_to_get_new_sneak_node = false;
923                 m_sneak_node_exists = false;
924         } else if (nodemgr->get(map->getNodeNoEx(current_node)).name != "air") {
925                 // We are on something, so make sure to recalculate the sneak
926                 // node.
927                 m_need_to_get_new_sneak_node = true;
928         }
929
930         if (m_need_to_get_new_sneak_node && physics_override_sneak) {
931                 m_sneak_node_bb_ymax = 0;
932                 v3s16 pos_i_bottom = floatToInt(position - v3f(0, position_y_mod, 0), BS);
933                 v2f player_p2df(position.X, position.Z);
934                 f32 min_distance_f = 100000.0 * BS;
935                 // If already seeking from some node, compare to it.
936                 v3s16 new_sneak_node = m_sneak_node;
937                 for (s16 x= -1; x <= 1; x++)
938                 for (s16 z= -1; z <= 1; z++) {
939                         v3s16 p = pos_i_bottom + v3s16(x, 0, z);
940                         v3f pf = intToFloat(p, BS);
941                         v2f node_p2df(pf.X, pf.Z);
942                         f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
943                         f32 max_axis_distance_f = MYMAX(
944                                         fabs(player_p2df.X - node_p2df.X),
945                                         fabs(player_p2df.Y - node_p2df.Y));
946
947                         if (distance_f > min_distance_f ||
948                                         max_axis_distance_f > 0.5 * BS + sneak_max + 0.1 * BS)
949                                 continue;
950
951                         // The node to be sneaked on has to be walkable
952                         node = map->getNodeNoEx(p, &is_valid_position);
953                         if (!is_valid_position || !nodemgr->get(node).walkable)
954                                 continue;
955                         // And the node above it has to be nonwalkable
956                         node = map->getNodeNoEx(p + v3s16(0, 1, 0), &is_valid_position);
957                         if (!is_valid_position || nodemgr->get(node).walkable)
958                                 continue;
959                         // If not 'sneak_glitch' the node 2 nodes above it has to be nonwalkable
960                         if (!physics_override_sneak_glitch) {
961                                 node =map->getNodeNoEx(p + v3s16(0, 2, 0), &is_valid_position);
962                                 if (!is_valid_position || nodemgr->get(node).walkable)
963                                         continue;
964                         }
965
966                         min_distance_f = distance_f;
967                         new_sneak_node = p;
968                 }
969
970                 bool sneak_node_found = (min_distance_f < 100000.0 * BS * 0.9);
971
972                 m_sneak_node = new_sneak_node;
973                 m_sneak_node_exists = sneak_node_found;
974
975                 if (sneak_node_found) {
976                         f32 cb_max = 0;
977                         MapNode n = map->getNodeNoEx(m_sneak_node);
978                         std::vector<aabb3f> nodeboxes;
979                         n.getCollisionBoxes(nodemgr, &nodeboxes);
980                         for (const auto &box : nodeboxes) {
981                                 if (box.MaxEdge.Y > cb_max)
982                                         cb_max = box.MaxEdge.Y;
983                         }
984                         m_sneak_node_bb_ymax = cb_max;
985                 }
986
987                 /*
988                         If sneaking, the player's collision box can be in air, so
989                         this has to be set explicitly
990                 */
991                 if (sneak_node_found && control.sneak)
992                         touching_ground = true;
993         }
994
995         /*
996                 Set new position but keep sneak node set
997         */
998         bool sneak_node_exists = m_sneak_node_exists;
999         setPosition(position);
1000         m_sneak_node_exists = sneak_node_exists;
1001
1002         /*
1003                 Report collisions
1004         */
1005         // Dont report if flying
1006         if (collision_info && !(g_settings->getBool("free_move") && fly_allowed)) {
1007                 for (const auto &info : result.collisions) {
1008                         collision_info->push_back(info);
1009                 }
1010         }
1011
1012         if (!result.standing_on_object && !touching_ground_was && touching_ground) {
1013                 MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
1014                 m_client->event()->put(e);
1015                 // Set camera impact value to be used for view bobbing
1016                 camera_impact = getSpeed().Y * -1;
1017         }
1018
1019         {
1020                 camera_barely_in_ceiling = false;
1021                 v3s16 camera_np = floatToInt(getEyePosition(), BS);
1022                 MapNode n = map->getNodeNoEx(camera_np);
1023                 if (n.getContent() != CONTENT_IGNORE) {
1024                         if (nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2)
1025                                 camera_barely_in_ceiling = true;
1026                 }
1027         }
1028
1029         /*
1030                 Update the node last under the player
1031         */
1032         m_old_node_below = floatToInt(position - v3f(0, BS / 2, 0), BS);
1033         m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
1034
1035         /*
1036                 Check properties of the node on which the player is standing
1037         */
1038         const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
1039         // Determine if jumping is possible
1040         m_can_jump = touching_ground && !in_liquid;
1041         if (itemgroup_get(f.groups, "disable_jump"))
1042                 m_can_jump = false;
1043         // Jump key pressed while jumping off from a bouncy block
1044         if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
1045                         m_speed.Y >= -0.5 * BS) {
1046                 float jumpspeed = movement_speed_jump * physics_override_jump;
1047                 if (m_speed.Y > 1) {
1048                         // Reduce boost when speed already is high
1049                         m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
1050                 } else {
1051                         m_speed.Y += jumpspeed;
1052                 }
1053                 setSpeed(m_speed);
1054                 m_can_jump = false;
1055         }
1056 }
1057
1058 float LocalPlayer::getSlipFactor(Environment *env, const v3f &speedH)
1059 {
1060
1061         if (!touching_ground)
1062                 return 1.0f;
1063
1064         float slip_factor = 1.0f;
1065         // Slip on slippery nodes
1066         const INodeDefManager *nodemgr = env->getGameDef()->ndef();
1067         Map *map = &env->getMap();
1068         const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(
1069                         floatToInt(getPosition() - v3f(0, 0.05f * BS, 0), BS)));
1070         int slippery = 0;
1071         if (f.walkable) {
1072                 slippery = itemgroup_get(f.groups, "slippery");
1073         } else if (is_slipping) {
1074                 // slipping over an edge? Check surroundings for slippery nodes
1075                 slippery = 2 << 16; // guard value, bigger than all realistic ones
1076                 for (int z = 0; z <= 1; z++) {
1077                         for (int x = 0; x <= 1; x++) {
1078                                 // this should cover all nodes surrounding player position
1079                                 v3f offset((x - 0.5f) * BS, 0.05f * BS, (z - 0.5f) * BS);
1080                                 const ContentFeatures &f2 = nodemgr->get(map->getNodeNoEx(
1081                                                 floatToInt(getPosition() - offset, BS)));
1082                                 if (f2.walkable) {
1083                                         // find least slippery node we might be standing on
1084                                         int s = itemgroup_get(f2.groups, "slippery");
1085                                         if (s < slippery)
1086                                                 slippery = s;
1087                                 }
1088                         }
1089                 }
1090                 // without any hits, ignore slippery
1091                 if (slippery >= (2 << 16))
1092                         slippery = 0;
1093         }
1094         if (slippery >= 1) {
1095                 if (speedH == v3f(0.0f)) {
1096                         slippery = slippery * 2;
1097                 }
1098                 slip_factor = core::clamp(1.0f / (slippery + 1), 0.001f, 1.0f);
1099                 is_slipping = true;
1100         } else {
1101                 // remember this to avoid checking the edge case above too often
1102                 is_slipping = false;
1103         }
1104         return slip_factor;
1105 }