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