+// float error is 10 - 9.96875 = 0.03125
+//#define COLL_ZERO 0.032 // broken unit tests
+#define COLL_ZERO 0
+
+
+struct NearbyCollisionInfo {
+ NearbyCollisionInfo(bool is_ul, bool is_obj, int bouncy,
+ const v3s16 &pos, const aabb3f &box) :
+ is_unloaded(is_ul),
+ is_object(is_obj),
+ bouncy(bouncy),
+ position(pos),
+ box(box)
+ {}
+
+ bool is_unloaded;
+ bool is_step_up = false;
+ bool is_object;
+ int bouncy;
+ v3s16 position;
+ aabb3f box;
+};
+
+
+// Helper function:
+// Checks for collision of a moving aabbox with a static aabbox
+// Returns -1 if no collision, 0 if X collision, 1 if Y collision, 2 if Z collision
+// The time after which the collision occurs is stored in dtime.
+int axisAlignedCollision(
+ const aabb3f &staticbox, const aabb3f &movingbox,
+ const v3f &speed, f32 d, f32 *dtime)
+{
+ //TimeTaker tt("axisAlignedCollision");
+
+ f32 xsize = (staticbox.MaxEdge.X - staticbox.MinEdge.X) - COLL_ZERO; // reduce box size for solve collision stuck (flying sand)
+ f32 ysize = (staticbox.MaxEdge.Y - staticbox.MinEdge.Y); // - COLL_ZERO; // Y - no sense for falling, but maybe try later
+ f32 zsize = (staticbox.MaxEdge.Z - staticbox.MinEdge.Z) - COLL_ZERO;
+
+ aabb3f relbox(
+ movingbox.MinEdge.X - staticbox.MinEdge.X,
+ movingbox.MinEdge.Y - staticbox.MinEdge.Y,
+ movingbox.MinEdge.Z - staticbox.MinEdge.Z,
+ movingbox.MaxEdge.X - staticbox.MinEdge.X,
+ movingbox.MaxEdge.Y - staticbox.MinEdge.Y,
+ movingbox.MaxEdge.Z - staticbox.MinEdge.Z
+ );
+
+ if(speed.X > 0) // Check for collision with X- plane
+ {
+ if (relbox.MaxEdge.X <= d) {
+ *dtime = -relbox.MaxEdge.X / speed.X;
+ if ((relbox.MinEdge.Y + speed.Y * (*dtime) < ysize) &&
+ (relbox.MaxEdge.Y + speed.Y * (*dtime) > COLL_ZERO) &&
+ (relbox.MinEdge.Z + speed.Z * (*dtime) < zsize) &&
+ (relbox.MaxEdge.Z + speed.Z * (*dtime) > COLL_ZERO))
+ return 0;
+ }
+ else if(relbox.MinEdge.X > xsize)
+ {
+ return -1;
+ }
+ }
+ else if(speed.X < 0) // Check for collision with X+ plane
+ {
+ if (relbox.MinEdge.X >= xsize - d) {
+ *dtime = (xsize - relbox.MinEdge.X) / speed.X;
+ if ((relbox.MinEdge.Y + speed.Y * (*dtime) < ysize) &&
+ (relbox.MaxEdge.Y + speed.Y * (*dtime) > COLL_ZERO) &&
+ (relbox.MinEdge.Z + speed.Z * (*dtime) < zsize) &&
+ (relbox.MaxEdge.Z + speed.Z * (*dtime) > COLL_ZERO))
+ return 0;
+ }
+ else if(relbox.MaxEdge.X < 0)
+ {
+ return -1;
+ }
+ }
+
+ // NO else if here
+
+ if(speed.Y > 0) // Check for collision with Y- plane
+ {
+ if (relbox.MaxEdge.Y <= d) {
+ *dtime = -relbox.MaxEdge.Y / speed.Y;
+ if ((relbox.MinEdge.X + speed.X * (*dtime) < xsize) &&
+ (relbox.MaxEdge.X + speed.X * (*dtime) > COLL_ZERO) &&
+ (relbox.MinEdge.Z + speed.Z * (*dtime) < zsize) &&
+ (relbox.MaxEdge.Z + speed.Z * (*dtime) > COLL_ZERO))
+ return 1;
+ }
+ else if(relbox.MinEdge.Y > ysize)
+ {
+ return -1;
+ }
+ }
+ else if(speed.Y < 0) // Check for collision with Y+ plane
+ {
+ if (relbox.MinEdge.Y >= ysize - d) {
+ *dtime = (ysize - relbox.MinEdge.Y) / speed.Y;
+ if ((relbox.MinEdge.X + speed.X * (*dtime) < xsize) &&
+ (relbox.MaxEdge.X + speed.X * (*dtime) > COLL_ZERO) &&
+ (relbox.MinEdge.Z + speed.Z * (*dtime) < zsize) &&
+ (relbox.MaxEdge.Z + speed.Z * (*dtime) > COLL_ZERO))
+ return 1;
+ }
+ else if(relbox.MaxEdge.Y < 0)
+ {
+ return -1;
+ }
+ }
+
+ // NO else if here
+
+ if(speed.Z > 0) // Check for collision with Z- plane
+ {
+ if (relbox.MaxEdge.Z <= d) {
+ *dtime = -relbox.MaxEdge.Z / speed.Z;
+ if ((relbox.MinEdge.X + speed.X * (*dtime) < xsize) &&
+ (relbox.MaxEdge.X + speed.X * (*dtime) > COLL_ZERO) &&
+ (relbox.MinEdge.Y + speed.Y * (*dtime) < ysize) &&
+ (relbox.MaxEdge.Y + speed.Y * (*dtime) > COLL_ZERO))
+ return 2;
+ }
+ //else if(relbox.MinEdge.Z > zsize)
+ //{
+ // return -1;
+ //}
+ }
+ else if(speed.Z < 0) // Check for collision with Z+ plane
+ {
+ if (relbox.MinEdge.Z >= zsize - d) {
+ *dtime = (zsize - relbox.MinEdge.Z) / speed.Z;
+ if ((relbox.MinEdge.X + speed.X * (*dtime) < xsize) &&
+ (relbox.MaxEdge.X + speed.X * (*dtime) > COLL_ZERO) &&
+ (relbox.MinEdge.Y + speed.Y * (*dtime) < ysize) &&
+ (relbox.MaxEdge.Y + speed.Y * (*dtime) > COLL_ZERO))
+ return 2;
+ }
+ //else if(relbox.MaxEdge.Z < 0)
+ //{
+ // return -1;
+ //}
+ }
+
+ return -1;
+}
+
+// Helper function:
+// Checks if moving the movingbox up by the given distance would hit a ceiling.
+bool wouldCollideWithCeiling(
+ const std::vector<NearbyCollisionInfo> &cinfo,
+ const aabb3f &movingbox,
+ f32 y_increase, f32 d)
+{
+ //TimeTaker tt("wouldCollideWithCeiling");
+
+ assert(y_increase >= 0); // pre-condition
+
+ for (const auto &it : cinfo) {
+ const aabb3f &staticbox = it.box;
+ if ((movingbox.MaxEdge.Y - d <= staticbox.MinEdge.Y) &&
+ (movingbox.MaxEdge.Y + y_increase > staticbox.MinEdge.Y) &&
+ (movingbox.MinEdge.X < staticbox.MaxEdge.X) &&
+ (movingbox.MaxEdge.X > staticbox.MinEdge.X) &&
+ (movingbox.MinEdge.Z < staticbox.MaxEdge.Z) &&
+ (movingbox.MaxEdge.Z > staticbox.MinEdge.Z))
+ return true;
+ }
+
+ return false;
+}
+
+static inline void getNeighborConnectingFace(const v3s16 &p,
+ const NodeDefManager *nodedef, Map *map, MapNode n, int v, int *neighbors)
+{
+ MapNode n2 = map->getNodeNoEx(p);
+ if (nodedef->nodeboxConnects(n, n2, v))
+ *neighbors |= v;
+}
+
+collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
+ f32 pos_max_d, const aabb3f &box_0,
+ f32 stepheight, f32 dtime,
+ v3f *pos_f, v3f *speed_f,
+ v3f accel_f, ActiveObject *self,
+ bool collideWithObjects)