Compare commits

...

18 Commits

Author SHA1 Message Date
sapier
52996cd5eb maualy merged object linking interface from cao_sao_split patch 2012-02-07 21:37:42 +01:00
sapier
61ae136431 Merge branch 'master' into sapier_experimental 2012-02-07 20:52:20 +01:00
sapier
30f16ded7e Merge branch 'object_object_collision' into sapier_experimental 2012-02-07 17:04:32 +01:00
sapier
d9ffd30445 added changes missing in last commit 2012-02-07 17:01:04 +01:00
sapier
c525330153 Merge remote branch 'upstream_kahrl/collision_allow_stairs_v2' into object_object_collision 2012-02-07 16:57:36 +01:00
sapier
435ea846db move getCollisionBox from ActiveObject to interface class Collidableobject 2012-02-07 16:52:32 +01:00
Kahrl
34eabf4df0 Fix rail's selection box and tweak the logic that computes pointedthing.node_abovesurface -- you no longer can place torches above each other, or do similar placement with other nodes with non-full selection box. 2012-02-07 03:05:15 +01:00
Perttu Ahola
993821a924 Tune brightness stuff and fog color 2012-02-06 17:40:48 +02:00
Perttu Ahola
ad5ac22442 Set default maximum viewing range to a bit more than default server send range to make fog work well 2012-02-06 17:34:45 +02:00
Perttu Ahola
94b25685c5 Fix calculating if block is in viewing range; fix fog and default minimum accordingly 2012-02-06 17:27:54 +02:00
sapier
413afa77d0 Merge branch 'object_object_collision' into sapier_experimental 2012-02-05 20:35:54 +01:00
sapier
ffe6025f61 Added object <-> object collision handling (player + luaentity support only) 2012-02-05 17:23:08 +01:00
sapier
f34f75291b disabled optimization for debug build to enable step by step debugging in gdb 2012-02-05 12:47:10 +01:00
sapier
8929a47296 Merge remote branch 'upstream_kahrl/collision_allow_stairs_v2' into object_object_collision 2012-02-05 12:41:01 +01:00
Kahrl
88cdd3a363 Players stay in environment even when dead, damage flash and fall damage fixes
Don't set m_removed on dead players (dead players are indicated by hp == 0). Local
damage flash is shown whatever the cause was (even from Lua set_hp). PlayerCAO
damage flash matches duration of local damage flash. Fall damage is dealt much more consistently (this is done by disallowing jumping when speed.Y is very negative, up to now jumping could sometimes negate fall damage)
2012-02-05 12:06:55 +02:00
Perttu Ahola
e15de8b70d Modify light values to work a bit better with non-smooth lighting 2012-02-05 12:02:40 +02:00
Perttu Ahola
61016962ee Add groups = {} to item definition 2012-02-04 02:20:05 +02:00
Kahrl
6bf4931fc2 NDT_NODEBOX, collision code rewrite with step height, stairs mod -- rebased after itemdef 2012-02-02 19:20:52 +01:00
34 changed files with 1604 additions and 876 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},
@@ -1296,7 +1302,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},
},
material = minetest.digprop_dirtlike(0.75),
})

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

@@ -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

@@ -49,7 +49,7 @@ void ClientLinkableObject::stepLinkedObjects(v3f pos,float dtime) {
}
bool ClientLinkableObject::handleLinkUnlinkMessages(u8 cmd,std::istringstream* is,ClientEnvironment *m_env) {
if(cmd == AO_Message_type::Link) // Link entity
if(cmd == 3) // Link entity
{
//Object to link entity to
u16 object_id = readU16(*is);
@@ -69,7 +69,7 @@ bool ClientLinkableObject::handleLinkUnlinkMessages(u8 cmd,std::istringstream* i
return true;
}
else if(cmd == AO_Message_type::UnLink) // UnLink entity
else if(cmd == 4) // UnLink entity
{
if (this->m_Parent == NULL) {
errorstream << "Unlinking object not linked!" << std::endl;

View File

@@ -30,21 +30,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "utility.h"
#include "log.h"
//this ain't the right place to define this but until cao/sao split
//is decided it'll have to stay here
struct AO_Message_type {
static const u8 SetPosition = 0x00;
static const u8 SetTextureMod = 0x01;
static const u8 SetSprite = 0x02;
static const u8 Punched = 0x03;
static const u8 TakeDamage = 0x04;
static const u8 Shoot = 0x05;
static const u8 Link = 0x06;
static const u8 UnLink = 0x07;
};
class ClientLinkableObject {
public:
ClientLinkableObject();

View File

@@ -1,6 +1,6 @@
/*
Minetest-c55
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2012 sapier
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,9 +16,21 @@ You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __COLLIDABLEOBJECT_H__
#define __COLLIDABLEOBJECT_H__
#ifndef CONTENT_CAO_HEADER
#define CONTENT_CAO_HEADER
#include <irrlichttypes.h>
#endif
class CollidableObject {
public:
virtual aabb3f* getCollisionBox() = 0;
inline float getFlexibility() { return m_Flexibility; }
inline int getWeight() { return m_Weight; }
protected:
int m_Weight;
float m_Flexibility;
aabb3f m_collisionbox;
};
#endif //__COLLIDABLEOBJECT_H__

View File

@@ -18,32 +18,276 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "collision.h"
#include "collidableobject.h"
#include "mapblock.h"
#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++)
{
CollidableObject* object = dynamic_cast<CollidableObject*>(*iter);
if (object != NULL)
{
aabb3f* object_collisionbox = object->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
@@ -54,49 +298,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)
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,108 +431,44 @@ 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;
f32 dtime_downcount = dtime;
u32 loopcount = 0;
@@ -216,6 +476,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 +503,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

@@ -17,10 +17,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "content_cao.h"
#include "tile.h"
#include "environment.h"
#include "collision.h"
#include "collidableobject.h"
#include "clientlinkableobject.h"
#include "settings.h"
#include <ICameraSceneNode.h>
#include <ITextSceneNode.h>
@@ -1681,7 +1682,7 @@ void MobV2CAO::setLooks(const std::string &looks)
#include "luaentity_common.h"
class LuaEntityCAO : public ClientActiveObject
class LuaEntityCAO : public ClientActiveObject , public CollidableObject , public ClientLinkableObject
{
private:
core::aabbox3d<f32> m_selection_box;
@@ -1896,35 +1897,40 @@ class LuaEntityCAO : public ClientActiveObject
void step(float dtime, ClientEnvironment *env)
{
if(m_prop->physical){
core::aabbox3d<f32> box = m_prop->collisionbox;
box.MinEdge *= BS;
box.MaxEdge *= BS;
collisionMoveResult moveresult;
f32 pos_max_d = BS*0.25; // Distance per iteration
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);
// Apply results
m_position = p_pos;
m_velocity = p_velocity;
bool is_end_position = moveresult.collides;
pos_translator.update(m_position, is_end_position, dtime);
pos_translator.translate(dtime);
updateNodePos();
if(!this->isLinked()) {
if(m_prop->physical){
core::aabbox3d<f32> box = m_prop->collisionbox;
box.MinEdge *= BS;
box.MaxEdge *= BS;
collisionMoveResult moveresult;
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;
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;
m_velocity += dtime * m_acceleration;
} else {
m_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration;
m_velocity += dtime * m_acceleration;
pos_translator.update(m_position, pos_translator.aim_is_end, pos_translator.anim_time);
pos_translator.translate(dtime);
updateNodePos();
bool is_end_position = moveresult.collides;
pos_translator.update(m_position, is_end_position, dtime);
pos_translator.translate(dtime);
updateNodePos();
} else {
m_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration;
m_velocity += dtime * m_acceleration;
pos_translator.update(m_position, pos_translator.aim_is_end, pos_translator.anim_time);
pos_translator.translate(dtime);
updateNodePos();
}
}
stepLinkedObjects(this->m_position,dtime);
m_anim_timer += dtime;
if(m_anim_timer >= m_anim_framelength){
m_anim_timer -= m_anim_framelength;
@@ -2096,7 +2102,37 @@ class LuaEntityCAO : public ClientActiveObject
updateTexturePos();
}
else if (handleLinkUnlinkMessages(cmd,&is,this->m_env))
{
//Link unlink already done in handleLinkUnlinkMessages!
}
}
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;
}
void setPosition(v3f toset, float dtime){
if (this->isLinked()) {
this->m_position = toset + this->m_linkOffset;
pos_translator.update(m_position, pos_translator.aim_is_end, pos_translator.anim_time);
pos_translator.translate(dtime);
updateNodePos();
}
}
void updateLinkState(bool value) {}
};
// Prototype
@@ -2106,7 +2142,7 @@ LuaEntityCAO proto_LuaEntityCAO(NULL, NULL);
PlayerCAO
*/
class PlayerCAO : public ClientActiveObject
class PlayerCAO : public ClientActiveObject, public CollidableObject , public ClientLinkableObject
{
private:
core::aabbox3d<f32> m_selection_box;
@@ -2119,6 +2155,7 @@ class PlayerCAO : public ClientActiveObject
bool m_is_local_player;
LocalPlayer *m_local_player;
float m_damage_visual_timer;
bool m_dead;
public:
PlayerCAO(IGameDef *gamedef, ClientEnvironment *env):
@@ -2130,7 +2167,8 @@ class PlayerCAO : public ClientActiveObject
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 +2190,8 @@ class PlayerCAO : public ClientActiveObject
m_position = readV3F1000(is);
// yaw
m_yaw = readF1000(is);
// dead
m_dead = readU8(is);
pos_translator.init(m_position);
@@ -2162,6 +2202,17 @@ class PlayerCAO : public ClientActiveObject
}
}
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 +2232,8 @@ class PlayerCAO : public ClientActiveObject
{
if(m_is_local_player)
return NULL;
if(m_dead)
return NULL;
return &m_selection_box;
}
v3f getPosition()
@@ -2256,6 +2309,7 @@ class PlayerCAO : public ClientActiveObject
m_text->setPosition(v3f(0, (f32)BS*2.1, 0));
updateTextures("");
updateVisibility();
updateNodePos();
}
@@ -2273,11 +2327,11 @@ class PlayerCAO : public ClientActiveObject
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 +2339,14 @@ class PlayerCAO : public ClientActiveObject
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)
@@ -2299,8 +2361,12 @@ class PlayerCAO : public ClientActiveObject
void step(float dtime, ClientEnvironment *env)
{
pos_translator.translate(dtime);
updateNodePos();
if(!isLinked()) {
pos_translator.translate(dtime);
updateNodePos();
}
updateVisibility();
if(m_damage_visual_timer > 0){
m_damage_visual_timer -= dtime;
@@ -2331,13 +2397,20 @@ class PlayerCAO : public ClientActiveObject
{
// 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();
}
else if (handleLinkUnlinkMessages(cmd,&is,this->m_env))
{
//Link unlink already done in handleLinkUnlinkMessages!
}
}
void updateTextures(const std::string &mod)
@@ -2363,6 +2436,26 @@ class PlayerCAO : public ClientActiveObject
}
}
}
void setPosition(v3f toset, float dtime){
if (isLinked()) {
this->m_position = toset + this->m_linkOffset;
pos_translator.update(this->m_position,false);
updateNodePos();
if(m_is_local_player) {
m_local_player->setPosition(this->m_position);
}
}
else {
errorstream<<"Got linked position update but not linked"<< std::endl;
}
}
void updateLinkState(bool value) {
if(m_is_local_player) {
m_local_player->Link(value);
}
}
};
// Prototype

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,39 @@ 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;
}
bool LuaEntitySAO::sendLinkMsg(ServerActiveObject* parent,v3f offset) {
std::ostringstream os(std::ios::binary);
writeU8(os, 3);
// parameters
writeU16(os, parent->getId());
writeV3F1000(os, offset);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
return true;
}
bool LuaEntitySAO::sendUnlinkMsg() {
std::ostringstream os(std::ios::binary);
writeU8(os, 4);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
return true;
}

View File

@@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "serverobject.h"
#include "content_object.h"
#include "collidableobject.h"
#include "serverlinkableobject.h"
class TestSAO : public ServerActiveObject
{
@@ -192,7 +194,7 @@ class MobV2SAO : public ServerActiveObject
struct LuaEntityProperties;
class LuaEntitySAO : public ServerActiveObject
class LuaEntitySAO : public ServerActiveObject, public CollidableObject , public ServerLinkableObject
{
public:
LuaEntitySAO(ServerEnvironment *env, v3f pos,
@@ -222,6 +224,9 @@ class LuaEntitySAO : public ServerActiveObject
void setSprite(v2s16 p, int num_frames, float framelength,
bool select_horiz_by_yawpitch);
std::string getName();
aabb3f* getCollisionBox();
bool sendLinkMsg(ServerActiveObject* parent,v3f offset);
bool sendUnlinkMsg();
private:
void sendPosition(bool do_interpolate, bool is_movement_end);

View File

@@ -64,8 +64,9 @@ void set_default_settings(Settings *settings)
settings->setDefault("wanted_fps", "30");
settings->setDefault("fps_max", "60");
settings->setDefault("viewing_range_nodes_max", "300");
settings->setDefault("viewing_range_nodes_min", "15");
// A bit more than the server will send around the player, to make fog blend well
settings->setDefault("viewing_range_nodes_min", "35");
settings->setDefault("viewing_range_nodes_max", "128");
settings->setDefault("screenW", "800");
settings->setDefault("screenH", "600");
settings->setDefault("address", "");

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
@@ -1890,6 +1908,7 @@ void ClientEnvironment::step(float dtime)
Get the speed the player is going
*/
bool is_climbing = lplayer->is_climbing;
bool linked = lplayer->m_linked;
f32 player_speed = lplayer->getSpeed().getLength();
@@ -1918,99 +1937,91 @@ void ClientEnvironment::step(float dtime)
/*
Stuff that has a maximum time increment
*/
if (!linked) {
u32 loopcount = 0;
do
{
loopcount++;
u32 loopcount = 0;
do
{
loopcount++;
f32 dtime_part;
if(dtime_downcount > dtime_max_increment)
{
dtime_part = dtime_max_increment;
dtime_downcount -= dtime_part;
}
else
{
dtime_part = dtime_downcount;
/*
Setting this to 0 (no -=dtime_part) disables an infinite loop
when dtime_part is so small that dtime_downcount -= dtime_part
does nothing
*/
dtime_downcount = 0;
}
/*
Handle local player
*/
{
v3f lplayerpos = lplayer->getPosition();
// Apply physics
if(free_move == false && is_climbing == false)
f32 dtime_part;
if(dtime_downcount > dtime_max_increment)
{
// Gravity
v3f speed = lplayer->getSpeed();
if(lplayer->swimming_up == false)
speed.Y -= 9.81 * BS * dtime_part * 2;
dtime_part = dtime_max_increment;
dtime_downcount -= dtime_part;
}
else
{
dtime_part = dtime_downcount;
/*
Setting this to 0 (no -=dtime_part) disables an infinite loop
when dtime_part is so small that dtime_downcount -= dtime_part
does nothing
*/
dtime_downcount = 0;
}
// Water resistance
if(lplayer->in_water_stable || lplayer->in_water)
/*
Handle local player
*/
{
v3f lplayerpos = lplayer->getPosition();
// Apply physics
if(free_move == false && is_climbing == false)
{
f32 max_down = 2.0*BS;
if(speed.Y < -max_down) speed.Y = -max_down;
// Gravity
v3f speed = lplayer->getSpeed();
if(lplayer->swimming_up == false)
speed.Y -= 9.81 * BS * dtime_part * 2;
f32 max = 2.5*BS;
if(speed.getLength() > max)
// Water resistance
if(lplayer->in_water_stable || lplayer->in_water)
{
speed = speed / speed.getLength() * max;
f32 max_down = 2.0*BS;
if(speed.Y < -max_down) speed.Y = -max_down;
f32 max = 2.5*BS;
if(speed.getLength() > max)
{
speed = speed / speed.getLength() * max;
}
}
lplayer->setSpeed(speed);
}
lplayer->setSpeed(speed);
/*
Move the lplayer.
This also does collision detection.
*/
lplayer->move(dtime_part, this, position_max_increment,
&player_collisions);
}
/*
Move the lplayer.
This also does collision detection.
*/
lplayer->move(dtime_part, *m_map, position_max_increment,
&player_collisions);
}
}
while(dtime_downcount > 0.001);
while(dtime_downcount > 0.001);
//std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
//std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
for(core::list<CollisionInfo>::Iterator
i = player_collisions.begin();
i != player_collisions.end(); i++)
{
CollisionInfo &info = *i;
if(info.t == COLLISION_FALL)
for(core::list<CollisionInfo>::Iterator
i = player_collisions.begin();
i != player_collisions.end(); i++)
{
//f32 tolerance = BS*10; // 2 without damage
f32 tolerance = BS*12; // 3 without damage
f32 factor = 1;
if(info.speed > tolerance)
CollisionInfo &info = *i;
if(info.t == COLLISION_FALL)
{
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);
//f32 tolerance = BS*10; // 2 without damage
f32 tolerance = BS*12; // 3 without damage
f32 factor = 1;
if(info.speed > tolerance)
{
f32 damage_f = (info.speed - tolerance)/BS*factor;
u16 damage = (u16)(damage_f+0.5);
damageLocalPlayer(damage, true);
}
}
}
}
}
/*
A quick draft of lava damage
@@ -2037,11 +2048,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 +2067,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 +2344,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 @@ class Environment
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 @@ class ServerEnvironment : public Environment
// This makes stuff happen
void step(f32 dtime);
//get a list of all active objects
core::list<ActiveObject*> getActiveObjects();
private:
/*
@@ -465,6 +470,9 @@ class ClientEnvironment : public Environment
// 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,64 @@ PointedThing getPointedThing(Client *client, v3f player_position,
if(!isPointableNode(n, client, liquids_pointable))
continue;
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] = {
// 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 = floatToInt(centerpoint + intToFloat(facedir, d), BS);
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] =
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;
@@ -574,7 +438,7 @@ void update_skybox(video::IVideoDriver* driver, ITextureSource *tsrc,
if(g_settings->getBool("enable_farmesh"))
return;*/
if(brightness >= 0.5)
if(brightness >= 0.7)
{
skybox = smgr->addSkyBoxSceneNode(
tsrc->getTextureRaw("skybox2.png"),
@@ -1112,9 +976,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 +1682,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 +1692,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 +1701,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
@@ -2117,14 +1972,21 @@ void the_game(
u32 daynight_ratio = client.getDayNightRatio();
u8 light8 = decode_light((daynight_ratio * LIGHT_SUN) / 1000);
brightness = (float)light8/255.0;
video::SColor bgcolor = video::SColor(
255,
bgcolor_bright.getRed() * brightness,
bgcolor_bright.getGreen() * brightness,
bgcolor_bright.getBlue() * brightness);
/*skycolor.getRed() * brightness,
skycolor.getGreen() * brightness,
skycolor.getBlue() * brightness);*/
// Make night look good
brightness = brightness * 1.15 - 0.15;
video::SColor bgcolor;
if(brightness >= 0.2 && brightness < 0.7)
bgcolor = video::SColor(
255,
bgcolor_bright.getRed() * brightness,
bgcolor_bright.getGreen() * brightness*0.7,
bgcolor_bright.getBlue() * brightness*0.5);
else
bgcolor = video::SColor(
255,
bgcolor_bright.getRed() * brightness,
bgcolor_bright.getGreen() * brightness,
bgcolor_bright.getBlue() * brightness);
/*
Update skybox
@@ -2139,7 +2001,7 @@ void the_game(
{
clouds->step(dtime);
clouds->update(v2f(player_position.X, player_position.Z),
0.05+brightness*0.95);
brightness);
}
/*
@@ -2155,7 +2017,7 @@ void the_game(
farmesh->step(dtime);
farmesh->update(v2f(player_position.X, player_position.Z),
0.05+brightness*0.95, farmesh_range);
brightness, farmesh_range);
}
// Store brightness value
@@ -2174,7 +2036,7 @@ void the_game(
}
else
{
range = draw_control.wanted_range*BS + MAP_BLOCKSIZE*BS*1.5;
range = draw_control.wanted_range*BS + 0.0*MAP_BLOCKSIZE*BS;
range *= 0.9;
if(draw_control.range_all)
range = 100000*BS;
@@ -2470,9 +2332,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 @@ class CNodeDefManager: public IWritableNodeDefManager
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

@@ -188,7 +188,8 @@ void Player::deSerialize(std::istream &is)
LocalPlayer::LocalPlayer(IGameDef *gamedef):
Player(gamedef),
m_sneak_node(32767,32767,32767),
m_sneak_node_exists(false)
m_sneak_node_exists(false),
m_linked(false)
{
// Initialize hp to 0, so that no hearts will be shown if server
// doesn't support health points
@@ -199,29 +200,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 +223,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 +272,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 +293,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 +302,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 +422,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 +525,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 @@ class Player
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,14 +232,18 @@ class LocalPlayer : public Player
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);
PlayerControl control;
inline void Link(bool value) {
m_linked = value;
}
bool m_linked;
private:
// This is used for determining the sneaking range
v3s16 m_sneak_node;

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 @@ class Server : public con::PeerHandler, public MapEventReceiver,
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)
@@ -131,6 +130,9 @@ void ServerRemotePlayer::step(float dtime, bool send_recommended)
if(send_recommended == false)
return;
if(isLinked())
return;
if(m_position_not_sent)
{
m_position_not_sent = false;
@@ -159,6 +161,8 @@ std::string ServerRemotePlayer::getClientInitializationData()
writeV3F1000(os, getPosition());
// yaw
writeF1000(os, getYaw());
// dead
writeU8(os, getHP() == 0);
return os.str();
}
@@ -247,10 +251,54 @@ 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;
}
bool ServerRemotePlayer::sendLinkMsg(ServerActiveObject* parent,v3f offset) {
std::ostringstream os(std::ios::binary);
writeU8(os, 3);
// parameters
writeU16(os, parent->getId());
writeV3F1000(os, offset);
// create message and add to list
ActiveObjectMessage aom(getId(), true, os.str());
m_messages_out.push_back(aom);
return true;
}
bool ServerRemotePlayer::sendUnlinkMsg() {
std::ostringstream os(std::ios::binary);
writeU8(os, 4);
// create message and add to list
ActiveObjectMessage aom(getId(), true, os.str());
m_messages_out.push_back(aom);
return true;
}

View File

@@ -22,13 +22,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "player.h"
#include "serverobject.h"
#include "collidableobject.h"
#include "serverlinkableobject.h"
#include "content_object.h" // Object type IDs
/*
Player on the server
*/
class ServerRemotePlayer : public Player, public ServerActiveObject
class ServerRemotePlayer : public Player, public ServerActiveObject , public CollidableObject , public ServerLinkableObject
{
public:
ServerRemotePlayer(ServerEnvironment *env);
@@ -40,7 +42,7 @@ class ServerRemotePlayer : public Player, public ServerActiveObject
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,11 +92,12 @@ class ServerRemotePlayer : public Player, public ServerActiveObject
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();
bool sendLinkMsg(ServerActiveObject* parent,v3f offset);
bool sendUnlinkMsg();
private:
bool m_position_not_sent;
};

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,

View File

@@ -208,7 +208,7 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
return true;
// If block is far away, it's not in sight
if(d > range * BS)
if(d > range)
return false;
// Maximum radius of a block