LCOV - code coverage report
Current view: top level - src - collision.cpp (source / functions) Hit Total Coverage
Test: report Lines: 249 274 90.9 %
Date: 2015-07-11 18:23:49 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 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 "collision.h"
      21             : #include "mapblock.h"
      22             : #include "map.h"
      23             : #include "nodedef.h"
      24             : #include "gamedef.h"
      25             : #include "log.h"
      26             : #include "environment.h"
      27             : #include "serverobject.h"
      28             : #include <vector>
      29             : #include <set>
      30             : #include "util/timetaker.h"
      31             : #include "profiler.h"
      32             : 
      33             : // float error is 10 - 9.96875 = 0.03125
      34             : //#define COLL_ZERO 0.032 // broken unit tests
      35             : #define COLL_ZERO 0
      36             : 
      37             : // Helper function:
      38             : // Checks for collision of a moving aabbox with a static aabbox
      39             : // Returns -1 if no collision, 0 if X collision, 1 if Y collision, 2 if Z collision
      40             : // The time after which the collision occurs is stored in dtime.
      41      781567 : int axisAlignedCollision(
      42             :                 const aabb3f &staticbox, const aabb3f &movingbox,
      43             :                 const v3f &speed, f32 d, f32 &dtime)
      44             : {
      45             :         //TimeTaker tt("axisAlignedCollision");
      46             : 
      47      781567 :         f32 xsize = (staticbox.MaxEdge.X - staticbox.MinEdge.X) - COLL_ZERO;     // reduce box size for solve collision stuck (flying sand)
      48      781567 :         f32 ysize = (staticbox.MaxEdge.Y - staticbox.MinEdge.Y); // - COLL_ZERO; // Y - no sense for falling, but maybe try later
      49      781567 :         f32 zsize = (staticbox.MaxEdge.Z - staticbox.MinEdge.Z) - COLL_ZERO;
      50             : 
      51             :         aabb3f relbox(
      52      781567 :                         movingbox.MinEdge.X - staticbox.MinEdge.X,
      53      781567 :                         movingbox.MinEdge.Y - staticbox.MinEdge.Y,
      54      781567 :                         movingbox.MinEdge.Z - staticbox.MinEdge.Z,
      55      781567 :                         movingbox.MaxEdge.X - staticbox.MinEdge.X,
      56      781567 :                         movingbox.MaxEdge.Y - staticbox.MinEdge.Y,
      57      781567 :                         movingbox.MaxEdge.Z - staticbox.MinEdge.Z
      58     4689402 :         );
      59             : 
      60      781567 :         if(speed.X > 0) // Check for collision with X- plane
      61             :         {
      62      143768 :                 if(relbox.MaxEdge.X <= d)
      63             :                 {
      64       47805 :                         dtime = - relbox.MaxEdge.X / speed.X;
      65       68031 :                         if((relbox.MinEdge.Y + speed.Y * dtime < ysize) &&
      66       35868 :                                         (relbox.MaxEdge.Y + speed.Y * dtime > COLL_ZERO) &&
      67       22618 :                                         (relbox.MinEdge.Z + speed.Z * dtime < zsize) &&
      68        6976 :                                         (relbox.MaxEdge.Z + speed.Z * dtime > COLL_ZERO))
      69        4067 :                                 return 0;
      70             :                 }
      71       95963 :                 else if(relbox.MinEdge.X > xsize)
      72             :                 {
      73       42065 :                         return -1;
      74             :                 }
      75             :         }
      76      637799 :         else if(speed.X < 0) // Check for collision with X+ plane
      77             :         {
      78      165556 :                 if(relbox.MinEdge.X >= xsize - d)
      79             :                 {
      80       53360 :                         dtime = (xsize - relbox.MinEdge.X) / speed.X;
      81       87781 :                         if((relbox.MinEdge.Y + speed.Y * dtime < ysize) &&
      82       54328 :                                         (relbox.MaxEdge.Y + speed.Y * dtime > COLL_ZERO) &&
      83       30965 :                                         (relbox.MinEdge.Z + speed.Z * dtime < zsize) &&
      84       11058 :                                         (relbox.MaxEdge.Z + speed.Z * dtime > COLL_ZERO))
      85        6457 :                                 return 0;
      86             :                 }
      87      112196 :                 else if(relbox.MaxEdge.X < 0)
      88             :                 {
      89       49756 :                         return -1;
      90             :                 }
      91             :         }
      92             : 
      93             :         // NO else if here
      94             : 
      95      679222 :         if(speed.Y > 0) // Check for collision with Y- plane
      96             :         {
      97        1376 :                 if(relbox.MaxEdge.Y <= d)
      98             :                 {
      99         548 :                         dtime = - relbox.MaxEdge.Y / speed.Y;
     100         951 :                         if((relbox.MinEdge.X + speed.X * dtime < xsize) &&
     101         669 :                                         (relbox.MaxEdge.X + speed.X * dtime > COLL_ZERO) &&
     102         461 :                                         (relbox.MinEdge.Z + speed.Z * dtime < zsize) &&
     103         195 :                                         (relbox.MaxEdge.Z + speed.Z * dtime > COLL_ZERO))
     104         125 :                                 return 1;
     105             :                 }
     106         828 :                 else if(relbox.MinEdge.Y > ysize)
     107             :                 {
     108         445 :                         return -1;
     109             :                 }
     110             :         }
     111      677846 :         else if(speed.Y < 0) // Check for collision with Y+ plane
     112             :         {
     113      339449 :                 if(relbox.MinEdge.Y >= ysize - d)
     114             :                 {
     115      217306 :                         dtime = (ysize - relbox.MinEdge.Y) / speed.Y;
     116      372191 :                         if((relbox.MinEdge.X + speed.X * dtime < xsize) &&
     117      243707 :                                         (relbox.MaxEdge.X + speed.X * dtime > COLL_ZERO) &&
     118      142458 :                                         (relbox.MinEdge.Z + speed.Z * dtime < zsize) &&
     119       53636 :                                         (relbox.MaxEdge.Z + speed.Z * dtime > COLL_ZERO))
     120       38306 :                                 return 1;
     121             :                 }
     122      122143 :                 else if(relbox.MaxEdge.Y < 0)
     123             :                 {
     124       48219 :                         return -1;
     125             :                 }
     126             :         }
     127             : 
     128             :         // NO else if here
     129             : 
     130      592127 :         if(speed.Z > 0) // Check for collision with Z- plane
     131             :         {
     132      143192 :                 if(relbox.MaxEdge.Z <= d)
     133             :                 {
     134       32359 :                         dtime = - relbox.MaxEdge.Z / speed.Z;
     135       55726 :                         if((relbox.MinEdge.X + speed.X * dtime < xsize) &&
     136       35384 :                                         (relbox.MaxEdge.X + speed.X * dtime > COLL_ZERO) &&
     137       17513 :                                         (relbox.MinEdge.Y + speed.Y * dtime < ysize) &&
     138        5496 :                                         (relbox.MaxEdge.Y + speed.Y * dtime > COLL_ZERO))
     139        4487 :                                 return 2;
     140             :                 }
     141             :                 //else if(relbox.MinEdge.Z > zsize)
     142             :                 //{
     143             :                 //      return -1;
     144             :                 //}
     145             :         }
     146      448935 :         else if(speed.Z < 0) // Check for collision with Z+ plane
     147             :         {
     148      101983 :                 if(relbox.MinEdge.Z >= zsize - d)
     149             :                 {
     150       51438 :                         dtime = (zsize - relbox.MinEdge.Z) / speed.Z;
     151       85775 :                         if((relbox.MinEdge.X + speed.X * dtime < xsize) &&
     152       58131 :                                         (relbox.MaxEdge.X + speed.X * dtime > COLL_ZERO) &&
     153       35848 :                                         (relbox.MinEdge.Y + speed.Y * dtime < ysize) &&
     154       12054 :                                         (relbox.MaxEdge.Y + speed.Y * dtime > COLL_ZERO))
     155       10056 :                                 return 2;
     156             :                 }
     157             :                 //else if(relbox.MaxEdge.Z < 0)
     158             :                 //{
     159             :                 //      return -1;
     160             :                 //}
     161             :         }
     162             : 
     163      577584 :         return -1;
     164             : }
     165             : 
     166             : // Helper function:
     167             : // Checks if moving the movingbox up by the given distance would hit a ceiling.
     168          22 : bool wouldCollideWithCeiling(
     169             :                 const std::vector<aabb3f> &staticboxes,
     170             :                 const aabb3f &movingbox,
     171             :                 f32 y_increase, f32 d)
     172             : {
     173             :         //TimeTaker tt("wouldCollideWithCeiling");
     174             : 
     175             :         assert(y_increase >= 0);     // pre-condition
     176             : 
     177        2282 :         for(std::vector<aabb3f>::const_iterator
     178          22 :                         i = staticboxes.begin();
     179        1536 :                         i != staticboxes.end(); i++)
     180             :         {
     181         746 :                 const aabb3f& staticbox = *i;
     182         970 :                 if((movingbox.MaxEdge.Y - d <= staticbox.MinEdge.Y) &&
     183         224 :                                 (movingbox.MaxEdge.Y + y_increase > staticbox.MinEdge.Y) &&
     184           0 :                                 (movingbox.MinEdge.X < staticbox.MaxEdge.X) &&
     185           0 :                                 (movingbox.MaxEdge.X > staticbox.MinEdge.X) &&
     186           0 :                                 (movingbox.MinEdge.Z < staticbox.MaxEdge.Z) &&
     187           0 :                                 (movingbox.MaxEdge.Z > staticbox.MinEdge.Z))
     188           0 :                         return true;
     189             :         }
     190             : 
     191          22 :         return false;
     192             : }
     193             : 
     194             : 
     195       11583 : collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
     196             :                 f32 pos_max_d, const aabb3f &box_0,
     197             :                 f32 stepheight, f32 dtime,
     198             :                 v3f &pos_f, v3f &speed_f,
     199             :                 v3f &accel_f,ActiveObject* self,
     200             :                 bool collideWithObjects)
     201             : {
     202       11583 :         Map *map = &env->getMap();
     203             :         //TimeTaker tt("collisionMoveSimple");
     204       23166 :     ScopeProfiler sp(g_profiler, "collisionMoveSimple avg", SPT_AVG);
     205             : 
     206       11583 :         collisionMoveResult result;
     207             : 
     208             :         /*
     209             :                 Calculate new velocity
     210             :         */
     211       11583 :         if( dtime > 0.5 ) {
     212           0 :                 infostream<<"collisionMoveSimple: WARNING: maximum step interval exceeded, lost movement details!"<<std::endl;
     213           0 :                 dtime = 0.5;
     214             :         }
     215       11583 :         speed_f += accel_f * dtime;
     216             : 
     217             :         // If there is no speed, there are no collisions
     218       11583 :         if(speed_f.getLength() == 0)
     219           8 :                 return result;
     220             : 
     221             :         // Limit speed for avoiding hangs
     222       11575 :         speed_f.Y=rangelim(speed_f.Y,-5000,5000);
     223       11575 :         speed_f.X=rangelim(speed_f.X,-5000,5000);
     224       11575 :         speed_f.Z=rangelim(speed_f.Z,-5000,5000);
     225             : 
     226             :         /*
     227             :                 Collect node boxes in movement range
     228             :         */
     229       23150 :         std::vector<aabb3f> cboxes;
     230       23150 :         std::vector<bool> is_unloaded;
     231       23150 :         std::vector<bool> is_step_up;
     232       23150 :         std::vector<bool> is_object;
     233       23150 :         std::vector<int> bouncy_values;
     234       23150 :         std::vector<v3s16> node_positions;
     235             :         {
     236             :         //TimeTaker tt2("collisionMoveSimple collect boxes");
     237       23150 :     ScopeProfiler sp(g_profiler, "collisionMoveSimple collect boxes avg", SPT_AVG);
     238             : 
     239       11575 :         v3s16 oldpos_i = floatToInt(pos_f, BS);
     240       11575 :         v3s16 newpos_i = floatToInt(pos_f + speed_f * dtime, BS);
     241       11575 :         s16 min_x = MYMIN(oldpos_i.X, newpos_i.X) + (box_0.MinEdge.X / BS) - 1;
     242       11575 :         s16 min_y = MYMIN(oldpos_i.Y, newpos_i.Y) + (box_0.MinEdge.Y / BS) - 1;
     243       11575 :         s16 min_z = MYMIN(oldpos_i.Z, newpos_i.Z) + (box_0.MinEdge.Z / BS) - 1;
     244       11575 :         s16 max_x = MYMAX(oldpos_i.X, newpos_i.X) + (box_0.MaxEdge.X / BS) + 1;
     245       11575 :         s16 max_y = MYMAX(oldpos_i.Y, newpos_i.Y) + (box_0.MaxEdge.Y / BS) + 1;
     246       11575 :         s16 max_z = MYMAX(oldpos_i.Z, newpos_i.Z) + (box_0.MaxEdge.Z / BS) + 1;
     247             : 
     248       57727 :         for(s16 x = min_x; x <= max_x; x++)
     249      246539 :         for(s16 y = min_y; y <= max_y; y++)
     250     1002547 :         for(s16 z = min_z; z <= max_z; z++)
     251             :         {
     252      802160 :                 v3s16 p(x,y,z);
     253             : 
     254             :                 bool is_position_valid;
     255      802160 :                 MapNode n = map->getNodeNoEx(p, &is_position_valid);
     256             : 
     257      802160 :                 if (is_position_valid) {
     258             :                         // Object collides into walkable nodes
     259             : 
     260      716382 :                         const ContentFeatures &f = gamedef->getNodeDefManager()->get(n);
     261      716382 :                         if(f.walkable == false)
     262      412958 :                                 continue;
     263      303424 :                         int n_bouncy_value = itemgroup_get(f.groups, "bouncy");
     264             : 
     265      606848 :                         std::vector<aabb3f> nodeboxes = n.getCollisionBoxes(gamedef->ndef());
     266     1524011 :                         for(std::vector<aabb3f>::iterator
     267      303424 :                                         i = nodeboxes.begin();
     268     1218290 :                                         i != nodeboxes.end(); i++)
     269             :                         {
     270      305721 :                                 aabb3f box = *i;
     271      305721 :                                 box.MinEdge += v3f(x, y, z)*BS;
     272      305721 :                                 box.MaxEdge += v3f(x, y, z)*BS;
     273      305721 :                                 cboxes.push_back(box);
     274      305721 :                                 is_unloaded.push_back(false);
     275      305721 :                                 is_step_up.push_back(false);
     276      305721 :                                 bouncy_values.push_back(n_bouncy_value);
     277      305721 :                                 node_positions.push_back(p);
     278      305721 :                                 is_object.push_back(false);
     279             :                         }
     280             :                 }
     281             :                 else {
     282             :                         // Collide with unloaded nodes
     283       85778 :                         aabb3f box = getNodeBox(p, BS);
     284       85778 :                         cboxes.push_back(box);
     285       85778 :                         is_unloaded.push_back(true);
     286       85778 :                         is_step_up.push_back(false);
     287       85778 :                         bouncy_values.push_back(0);
     288       85778 :                         node_positions.push_back(p);
     289       85778 :                         is_object.push_back(false);
     290             :                 }
     291             :         }
     292             :         } // tt2
     293             : 
     294       11575 :         if(collideWithObjects)
     295             :         {
     296       22830 :                 ScopeProfiler sp(g_profiler, "collisionMoveSimple objects avg", SPT_AVG);
     297             :                 //TimeTaker tt3("collisionMoveSimple collect object boxes");
     298             : 
     299             :                 /* add object boxes to cboxes */
     300             : 
     301             : 
     302       22830 :                 std::vector<ActiveObject*> objects;
     303             : #ifndef SERVER
     304       11415 :                 ClientEnvironment *c_env = dynamic_cast<ClientEnvironment*>(env);
     305       11415 :                 if (c_env != 0) {
     306       11415 :                         f32 distance = speed_f.getLength();
     307       22830 :                         std::vector<DistanceSortedActiveObject> clientobjects;
     308       11415 :                         c_env->getActiveObjects(pos_f,distance * 1.5,clientobjects);
     309       21969 :                         for (size_t i=0; i < clientobjects.size(); i++) {
     310       10554 :                                 if ((self == 0) || (self != clientobjects[i].obj)) {
     311        2889 :                                         objects.push_back((ActiveObject*)clientobjects[i].obj);
     312             :                                 }
     313             :                         }
     314             :                 }
     315             :                 else
     316             : #endif
     317             :                 {
     318           0 :                         ServerEnvironment *s_env = dynamic_cast<ServerEnvironment*>(env);
     319           0 :                         if (s_env != 0) {
     320           0 :                                 f32 distance = speed_f.getLength();
     321           0 :                                 std::vector<u16> s_objects;
     322           0 :                                 s_env->getObjectsInsideRadius(s_objects, pos_f, distance * 1.5);
     323           0 :                                 for (std::vector<u16>::iterator iter = s_objects.begin(); iter != s_objects.end(); iter++) {
     324           0 :                                         ServerActiveObject *current = s_env->getActiveObject(*iter);
     325           0 :                                         if ((self == 0) || (self != current)) {
     326           0 :                                                 objects.push_back((ActiveObject*)current);
     327             :                                         }
     328             :                                 }
     329             :                         }
     330             :                 }
     331             : 
     332       42912 :                 for (std::vector<ActiveObject*>::const_iterator iter = objects.begin();
     333       28608 :                                 iter != objects.end(); ++iter) {
     334        2889 :                         ActiveObject *object = *iter;
     335             : 
     336        2889 :                         if (object != NULL) {
     337        2889 :                                 aabb3f object_collisionbox;
     338        3089 :                                 if (object->getCollisionBox(&object_collisionbox) &&
     339         200 :                                                 object->collideWithObjects()) {
     340          63 :                                         cboxes.push_back(object_collisionbox);
     341          63 :                                         is_unloaded.push_back(false);
     342          63 :                                         is_step_up.push_back(false);
     343          63 :                                         bouncy_values.push_back(0);
     344          63 :                                         node_positions.push_back(v3s16(0,0,0));
     345          63 :                                         is_object.push_back(true);
     346             :                                 }
     347             :                         }
     348             :                 }
     349             :         } //tt3
     350             : 
     351             :         assert(cboxes.size() == is_unloaded.size());    // post-condition
     352             :         assert(cboxes.size() == is_step_up.size());     // post-condition
     353             :         assert(cboxes.size() == bouncy_values.size());  // post-condition
     354             :         assert(cboxes.size() == node_positions.size()); // post-condition
     355             :         assert(cboxes.size() == is_object.size());      // post-condition
     356             : 
     357             :         /*
     358             :                 Collision detection
     359             :         */
     360             : 
     361             :         /*
     362             :                 Collision uncertainty radius
     363             :                 Make it a bit larger than the maximum distance of movement
     364             :         */
     365       11575 :         f32 d = pos_max_d * 1.1;
     366             :         // A fairly large value in here makes moving smoother
     367             :         //f32 d = 0.15*BS;
     368             : 
     369             :         // This should always apply, otherwise there are glitches
     370             :         assert(d > pos_max_d);       // invariant
     371             : 
     372       11575 :         int loopcount = 0;
     373             : 
     374       57407 :         while(dtime > BS*1e-10)
     375             :         {
     376             :                 //TimeTaker tt3("collisionMoveSimple dtime loop");
     377       45832 :         ScopeProfiler sp(g_profiler, "collisionMoveSimple dtime loop avg", SPT_AVG);
     378             : 
     379             :                 // Avoid infinite loop
     380       22916 :                 loopcount++;
     381       22916 :                 if(loopcount >= 100)
     382             :                 {
     383           0 :                         infostream<<"collisionMoveSimple: WARNING: Loop count exceeded, aborting to avoid infiniite loop"<<std::endl;
     384           0 :                         dtime = 0;
     385           0 :                         break;
     386             :                 }
     387             : 
     388       22916 :                 aabb3f movingbox = box_0;
     389       22916 :                 movingbox.MinEdge += pos_f;
     390       22916 :                 movingbox.MaxEdge += pos_f;
     391             : 
     392       22916 :                 int nearest_collided = -1;
     393       22916 :                 f32 nearest_dtime = dtime;
     394       22916 :                 u32 nearest_boxindex = -1;
     395             : 
     396             :                 /*
     397             :                         Go through every nodebox, find nearest collision
     398             :                 */
     399      804526 :                 for(u32 boxindex = 0; boxindex < cboxes.size(); boxindex++)
     400             :                 {
     401             :                         // Ignore if already stepped up this nodebox.
     402      781610 :                         if(is_step_up[boxindex])
     403      770114 :                                 continue;
     404             : 
     405             :                         // Find nearest collision of the two boxes (raytracing-like)
     406             :                         f32 dtime_tmp;
     407             :                         int collided = axisAlignedCollision(
     408      781567 :                                         cboxes[boxindex], movingbox, speed_f, d, dtime_tmp);
     409             : 
     410      781567 :                         if(collided == -1 || dtime_tmp >= nearest_dtime)
     411      770028 :                                 continue;
     412             : 
     413       11539 :                         nearest_dtime = dtime_tmp;
     414       11539 :                         nearest_collided = collided;
     415       11539 :                         nearest_boxindex = boxindex;
     416             :                 }
     417             : 
     418       22916 :                 if(nearest_collided == -1)
     419             :                 {
     420             :                         // No collision with any collision box.
     421       11575 :                         pos_f += speed_f * dtime;
     422       11575 :                         dtime = 0;  // Set to 0 to avoid "infinite" loop due to small FP numbers
     423             :                 }
     424             :                 else
     425             :                 {
     426             :                         // Otherwise, a collision occurred.
     427             : 
     428       11341 :                         const aabb3f& cbox = cboxes[nearest_boxindex];
     429             : 
     430             :                         // Check for stairs.
     431         179 :                         bool step_up = (nearest_collided != 1) && // must not be Y direction
     432         357 :                                         (movingbox.MinEdge.Y < cbox.MaxEdge.Y) &&
     433       11541 :                                         (movingbox.MinEdge.Y + stepheight > cbox.MaxEdge.Y) &&
     434          22 :                                         (!wouldCollideWithCeiling(cboxes, movingbox,
     435          22 :                                                         cbox.MaxEdge.Y - movingbox.MinEdge.Y,
     436       11363 :                                                         d));
     437             : 
     438             :                         // Get bounce multiplier
     439       11341 :                         bool bouncy = (bouncy_values[nearest_boxindex] >= 1);
     440       11341 :                         float bounce = -(float)bouncy_values[nearest_boxindex] / 100.0;
     441             : 
     442             :                         // Move to the point of collision and reduce dtime by nearest_dtime
     443       11341 :                         if(nearest_dtime < 0)
     444             :                         {
     445             :                                 // Handle negative nearest_dtime (can be caused by the d allowance)
     446          95 :                                 if(!step_up)
     447             :                                 {
     448          81 :                                         if(nearest_collided == 0)
     449          42 :                                                 pos_f.X += speed_f.X * nearest_dtime;
     450          81 :                                         if(nearest_collided == 1)
     451           3 :                                                 pos_f.Y += speed_f.Y * nearest_dtime;
     452          81 :                                         if(nearest_collided == 2)
     453          36 :                                                 pos_f.Z += speed_f.Z * nearest_dtime;
     454             :                                 }
     455             :                         }
     456             :                         else
     457             :                         {
     458       11246 :                                 pos_f += speed_f * nearest_dtime;
     459       11246 :                                 dtime -= nearest_dtime;
     460             :                         }
     461             :                         
     462       11341 :                         bool is_collision = true;
     463       11341 :                         if(is_unloaded[nearest_boxindex])
     464        1092 :                                 is_collision = false;
     465             : 
     466       11341 :                         CollisionInfo info;
     467       11341 :                         if (is_object[nearest_boxindex]) {
     468           1 :                                 info.type = COLLISION_OBJECT;
     469             :                         }
     470             :                         else {
     471       11340 :                                 info.type = COLLISION_NODE;
     472             :                         }
     473       11341 :                         info.node_p = node_positions[nearest_boxindex];
     474       11341 :                         info.bouncy = bouncy;
     475       11341 :                         info.old_speed = speed_f;
     476             : 
     477             :                         // Set the speed component that caused the collision to zero
     478       11341 :                         if(step_up)
     479             :                         {
     480             :                                 // Special case: Handle stairs
     481          22 :                                 is_step_up[nearest_boxindex] = true;
     482          22 :                                 is_collision = false;
     483             :                         }
     484       11319 :                         else if(nearest_collided == 0) // X
     485             :                         {
     486          78 :                                 if(fabs(speed_f.X) > BS*3)
     487           0 :                                         speed_f.X *= bounce;
     488             :                                 else
     489          78 :                                         speed_f.X = 0;
     490          78 :                                 result.collides = true;
     491          78 :                                 result.collides_xz = true;
     492             :                         }
     493       11241 :                         else if(nearest_collided == 1) // Y
     494             :                         {
     495       11162 :                                 if(fabs(speed_f.Y) > BS*3)
     496          18 :                                         speed_f.Y *= bounce;
     497             :                                 else
     498       11144 :                                         speed_f.Y = 0;
     499       11162 :                                 result.collides = true;
     500             :                         }
     501          79 :                         else if(nearest_collided == 2) // Z
     502             :                         {
     503          79 :                                 if(fabs(speed_f.Z) > BS*3)
     504           0 :                                         speed_f.Z *= bounce;
     505             :                                 else
     506          79 :                                         speed_f.Z = 0;
     507          79 :                                 result.collides = true;
     508          79 :                                 result.collides_xz = true;
     509             :                         }
     510             : 
     511       11341 :                         info.new_speed = speed_f;
     512       11341 :                         if(info.new_speed.getDistanceFrom(info.old_speed) < 0.1*BS)
     513         562 :                                 is_collision = false;
     514             : 
     515       11341 :                         if(is_collision){
     516        9777 :                                 result.collisions.push_back(info);
     517             :                         }
     518             :                 }
     519             :         }
     520             : 
     521             :         /*
     522             :                 Final touches: Check if standing on ground, step up stairs.
     523             :         */
     524       11575 :         aabb3f box = box_0;
     525       11575 :         box.MinEdge += pos_f;
     526       11575 :         box.MaxEdge += pos_f;
     527      403137 :         for(u32 boxindex = 0; boxindex < cboxes.size(); boxindex++)
     528             :         {
     529      391562 :                 const aabb3f& cbox = cboxes[boxindex];
     530             : 
     531             :                 /*
     532             :                         See if the object is touching ground.
     533             : 
     534             :                         Object touches ground if object's minimum Y is near node's
     535             :                         maximum Y and object's X-Z-area overlaps with the node's
     536             :                         X-Z-area.
     537             : 
     538             :                         Use 0.15*BS so that it is easier to get on a node.
     539             :                 */
     540      391562 :                 if(
     541      639546 :                                 cbox.MaxEdge.X-d > box.MinEdge.X &&
     542      367900 :                                 cbox.MinEdge.X+d < box.MaxEdge.X &&
     543      181603 :                                 cbox.MaxEdge.Z-d > box.MinEdge.Z &&
     544       61687 :                                 cbox.MinEdge.Z+d < box.MaxEdge.Z
     545             :                 ){
     546       38528 :                         if(is_step_up[boxindex])
     547             :                         {
     548           0 :                                 pos_f.Y += (cbox.MaxEdge.Y - box.MinEdge.Y);
     549           0 :                                 box = box_0;
     550           0 :                                 box.MinEdge += pos_f;
     551           0 :                                 box.MaxEdge += pos_f;
     552             :                         }
     553       38528 :                         if(fabs(cbox.MaxEdge.Y-box.MinEdge.Y) < 0.15*BS)
     554             :                         {
     555       19962 :                                 result.touching_ground = true;
     556       19962 :                                 if(is_unloaded[boxindex])
     557        1778 :                                         result.standing_on_unloaded = true;
     558             :                         }
     559             :                 }
     560             :         }
     561             : 
     562       11575 :         return result;
     563           3 : }
     564             : 
     565             : #if 0
     566             : // This doesn't seem to work and isn't used
     567             : collisionMoveResult collisionMovePrecise(Map *map, IGameDef *gamedef,
     568             :                 f32 pos_max_d, const aabb3f &box_0,
     569             :                 f32 stepheight, f32 dtime,
     570             :                 v3f &pos_f, v3f &speed_f, v3f &accel_f)
     571             : {
     572             :         //TimeTaker tt("collisionMovePrecise");
     573             :     ScopeProfiler sp(g_profiler, "collisionMovePrecise avg", SPT_AVG);
     574             :         
     575             :         collisionMoveResult final_result;
     576             : 
     577             :         // If there is no speed, there are no collisions
     578             :         if(speed_f.getLength() == 0)
     579             :                 return final_result;
     580             : 
     581             :         // Don't allow overly huge dtime
     582             :         if(dtime > 2.0)
     583             :                 dtime = 2.0;
     584             : 
     585             :         f32 dtime_downcount = dtime;
     586             : 
     587             :         u32 loopcount = 0;
     588             :         do
     589             :         {
     590             :                 loopcount++;
     591             : 
     592             :                 // Maximum time increment (for collision detection etc)
     593             :                 // time = distance / speed
     594             :                 f32 dtime_max_increment = 1.0;
     595             :                 if(speed_f.getLength() != 0)
     596             :                         dtime_max_increment = pos_max_d / speed_f.getLength();
     597             : 
     598             :                 // Maximum time increment is 10ms or lower
     599             :                 if(dtime_max_increment > 0.01)
     600             :                         dtime_max_increment = 0.01;
     601             : 
     602             :                 f32 dtime_part;
     603             :                 if(dtime_downcount > dtime_max_increment)
     604             :                 {
     605             :                         dtime_part = dtime_max_increment;
     606             :                         dtime_downcount -= dtime_part;
     607             :                 }
     608             :                 else
     609             :                 {
     610             :                         dtime_part = dtime_downcount;
     611             :                         /*
     612             :                                 Setting this to 0 (no -=dtime_part) disables an infinite loop
     613             :                                 when dtime_part is so small that dtime_downcount -= dtime_part
     614             :                                 does nothing
     615             :                         */
     616             :                         dtime_downcount = 0;
     617             :                 }
     618             : 
     619             :                 collisionMoveResult result = collisionMoveSimple(map, gamedef,
     620             :                                 pos_max_d, box_0, stepheight, dtime_part,
     621             :                                 pos_f, speed_f, accel_f);
     622             : 
     623             :                 if(result.touching_ground)
     624             :                         final_result.touching_ground = true;
     625             :                 if(result.collides)
     626             :                         final_result.collides = true;
     627             :                 if(result.collides_xz)
     628             :                         final_result.collides_xz = true;
     629             :                 if(result.standing_on_unloaded)
     630             :                         final_result.standing_on_unloaded = true;
     631             :         }
     632             :         while(dtime_downcount > 0.001);
     633             : 
     634             :         return final_result;
     635             : }
     636             : #endif

Generated by: LCOV version 1.11