Custom boxy nodes (stairs, slabs) and collision changes
authorKahrl <kahrl@gmx.net>
Mon, 19 Mar 2012 03:25:09 +0000 (04:25 +0100)
committerPerttu Ahola <celeron55@gmail.com>
Sun, 17 Jun 2012 13:34:39 +0000 (16:34 +0300)
19 files changed:
games/minimal/mods/default/init.lua
games/minimal/mods/stairs/depends.txt [new file with mode: 0644]
games/minimal/mods/stairs/init.lua [new file with mode: 0644]
src/camera.cpp
src/collision.cpp
src/collision.h
src/content_cao.cpp
src/content_mapblock.cpp
src/content_sao.cpp
src/game.cpp
src/localplayer.cpp
src/mapnode.cpp
src/mapnode.h
src/nodedef.cpp
src/nodedef.h
src/player.cpp
src/scriptapi.cpp
src/test.cpp
src/tile.h

index 64dcbbdfeeade3b6988e85c373fd07c8f6fb06c8..cb424cb5bdc056471794b6bb4f0c1924baaca285 100644 (file)
@@ -926,7 +926,7 @@ minetest.register_node("default:rail", {
        walkable = false,
        selection_box = {
                type = "fixed",
-               --fixed = <default>
+               fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
        },
        groups = {bendy=2,snappy=1,dig_immediate=2},
 })
diff --git a/games/minimal/mods/stairs/depends.txt b/games/minimal/mods/stairs/depends.txt
new file mode 100644 (file)
index 0000000..4ad96d5
--- /dev/null
@@ -0,0 +1 @@
+default
diff --git a/games/minimal/mods/stairs/init.lua b/games/minimal/mods/stairs/init.lua
new file mode 100644 (file)
index 0000000..4929d13
--- /dev/null
@@ -0,0 +1,93 @@
+stairs = {}
+
+-- Node will be called stairs:stair_<subname>
+function stairs.register_stair(subname, recipeitem, groups, images, description)
+       minetest.register_node("stairs:stair_" .. subname, {
+               description = description,
+               drawtype = "nodebox",
+               tile_images = images,
+               paramtype = "light",
+               paramtype2 = "facedir",
+               is_ground_content = true,
+               groups = groups,
+               node_box = {
+                       type = "fixed",
+                       fixed = {
+                               {-0.5, -0.5, -0.5, 0.5, 0, 0.5},
+                               {-0.5, 0, 0, 0.5, 0.5, 0.5},
+                       },
+               },
+       })
+
+       minetest.register_craft({
+               output = 'stairs:stair_' .. subname .. ' 4',
+               recipe = {
+                       {recipeitem, "", ""},
+                       {recipeitem, recipeitem, ""},
+                       {recipeitem, recipeitem, recipeitem},
+               },
+       })
+end
+
+-- Node will be called stairs:slab_<subname>
+function stairs.register_slab(subname, recipeitem, groups, images, description)
+       minetest.register_node("stairs:slab_" .. subname, {
+               description = description,
+               drawtype = "nodebox",
+               tile_images = images,
+               paramtype = "light",
+               is_ground_content = true,
+               groups = groups,
+               node_box = {
+                       type = "fixed",
+                       fixed = {-0.5, -0.5, -0.5, 0.5, 0, 0.5},
+               },
+               selection_box = {
+                       type = "fixed",
+                       fixed = {-0.5, -0.5, -0.5, 0.5, 0, 0.5},
+               },
+       })
+
+       minetest.register_craft({
+               output = 'stairs:slab_' .. subname .. ' 3',
+               recipe = {
+                       {recipeitem, recipeitem, recipeitem},
+               },
+       })
+end
+
+-- Nodes will be called stairs:{stair,slab}_<subname>
+function stairs.register_stair_and_slab(subname, recipeitem, groups, images, desc_stair, desc_slab)
+       stairs.register_stair(subname, recipeitem, groups, images, desc_stair)
+       stairs.register_slab(subname, recipeitem, groups, images, desc_slab)
+end
+
+stairs.register_stair_and_slab("wood", "default:wood",
+               {snappy=2,choppy=2,oddly_breakable_by_hand=2},
+               {"default_wood.png"},
+               "Wooden stair",
+               "Wooden slab")
+
+stairs.register_stair_and_slab("stone", "default:stone",
+               {cracky=3},
+               {"default_stone.png"},
+               "Stone stair",
+               "Stone slab")
+
+stairs.register_stair_and_slab("cobble", "default:cobble",
+               {cracky=3},
+               {"default_cobble.png"},
+               "Cobble stair",
+               "Cobble slab")
+
+stairs.register_stair_and_slab("brick", "default:brick",
+               {cracky=3},
+               {"default_brick.png"},
+               "Brick stair",
+               "Brick slab")
+
+stairs.register_stair_and_slab("sandstone", "default:sandstone",
+               {crumbly=2,cracky=2},
+               {"default_sandstone.png"},
+               "Sandstone stair",
+               "Sandstone slab")
index 1ef594eeadacc5f762ae01374c850a94fea2dda3..32dd85e52322aa292271838e457f1ae78e579dfc 100644 (file)
@@ -213,8 +213,22 @@ void Camera::step(f32 dtime)
 void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize,
                f32 tool_reload_ratio)
 {
+       // Get player position
+       // Smooth the movement when walking up stairs
+       v3f old_player_position = m_playernode->getPosition();
+       v3f player_position = player->getPosition();
+       //if(player->touching_ground && player_position.Y > old_player_position.Y)
+       if(player->touching_ground &&
+                       player_position.Y > old_player_position.Y)
+       {
+               f32 oldy = old_player_position.Y;
+               f32 newy = player_position.Y;
+               f32 t = exp(-23*frametime);
+               player_position.Y = oldy * t + newy * (1-t);
+       }
+
        // Set player node transformation
-       m_playernode->setPosition(player->getPosition());
+       m_playernode->setPosition(player_position);
        m_playernode->setRotation(v3f(0, -1 * player->getYaw(), 0));
        m_playernode->updateAbsolutePosition();
 
index f8db42d2690ebe5649313200cc5964157f556670..09a7df7c2c069265c36ba4a1245fb9ec480cb472 100644 (file)
@@ -22,32 +22,249 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "map.h"
 #include "nodedef.h"
 #include "gamedef.h"
+#include "log.h"
+#include <vector>
+#include "util/timetaker.h"
+#include "main.h" // g_profiler
+#include "profiler.h"
+
+// 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);
+       f32 ysize = (staticbox.MaxEdge.Y - staticbox.MinEdge.Y);
+       f32 zsize = (staticbox.MaxEdge.Z - staticbox.MinEdge.Z);
+
+       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 > 0) &&
+                                       (relbox.MinEdge.Z + speed.Z * dtime < zsize) &&
+                                       (relbox.MaxEdge.Z + speed.Z * dtime > 0))
+                               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 > 0) &&
+                                       (relbox.MinEdge.Z + speed.Z * dtime < zsize) &&
+                                       (relbox.MaxEdge.Z + speed.Z * dtime > 0))
+                               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 > 0) &&
+                                       (relbox.MinEdge.Z + speed.Z * dtime < zsize) &&
+                                       (relbox.MaxEdge.Z + speed.Z * dtime > 0))
+                               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 > 0) &&
+                                       (relbox.MinEdge.Z + speed.Z * dtime < zsize) &&
+                                       (relbox.MaxEdge.Z + speed.Z * dtime > 0))
+                               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 > 0) &&
+                                       (relbox.MinEdge.Y + speed.Y * dtime < ysize) &&
+                                       (relbox.MaxEdge.Y + speed.Y * dtime > 0))
+                               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 > 0) &&
+                                       (relbox.MinEdge.Y + speed.Y * dtime < ysize) &&
+                                       (relbox.MaxEdge.Y + speed.Y * dtime > 0))
+                               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<aabb3f> &staticboxes,
+               const aabb3f &movingbox,
+               f32 y_increase, f32 d)
+{
+       //TimeTaker tt("wouldCollideWithCeiling");
+
+       assert(y_increase >= 0);
+
+       for(std::vector<aabb3f>::const_iterator
+                       i = staticboxes.begin();
+                       i != staticboxes.end(); i++)
+       {
+               const aabb3f& staticbox = *i;
+               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;
+}
+
 
 collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
-               f32 pos_max_d, const core::aabbox3d<f32> &box_0,
-               f32 dtime, v3f &pos_f, v3f &speed_f)
+               f32 pos_max_d, const aabb3f &box_0,
+               f32 stepheight, f32 dtime,
+               v3f &pos_f, v3f &speed_f, v3f &accel_f)
 {
+       //TimeTaker tt("collisionMoveSimple");
+    ScopeProfiler sp(g_profiler, "collisionMoveSimple avg", SPT_AVG);
+
        collisionMoveResult result;
 
-       // If there is no speed, there are no collisions
+       /*
+               Calculate new velocity
+       */
+       speed_f += accel_f * dtime;
+
+    // If there is no speed, there are no collisions
        if(speed_f.getLength() == 0)
                return result;
 
-       v3f oldpos_f = pos_f;
-       v3s16 oldpos_i = floatToInt(oldpos_f, BS);
-
        /*
-               Calculate new position
+               Collect node boxes in movement range
        */
-       pos_f += speed_f * dtime;
+       std::vector<aabb3f> cboxes;
+       std::vector<bool> is_unloaded;
+       std::vector<bool> is_step_up;
+       {
+       //TimeTaker tt2("collisionMoveSimple collect boxes");
+    ScopeProfiler sp(g_profiler, "collisionMoveSimple collect boxes avg", SPT_AVG);
+
+       v3s16 oldpos_i = floatToInt(pos_f, BS);
+       v3s16 newpos_i = floatToInt(pos_f + speed_f * dtime, BS);
+       s16 min_x = MYMIN(oldpos_i.X, newpos_i.X) + (box_0.MinEdge.X / BS) - 1;
+       s16 min_y = MYMIN(oldpos_i.Y, newpos_i.Y) + (box_0.MinEdge.Y / BS) - 1;
+       s16 min_z = MYMIN(oldpos_i.Z, newpos_i.Z) + (box_0.MinEdge.Z / BS) - 1;
+       s16 max_x = MYMAX(oldpos_i.X, newpos_i.X) + (box_0.MaxEdge.X / BS) + 1;
+       s16 max_y = MYMAX(oldpos_i.Y, newpos_i.Y) + (box_0.MaxEdge.Y / BS) + 1;
+       s16 max_z = MYMAX(oldpos_i.Z, newpos_i.Z) + (box_0.MaxEdge.Z / BS) + 1;
+
+       for(s16 x = min_x; x <= max_x; x++)
+       for(s16 y = min_y; y <= max_y; y++)
+       for(s16 z = min_z; z <= max_z; z++)
+       {
+               try{
+                       // Object collides into walkable nodes
+                       MapNode n = map->getNode(v3s16(x,y,z));
+                       if(gamedef->getNodeDefManager()->get(n).walkable == false)
+                               continue;
+
+                       std::vector<aabb3f> nodeboxes = n.getNodeBoxes(gamedef->ndef());
+                       for(std::vector<aabb3f>::iterator
+                                       i = nodeboxes.begin();
+                                       i != nodeboxes.end(); i++)
+                       {
+                               aabb3f box = *i;
+                               box.MinEdge += v3f(x, y, z)*BS;
+                               box.MaxEdge += v3f(x, y, z)*BS;
+                               cboxes.push_back(box);
+                               is_unloaded.push_back(false);
+                               is_step_up.push_back(false);
+                       }
+               }
+               catch(InvalidPositionException &e)
+               {
+                       // Collide with unloaded nodes
+                       aabb3f box = getNodeBox(v3s16(x,y,z), BS);
+                       cboxes.push_back(box);
+                       is_unloaded.push_back(true);
+                       is_step_up.push_back(false);
+               }
+       }
+       } // tt2
+
+       assert(cboxes.size() == is_unloaded.size());
+       assert(cboxes.size() == is_step_up.size());
 
        /*
                Collision detection
        */
-       
-       // position in nodes
-       v3s16 pos_i = floatToInt(pos_f, BS);
-       
+
        /*
                Collision uncertainty radius
                Make it a bit larger than the maximum distance of movement
@@ -58,49 +275,129 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
 
        // This should always apply, otherwise there are glitches
        assert(d > pos_max_d);
-       
-       /*
-               Calculate collision box
-       */
-       core::aabbox3d<f32> box = box_0;
-       box.MaxEdge += pos_f;
-       box.MinEdge += pos_f;
-       core::aabbox3d<f32> oldbox = box_0;
-       oldbox.MaxEdge += oldpos_f;
-       oldbox.MinEdge += oldpos_f;
 
-       /*
-               If the object lies on a walkable node, this is set to true.
-       */
-       result.touching_ground = false;
-       
-       /*
-               Go through every node around the object
-       */
-       s16 min_x = (box_0.MinEdge.X / BS) - 2;
-       s16 min_y = (box_0.MinEdge.Y / BS) - 2;
-       s16 min_z = (box_0.MinEdge.Z / BS) - 2;
-       s16 max_x = (box_0.MaxEdge.X / BS) + 1;
-       s16 max_y = (box_0.MaxEdge.Y / BS) + 1;
-       s16 max_z = (box_0.MaxEdge.Z / BS) + 1;
-       for(s16 y = oldpos_i.Y + min_y; y <= oldpos_i.Y + max_y; y++)
-       for(s16 z = oldpos_i.Z + min_z; z <= oldpos_i.Z + max_z; z++)
-       for(s16 x = oldpos_i.X + min_x; x <= oldpos_i.X + max_x; x++)
+       int loopcount = 0;
+
+       while(dtime > BS*1e-10)
        {
-               try{
-                       // Object collides into walkable nodes
-                       MapNode n = map->getNode(v3s16(x,y,z));
-                       if(gamedef->getNodeDefManager()->get(n).walkable == false)
+               //TimeTaker tt3("collisionMoveSimple dtime loop");
+        ScopeProfiler sp(g_profiler, "collisionMoveSimple dtime loop avg", SPT_AVG);
+
+               // Avoid infinite loop
+               loopcount++;
+               if(loopcount >= 100)
+               {
+                       infostream<<"collisionMoveSimple: WARNING: Loop count exceeded, aborting to avoid infiniite loop"<<std::endl;
+                       dtime = 0;
+                       break;
+               }
+
+               aabb3f movingbox = box_0;
+               movingbox.MinEdge += pos_f;
+               movingbox.MaxEdge += pos_f;
+
+               int nearest_collided = -1;
+               f32 nearest_dtime = dtime;
+               u32 nearest_boxindex = -1;
+
+               /*
+                       Go through every nodebox, find nearest collision
+               */
+               for(u32 boxindex = 0; boxindex < cboxes.size(); boxindex++)
+               {
+                       // Ignore if already stepped up this nodebox.
+                       if(is_step_up[boxindex])
+                               continue;
+
+                       // Find nearest collision of the two boxes (raytracing-like)
+                       f32 dtime_tmp;
+                       int collided = axisAlignedCollision(
+                                       cboxes[boxindex], movingbox, speed_f, d, dtime_tmp);
+
+                       if(collided == -1 || dtime_tmp >= nearest_dtime)
                                continue;
+
+                       nearest_dtime = dtime_tmp;
+                       nearest_collided = collided;
+                       nearest_boxindex = boxindex;
                }
-               catch(InvalidPositionException &e)
+
+               if(nearest_collided == -1)
                {
-                       // Doing nothing here will block the object from
-                       // walking over map borders
+                       // No collision with any collision box.
+                       pos_f += speed_f * dtime;
+                       dtime = 0;  // Set to 0 to avoid "infinite" loop due to small FP numbers
                }
+               else
+               {
+                       // Otherwise, a collision occurred.
+
+                       const aabb3f& cbox = cboxes[nearest_boxindex];
+
+                       // Check for stairs.
+                       bool step_up = (nearest_collided != 1) && // must not be Y direction
+                                       (movingbox.MinEdge.Y < cbox.MaxEdge.Y) &&
+                                       (movingbox.MinEdge.Y + stepheight > cbox.MaxEdge.Y) &&
+                                       (!wouldCollideWithCeiling(cboxes, movingbox,
+                                                       cbox.MaxEdge.Y - movingbox.MinEdge.Y,
+                                                       d));
+
+                       // Move to the point of collision and reduce dtime by nearest_dtime
+                       if(nearest_dtime < 0)
+                       {
+                               // Handle negative nearest_dtime (can be caused by the d allowance)
+                               if(!step_up)
+                               {
+                                       if(nearest_collided == 0)
+                                               pos_f.X += speed_f.X * nearest_dtime;
+                                       if(nearest_collided == 1)
+                                               pos_f.Y += speed_f.Y * nearest_dtime;
+                                       if(nearest_collided == 2)
+                                               pos_f.Z += speed_f.Z * nearest_dtime;
+                               }
+                       }
+                       else
+                       {
+                               pos_f += speed_f * nearest_dtime;
+                               dtime -= nearest_dtime;
+                       }
+
+                       // Set the speed component that caused the collision to zero
+                       if(step_up)
+                       {
+                               // Special case: Handle stairs
+                               is_step_up[nearest_boxindex] = true;
+                       }
+                       else if(nearest_collided == 0) // X
+                       {
+                               speed_f.X = 0;
+                               result.collides = true;
+                               result.collides_xz = true;
+                       }
+                       else if(nearest_collided == 1) // Y
+                       {
+                               speed_f.Y = 0;
+                               result.collides = true;
+                       }
+                       else if(nearest_collided == 2) // Z
+                       {
+                               speed_f.Z = 0;
+                               result.collides = true;
+                               result.collides_xz = true;
+                       }
+               }
+       }
+
+       /*
+               Final touches: Check if standing on ground, step up stairs.
+       */
+       aabb3f box = box_0;
+       box.MinEdge += pos_f;
+       box.MaxEdge += pos_f;
+       for(u32 boxindex = 0; boxindex < cboxes.size(); boxindex++)
+       {
+               const aabb3f& cbox = cboxes[boxindex];
 
-               core::aabbox3d<f32> nodebox = getNodeBox(v3s16(x,y,z), BS);
-               
                /*
                        See if the object is touching ground.
 
@@ -111,112 +408,50 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
                        Use 0.15*BS so that it is easier to get on a node.
                */
                if(
-                               //fabs(nodebox.MaxEdge.Y-box.MinEdge.Y) < d
-                               fabs(nodebox.MaxEdge.Y-box.MinEdge.Y) < 0.15*BS
-                               && nodebox.MaxEdge.X-d > box.MinEdge.X
-                               && nodebox.MinEdge.X+d < box.MaxEdge.X
-                               && nodebox.MaxEdge.Z-d > box.MinEdge.Z
-                               && nodebox.MinEdge.Z+d < box.MaxEdge.Z
+                               cbox.MaxEdge.X-d > box.MinEdge.X &&
+                               cbox.MinEdge.X+d < box.MaxEdge.X &&
+                               cbox.MaxEdge.Z-d > box.MinEdge.Z &&
+                               cbox.MinEdge.Z+d < box.MaxEdge.Z
                ){
-                       result.touching_ground = true;
-               }
-               
-               // If object doesn't intersect with node, ignore node.
-               if(box.intersectsWithBox(nodebox) == false)
-                       continue;
-               
-               /*
-                       Go through every axis
-               */
-               v3f dirs[3] = {
-                       v3f(0,0,1), // back-front
-                       v3f(0,1,0), // top-bottom
-                       v3f(1,0,0), // right-left
-               };
-               for(u16 i=0; i<3; i++)
-               {
-                       /*
-                               Calculate values along the axis
-                       */
-                       f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[i]);
-                       f32 nodemin = nodebox.MinEdge.dotProduct(dirs[i]);
-                       f32 objectmax = box.MaxEdge.dotProduct(dirs[i]);
-                       f32 objectmin = box.MinEdge.dotProduct(dirs[i]);
-                       f32 objectmax_old = oldbox.MaxEdge.dotProduct(dirs[i]);
-                       f32 objectmin_old = oldbox.MinEdge.dotProduct(dirs[i]);
-                       
-                       /*
-                               Check collision for the axis.
-                               Collision happens when object is going through a surface.
-                       */
-                       bool negative_axis_collides =
-                               (nodemax > objectmin && nodemax <= objectmin_old + d
-                                       && speed_f.dotProduct(dirs[i]) < 0);
-                       bool positive_axis_collides =
-                               (nodemin < objectmax && nodemin >= objectmax_old - d
-                                       && speed_f.dotProduct(dirs[i]) > 0);
-                       bool main_axis_collides =
-                                       negative_axis_collides || positive_axis_collides;
-                       
-                       /*
-                               Check overlap of object and node in other axes
-                       */
-                       bool other_axes_overlap = true;
-                       for(u16 j=0; j<3; j++)
+                       if(is_step_up[boxindex])
                        {
-                               if(j == i)
-                                       continue;
-                               f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[j]);
-                               f32 nodemin = nodebox.MinEdge.dotProduct(dirs[j]);
-                               f32 objectmax = box.MaxEdge.dotProduct(dirs[j]);
-                               f32 objectmin = box.MinEdge.dotProduct(dirs[j]);
-                               if(!(nodemax - d > objectmin && nodemin + d < objectmax))
-                               {
-                                       other_axes_overlap = false;
-                                       break;
-                               }
+                               pos_f.Y += (cbox.MaxEdge.Y - box.MinEdge.Y);
+                               box = box_0;
+                               box.MinEdge += pos_f;
+                               box.MaxEdge += pos_f;
                        }
-                       
-                       /*
-                               If this is a collision, revert the pos_f in the main
-                               direction.
-                       */
-                       if(other_axes_overlap && main_axis_collides)
+                       if(fabs(cbox.MaxEdge.Y-box.MinEdge.Y) < 0.15*BS)
                        {
-                               speed_f -= speed_f.dotProduct(dirs[i]) * dirs[i];
-                               pos_f -= pos_f.dotProduct(dirs[i]) * dirs[i];
-                               pos_f += oldpos_f.dotProduct(dirs[i]) * dirs[i];
-                               result.collides = true;
+                               result.touching_ground = true;
+                               if(is_unloaded[boxindex])
+                                       result.standing_on_unloaded = true;
                        }
-               
                }
-       } // xyz
-       
+       }
+
        return result;
 }
 
+#if 0
+// This doesn't seem to work and isn't used
 collisionMoveResult collisionMovePrecise(Map *map, IGameDef *gamedef,
-               f32 pos_max_d, const core::aabbox3d<f32> &box_0,
-               f32 dtime, v3f &pos_f, v3f &speed_f)
+               f32 pos_max_d, const aabb3f &box_0,
+               f32 stepheight, f32 dtime,
+               v3f &pos_f, v3f &speed_f, v3f &accel_f)
 {
-       collisionMoveResult final_result;
+       //TimeTaker tt("collisionMovePrecise");
+    ScopeProfiler sp(g_profiler, "collisionMovePrecise avg", SPT_AVG);
        
+       collisionMoveResult final_result;
+
        // If there is no speed, there are no collisions
        if(speed_f.getLength() == 0)
                return final_result;
 
-       // Maximum time increment (for collision detection etc)
-       // time = distance / speed
-       f32 dtime_max_increment = pos_max_d / speed_f.getLength();
-       
-       // Maximum time increment is 10ms or lower
-       if(dtime_max_increment > 0.01)
-               dtime_max_increment = 0.01;
-       
        // Don't allow overly huge dtime
        if(dtime > 2.0)
                dtime = 2.0;
-       
+
        f32 dtime_downcount = dtime;
 
        u32 loopcount = 0;
@@ -224,6 +459,16 @@ collisionMoveResult collisionMovePrecise(Map *map, IGameDef *gamedef,
        {
                loopcount++;
 
+               // Maximum time increment (for collision detection etc)
+               // time = distance / speed
+               f32 dtime_max_increment = 1.0;
+               if(speed_f.getLength() != 0)
+                       dtime_max_increment = pos_max_d / speed_f.getLength();
+
+               // Maximum time increment is 10ms or lower
+               if(dtime_max_increment > 0.01)
+                       dtime_max_increment = 0.01;
+
                f32 dtime_part;
                if(dtime_downcount > dtime_max_increment)
                {
@@ -242,17 +487,20 @@ collisionMoveResult collisionMovePrecise(Map *map, IGameDef *gamedef,
                }
 
                collisionMoveResult result = collisionMoveSimple(map, gamedef,
-                               pos_max_d, box_0, dtime_part, pos_f, speed_f);
+                               pos_max_d, box_0, stepheight, dtime_part,
+                               pos_f, speed_f, accel_f);
 
                if(result.touching_ground)
                        final_result.touching_ground = true;
                if(result.collides)
                        final_result.collides = true;
+               if(result.collides_xz)
+                       final_result.collides_xz = true;
+               if(result.standing_on_unloaded)
+                       final_result.standing_on_unloaded = true;
        }
        while(dtime_downcount > 0.001);
-               
 
        return final_result;
 }
-
-
+#endif
index a4eca0dd821a6a9ce948c6019f1dc1c4f7730f13..243c4b294732439b75bd562eda7915fadb940c80 100644 (file)
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define COLLISION_HEADER
 
 #include "irrlichttypes_bloated.h"
+#include <vector>
 
 class Map;
 class IGameDef;
@@ -29,22 +30,47 @@ struct collisionMoveResult
 {
        bool touching_ground;
        bool collides;
+       bool collides_xz;
+       bool standing_on_unloaded;
 
        collisionMoveResult():
                touching_ground(false),
-               collides(false)
+               collides(false),
+               collides_xz(false),
+               standing_on_unloaded(false)
        {}
 };
 
 // Moves using a single iteration; speed should not exceed pos_max_d/dtime
 collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
-               f32 pos_max_d, const core::aabbox3d<f32> &box_0,
-               f32 dtime, v3f &pos_f, v3f &speed_f);
+               f32 pos_max_d, const aabb3f &box_0,
+               f32 stepheight, f32 dtime,
+               v3f &pos_f, v3f &speed_f, v3f &accel_f);
 
+#if 0
+// This doesn't seem to work and isn't used
 // Moves using as many iterations as needed
 collisionMoveResult collisionMovePrecise(Map *map, IGameDef *gamedef,
-               f32 pos_max_d, const core::aabbox3d<f32> &box_0,
-               f32 dtime, v3f &pos_f, v3f &speed_f);
+               f32 pos_max_d, const aabb3f &box_0,
+               f32 stepheight, f32 dtime,
+               v3f &pos_f, v3f &speed_f, v3f &accel_f);
+#endif
+
+// 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
+// dtime receives time until first collision, invalid if -1 is returned
+int axisAlignedCollision(
+               const aabb3f &staticbox, const aabb3f &movingbox,
+               const v3f &speed, f32 d, f32 &dtime);
+
+// Helper function:
+// Checks if moving the movingbox up by the given distance would hit a ceiling.
+bool wouldCollideWithCeiling(
+               const std::vector<aabb3f> &staticboxes,
+               const aabb3f &movingbox,
+               f32 y_increase, f32 d);
+
 
 enum CollisionType
 {
index c993f3f834e3f3f8720cbe1816ecb6917adbc7dd..5702a73b617060fc9db0055d7e12e9a08e2268df 100644 (file)
@@ -881,22 +881,24 @@ public:
                        box.MinEdge *= BS;
                        box.MaxEdge *= BS;
                        collisionMoveResult moveresult;
-                       f32 pos_max_d = BS*0.25; // Distance per iteration
+                       f32 pos_max_d = BS*0.125; // Distance per iteration
+                       f32 stepheight = 0;
                        v3f p_pos = m_position;
                        v3f p_velocity = m_velocity;
+                       v3f p_acceleration = m_acceleration;
                        IGameDef *gamedef = env->getGameDef();
-                       moveresult = collisionMovePrecise(&env->getMap(), gamedef,
-                                       pos_max_d, box, dtime, p_pos, p_velocity);
+                       moveresult = collisionMoveSimple(&env->getMap(), gamedef,
+                                       pos_max_d, box, stepheight, dtime,
+                                       p_pos, p_velocity, p_acceleration);
                        // Apply results
                        m_position = p_pos;
                        m_velocity = p_velocity;
+                       m_acceleration = p_acceleration;
                        
                        bool is_end_position = moveresult.collides;
                        pos_translator.update(m_position, is_end_position, dtime);
                        pos_translator.translate(dtime);
                        updateNodePos();
-
-                       m_velocity += dtime * m_acceleration;
                } else {
                        m_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration;
                        m_velocity += dtime * m_acceleration;
index ebf9fd59e88e4ac6747c2f6cb4f4acf0e5565894..d87ae32fbde761cf58ce7fc23d9517d49a188954 100644 (file)
@@ -1027,6 +1027,53 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                        u16 indices[] = {0,1,2,2,3,0};
                        collector.append(tile, vertices, 4, indices, 6);
                break;}
+               case NDT_NODEBOX:
+               {
+                       TileSpec tiles[6];
+                       for(int i = 0; i < 6; i++)
+                       {
+                               tiles[i] = getNodeTileN(n, p, i, data);
+                       }
+
+                       u16 l = getInteriorLight(n, 0, data);
+                       video::SColor c = MapBlock_LightColor(255, l);
+
+                       v3f pos = intToFloat(p, BS);
+
+                       std::vector<aabb3f> boxes = n.getNodeBoxes(nodedef);
+                       for(std::vector<aabb3f>::iterator
+                                       i = boxes.begin();
+                                       i != boxes.end(); i++)
+                       {
+                               aabb3f box = *i;
+                               box.MinEdge += pos;
+                               box.MaxEdge += pos;
+
+                               // Compute texture coords
+                               f32 tx1 = (i->MinEdge.X/BS)+0.5;
+                               f32 ty1 = (i->MinEdge.Y/BS)+0.5;
+                               f32 tz1 = (i->MinEdge.Z/BS)+0.5;
+                               f32 tx2 = (i->MaxEdge.X/BS)+0.5;
+                               f32 ty2 = (i->MaxEdge.Y/BS)+0.5;
+                               f32 tz2 = (i->MaxEdge.Z/BS)+0.5;
+                               f32 txc[24] = {
+                                       // up
+                                       tx1, 1-tz2, tx2, 1-tz1,
+                                       // down
+                                       tx1, tz1, tx2, tz2,
+                                       // right
+                                       tz1, 1-ty2, tz2, 1-ty1,
+                                       // left
+                                       1-tz2, 1-ty2, 1-tz1, 1-ty1,
+                                       // back
+                                       1-tx2, 1-ty2, 1-tx1, 1-ty1,
+                                       // front
+                                       tx1, 1-ty2, tx2, 1-ty1,
+                               };
+
+                               makeCuboid(&collector, box, tiles, 6, c, txc);
+                       }
+               break;}
                }
        }
 }
index 468a3911048065a1525f576ada941aa3ccfcb01d..e9b5782a9b53b93dfde890e53eb63ea00b43ee53 100644 (file)
@@ -206,9 +206,12 @@ public:
                        m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
                v3f pos_f = getBasePosition();
                v3f pos_f_old = pos_f;
+               v3f accel_f = v3f(0,0,0);
+               f32 stepheight = 0;
                IGameDef *gamedef = m_env->getGameDef();
                moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
-                               pos_max_d, box, dtime, pos_f, m_speed_f);
+                               pos_max_d, box, stepheight, dtime,
+                               pos_f, m_speed_f, accel_f);
                
                if(send_recommended == false)
                        return;
@@ -452,16 +455,18 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
                box.MaxEdge *= BS;
                collisionMoveResult moveresult;
                f32 pos_max_d = BS*0.25; // Distance per iteration
-               v3f p_pos = getBasePosition();
+               f32 stepheight = 0; // Maximum climbable step height
+               v3f p_pos = m_base_position;
                v3f p_velocity = m_velocity;
+               v3f p_acceleration = m_acceleration;
                IGameDef *gamedef = m_env->getGameDef();
-               moveresult = collisionMovePrecise(&m_env->getMap(), gamedef,
-                               pos_max_d, box, dtime, p_pos, p_velocity);
+               moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
+                               pos_max_d, box, stepheight, dtime,
+                               p_pos, p_velocity, p_acceleration);
                // Apply results
-               setBasePosition(p_pos);
+               m_base_position = p_pos;
                m_velocity = p_velocity;
-
-               m_velocity += dtime * m_acceleration;
+               m_acceleration = p_acceleration;
        } else {
                m_base_position += dtime * m_velocity + 0.5 * dtime
                                * dtime * m_acceleration;
index c8defd82d39abd596dee4fb524afbd769eb56909..98ffac3d56a30c94855cd6857a26eb453852edfc 100644 (file)
@@ -61,6 +61,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #endif
 #include "event_manager.h"
 #include <list>
+#include "util/directiontables.h"
 
 /*
        Text input system
@@ -294,14 +295,12 @@ PointedThing getPointedThing(Client *client, v3f player_position,
                core::line3d<f32> shootline, f32 d,
                bool liquids_pointable,
                bool look_for_object,
-               core::aabbox3d<f32> &hilightbox,
-               bool &should_show_hilightbox,
+               std::vector<aabb3f> &hilightboxes,
                ClientActiveObject *&selected_object)
 {
        PointedThing result;
 
-       hilightbox = core::aabbox3d<f32>(0,0,0,0,0,0);
-       should_show_hilightbox = false;
+       hilightboxes.clear();
        selected_object = NULL;
 
        INodeDefManager *nodedef = client->getNodeDefManager();
@@ -312,27 +311,27 @@ PointedThing getPointedThing(Client *client, v3f player_position,
        {
                selected_object = client->getSelectedActiveObject(d*BS,
                                camera_position, shootline);
-       }
-       if(selected_object != NULL)
-       {
-               core::aabbox3d<f32> *selection_box
-                       = selected_object->getSelectionBox();
-               // Box should exist because object was returned in the
-               // first place
-               assert(selection_box);
-
-               v3f pos = selected_object->getPosition();
 
-               hilightbox = core::aabbox3d<f32>(
-                               selection_box->MinEdge + pos,
-                               selection_box->MaxEdge + pos
-               );
+               if(selected_object != NULL)
+               {
+                       if(selected_object->doShowSelectionBox())
+                       {
+                               aabb3f *selection_box = selected_object->getSelectionBox();
+                               // Box should exist because object was
+                               // returned in the first place
+                               assert(selection_box);
+
+                               v3f pos = selected_object->getPosition();
+                               hilightboxes.push_back(aabb3f(
+                                               selection_box->MinEdge + pos,
+                                               selection_box->MaxEdge + pos));
+                       }
 
-               should_show_hilightbox = selected_object->doShowSelectionBox();
 
-               result.type = POINTEDTHING_OBJECT;
-               result.object_id = selected_object->getId();
-               return result;
+                       result.type = POINTEDTHING_OBJECT;
+                       result.object_id = selected_object->getId();
+                       return result;
+               }
        }
 
        // That didn't work, try to find a pointed at node
@@ -368,196 +367,64 @@ PointedThing getPointedThing(Client *client, v3f player_position,
                if(!isPointableNode(n, client, liquids_pointable))
                        continue;
 
+               std::vector<aabb3f> boxes = n.getSelectionBoxes(nodedef);
+
                v3s16 np(x,y,z);
                v3f npf = intToFloat(np, BS);
-               
-               f32 d = 0.01;
-               
-               v3s16 dirs[6] = {
-                       v3s16(0,0,1), // back
-                       v3s16(0,1,0), // top
-                       v3s16(1,0,0), // right
-                       v3s16(0,0,-1), // front
-                       v3s16(0,-1,0), // bottom
-                       v3s16(-1,0,0), // left
-               };
-               
-               const ContentFeatures &f = nodedef->get(n);
-               
-               if(f.selection_box.type == NODEBOX_FIXED)
+
+               for(std::vector<aabb3f>::const_iterator
+                               i = boxes.begin();
+                               i != boxes.end(); i++)
                {
-                       core::aabbox3d<f32> box = f.selection_box.fixed;
+                       aabb3f box = *i;
                        box.MinEdge += npf;
                        box.MaxEdge += npf;
 
-                       v3s16 facedirs[6] = {
-                               v3s16(-1,0,0),
-                               v3s16(1,0,0),
-                               v3s16(0,-1,0),
-                               v3s16(0,1,0),
-                               v3s16(0,0,-1),
-                               v3s16(0,0,1),
-                       };
-
-                       core::aabbox3d<f32> faceboxes[6] = {
-                               // X-
-                               core::aabbox3d<f32>(
-                                       box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z,
-                                       box.MinEdge.X+d, box.MaxEdge.Y, box.MaxEdge.Z
-                               ),
-                               // X+
-                               core::aabbox3d<f32>(
-                                       box.MaxEdge.X-d, box.MinEdge.Y, box.MinEdge.Z,
-                                       box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z
-                               ),
-                               // Y-
-                               core::aabbox3d<f32>(
-                                       box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z,
-                                       box.MaxEdge.X, box.MinEdge.Y+d, box.MaxEdge.Z
-                               ),
-                               // Y+
-                               core::aabbox3d<f32>(
-                                       box.MinEdge.X, box.MaxEdge.Y-d, box.MinEdge.Z,
-                                       box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z
-                               ),
-                               // Z-
-                               core::aabbox3d<f32>(
-                                       box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z,
-                                       box.MaxEdge.X, box.MaxEdge.Y, box.MinEdge.Z+d
-                               ),
-                               // Z+
-                               core::aabbox3d<f32>(
-                                       box.MinEdge.X, box.MinEdge.Y, box.MaxEdge.Z-d,
-                                       box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z
-                               ),
-                       };
-
-                       for(u16 i=0; i<6; i++)
+                       for(u16 j=0; j<6; j++)
                        {
-                               v3f facedir_f(facedirs[i].X, facedirs[i].Y, facedirs[i].Z);
-                               v3f centerpoint = npf + facedir_f * BS/2;
+                               v3s16 facedir = g_6dirs[j];
+                               aabb3f facebox = box;
+
+                               f32 d = 0.001*BS;
+                               if(facedir.X > 0)
+                                       facebox.MinEdge.X = facebox.MaxEdge.X-d;
+                               else if(facedir.X < 0)
+                                       facebox.MaxEdge.X = facebox.MinEdge.X+d;
+                               else if(facedir.Y > 0)
+                                       facebox.MinEdge.Y = facebox.MaxEdge.Y-d;
+                               else if(facedir.Y < 0)
+                                       facebox.MaxEdge.Y = facebox.MinEdge.Y+d;
+                               else if(facedir.Z > 0)
+                                       facebox.MinEdge.Z = facebox.MaxEdge.Z-d;
+                               else if(facedir.Z < 0)
+                                       facebox.MaxEdge.Z = facebox.MinEdge.Z+d;
+
+                               v3f centerpoint = facebox.getCenter();
                                f32 distance = (centerpoint - camera_position).getLength();
                                if(distance >= mindistance)
                                        continue;
-                               if(!faceboxes[i].intersectsWithLine(shootline))
+                               if(!facebox.intersectsWithLine(shootline))
                                        continue;
+
+                               v3s16 np_above = np + facedir;
+
                                result.type = POINTEDTHING_NODE;
                                result.node_undersurface = np;
-                               result.node_abovesurface = np+facedirs[i];
+                               result.node_abovesurface = np_above;
                                mindistance = distance;
-                               hilightbox = box;
-                               should_show_hilightbox = true;
-                       }
-               }
-               else if(f.selection_box.type == NODEBOX_WALLMOUNTED)
-               {
-                       v3s16 dir = n.getWallMountedDir(nodedef);
-                       v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
-                       dir_f *= BS/2 - BS/6 - BS/20;
-                       v3f cpf = npf + dir_f;
-                       f32 distance = (cpf - camera_position).getLength();
-
-                       core::aabbox3d<f32> box;
-                       
-                       // top
-                       if(dir == v3s16(0,1,0)){
-                               box = f.selection_box.wall_top;
-                       }
-                       // bottom
-                       else if(dir == v3s16(0,-1,0)){
-                               box = f.selection_box.wall_bottom;
-                       }
-                       // side
-                       else{
-                               v3f vertices[2] =
-                               {
-                                       f.selection_box.wall_side.MinEdge,
-                                       f.selection_box.wall_side.MaxEdge
-                               };
-
-                               for(s32 i=0; i<2; i++)
-                               {
-                                       if(dir == v3s16(-1,0,0))
-                                               vertices[i].rotateXZBy(0);
-                                       if(dir == v3s16(1,0,0))
-                                               vertices[i].rotateXZBy(180);
-                                       if(dir == v3s16(0,0,-1))
-                                               vertices[i].rotateXZBy(90);
-                                       if(dir == v3s16(0,0,1))
-                                               vertices[i].rotateXZBy(-90);
-                               }
-
-                               box = core::aabbox3d<f32>(vertices[0]);
-                               box.addInternalPoint(vertices[1]);
-                       }
 
-                       box.MinEdge += npf;
-                       box.MaxEdge += npf;
-                       
-                       if(distance < mindistance)
-                       {
-                               if(box.intersectsWithLine(shootline))
+                               hilightboxes.clear();
+                               for(std::vector<aabb3f>::const_iterator
+                                               i2 = boxes.begin();
+                                               i2 != boxes.end(); i2++)
                                {
-                                       result.type = POINTEDTHING_NODE;
-                                       result.node_undersurface = np;
-                                       result.node_abovesurface = np;
-                                       mindistance = distance;
-                                       hilightbox = box;
-                                       should_show_hilightbox = true;
+                                       aabb3f box = *i2;
+                                       box.MinEdge += npf + v3f(-d,-d,-d);
+                                       box.MaxEdge += npf + v3f(d,d,d);
+                                       hilightboxes.push_back(box);
                                }
                        }
                }
-               else // NODEBOX_REGULAR
-               {
-                       for(u16 i=0; i<6; i++)
-                       {
-                               v3f dir_f = v3f(dirs[i].X,
-                                               dirs[i].Y, dirs[i].Z);
-                               v3f centerpoint = npf + dir_f * BS/2;
-                               f32 distance =
-                                               (centerpoint - camera_position).getLength();
-                               
-                               if(distance < mindistance)
-                               {
-                                       core::CMatrix4<f32> m;
-                                       m.buildRotateFromTo(v3f(0,0,1), dir_f);
-
-                                       // This is the back face
-                                       v3f corners[2] = {
-                                               v3f(BS/2, BS/2, BS/2),
-                                               v3f(-BS/2, -BS/2, BS/2+d)
-                                       };
-                                       
-                                       for(u16 j=0; j<2; j++)
-                                       {
-                                               m.rotateVect(corners[j]);
-                                               corners[j] += npf;
-                                       }
-
-                                       core::aabbox3d<f32> facebox(corners[0]);
-                                       facebox.addInternalPoint(corners[1]);
-
-                                       if(facebox.intersectsWithLine(shootline))
-                                       {
-                                               result.type = POINTEDTHING_NODE;
-                                               result.node_undersurface = np;
-                                               result.node_abovesurface = np + dirs[i];
-                                               mindistance = distance;
-
-                                               //hilightbox = facebox;
-
-                                               const float d = 0.502;
-                                               core::aabbox3d<f32> nodebox
-                                                               (-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);
-                                               v3f nodepos_f = intToFloat(np, BS);
-                                               nodebox.MinEdge += nodepos_f;
-                                               nodebox.MaxEdge += nodepos_f;
-                                               hilightbox = nodebox;
-                                               should_show_hilightbox = true;
-                                       }
-                               } // if distance < mindistance
-                       } // for dirs
-               } // regular block
        } // for coords
 
        return result;
@@ -1514,7 +1381,7 @@ void the_game(
                        hotbar_imagesize = 64;
                
                // Hilight boxes collected during the loop and displayed
-               core::list< core::aabbox3d<f32> > hilightboxes;
+               std::vector<aabb3f> hilightboxes;
                
                // Info text
                std::wstring infotext;
@@ -2127,8 +1994,6 @@ void the_game(
                core::line3d<f32> shootline(camera_position,
                                camera_position + camera_direction * BS * (d+1));
 
-               core::aabbox3d<f32> hilightbox;
-               bool should_show_hilightbox = false;
                ClientActiveObject *selected_object = NULL;
 
                PointedThing pointed = getPointedThing(
@@ -2137,7 +2002,7 @@ void the_game(
                                camera_position, shootline, d,
                                playeritem_liquids_pointable, !ldown_for_dig,
                                // output
-                               hilightbox, should_show_hilightbox,
+                               hilightboxes,
                                selected_object);
 
                if(pointed != pointed_old)
@@ -2146,12 +2011,6 @@ void the_game(
                        //dstream<<"Pointing at "<<pointed.dump()<<std::endl;
                }
 
-               /*
-                       Visualize selection
-               */
-               if(should_show_hilightbox)
-                       hilightboxes.push_back(hilightbox);
-
                /*
                        Stop digging when
                        - releasing left mouse button
@@ -2818,9 +2677,10 @@ void the_game(
 
                if(show_hud)
                {
-                       for(core::list<aabb3f>::Iterator i=hilightboxes.begin();
-                                       i != hilightboxes.end(); i++)
-                       {
+                       for(std::vector<aabb3f>::const_iterator
+                                       i = hilightboxes.begin();
+                                       i != hilightboxes.end(); i++)
+                       {
                                /*infostream<<"hilightbox min="
                                                <<"("<<i->MinEdge.X<<","<<i->MinEdge.Y<<","<<i->MinEdge.Z<<")"
                                                <<" max="
index 2bd62dabf6f70d65d8ce684506dc9a63d3592bba..df668b36dee419b500cadf9cec2e5a16ac57df0c 100644 (file)
@@ -52,24 +52,15 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
        INodeDefManager *nodemgr = m_gamedef->ndef();
 
        v3f position = getPosition();
-       v3f oldpos = position;
-       v3s16 oldpos_i = floatToInt(oldpos, BS);
 
        v3f old_speed = m_speed;
 
-       /*std::cout<<"oldpos_i=("<<oldpos_i.X<<","<<oldpos_i.Y<<","
-                       <<oldpos_i.Z<<")"<<std::endl;*/
-
-       /*
-               Calculate new position
-       */
-       position += m_speed * dtime;
-       
        // Skip collision detection if a special movement mode is used
        bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
        bool free_move = fly_allowed && g_settings->getBool("free_move");
        if(free_move)
        {
+        position += m_speed * dtime;
                setPosition(position);
                return;
        }
@@ -78,9 +69,6 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
                Collision detection
        */
        
-       // Player position in nodes
-       v3s16 pos_i = floatToInt(position, BS);
-       
        /*
                Check if player is in water (the oscillating value)
        */
@@ -147,13 +135,6 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
        // Maximum distance over border for sneaking
        f32 sneak_max = BS*0.4;
 
-       /*
-               If sneaking, player has larger collision radius to keep from
-               falling
-       */
-       /*if(control.sneak)
-               player_radius = sneak_max + d*1.1;*/
-       
        /*
                If sneaking, keep in range from the last walked node and don't
                fall off from it
@@ -170,22 +151,8 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
                {
                        position.Y = min_y;
 
-                       //v3f old_speed = m_speed;
-
                        if(m_speed.Y < 0)
                                m_speed.Y = 0;
-
-                       /*if(collision_info)
-                       {
-                               // Report fall collision
-                               if(old_speed.Y < m_speed.Y - 0.1)
-                               {
-                                       CollisionInfo info;
-                                       info.t = COLLISION_FALL;
-                                       info.speed = m_speed.Y - old_speed.Y;
-                                       collision_info->push_back(info);
-                               }
-                       }*/
                }
        }
 
@@ -193,22 +160,22 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
                Calculate player collision box (new and old)
        */
        core::aabbox3d<f32> playerbox(
-               position.X - player_radius,
-               position.Y - 0.0,
-               position.Z - player_radius,
-               position.X + player_radius,
-               position.Y + player_height,
-               position.Z + player_radius
-       );
-       core::aabbox3d<f32> playerbox_old(
-               oldpos.X - player_radius,
-               oldpos.Y - 0.0,
-               oldpos.Z - player_radius,
-               oldpos.X + player_radius,
-               oldpos.Y + player_height,
-               oldpos.Z + player_radius
+               -player_radius,
+               0.0,
+               -player_radius,
+               player_radius,
+               player_height,
+               player_radius
        );
 
+       float player_stepheight = touching_ground ? (BS*0.6) : (BS*0.2);
+
+       v3f accel_f = v3f(0,0,0);
+
+       collisionMoveResult result = collisionMoveSimple(&map, m_gamedef,
+                       pos_max_d, playerbox, player_stepheight, dtime,
+                       position, m_speed, accel_f);
+
        /*
                If the player's feet touch the topside of any node, this is
                set to true.
@@ -216,154 +183,9 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
                Player is allowed to jump when this is true.
        */
        bool touching_ground_was = touching_ground;
-       touching_ground = false;
-
-       /*std::cout<<"Checking collisions for ("
-                       <<oldpos_i.X<<","<<oldpos_i.Y<<","<<oldpos_i.Z
-                       <<") -> ("
-                       <<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z
-                       <<"):"<<std::endl;*/
-       
-       bool standing_on_unloaded = false;
-       
-       /*
-               Go through every node around the player
-       */
-       for(s16 y = oldpos_i.Y - 1; y <= oldpos_i.Y + 2; y++)
-       for(s16 z = oldpos_i.Z - 1; z <= oldpos_i.Z + 1; z++)
-       for(s16 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++)
-       {
-               bool is_unloaded = false;
-               try{
-                       // Player collides into walkable nodes
-                       if(nodemgr->get(map.getNode(v3s16(x,y,z))).walkable == false)
-                               continue;
-               }
-               catch(InvalidPositionException &e)
-               {
-                       is_unloaded = true;
-                       // Doing nothing here will block the player from
-                       // walking over map borders
-               }
-
-               core::aabbox3d<f32> nodebox = getNodeBox(v3s16(x,y,z), BS);
-               
-               /*
-                       See if the player is touching ground.
-
-                       Player touches ground if player's minimum Y is near node's
-                       maximum Y and player's X-Z-area overlaps with the node's
-                       X-Z-area.
-
-                       Use 0.15*BS so that it is easier to get on a node.
-               */
-               if(
-                               //fabs(nodebox.MaxEdge.Y-playerbox.MinEdge.Y) < d
-                               fabs(nodebox.MaxEdge.Y-playerbox.MinEdge.Y) < 0.15*BS
-                               && nodebox.MaxEdge.X-d > playerbox.MinEdge.X
-                               && nodebox.MinEdge.X+d < playerbox.MaxEdge.X
-                               && nodebox.MaxEdge.Z-d > playerbox.MinEdge.Z
-                               && nodebox.MinEdge.Z+d < playerbox.MaxEdge.Z
-               ){
-                       touching_ground = true;
-                       if(is_unloaded)
-                               standing_on_unloaded = true;
-               }
-               
-               // If player doesn't intersect with node, ignore node.
-               if(playerbox.intersectsWithBox(nodebox) == false)
-                       continue;
-               
-               /*
-                       Go through every axis
-               */
-               v3f dirs[3] = {
-                       v3f(0,0,1), // back-front
-                       v3f(0,1,0), // top-bottom
-                       v3f(1,0,0), // right-left
-               };
-               for(u16 i=0; i<3; i++)
-               {
-                       /*
-                               Calculate values along the axis
-                       */
-                       f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[i]);
-                       f32 nodemin = nodebox.MinEdge.dotProduct(dirs[i]);
-                       f32 playermax = playerbox.MaxEdge.dotProduct(dirs[i]);
-                       f32 playermin = playerbox.MinEdge.dotProduct(dirs[i]);
-                       f32 playermax_old = playerbox_old.MaxEdge.dotProduct(dirs[i]);
-                       f32 playermin_old = playerbox_old.MinEdge.dotProduct(dirs[i]);
-                       
-                       /*
-                               Check collision for the axis.
-                               Collision happens when player is going through a surface.
-                       */
-                       /*f32 neg_d = d;
-                       f32 pos_d = d;
-                       // Make it easier to get on top of a node
-                       if(i == 1)
-                               neg_d = 0.15*BS;
-                       bool negative_axis_collides =
-                               (nodemax > playermin && nodemax <= playermin_old + neg_d
-                                       && m_speed.dotProduct(dirs[i]) < 0);
-                       bool positive_axis_collides =
-                               (nodemin < playermax && nodemin >= playermax_old - pos_d
-                                       && m_speed.dotProduct(dirs[i]) > 0);*/
-                       bool negative_axis_collides =
-                               (nodemax > playermin && nodemax <= playermin_old + d
-                                       && m_speed.dotProduct(dirs[i]) < 0);
-                       bool positive_axis_collides =
-                               (nodemin < playermax && nodemin >= playermax_old - d
-                                       && m_speed.dotProduct(dirs[i]) > 0);
-                       bool main_axis_collides =
-                                       negative_axis_collides || positive_axis_collides;
-                       
-                       /*
-                               Check overlap of player and node in other axes
-                       */
-                       bool other_axes_overlap = true;
-                       for(u16 j=0; j<3; j++)
-                       {
-                               if(j == i)
-                                       continue;
-                               f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[j]);
-                               f32 nodemin = nodebox.MinEdge.dotProduct(dirs[j]);
-                               f32 playermax = playerbox.MaxEdge.dotProduct(dirs[j]);
-                               f32 playermin = playerbox.MinEdge.dotProduct(dirs[j]);
-                               if(!(nodemax - d > playermin && nodemin + d < playermax))
-                               {
-                                       other_axes_overlap = false;
-                                       break;
-                               }
-                       }
-                       
-                       /*
-                               If this is a collision, revert the position in the main
-                               direction.
-                       */
-                       if(other_axes_overlap && main_axis_collides)
-                       {
-                               //v3f old_speed = m_speed;
-
-                               m_speed -= m_speed.dotProduct(dirs[i]) * dirs[i];
-                               position -= position.dotProduct(dirs[i]) * dirs[i];
-                               position += oldpos.dotProduct(dirs[i]) * dirs[i];
-                               
-                               /*if(collision_info)
-                               {
-                                       // Report fall collision
-                                       if(old_speed.Y < m_speed.Y - 0.1)
-                                       {
-                                               CollisionInfo info;
-                                               info.t = COLLISION_FALL;
-                                               info.speed = m_speed.Y - old_speed.Y;
-                                               collision_info->push_back(info);
-                                       }
-                               }*/
-                       }
-               
-               }
-       } // xyz
+       touching_ground = result.touching_ground;
+    
+    bool standing_on_unloaded = result.standing_on_unloaded;
 
        /*
                Check the nodes under the player to see from which node the
index 4de84dd1d9190a9dc32d6e447915d8704703032c..e12f252fcd269aa2df045d418dd5b6d6e7c8f24c 100644 (file)
@@ -134,7 +134,98 @@ v3s16 MapNode::getWallMountedDir(INodeDefManager *nodemgr) const
        }
 }
 
+static std::vector<aabb3f> transformNodeBox(const MapNode &n,
+               const NodeBox &nodebox, INodeDefManager *nodemgr)
+{
+       std::vector<aabb3f> boxes;
+       if(nodebox.type == NODEBOX_FIXED)
+       {
+               const std::vector<aabb3f> &fixed = nodebox.fixed;
+               int facedir = n.getFaceDir(nodemgr);
+               for(std::vector<aabb3f>::const_iterator
+                               i = fixed.begin();
+                               i != fixed.end(); i++)
+               {
+                       aabb3f box = *i;
+                       if(facedir == 1)
+                       {
+                               box.MinEdge.rotateXZBy(-90);
+                               box.MaxEdge.rotateXZBy(-90);
+                               box.repair();
+                       }
+                       else if(facedir == 2)
+                       {
+                               box.MinEdge.rotateXZBy(180);
+                               box.MaxEdge.rotateXZBy(180);
+                               box.repair();
+                       }
+                       else if(facedir == 3)
+                       {
+                               box.MinEdge.rotateXZBy(90);
+                               box.MaxEdge.rotateXZBy(90);
+                               box.repair();
+                       }
+                       boxes.push_back(box);
+               }
+       }
+       else if(nodebox.type == NODEBOX_WALLMOUNTED)
+       {
+               v3s16 dir = n.getWallMountedDir(nodemgr);
+
+               // top
+               if(dir == v3s16(0,1,0))
+               {
+                       boxes.push_back(nodebox.wall_top);
+               }
+               // bottom
+               else if(dir == v3s16(0,-1,0))
+               {
+                       boxes.push_back(nodebox.wall_bottom);
+               }
+               // side
+               else
+               {
+                       v3f vertices[2] =
+                       {
+                               nodebox.wall_side.MinEdge,
+                               nodebox.wall_side.MaxEdge
+                       };
+
+                       for(s32 i=0; i<2; i++)
+                       {
+                               if(dir == v3s16(-1,0,0))
+                                       vertices[i].rotateXZBy(0);
+                               if(dir == v3s16(1,0,0))
+                                       vertices[i].rotateXZBy(180);
+                               if(dir == v3s16(0,0,-1))
+                                       vertices[i].rotateXZBy(90);
+                               if(dir == v3s16(0,0,1))
+                                       vertices[i].rotateXZBy(-90);
+                       }
+
+                       aabb3f box = aabb3f(vertices[0]);
+                       box.addInternalPoint(vertices[1]);
+                       boxes.push_back(box);
+               }
+       }
+       else // NODEBOX_REGULAR
+       {
+               boxes.push_back(aabb3f(-BS/2,-BS/2,-BS/2,BS/2,BS/2,BS/2));
+       }
+       return boxes;
+}
+
+std::vector<aabb3f> MapNode::getNodeBoxes(INodeDefManager *nodemgr) const
+{
+       const ContentFeatures &f = nodemgr->get(*this);
+       return transformNodeBox(*this, f.node_box, nodemgr);
+}
 
+std::vector<aabb3f> MapNode::getSelectionBoxes(INodeDefManager *nodemgr) const
+{
+       const ContentFeatures &f = nodemgr->get(*this);
+       return transformNodeBox(*this, f.selection_box, nodemgr);
+}
 
 u32 MapNode::serializedLength(u8 version)
 {
index 32e46b63f26be0a9ef19603ffe29946f84575c75..751563135a47e498ec35a4cf2d51495d1aec0c9a 100644 (file)
@@ -22,7 +22,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "irrlichttypes.h"
 #include "irr_v3d.h"
+#include "irr_aabb3d.h"
 #include "light.h"
+#include <vector>
 
 class INodeDefManager;
 
@@ -196,6 +198,17 @@ struct MapNode
        u8 getWallMounted(INodeDefManager *nodemgr) const;
        v3s16 getWallMountedDir(INodeDefManager *nodemgr) const;
 
+       /*
+               Gets list of node boxes (used for rendering (NDT_NODEBOX)
+               and collision)
+       */
+       std::vector<aabb3f> getNodeBoxes(INodeDefManager *nodemgr) const;
+
+       /*
+               Gets list of selection boxes
+       */
+       std::vector<aabb3f> getSelectionBoxes(INodeDefManager *nodemgr) const;
+
        /*
                Serialization functions
        */
index 80bfae3e7149c9e68138a0173150f96bd37bf434..1b85a9558e606e2fbd144bc0e6ab2bbece8f5fa0 100644 (file)
@@ -33,34 +33,74 @@ with this program; if not, write to the Free Software Foundation, Inc.,
        NodeBox
 */
 
+void NodeBox::reset()
+{
+       type = NODEBOX_REGULAR;
+       // default is empty
+       fixed.clear();
+       // default is sign/ladder-like
+       wall_top = aabb3f(-BS/2, BS/2-BS/16., -BS/2, BS/2, BS/2, BS/2);
+       wall_bottom = aabb3f(-BS/2, -BS/2, -BS/2, BS/2, -BS/2+BS/16., BS/2);
+       wall_side = aabb3f(-BS/2, -BS/2, -BS/2, -BS/2+BS/16., BS/2, BS/2);
+}
+
 void NodeBox::serialize(std::ostream &os) const
 {
-       writeU8(os, 0); // version
+       writeU8(os, 1); // version
        writeU8(os, type);
-       writeV3F1000(os, fixed.MinEdge);
-       writeV3F1000(os, fixed.MaxEdge);
-       writeV3F1000(os, wall_top.MinEdge);
-       writeV3F1000(os, wall_top.MaxEdge);
-       writeV3F1000(os, wall_bottom.MinEdge);
-       writeV3F1000(os, wall_bottom.MaxEdge);
-       writeV3F1000(os, wall_side.MinEdge);
-       writeV3F1000(os, wall_side.MaxEdge);
+
+       if(type == NODEBOX_FIXED)
+       {
+               writeU16(os, fixed.size());
+               for(std::vector<aabb3f>::const_iterator
+                               i = fixed.begin();
+                               i != fixed.end(); i++)
+               {
+                       writeV3F1000(os, i->MinEdge);
+                       writeV3F1000(os, i->MaxEdge);
+               }
+       }
+       else if(type == NODEBOX_WALLMOUNTED)
+       {
+               writeV3F1000(os, wall_top.MinEdge);
+               writeV3F1000(os, wall_top.MaxEdge);
+               writeV3F1000(os, wall_bottom.MinEdge);
+               writeV3F1000(os, wall_bottom.MaxEdge);
+               writeV3F1000(os, wall_side.MinEdge);
+               writeV3F1000(os, wall_side.MaxEdge);
+       }
 }
 
 void NodeBox::deSerialize(std::istream &is)
 {
        int version = readU8(is);
-       if(version != 0)
+       if(version != 1)
                throw SerializationError("unsupported NodeBox version");
+
+       reset();
+
        type = (enum NodeBoxType)readU8(is);
-       fixed.MinEdge = readV3F1000(is);
-       fixed.MaxEdge = readV3F1000(is);
-       wall_top.MinEdge = readV3F1000(is);
-       wall_top.MaxEdge = readV3F1000(is);
-       wall_bottom.MinEdge = readV3F1000(is);
-       wall_bottom.MaxEdge = readV3F1000(is);
-       wall_side.MinEdge = readV3F1000(is);
-       wall_side.MaxEdge = readV3F1000(is);
+
+       if(type == NODEBOX_FIXED)
+       {
+               u16 fixed_count = readU16(is);
+               while(fixed_count--)
+               {
+                       aabb3f box;
+                       box.MinEdge = readV3F1000(is);
+                       box.MaxEdge = readV3F1000(is);
+                       fixed.push_back(box);
+               }
+       }
+       else if(type == NODEBOX_WALLMOUNTED)
+       {
+               wall_top.MinEdge = readV3F1000(is);
+               wall_top.MaxEdge = readV3F1000(is);
+               wall_bottom.MinEdge = readV3F1000(is);
+               wall_bottom.MaxEdge = readV3F1000(is);
+               wall_side.MinEdge = readV3F1000(is);
+               wall_side.MaxEdge = readV3F1000(is);
+       }
 }
 
 /*
@@ -165,6 +205,7 @@ void ContentFeatures::reset()
        liquid_viscosity = 0;
        light_source = 0;
        damage_per_second = 0;
+       node_box = NodeBox();
        selection_box = NodeBox();
        legacy_facedir_simple = false;
        legacy_wallmounted = false;
@@ -214,6 +255,7 @@ void ContentFeatures::serialize(std::ostream &os)
        writeU8(os, liquid_viscosity);
        writeU8(os, light_source);
        writeU32(os, damage_per_second);
+       node_box.serialize(os);
        selection_box.serialize(os);
        writeU8(os, legacy_facedir_simple);
        writeU8(os, legacy_wallmounted);
@@ -277,6 +319,7 @@ void ContentFeatures::deSerialize(std::istream &is)
        liquid_viscosity = readU8(is);
        light_source = readU8(is);
        damage_per_second = readU32(is);
+       node_box.deSerialize(is);
        selection_box.deSerialize(is);
        legacy_facedir_simple = readU8(is);
        legacy_wallmounted = readU8(is);
@@ -577,6 +620,7 @@ public:
                        case NDT_PLANTLIKE:
                        case NDT_FENCELIKE:
                        case NDT_RAILLIKE:
+                       case NDT_NODEBOX:
                                f->solidness = 0;
                                break;
                        }
index fcd06be71d06f6024cc86649444dd5bcbb903f1e..7c6931834b98d99dccb6ab5b980a10b5c2801edf 100644 (file)
@@ -65,7 +65,7 @@ enum LiquidType
 enum NodeBoxType
 {
        NODEBOX_REGULAR, // Regular block; allows buildable_to
-       NODEBOX_FIXED, // Static separately defined box
+       NODEBOX_FIXED, // Static separately defined box(es)
        NODEBOX_WALLMOUNTED, // Box for wall mounted nodes; (top, bottom, side)
 };
 
@@ -74,22 +74,16 @@ struct NodeBox
        enum NodeBoxType type;
        // NODEBOX_REGULAR (no parameters)
        // NODEBOX_FIXED
-       core::aabbox3d<f32> fixed;
+       std::vector<aabb3f> fixed;
        // NODEBOX_WALLMOUNTED
-       core::aabbox3d<f32> wall_top;
-       core::aabbox3d<f32> wall_bottom;
-       core::aabbox3d<f32> wall_side; // being at the -X side
-
-       NodeBox():
-               type(NODEBOX_REGULAR),
-               // default is rail-like
-               fixed(-BS/2, -BS/2, -BS/2, BS/2, -BS/2+BS/16., BS/2),
-               // default is sign/ladder-like
-               wall_top(-BS/2, BS/2-BS/16., -BS/2, BS/2, BS/2, BS/2),
-               wall_bottom(-BS/2, -BS/2, -BS/2, BS/2, -BS/2+BS/16., BS/2),
-               wall_side(-BS/2, -BS/2, -BS/2, -BS/2+BS/16., BS/2, BS/2)
-       {}
+       aabb3f wall_top;
+       aabb3f wall_bottom;
+       aabb3f wall_side; // being at the -X side
 
+       NodeBox()
+       { reset(); }
+
+       void reset();
        void serialize(std::ostream &os) const;
        void deSerialize(std::istream &is);
 };
@@ -143,6 +137,7 @@ enum NodeDrawType
        NDT_PLANTLIKE,
        NDT_FENCELIKE,
        NDT_RAILLIKE,
+       NDT_NODEBOX,
 };
 
 #define CF_SPECIAL_COUNT 2
@@ -217,6 +212,7 @@ struct ContentFeatures
        // Amount of light the node emits
        u8 light_source;
        u32 damage_per_second;
+       NodeBox node_box;
        NodeBox selection_box;
        // Compatibility with old maps
        // Set to true if paramtype used to be 'facedir_simple'
index d470fa6ff2dea8dd5a1ebec00d22d66e89f1fbe8..999d842fa9dc37e6f6e9037002da285152c44d4f 100644 (file)
@@ -166,6 +166,10 @@ void Player::deSerialize(std::istream &is)
        RemotePlayer
 */
 
+
+
+
+
 void RemotePlayer::setPosition(const v3f &position)
 {
        Player::setPosition(position);
index 289ad31f874bee578f683583436037f4c6329fdf..cf2a01c64bf073fe8fd49a26987f895c37ee14cd 100644 (file)
@@ -382,6 +382,7 @@ struct EnumString es_DrawType[] =
        {NDT_PLANTLIKE, "plantlike"},
        {NDT_FENCELIKE, "fencelike"},
        {NDT_RAILLIKE, "raillike"},
+       {NDT_NODEBOX, "nodebox"},
        {0, NULL},
 };
 
@@ -595,52 +596,89 @@ static video::SColor readARGB8(lua_State *L, int index)
        return color;
 }
 
-static core::aabbox3d<f32> read_aabbox3df32(lua_State *L, int index, f32 scale)
+static aabb3f read_aabb3f(lua_State *L, int index, f32 scale)
 {
-       core::aabbox3d<f32> box;
-       if(lua_istable(L, -1)){
-               lua_rawgeti(L, -1, 1);
+       aabb3f box;
+       if(lua_istable(L, index)){
+               lua_rawgeti(L, index, 1);
                box.MinEdge.X = lua_tonumber(L, -1) * scale;
                lua_pop(L, 1);
-               lua_rawgeti(L, -1, 2);
+               lua_rawgeti(L, index, 2);
                box.MinEdge.Y = lua_tonumber(L, -1) * scale;
                lua_pop(L, 1);
-               lua_rawgeti(L, -1, 3);
+               lua_rawgeti(L, index, 3);
                box.MinEdge.Z = lua_tonumber(L, -1) * scale;
                lua_pop(L, 1);
-               lua_rawgeti(L, -1, 4);
+               lua_rawgeti(L, index, 4);
                box.MaxEdge.X = lua_tonumber(L, -1) * scale;
                lua_pop(L, 1);
-               lua_rawgeti(L, -1, 5);
+               lua_rawgeti(L, index, 5);
                box.MaxEdge.Y = lua_tonumber(L, -1) * scale;
                lua_pop(L, 1);
-               lua_rawgeti(L, -1, 6);
+               lua_rawgeti(L, index, 6);
                box.MaxEdge.Z = lua_tonumber(L, -1) * scale;
                lua_pop(L, 1);
        }
        return box;
 }
 
-#if 0
-/*
-       MaterialProperties
-*/
+static std::vector<aabb3f> read_aabb3f_vector(lua_State *L, int index, f32 scale)
+{
+       std::vector<aabb3f> boxes;
+       if(lua_istable(L, index)){
+               int n = lua_objlen(L, index);
+               // Check if it's a single box or a list of boxes
+               bool possibly_single_box = (n == 6);
+               for(int i = 1; i <= n && possibly_single_box; i++){
+                       lua_rawgeti(L, index, i);
+                       if(!lua_isnumber(L, -1))
+                               possibly_single_box = false;
+                       lua_pop(L, 1);
+               }
+               if(possibly_single_box){
+                       // Read a single box
+                       boxes.push_back(read_aabb3f(L, index, scale));
+               } else {
+                       // Read a list of boxes
+                       for(int i = 1; i <= n; i++){
+                               lua_rawgeti(L, index, i);
+                               boxes.push_back(read_aabb3f(L, -1, scale));
+                               lua_pop(L, 1);
+                       }
+               }
+       }
+       return boxes;
+}
 
-static MaterialProperties read_material_properties(
-               lua_State *L, int table)
+static NodeBox read_nodebox(lua_State *L, int index)
 {
-       MaterialProperties prop;
-       prop.diggability = (Diggability)getenumfield(L, -1, "diggability",
-                       es_Diggability, DIGGABLE_NORMAL);
-       getfloatfield(L, -1, "constant_time", prop.constant_time);
-       getfloatfield(L, -1, "weight", prop.weight);
-       getfloatfield(L, -1, "crackiness", prop.crackiness);
-       getfloatfield(L, -1, "crumbliness", prop.crumbliness);
-       getfloatfield(L, -1, "cuttability", prop.cuttability);
-       getfloatfield(L, -1, "flammability", prop.flammability);
-       return prop;
+       NodeBox nodebox;
+       if(lua_istable(L, -1)){
+               nodebox.type = (NodeBoxType)getenumfield(L, index, "type",
+                               es_NodeBoxType, NODEBOX_REGULAR);
+
+               lua_getfield(L, index, "fixed");
+               if(lua_istable(L, -1))
+                       nodebox.fixed = read_aabb3f_vector(L, -1, BS);
+               lua_pop(L, 1);
+
+               lua_getfield(L, index, "wall_top");
+               if(lua_istable(L, -1))
+                       nodebox.wall_top = read_aabb3f(L, -1, BS);
+               lua_pop(L, 1);
+
+               lua_getfield(L, index, "wall_bottom");
+               if(lua_istable(L, -1))
+                       nodebox.wall_bottom = read_aabb3f(L, -1, BS);
+               lua_pop(L, 1);
+
+               lua_getfield(L, index, "wall_side");
+               if(lua_istable(L, -1))
+                       nodebox.wall_side = read_aabb3f(L, -1, BS);
+               lua_pop(L, 1);
+       }
+       return nodebox;
 }
-#endif
 
 /*
        Groups
@@ -891,7 +929,7 @@ static void read_object_properties(lua_State *L, int index,
 
        lua_getfield(L, -1, "collisionbox");
        if(lua_istable(L, -1))
-               prop->collisionbox = read_aabbox3df32(L, -1, 1.0);
+               prop->collisionbox = read_aabb3f(L, -1, 1.0);
        lua_pop(L, 1);
 
        getstringfield(L, -1, "visual", prop->visual);
@@ -1203,33 +1241,16 @@ static ContentFeatures read_content_features(lua_State *L, int index)
        f.damage_per_second = getintfield_default(L, index,
                        "damage_per_second", f.damage_per_second);
        
-       lua_getfield(L, index, "selection_box");
-       if(lua_istable(L, -1)){
-               f.selection_box.type = (NodeBoxType)getenumfield(L, -1, "type",
-                               es_NodeBoxType, NODEBOX_REGULAR);
-
-               lua_getfield(L, -1, "fixed");
-               if(lua_istable(L, -1))
-                       f.selection_box.fixed = read_aabbox3df32(L, -1, BS);
-               lua_pop(L, 1);
-
-               lua_getfield(L, -1, "wall_top");
-               if(lua_istable(L, -1))
-                       f.selection_box.wall_top = read_aabbox3df32(L, -1, BS);
-               lua_pop(L, 1);
-
-               lua_getfield(L, -1, "wall_bottom");
-               if(lua_istable(L, -1))
-                       f.selection_box.wall_bottom = read_aabbox3df32(L, -1, BS);
-               lua_pop(L, 1);
-
-               lua_getfield(L, -1, "wall_side");
-               if(lua_istable(L, -1))
-                       f.selection_box.wall_side = read_aabbox3df32(L, -1, BS);
-               lua_pop(L, 1);
-       }
+       lua_getfield(L, index, "node_box");
+       if(lua_istable(L, -1))
+               f.node_box = read_nodebox(L, -1);
        lua_pop(L, 1);
 
+       lua_getfield(L, index, "selection_box");
+       if(lua_istable(L, -1))
+               f.selection_box = read_nodebox(L, -1);
+       lua_pop(L, 1);
+
        // Set to true if paramtype used to be 'facedir_simple'
        getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple);
        // Set to true if wall_mounted used to be set to true
@@ -5604,6 +5625,21 @@ void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
        // Set default values that differ from ObjectProperties defaults
        prop->hp_max = 10;
        
+       /* Read stuff */
+       
+       prop->hp_max = getintfield_default(L, -1, "hp_max", 10);
+
+       getboolfield(L, -1, "physical", prop->physical);
+
+       getfloatfield(L, -1, "weight", prop->weight);
+
+       lua_getfield(L, -1, "collisionbox");
+       if(lua_istable(L, -1))
+               prop->collisionbox = read_aabb3f(L, -1, 1.0);
+       lua_pop(L, 1);
+
+       getstringfield(L, -1, "visual", prop->visual);
+       
        // Deprecated: read object properties directly
        read_object_properties(L, -1, prop);
        
index 3dc6814b158c0badd8812f1dca711b73c8f39f87..9b1346274a4c4613c4af401b50c94a7360ddb22a 100644 (file)
@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "connection.h"
 #include "serialization.h"
 #include "voxel.h"
+#include "collision.h"
 #include <sstream>
 #include "porting.h"
 #include "content_mapnode.h"
@@ -1075,6 +1076,153 @@ struct TestMapSector
 };
 #endif
 
+struct TestCollision
+{
+       void Run()
+       {
+               /*
+                       axisAlignedCollision
+               */
+
+               for(s16 bx = -3; bx <= 3; bx++)
+               for(s16 by = -3; by <= 3; by++)
+               for(s16 bz = -3; bz <= 3; bz++)
+               {
+                       // X-
+                       {
+                               aabb3f s(bx, by, bz, bx+1, by+1, bz+1);
+                               aabb3f m(bx-2, by, bz, bx-1, by+1, bz+1);
+                               v3f v(1, 0, 0);
+                               f32 dtime = 0;
+                               assert(axisAlignedCollision(s, m, v, 0, dtime) == 0);
+                               assert(fabs(dtime - 1.000) < 0.001);
+                       }
+                       {
+                               aabb3f s(bx, by, bz, bx+1, by+1, bz+1);
+                               aabb3f m(bx-2, by, bz, bx-1, by+1, bz+1);
+                               v3f v(-1, 0, 0);
+                               f32 dtime = 0;
+                               assert(axisAlignedCollision(s, m, v, 0, dtime) == -1);
+                       }
+                       {
+                               aabb3f s(bx, by, bz, bx+1, by+1, bz+1);
+                               aabb3f m(bx-2, by+1.5, bz, bx-1, by+2.5, bz-1);
+                               v3f v(1, 0, 0);
+                               f32 dtime;
+                               assert(axisAlignedCollision(s, m, v, 0, dtime) == -1);
+                       }
+                       {
+                               aabb3f s(bx, by, bz, bx+1, by+1, bz+1);
+                               aabb3f m(bx-2, by-1.5, bz, bx-1.5, by+0.5, bz+1);
+                               v3f v(0.5, 0.1, 0);
+                               f32 dtime;
+                               assert(axisAlignedCollision(s, m, v, 0, dtime) == 0);
+                               assert(fabs(dtime - 3.000) < 0.001);
+                       }
+                       {
+                               aabb3f s(bx, by, bz, bx+1, by+1, bz+1);
+                               aabb3f m(bx-2, by-1.5, bz, bx-1.5, by+0.5, bz+1);
+                               v3f v(0.5, 0.1, 0);
+                               f32 dtime;
+                               assert(axisAlignedCollision(s, m, v, 0, dtime) == 0);
+                               assert(fabs(dtime - 3.000) < 0.001);
+                       }
+
+                       // X+
+                       {
+                               aabb3f s(bx, by, bz, bx+1, by+1, bz+1);
+                               aabb3f m(bx+2, by, bz, bx+3, by+1, bz+1);
+                               v3f v(-1, 0, 0);
+                               f32 dtime;
+                               assert(axisAlignedCollision(s, m, v, 0, dtime) == 0);
+                               assert(fabs(dtime - 1.000) < 0.001);
+                       }
+                       {
+                               aabb3f s(bx, by, bz, bx+1, by+1, bz+1);
+                               aabb3f m(bx+2, by, bz, bx+3, by+1, bz+1);
+                               v3f v(1, 0, 0);
+                               f32 dtime;
+                               assert(axisAlignedCollision(s, m, v, 0, dtime) == -1);
+                       }
+                       {
+                               aabb3f s(bx, by, bz, bx+1, by+1, bz+1);
+                               aabb3f m(bx+2, by, bz+1.5, bx+3, by+1, bz+3.5);
+                               v3f v(-1, 0, 0);
+                               f32 dtime;
+                               assert(axisAlignedCollision(s, m, v, 0, dtime) == -1);
+                       }
+                       {
+                               aabb3f s(bx, by, bz, bx+1, by+1, bz+1);
+                               aabb3f m(bx+2, by-1.5, bz, bx+2.5, by-0.5, bz+1);
+                               v3f v(-0.5, 0.2, 0);
+                               f32 dtime;
+                               assert(axisAlignedCollision(s, m, v, 0, dtime) == 1);  // Y, not X!
+                               assert(fabs(dtime - 2.500) < 0.001);
+                       }
+                       {
+                               aabb3f s(bx, by, bz, bx+1, by+1, bz+1);
+                               aabb3f m(bx+2, by-1.5, bz, bx+2.5, by-0.5, bz+1);
+                               v3f v(-0.5, 0.3, 0);
+                               f32 dtime;
+                               assert(axisAlignedCollision(s, m, v, 0, dtime) == 0);
+                               assert(fabs(dtime - 2.000) < 0.001);
+                       }
+
+                       // TODO: Y-, Y+, Z-, Z+
+
+                       // misc
+                       {
+                               aabb3f s(bx, by, bz, bx+2, by+2, bz+2);
+                               aabb3f m(bx+2.3, by+2.29, bz+2.29, bx+4.2, by+4.2, bz+4.2);
+                               v3f v(-1./3, -1./3, -1./3);
+                               f32 dtime;
+                               assert(axisAlignedCollision(s, m, v, 0, dtime) == 0);
+                               assert(fabs(dtime - 0.9) < 0.001);
+                       }
+                       {
+                               aabb3f s(bx, by, bz, bx+2, by+2, bz+2);
+                               aabb3f m(bx+2.29, by+2.3, bz+2.29, bx+4.2, by+4.2, bz+4.2);
+                               v3f v(-1./3, -1./3, -1./3);
+                               f32 dtime;
+                               assert(axisAlignedCollision(s, m, v, 0, dtime) == 1);
+                               assert(fabs(dtime - 0.9) < 0.001);
+                       }
+                       {
+                               aabb3f s(bx, by, bz, bx+2, by+2, bz+2);
+                               aabb3f m(bx+2.29, by+2.29, bz+2.3, bx+4.2, by+4.2, bz+4.2);
+                               v3f v(-1./3, -1./3, -1./3);
+                               f32 dtime;
+                               assert(axisAlignedCollision(s, m, v, 0, dtime) == 2);
+                               assert(fabs(dtime - 0.9) < 0.001);
+                       }
+                       {
+                               aabb3f s(bx, by, bz, bx+2, by+2, bz+2);
+                               aabb3f m(bx-4.2, by-4.2, bz-4.2, bx-2.3, by-2.29, bz-2.29);
+                               v3f v(1./7, 1./7, 1./7);
+                               f32 dtime;
+                               assert(axisAlignedCollision(s, m, v, 0, dtime) == 0);
+                               assert(fabs(dtime - 16.1) < 0.001);
+                       }
+                       {
+                               aabb3f s(bx, by, bz, bx+2, by+2, bz+2);
+                               aabb3f m(bx-4.2, by-4.2, bz-4.2, bx-2.29, by-2.3, bz-2.29);
+                               v3f v(1./7, 1./7, 1./7);
+                               f32 dtime;
+                               assert(axisAlignedCollision(s, m, v, 0, dtime) == 1);
+                               assert(fabs(dtime - 16.1) < 0.001);
+                       }
+                       {
+                               aabb3f s(bx, by, bz, bx+2, by+2, bz+2);
+                               aabb3f m(bx-4.2, by-4.2, bz-4.2, bx-2.29, by-2.29, bz-2.3);
+                               v3f v(1./7, 1./7, 1./7);
+                               f32 dtime;
+                               assert(axisAlignedCollision(s, m, v, 0, dtime) == 2);
+                               assert(fabs(dtime - 16.1) < 0.001);
+                       }
+               }
+       }
+};
+
 struct TestSocket
 {
        void Run()
@@ -1544,6 +1692,7 @@ void run_tests()
        TESTPARAMS(TestInventory, idef);
        //TEST(TestMapBlock);
        //TEST(TestMapSector);
+       TEST(TestCollision);
        if(INTERNET_SIMULATOR == false){
                TEST(TestSocket);
                dout_con<<"=== BEGIN RUNNING UNIT TESTS FOR CONNECTION ==="<<std::endl;
index 8c1f42e075f4fe9405b4aad5552aa23ba11f2840..ae986e797ebdc38ce8113a8f149ae244c38805a6 100644 (file)
@@ -61,6 +61,14 @@ struct AtlasPointer
        v2f size; // Size in atlas
        u16 tiled; // X-wise tiling count. If 0, width of atlas is width of image.
 
+       AtlasPointer():
+               id(0),
+               atlas(NULL),
+               pos(0,0),
+               size(1,1),
+               tiled(1)
+       {}
+
        AtlasPointer(
                        u16 id_,
                        video::ITexture *atlas_=NULL,