1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-08-01 17:38:41 +00:00

Merge branch 'object_object_collision' into sapier_experimental

This commit is contained in:
sapier 2012-02-05 20:35:54 +01:00
commit 413afa77d0
30 changed files with 1365 additions and 719 deletions

View file

@ -359,6 +359,7 @@ minetest.nodedef_default = {
type="node",
-- name intentionally not defined here
description = "",
groups = {},
inventory_image = "",
wield_image = "",
wield_scale = {x=1,y=1,z=1},
@ -418,6 +419,7 @@ minetest.craftitemdef_default = {
type="craft",
-- name intentionally not defined here
description = "",
groups = {},
inventory_image = "",
wield_image = "",
wield_scale = {x=1,y=1,z=1},
@ -435,6 +437,7 @@ minetest.tooldef_default = {
type="tool",
-- name intentionally not defined here
description = "",
groups = {},
inventory_image = "",
wield_image = "",
wield_scale = {x=1,y=1,z=1},
@ -452,6 +455,7 @@ minetest.noneitemdef_default = { -- This is used for the hand and unknown items
type="none",
-- name intentionally not defined here
description = "",
groups = {},
inventory_image = "",
wield_image = "",
wield_scale = {x=1,y=1,z=1},

View file

@ -308,6 +308,12 @@
-- Item definition options (register_node, register_craftitem, register_tool)
-- {
-- description = "Steel Axe",
-- groups = {}, -- key=name, value=rating; rating=1..3.
-- if rating not applicable, use 1.
-- eg. {wool=1, fluffy=3}
-- {soil=2, outerspace=1, crumbly=1}
-- {hard=3, brittle=3, spikes=2
-- {hard=1, metal=1, spikes=1}
-- inventory_image = "default_tool_steelaxe.png",
-- wield_image = "",
-- wield_scale = {x=1,y=1,z=1},

View file

@ -0,0 +1 @@
default

93
data/mods/stairs/init.lua Normal file
View file

@ -0,0 +1,93 @@
stairs = {}
-- Node will be called stairs:stair_<subname>
function stairs.register_stair(subname, recipeitem, material, images, description)
minetest.register_node("stairs:stair_" .. subname, {
description = description,
drawtype = "nodebox",
tile_images = images,
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = true,
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},
},
},
material = material,
})
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, material, images, description)
minetest.register_node("stairs:slab_" .. subname, {
description = description,
drawtype = "nodebox",
tile_images = images,
paramtype = "light",
is_ground_content = true,
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},
},
material = material,
})
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, material, images, desc_stair, desc_slab)
stairs.register_stair(subname, recipeitem, material, images, desc_stair)
stairs.register_slab(subname, recipeitem, material, images, desc_slab)
end
stairs.register_stair_and_slab("wood", "default:wood",
minetest.digprop_woodlike(0.75),
{"default_wood.png"},
"Wooden stair",
"Wooden slab")
stairs.register_stair_and_slab("stone", "default:stone",
minetest.digprop_stonelike(0.75),
{"default_stone.png"},
"Stone stair",
"Stone slab")
stairs.register_stair_and_slab("cobble", "default:cobble",
minetest.digprop_stonelike(0.75),
{"default_cobble.png"},
"Cobble stair",
"Cobble slab")
stairs.register_stair_and_slab("brick", "default:brick",
minetest.digprop_stonelike(0.75),
{"default_brick.png"},
"Brick stair",
"Brick slab")
stairs.register_stair_and_slab("sandstone", "default:sandstone",
minetest.digprop_stonelike(0.75),
{"default_sandstone.png"},
"Sandstone stair",
"Sandstone slab")

View file

@ -283,7 +283,7 @@ else()
endif()
set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG ${RELEASE_WARNING_FLAGS} ${WARNING_FLAGS} -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops")
set(CMAKE_CXX_FLAGS_DEBUG "-g -O1 -Wall ${WARNING_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall ${WARNING_FLAGS}")
if(USE_GPROF)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg")

View file

@ -62,6 +62,7 @@ public:
virtual u8 getType() const = 0;
virtual aabb3f* getCollisionBox() = 0;
protected:
u16 m_id; // 0 is invalid, "no id"
};

View file

@ -1171,8 +1171,18 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
std::istringstream is(datastring, std::ios_base::binary);
Player *player = m_env.getLocalPlayer();
assert(player != NULL);
u8 oldhp = player->hp;
u8 hp = readU8(is);
player->hp = hp;
if(hp < oldhp)
{
// Add to ClientEvent queue
ClientEvent event;
event.type = CE_PLAYER_DAMAGE;
event.player_damage.amount = oldhp - hp;
m_client_event_queue.push_back(event);
}
}
else if(command == TOCLIENT_MOVE_PLAYER)
{

View file

@ -22,28 +22,266 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "map.h"
#include "nodedef.h"
#include "gamedef.h"
#include "environment.h"
#include "log.h"
#include <vector>
#include <list>
collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
f32 pos_max_d, const core::aabbox3d<f32> &box_0,
f32 dtime, v3f &pos_f, v3f &speed_f)
// 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(Environment* env,
f32 pos_max_d, const aabb3f &box_0,
f32 stepheight, f32 dtime,
v3f &pos_f, v3f &speed_f, v3f &accel_f)
{
Map * map = &env->getMap();
IGameDef * gamedef = env->getGameDef();
TimeTaker tt("collisionMoveSimple");
collisionMoveResult result;
v3f oldpos_f = pos_f;
v3s16 oldpos_i = floatToInt(oldpos_f, BS);
/*
Calculate new velocity
*/
speed_f += accel_f * dtime;
/*
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");
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());
{
TimeTaker tt3("collisionMoveSimple collect object boxes");
/* add object boxes to cboxes */
core::list<ActiveObject*> objects = env->getActiveObjects();
for (core::list<ActiveObject*>::Iterator iter = objects.begin();
iter != objects.end(); iter++)
{
aabb3f* object_collisionbox = (*iter)->getCollisionBox();
//TODO do we need to check if it's really near enough?
if (object_collisionbox != NULL)
{
cboxes.push_back(*object_collisionbox);
is_unloaded.push_back(false);
is_step_up.push_back(false);
}
}
} //tt3
/*
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
@ -55,47 +293,127 @@ 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;
int loopcount = 0;
/*
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++)
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)
continue;
}
catch(InvalidPositionException &e)
TimeTaker tt3("collisionMoveSimple dtime loop");
// Avoid infinite loop
loopcount++;
if(loopcount >= 100)
{
// Doing nothing here will block the object from
// walking over map borders
infostream<<"collisionMoveSimple: WARNING: Loop count exceeded, "
"aborting to avoid infiniite loop"<<std::endl;
dtime = 0;
break;
}
core::aabbox3d<f32> nodebox = getNodeBox(v3s16(x,y,z), BS);
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;
}
if(nearest_collided == -1)
{
// 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];
/*
See if the object is touching ground.
@ -107,104 +425,40 @@ 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;
}
collisionMoveResult collisionMovePrecise(Map *map, IGameDef *gamedef,
f32 pos_max_d, const core::aabbox3d<f32> &box_0,
f32 dtime, v3f &pos_f, v3f &speed_f)
collisionMoveResult collisionMovePrecise(Environment* env,
f32 pos_max_d, const aabb3f &box_0,
f32 stepheight, f32 dtime,
v3f &pos_f, v3f &speed_f, v3f &accel_f)
{
TimeTaker tt("collisionMovePrecise");
infostream<<"start collisionMovePrecise\n";
collisionMoveResult 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;
@ -216,6 +470,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)
{
@ -233,18 +497,22 @@ collisionMoveResult collisionMovePrecise(Map *map, IGameDef *gamedef,
dtime_downcount = 0;
}
collisionMoveResult result = collisionMoveSimple(map, gamedef,
pos_max_d, box_0, dtime_part, pos_f, speed_f);
collisionMoveResult result = collisionMoveSimple(env,
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);
infostream<<"end collisionMovePrecise\n";
return final_result;
}

View file

@ -21,30 +21,52 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define COLLISION_HEADER
#include "common_irrlicht.h"
#include <vector>
class Map;
class IGameDef;
class Environment;
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);
collisionMoveResult collisionMoveSimple(Environment* env,
f32 pos_max_d, const aabb3f &box_0,
f32 stepheight, f32 dtime,
v3f &pos_f, v3f &speed_f, v3f &accel_f);
// 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);
collisionMoveResult collisionMovePrecise(Environment* env,
f32 pos_max_d, const aabb3f &box_0,
f32 stepheight, f32 dtime,
v3f &pos_f, v3f &speed_f, v3f &accel_f);
// 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
{

View file

@ -1701,6 +1701,7 @@ private:
int m_anim_num_frames;
float m_anim_framelength;
float m_anim_timer;
aabb3f m_collisionbox;
public:
LuaEntityCAO(IGameDef *gamedef, ClientEnvironment *env):
@ -1901,22 +1902,23 @@ 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;
IGameDef *gamedef = env->getGameDef();
moveresult = collisionMovePrecise(&env->getMap(), gamedef,
pos_max_d, box, dtime, p_pos, p_velocity);
v3f p_acceleration = m_acceleration;
moveresult = collisionMovePrecise(env,
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;
@ -2097,6 +2099,21 @@ public:
updateTexturePos();
}
}
aabb3f* getCollisionBox() {
if (m_prop->physical) {
//update collision box
m_collisionbox.MinEdge = m_prop->collisionbox.MinEdge * BS;
m_collisionbox.MaxEdge = m_prop->collisionbox.MaxEdge * BS;
m_collisionbox.MinEdge += m_position;
m_collisionbox.MaxEdge += m_position;
return &m_collisionbox;
}
return NULL;
}
};
// Prototype
@ -2119,6 +2136,8 @@ private:
bool m_is_local_player;
LocalPlayer *m_local_player;
float m_damage_visual_timer;
bool m_dead;
aabb3f m_collisionbox;
public:
PlayerCAO(IGameDef *gamedef, ClientEnvironment *env):
@ -2130,7 +2149,8 @@ public:
m_yaw(0),
m_is_local_player(false),
m_local_player(NULL),
m_damage_visual_timer(0)
m_damage_visual_timer(0),
m_dead(false)
{
if(gamedef == NULL)
ClientActiveObject::registerType(getType(), create);
@ -2152,6 +2172,8 @@ public:
m_position = readV3F1000(is);
// yaw
m_yaw = readF1000(is);
// dead
m_dead = readU8(is);
pos_translator.init(m_position);
@ -2162,6 +2184,17 @@ public:
}
}
aabb3f* getCollisionBox() {
//update collision box
m_collisionbox.MinEdge = m_selection_box.MinEdge;
m_collisionbox.MaxEdge = m_selection_box.MaxEdge;
m_collisionbox.MinEdge += m_position;
m_collisionbox.MaxEdge += m_position;
return &m_collisionbox;
}
~PlayerCAO()
{
if(m_node)
@ -2181,6 +2214,8 @@ public:
{
if(m_is_local_player)
return NULL;
if(m_dead)
return NULL;
return &m_selection_box;
}
v3f getPosition()
@ -2256,6 +2291,7 @@ public:
m_text->setPosition(v3f(0, (f32)BS*2.1, 0));
updateTextures("");
updateVisibility();
updateNodePos();
}
@ -2273,11 +2309,11 @@ public:
if(m_node == NULL)
return;
m_node->setVisible(true);
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
setMeshColor(m_node->getMesh(), color);
updateVisibility();
}
v3s16 getLightPosition()
@ -2285,6 +2321,14 @@ public:
return floatToInt(m_position+v3f(0,BS*1.5,0), BS);
}
void updateVisibility()
{
if(m_node == NULL)
return;
m_node->setVisible(!m_dead);
}
void updateNodePos()
{
if(m_node == NULL)
@ -2300,6 +2344,7 @@ public:
void step(float dtime, ClientEnvironment *env)
{
pos_translator.translate(dtime);
updateVisibility();
updateNodePos();
if(m_damage_visual_timer > 0){
@ -2331,13 +2376,16 @@ public:
{
// damage
s16 damage = readS16(is);
if(m_is_local_player)
m_env->damageLocalPlayer(damage, false);
m_damage_visual_timer = 0.5;
m_damage_visual_timer = 0.05;
if(damage >= 2)
m_damage_visual_timer += 0.05 * damage;
updateTextures("^[brighten");
}
else if(cmd == 2) // died or respawned
{
m_dead = readU8(is);
updateVisibility();
}
}
void updateTextures(const std::string &mod)

View file

@ -985,6 +985,72 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
u16 indices[] = {0,1,2,2,3,0};
collector.append(material_rail, vertices, 4, indices, 6);
break;}
case NDT_NODEBOX:
{
v3s16 facedirs[6] = {
v3s16(0,1,0),
v3s16(0,-1,0),
v3s16(1,0,0),
v3s16(-1,0,0),
v3s16(0,0,1),
v3s16(0,0,-1),
};
video::SMaterial material_nodebox[6];
AtlasPointer pa_nodebox[6];
for(int i = 0; i < 6; i++)
{
material_nodebox[i].setFlag(video::EMF_LIGHTING, false);
material_nodebox[i].setFlag(video::EMF_BILINEAR_FILTER, false);
material_nodebox[i].setFlag(video::EMF_FOG_ENABLE, true);
material_nodebox[i].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
TileSpec tile = getNodeTile(n, p, facedirs[i],
&data->m_temp_mods, tsrc, nodedef);
pa_nodebox[i] = tile.texture;
material_nodebox[i].setTexture(0, pa_nodebox[i].atlas);
}
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
video::SColor c = MapBlock_LightColor(255, l);
v3f pos = intToFloat(p+blockpos_nodes, 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,
material_nodebox, pa_nodebox, 6,
c, txc);
}
break;}
}
}
}

View file

@ -161,9 +161,11 @@ void ItemSAO::step(float dtime, bool send_recommended)
m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
v3f pos_f = getBasePosition();
v3f pos_f_old = pos_f;
IGameDef *gamedef = m_env->getGameDef();
moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
pos_max_d, box, dtime, pos_f, m_speed_f);
v3f accel_f = v3f(0,0,0);
f32 stepheight = 0;
moveresult = collisionMoveSimple(m_env,
pos_max_d, box, stepheight, dtime,
pos_f, m_speed_f, accel_f);
if(send_recommended == false)
return;
@ -402,9 +404,11 @@ void RatSAO::step(float dtime, bool send_recommended)
m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
v3f pos_f = getBasePosition();
v3f pos_f_old = pos_f;
IGameDef *gamedef = m_env->getGameDef();
moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
pos_max_d, box, dtime, pos_f, m_speed_f);
v3f accel_f = v3f(0,0,0);
f32 stepheight = 0;
moveresult = collisionMoveSimple(m_env,
pos_max_d, box, stepheight, dtime,
pos_f, m_speed_f, accel_f);
m_touching_ground = moveresult.touching_ground;
setBasePosition(pos_f);
@ -650,9 +654,11 @@ void Oerkki1SAO::step(float dtime, bool send_recommended)
m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);*/
v3f pos_f = getBasePosition();
v3f pos_f_old = pos_f;
IGameDef *gamedef = m_env->getGameDef();
moveresult = collisionMovePrecise(&m_env->getMap(), gamedef,
pos_max_d, box, dtime, pos_f, m_speed_f);
v3f accel_f = v3f(0,0,0);
f32 stepheight = 0;
moveresult = collisionMovePrecise(m_env,
pos_max_d, box, stepheight, dtime,
pos_f, m_speed_f, accel_f);
m_touching_ground = moveresult.touching_ground;
// Do collision damage
@ -897,9 +903,11 @@ void FireflySAO::step(float dtime, bool send_recommended)
m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
v3f pos_f = getBasePosition();
v3f pos_f_old = pos_f;
IGameDef *gamedef = m_env->getGameDef();
moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
pos_max_d, box, dtime, pos_f, m_speed_f);
v3f accel_f = v3f(0,0,0);
f32 stepheight = 0;
moveresult = collisionMoveSimple(m_env,
pos_max_d, box, stepheight, dtime,
pos_f, m_speed_f, accel_f);
m_touching_ground = moveresult.touching_ground;
setBasePosition(pos_f);
@ -1616,16 +1624,17 @@ 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;
IGameDef *gamedef = m_env->getGameDef();
moveresult = collisionMovePrecise(&m_env->getMap(), gamedef,
pos_max_d, box, dtime, p_pos, p_velocity);
v3f p_acceleration = m_acceleration;
moveresult = collisionMovePrecise(m_env,
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;
@ -1828,3 +1837,18 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
m_messages_out.push_back(aom);
}
aabb3f* LuaEntitySAO::getCollisionBox() {
if (m_prop->physical) {
//update collision box
m_collisionbox.MinEdge = m_prop->collisionbox.MinEdge * BS;
m_collisionbox.MaxEdge = m_prop->collisionbox.MaxEdge * BS;
m_collisionbox.MinEdge += m_base_position;
m_collisionbox.MaxEdge += m_base_position;
return &m_collisionbox;
}
return NULL;
}

View file

@ -32,6 +32,7 @@ public:
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data);
void step(float dtime, bool send_recommended);
inline aabb3f* getCollisionBox() { return NULL; }
private:
float m_timer1;
float m_age;
@ -51,6 +52,7 @@ public:
ItemStack createItemStack();
void punch(ServerActiveObject *puncher, float time_from_last_punch);
float getMinimumSavedMovement(){ return 0.1*BS; }
inline aabb3f* getCollisionBox() { return NULL; }
private:
std::string m_itemstring;
bool m_itemstring_changed;
@ -71,6 +73,7 @@ public:
std::string getClientInitializationData();
std::string getStaticData();
void punch(ServerActiveObject *puncher, float time_from_last_punch);
inline aabb3f* getCollisionBox() { return NULL; }
private:
bool m_is_active;
IntervalLimiter m_inactive_interval;
@ -97,6 +100,7 @@ public:
std::string getStaticData();
void punch(ServerActiveObject *puncher, float time_from_last_punch);
bool isPeaceful(){return false;}
inline aabb3f* getCollisionBox() { return NULL; }
private:
void doDamage(u16 d);
@ -125,6 +129,7 @@ public:
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
inline aabb3f* getCollisionBox() { return NULL; }
private:
bool m_is_active;
IntervalLimiter m_inactive_interval;
@ -155,6 +160,7 @@ public:
void step(float dtime, bool send_recommended);
void punch(ServerActiveObject *puncher, float time_from_last_punch);
bool isPeaceful();
inline aabb3f* getCollisionBox() { return NULL; }
private:
void sendPosition();
void setPropertyDefaults();
@ -222,6 +228,7 @@ public:
void setSprite(v2s16 p, int num_frames, float framelength,
bool select_horiz_by_yawpitch);
std::string getName();
aabb3f* getCollisionBox();
private:
void sendPosition(bool do_interpolate, bool is_movement_end);
@ -238,6 +245,7 @@ private:
v3f m_last_sent_velocity;
float m_last_sent_position_timer;
float m_last_sent_move_precision;
aabb3f m_collisionbox;
};
#endif

View file

@ -812,6 +812,8 @@ void ServerEnvironment::clearAllObjects()
i.atEnd()==false; i++)
{
ServerActiveObject* obj = i.getNode()->getValue();
if(obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
continue;
u16 id = i.getNode()->getKey();
v3f objectpos = obj->getBasePosition();
// Delete static object if block is loaded
@ -933,7 +935,7 @@ void ServerEnvironment::step(float dtime)
v3f playerpos = player->getPosition();
// Move
player->move(dtime, *m_map, 100*BS);
player->move(dtime, this, 100*BS);
/*
Add footsteps to grass
@ -1816,6 +1818,22 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
}
}
//get a list of all active objects
core::list<ActiveObject*> ServerEnvironment::getActiveObjects() {
core::list<ActiveObject*> retval;
if (m_active_objects.size() > 0 )
{
for (core::map<u16, ServerActiveObject*>::Iterator iter=m_active_objects.getIterator();
iter.atEnd()==false; iter++) {
retval.push_back(iter.getNode()->getValue());
}
}
return retval;
}
#ifndef SERVER
@ -1976,7 +1994,7 @@ void ClientEnvironment::step(float dtime)
Move the lplayer.
This also does collision detection.
*/
lplayer->move(dtime_part, *m_map, position_max_increment,
lplayer->move(dtime_part, this, position_max_increment,
&player_collisions);
}
}
@ -1998,16 +2016,7 @@ void ClientEnvironment::step(float dtime)
{
f32 damage_f = (info.speed - tolerance)/BS*factor;
u16 damage = (u16)(damage_f+0.5);
if(lplayer->hp > damage)
lplayer->hp -= damage;
else
lplayer->hp = 0;
ClientEnvEvent event;
event.type = CEE_PLAYER_DAMAGE;
event.player_damage.amount = damage;
event.player_damage.send_to_server = true;
m_client_event_queue.push_back(event);
damageLocalPlayer(damage, true);
}
}
}
@ -2037,11 +2046,7 @@ void ClientEnvironment::step(float dtime)
if(damage_per_second != 0)
{
ClientEnvEvent event;
event.type = CEE_PLAYER_DAMAGE;
event.player_damage.amount = damage_per_second;
event.player_damage.send_to_server = true;
m_client_event_queue.push_back(event);
damageLocalPlayer(damage_per_second, true);
}
}
@ -2060,7 +2065,7 @@ void ClientEnvironment::step(float dtime)
if(player->isLocal() == false)
{
// Move
player->move(dtime, *m_map, 100*BS);
player->move(dtime, this, 100*BS);
}
@ -2337,6 +2342,21 @@ ClientEnvEvent ClientEnvironment::getClientEvent()
return m_client_event_queue.pop_front();
}
//get a list of all active objects
core::list<ActiveObject*> ClientEnvironment::getActiveObjects() {
core::list<ActiveObject*> retval;
if (m_active_objects.size() > 0 )
{
for (core::map<u16, ClientActiveObject*>::Iterator iter=m_active_objects.getIterator();
iter.atEnd()==false; iter++)
{
retval.push_back(iter.getNode()->getValue());
}
}
return retval;
}
#endif // #ifndef SERVER

View file

@ -87,6 +87,9 @@ public:
return m_time_of_day;
}
virtual IGameDef *getGameDef() = 0;
virtual core::list<ActiveObject*> getActiveObjects() = 0;
protected:
// peer_ids in here should be unique, except that there may be many 0s
core::list<Player*> m_players;
@ -283,6 +286,8 @@ public:
// This makes stuff happen
void step(f32 dtime);
//get a list of all active objects
core::list<ActiveObject*> getActiveObjects();
private:
/*
@ -465,6 +470,9 @@ public:
// Get event from queue. CEE_NONE is returned if queue is empty.
ClientEnvEvent getClientEvent();
//get a list of all active objects
core::list<ActiveObject*> getActiveObjects();
private:
ClientMap *m_map;
scene::ISceneManager *m_smgr;

View file

@ -293,44 +293,40 @@ 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();
// First try to find a pointed at active object
if(look_for_object)
{
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();
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);
hilightbox = core::aabbox3d<f32>(
selection_box->MinEdge + pos,
selection_box->MaxEdge + pos
);
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
@ -366,196 +362,88 @@ PointedThing getPointedThing(Client *client, v3f player_position,
if(!isPointableNode(n, client, liquids_pointable))
continue;
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),
};
std::vector<aabb3f> boxes = n.getSelectionBoxes(client->ndef());
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] = {
f32 d = 0.001*BS;
aabb3f faceboxes[6] = {
// X-
core::aabbox3d<f32>(
aabb3f(
box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z,
box.MinEdge.X+d, box.MaxEdge.Y, box.MaxEdge.Z
),
// X+
core::aabbox3d<f32>(
aabb3f(
box.MaxEdge.X-d, box.MinEdge.Y, box.MinEdge.Z,
box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z
),
// Y-
core::aabbox3d<f32>(
aabb3f(
box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z,
box.MaxEdge.X, box.MinEdge.Y+d, box.MaxEdge.Z
),
// Y+
core::aabbox3d<f32>(
aabb3f(
box.MinEdge.X, box.MaxEdge.Y-d, box.MinEdge.Z,
box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z
),
// Z-
core::aabbox3d<f32>(
aabb3f(
box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z,
box.MaxEdge.X, box.MaxEdge.Y, box.MinEdge.Z+d
),
// Z+
core::aabbox3d<f32>(
aabb3f(
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;
v3f centerpoint = faceboxes[j].getCenter();
f32 distance = (centerpoint - camera_position).getLength();
if(distance >= mindistance)
continue;
if(!faceboxes[i].intersectsWithLine(shootline))
if(!faceboxes[j].intersectsWithLine(shootline))
continue;
result.type = POINTEDTHING_NODE;
result.node_undersurface = np;
result.node_abovesurface = np+facedirs[i];
result.node_abovesurface = np+facedirs[j];
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] =
hilightboxes.clear();
for(std::vector<aabb3f>::const_iterator
i2 = boxes.begin();
i2 != boxes.end(); i2++)
{
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))
{
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;
@ -1112,9 +1000,6 @@ void the_game(
else
hotbar_imagesize = 64;
// Hilight boxes collected during the loop and displayed
core::list< core::aabbox3d<f32> > hilightboxes;
// Info text
std::wstring infotext;
@ -1821,8 +1706,8 @@ 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;
// Hilight boxes collected during the loop and displayed
std::vector<aabb3f> hilightboxes;
ClientActiveObject *selected_object = NULL;
PointedThing pointed = getPointedThing(
@ -1831,7 +1716,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)
@ -1840,12 +1725,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
@ -2470,9 +2349,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="

View file

@ -21,7 +21,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#if 1
/*
Made using this and adding 230 as the second last one:
Made using this and:
- adding 220 as the second last one
- replacing the third last one (212) with 195
#!/usr/bin/python
@ -63,8 +65,8 @@ u8 light_decode_table[LIGHT_MAX+1] =
121,
146,
176,
212,
230,
195,
220,
255,
};
#endif

View file

@ -132,7 +132,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)
{

View file

@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes.h"
#include "light.h"
#include <vector>
class INodeDefManager;
@ -195,6 +196,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
*/

View file

@ -32,34 +32,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);
}
}
/*
@ -143,6 +183,7 @@ void ContentFeatures::reset()
liquid_viscosity = 0;
light_source = 0;
damage_per_second = 0;
node_box = NodeBox();
selection_box = NodeBox();
material = MaterialProperties();
// Make unknown blocks diggable
@ -154,7 +195,7 @@ void ContentFeatures::reset()
void ContentFeatures::serialize(std::ostream &os)
{
writeU8(os, 1); // version
writeU8(os, 2); // version
os<<serializeString(name);
writeU8(os, drawtype);
writeF1000(os, visual_scale);
@ -187,6 +228,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);
material.serialize(os);
writeU8(os, legacy_facedir_simple);
@ -196,7 +238,7 @@ void ContentFeatures::serialize(std::ostream &os)
void ContentFeatures::deSerialize(std::istream &is)
{
int version = readU8(is);
if(version != 1)
if(version != 2)
throw SerializationError("unsupported ContentFeatures version");
name = deSerializeString(is);
drawtype = (enum NodeDrawType)readU8(is);
@ -232,6 +274,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);
material.deSerialize(is);
legacy_facedir_simple = readU8(is);
@ -509,6 +552,7 @@ public:
case NDT_PLANTLIKE:
case NDT_FENCELIKE:
case NDT_RAILLIKE:
case NDT_NODEBOX:
f->solidness = 0;
break;
}

View file

@ -62,7 +62,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)
};
@ -71,22 +71,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
aabb3f wall_top;
aabb3f wall_bottom;
aabb3f 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)
{}
NodeBox()
{ reset(); }
void reset();
void serialize(std::ostream &os) const;
void deSerialize(std::istream &is);
};
@ -122,6 +116,7 @@ enum NodeDrawType
NDT_PLANTLIKE,
NDT_FENCELIKE,
NDT_RAILLIKE,
NDT_NODEBOX,
};
#define CF_SPECIAL_COUNT 2
@ -193,6 +188,7 @@ struct ContentFeatures
// Amount of light the node emits
u8 light_source;
u32 damage_per_second;
NodeBox node_box;
NodeBox selection_box;
MaterialProperties material;
// Compatibility with old maps

View file

@ -199,29 +199,21 @@ LocalPlayer::~LocalPlayer()
{
}
void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
void LocalPlayer::move(f32 dtime, Environment* env, f32 pos_max_d,
core::list<CollisionInfo> *collision_info)
{
Map& map = env->getMap();
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 free_move = g_settings->getBool("free_move");
if(free_move)
{
position += m_speed * dtime;
setPosition(position);
return;
}
@ -230,9 +222,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)
*/
@ -282,30 +271,12 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
is_climbing = false;
}
/*
Collision uncertainty radius
Make it a bit larger than the maximum distance of movement
*/
//f32 d = pos_max_d * 1.1;
// A fairly large value in here makes moving smoother
f32 d = 0.15*BS;
// This should always apply, otherwise there are glitches
assert(d > pos_max_d);
float player_radius = BS*0.35;
float player_height = BS*1.7;
// 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
@ -321,23 +292,8 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
if(position.Y < min_y)
{
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);
}
}*/
}
}
@ -345,176 +301,31 @@ 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(env,
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.
Player is allowed to jump when this is true.
*/
touching_ground = false;
touching_ground = result.touching_ground;
/*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
bool standing_on_unloaded = result.standing_on_unloaded;
/*
Check the nodes under the player to see from which node the
@ -610,9 +421,9 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
}
}
void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
void LocalPlayer::move(f32 dtime,Environment* env, f32 pos_max_d)
{
move(dtime, map, pos_max_d, NULL);
move(dtime, env, pos_max_d, NULL);
}
void LocalPlayer::applyControl(float dtime)
@ -713,14 +524,17 @@ void LocalPlayer::applyControl(float dtime)
}
else if(touching_ground)
{
v3f speed = getSpeed();
/*
NOTE: The d value in move() affects jump height by
raising the height at which the jump speed is kept
at its starting value
*/
speed.Y = 6.5*BS;
setSpeed(speed);
v3f speed = getSpeed();
if(speed.Y >= -0.5*BS)
{
speed.Y = 6.5*BS;
setSpeed(speed);
}
}
// Use the oscillating value for getting out of water
// (so that the player doesn't fly on the surface)

View file

@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Map;
class IGameDef;
struct CollisionInfo;
class Environment;
class Player
{
@ -42,7 +43,7 @@ public:
void resetInventory();
//void move(f32 dtime, Map &map);
virtual void move(f32 dtime, Map &map, f32 pos_max_d) = 0;
virtual void move(f32 dtime, Environment* env, f32 pos_max_d) = 0;
v3f getSpeed()
{
@ -231,9 +232,9 @@ public:
return true;
}
void move(f32 dtime, Map &map, f32 pos_max_d,
void move(f32 dtime, Environment* env, f32 pos_max_d,
core::list<CollisionInfo> *collision_info);
void move(f32 dtime, Map &map, f32 pos_max_d);
void move(f32 dtime, Environment* env, f32 pos_max_d);
void applyControl(float dtime);

View file

@ -381,6 +381,7 @@ struct EnumString es_DrawType[] =
{NDT_PLANTLIKE, "plantlike"},
{NDT_FENCELIKE, "fencelike"},
{NDT_RAILLIKE, "raillike"},
{NDT_NODEBOX, "nodebox"},
{0, NULL},
};
@ -587,32 +588,93 @@ 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;
}
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 NodeBox read_nodebox(lua_State *L, int index)
{
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;
}
/*
MaterialProperties
*/
@ -932,33 +994,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);
lua_getfield(L, index, "material");
if(lua_istable(L, -1)){
f.material = read_material_properties(L, -1);
@ -4363,7 +4408,7 @@ void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
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);

View file

@ -1270,7 +1270,8 @@ void Server::AsyncRunStep()
/*
Handle player HPs (die if hp=0)
*/
HandlePlayerHP(player, 0);
if(player->hp == 0 && player->m_hp_not_sent)
DiePlayer(player);
/*
Send player inventories and HPs if necessary
@ -1284,9 +1285,9 @@ void Server::AsyncRunStep()
}
/*
Add to environment if is not in respawn screen
Add to environment
*/
if(!player->m_is_in_environment && !player->m_respawn_active){
if(!player->m_is_in_environment){
player->m_removed = false;
player->setId(0);
m_env->addActiveObject(player);
@ -2129,6 +2130,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Send HP
SendPlayerHP(player);
// Show death screen if necessary
if(player->hp == 0)
SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
// Send time of day
{
SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
@ -2159,11 +2164,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
}
/*
Check HP, respawn if necessary
*/
HandlePlayerHP(player, 0);
/*
Print out action
*/
@ -2662,16 +2662,25 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
std::istringstream is(datastring, std::ios_base::binary);
u8 damage = readU8(is);
ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
if(g_settings->getBool("enable_damage"))
{
actionstream<<player->getName()<<" damaged by "
<<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
<<std::endl;
HandlePlayerHP(player, damage);
srp->setHP(srp->getHP() - damage);
if(srp->getHP() == 0 && srp->m_hp_not_sent)
DiePlayer(srp);
if(srp->m_hp_not_sent)
SendPlayerHP(player);
}
else
{
// Force send (to correct the client's predicted HP)
SendPlayerHP(player);
}
}
@ -2751,8 +2760,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
if(player->hp != 0)
return;
srp->m_respawn_active = false;
RespawnPlayer(player);
actionstream<<player->getName()<<" respawns at "
@ -2811,6 +2818,13 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
infostream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="<<item_i<<", pointed="<<pointed.dump()<<std::endl;
if(player->hp == 0)
{
infostream<<"TOSERVER_INTERACT: "<<srp->getName()
<<" tried to interact, but is dead!"<<std::endl;
return;
}
v3f player_pos = srp->m_last_good_position;
// Update wielded item
@ -3968,26 +3982,14 @@ void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend
Something random
*/
void Server::HandlePlayerHP(Player *player, s16 damage)
void Server::DiePlayer(Player *player)
{
ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
if(srp->m_respawn_active)
return;
if(player->hp > damage)
{
if(damage != 0){
player->hp -= damage;
SendPlayerHP(player);
}
return;
}
infostream<<"Server::HandlePlayerHP(): Player "
infostream<<"Server::DiePlayer(): Player "
<<player->getName()<<" dies"<<std::endl;
player->hp = 0;
srp->setHP(0);
// Trigger scripted stuff
scriptapi_on_dieplayer(m_lua, srp);
@ -3999,24 +4001,13 @@ void Server::HandlePlayerHP(Player *player, s16 damage)
}
SendPlayerHP(player);
RemoteClient *client = getClient(player->peer_id);
if(client->net_proto_version >= 3)
{
SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
srp->m_removed = true;
srp->m_respawn_active = true;
}
else
{
RespawnPlayer(player);
}
SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
}
void Server::RespawnPlayer(Player *player)
{
player->hp = 20;
ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
srp->setHP(20);
bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
if(!repositioned){
v3f pos = findSpawnPos(m_env->getServerMap());
@ -4268,6 +4259,14 @@ ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
// Got one.
player->peer_id = peer_id;
// Re-add player to environment
if(player->m_removed)
{
player->m_removed = false;
player->setId(0);
m_env->addActiveObject(player);
}
// Reset inventory to creative if in creative mode
if(g_settings->getBool("creative_mode"))
{
@ -4305,12 +4304,13 @@ ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
v3f pos = findSpawnPos(m_env->getServerMap());
player = new ServerRemotePlayer(m_env, pos, peer_id, name);
ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
/* Add player to environment */
m_env->addPlayer(player);
m_env->addActiveObject(srp);
/* Run scripts */
ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
scriptapi_on_newplayer(m_lua, srp);
/* Add stuff to inventory */

View file

@ -592,7 +592,7 @@ private:
Something random
*/
void HandlePlayerHP(Player *player, s16 damage);
void DiePlayer(Player *player);
void RespawnPlayer(Player *player);
void UpdateCrafting(u16 peer_id);

View file

@ -34,7 +34,6 @@ ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env):
m_wield_index(0),
m_inventory_not_sent(false),
m_hp_not_sent(false),
m_respawn_active(false),
m_is_in_environment(false),
m_time_from_last_punch(0),
m_position_not_sent(false)
@ -159,6 +158,8 @@ std::string ServerRemotePlayer::getClientInitializationData()
writeV3F1000(os, getPosition());
// yaw
writeF1000(os, getYaw());
// dead
writeU8(os, getHP() == 0);
return os.str();
}
@ -247,10 +248,34 @@ void ServerRemotePlayer::setHP(s16 hp_)
if(hp != oldhp)
m_hp_not_sent = true;
// On death or reincarnation send an active object message
if((hp == 0) != (oldhp == 0))
{
std::ostringstream os(std::ios::binary);
// command (2 = update death state)
writeU8(os, 2);
// dead?
writeU8(os, hp == 0);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
}
s16 ServerRemotePlayer::getHP()
{
return hp;
}
aabb3f* ServerRemotePlayer::getCollisionBox() {
m_collisionbox.MinEdge = aabb3f(-BS/3.,0.0,-BS/3., BS/3.,BS*2.0,BS/3.).MinEdge;
m_collisionbox.MaxEdge = aabb3f(-BS/3.,0.0,-BS/3., BS/3.,BS*2.0,BS/3.).MaxEdge;
m_collisionbox.MinEdge += m_position;
m_collisionbox.MaxEdge += m_position;
return &m_collisionbox;
}

View file

@ -40,7 +40,7 @@ public:
virtual bool isLocal() const
{ return false; }
virtual void move(f32 dtime, Map &map, f32 pos_max_d)
virtual void move(f32 dtime, Environment* env, f32 pos_max_d)
{
}
@ -90,13 +90,13 @@ public:
int m_wield_index;
bool m_inventory_not_sent;
bool m_hp_not_sent;
bool m_respawn_active;
bool m_is_in_environment;
// Incremented by step(), read and reset by Server
float m_time_from_last_punch;
aabb3f* getCollisionBox();
private:
bool m_position_not_sent;
aabb3f m_collisionbox;
};
#endif

View file

@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "utility.h"
#include "serialization.h"
#include "voxel.h"
#include "collision.h"
#include <sstream>
#include "porting.h"
#include "content_mapnode.h"
@ -816,6 +817,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()
@ -1279,6 +1427,7 @@ void run_tests()
TESTPARAMS(TestVoxelManipulator, ndef);
//TEST(TestMapBlock);
//TEST(TestMapSector);
TEST(TestCollision);
if(INTERNET_SIMULATOR == false){
TEST(TestSocket);
dout_con<<"=== BEGIN RUNNING UNIT TESTS FOR CONNECTION ==="<<std::endl;

View file

@ -58,6 +58,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,