diff --git a/src/activeobject.h b/src/activeobject.h index e454f2c8c..1a75fba2e 100644 --- a/src/activeobject.h +++ b/src/activeobject.h @@ -61,7 +61,7 @@ public: } virtual u8 getType() const = 0; - + virtual bool getCollisionBox(aabb3f *toset) = 0; protected: u16 m_id; // 0 is invalid, "no id" }; diff --git a/src/collision.cpp b/src/collision.cpp index 58517b779..806a3b720 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -23,7 +23,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodedef.h" #include "gamedef.h" #include "log.h" +#include "environment.h" +#include "serverobject.h" #include +#include #include "util/timetaker.h" #include "main.h" // g_profiler #include "profiler.h" @@ -186,11 +189,12 @@ bool wouldCollideWithCeiling( } -collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef, +collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, f32 pos_max_d, const aabb3f &box_0, f32 stepheight, f32 dtime, v3f &pos_f, v3f &speed_f, v3f &accel_f) { + Map *map = &env->getMap(); //TimeTaker tt("collisionMoveSimple"); ScopeProfiler sp(g_profiler, "collisionMoveSimple avg", SPT_AVG); @@ -215,6 +219,7 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef, std::vector cboxes; std::vector is_unloaded; std::vector is_step_up; + std::vector is_object; std::vector bouncy_values; std::vector node_positions; { @@ -256,6 +261,7 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef, is_step_up.push_back(false); bouncy_values.push_back(n_bouncy_value); node_positions.push_back(p); + is_object.push_back(false); } } catch(InvalidPositionException &e) @@ -267,14 +273,72 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef, is_step_up.push_back(false); bouncy_values.push_back(0); node_positions.push_back(p); + is_object.push_back(false); } } } // tt2 + { + ScopeProfiler sp(g_profiler, "collisionMoveSimple objects avg", SPT_AVG); + //TimeTaker tt3("collisionMoveSimple collect object boxes"); + + /* add object boxes to cboxes */ + + + std::list objects; +#ifndef SERVER + ClientEnvironment *c_env = dynamic_cast(env); + if (c_env != 0) + { + f32 distance = speed_f.getLength(); + std::vector clientobjects; + c_env->getActiveObjects(pos_f,distance * 1.5,clientobjects); + for (int i=0; i < clientobjects.size(); i++) + { + objects.push_back((ActiveObject*)clientobjects[i].obj); + } + } + else +#endif + { + ServerEnvironment *s_env = dynamic_cast(env); + if (s_env != 0) + { + f32 distance = speed_f.getLength(); + std::set s_objects = s_env->getObjectsInsideRadius(pos_f,distance * 1.5); + for (std::set::iterator iter = s_objects.begin(); iter != s_objects.end(); iter++) + { + ServerActiveObject *current = s_env->getActiveObject(*iter); + objects.push_back((ActiveObject*)current); + } + } + } + + for (std::list::const_iterator iter = objects.begin();iter != objects.end(); ++iter) + { + ActiveObject *object = *iter; + + if (object != NULL) + { + aabb3f object_collisionbox; + if (object->getCollisionBox(&object_collisionbox)) + { + cboxes.push_back(object_collisionbox); + is_unloaded.push_back(false); + is_step_up.push_back(false); + bouncy_values.push_back(0); + node_positions.push_back(v3s16(0,0,0)); + is_object.push_back(true); + } + } + } + } //tt3 + assert(cboxes.size() == is_unloaded.size()); assert(cboxes.size() == is_step_up.size()); assert(cboxes.size() == bouncy_values.size()); assert(cboxes.size() == node_positions.size()); + assert(cboxes.size() == is_object.size()); /* Collision detection @@ -386,7 +450,11 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef, is_collision = false; CollisionInfo info; - info.type = COLLISION_NODE; + if (is_object[nearest_boxindex]) { + info.type = COLLISION_OBJECT; + } + else + info.type = COLLISION_NODE; info.node_p = node_positions[nearest_boxindex]; info.bouncy = bouncy; info.old_speed = speed_f; diff --git a/src/collision.h b/src/collision.h index 38cc3efb3..117818456 100644 --- a/src/collision.h +++ b/src/collision.h @@ -25,10 +25,12 @@ with this program; if not, write to the Free Software Foundation, Inc., class Map; class IGameDef; +class Environment; enum CollisionType { - COLLISION_NODE + COLLISION_NODE, + COLLISION_OBJECT, }; struct CollisionInfo @@ -65,7 +67,7 @@ struct collisionMoveResult }; // Moves using a single iteration; speed should not exceed pos_max_d/dtime -collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef, +collisionMoveResult collisionMoveSimple(Environment *env,IGameDef *gamedef, f32 pos_max_d, const aabb3f &box_0, f32 stepheight, f32 dtime, v3f &pos_f, v3f &speed_f, v3f &accel_f); diff --git a/src/content_cao.cpp b/src/content_cao.cpp index 269667fe5..ee1009b6c 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -174,6 +174,7 @@ public: void processMessage(const std::string &data); + bool getCollisionBox(aabb3f *toset) { return false; } private: scene::IMeshSceneNode *m_node; v3f m_position; @@ -329,6 +330,7 @@ public: std::string infoText() {return m_infotext;} + bool getCollisionBox(aabb3f *toset) { return false; } private: core::aabbox3d m_selection_box; scene::IMeshSceneNode *m_node; @@ -643,6 +645,22 @@ public: ClientActiveObject::registerType(getType(), create); } + bool getCollisionBox(aabb3f *toset) { + if (m_prop.physical) { + aabb3f retval; + //update collision box + toset->MinEdge = m_prop.collisionbox.MinEdge * BS; + toset->MaxEdge = m_prop.collisionbox.MaxEdge * BS; + + toset->MinEdge += m_position; + toset->MaxEdge += m_position; + + return true; + } + + return false; + } + void initialize(const std::string &data) { infostream<<"GenericCAO: Got init data"<getGameDef(); - moveresult = collisionMoveSimple(&env->getMap(), gamedef, + moveresult = collisionMoveSimple(env,env->getGameDef(), pos_max_d, box, stepheight, dtime, p_pos, p_velocity, p_acceleration); // Apply results diff --git a/src/content_sao.cpp b/src/content_sao.cpp index d7afc31d8..468dfd218 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -64,6 +64,10 @@ public: infostream<<"DummyLoadSAO step"<getGameDef(); - moveresult = collisionMoveSimple(&m_env->getMap(), gamedef, + moveresult = collisionMoveSimple(m_env,m_env->getGameDef(), pos_max_d, box, stepheight, dtime, pos_f, m_speed_f, accel_f); @@ -314,6 +321,10 @@ public: return 0; } + bool getCollisionBox(aabb3f *toset) { + return false; + } + private: std::string m_itemstring; @@ -490,8 +501,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) v3f p_pos = m_base_position; v3f p_velocity = m_velocity; v3f p_acceleration = m_acceleration; - IGameDef *gamedef = m_env->getGameDef(); - moveresult = collisionMoveSimple(&m_env->getMap(), gamedef, + moveresult = collisionMoveSimple(m_env,m_env->getGameDef(), pos_max_d, box, stepheight, dtime, p_pos, p_velocity, p_acceleration); // Apply results @@ -880,6 +890,22 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) m_messages_out.push_back(aom); } +bool LuaEntitySAO::getCollisionBox(aabb3f *toset) { + if (m_prop.physical) + { + //update collision box + toset->MinEdge = m_prop.collisionbox.MinEdge * BS; + toset->MaxEdge = m_prop.collisionbox.MaxEdge * BS; + + toset->MinEdge += m_base_position; + toset->MaxEdge += m_base_position; + + return true; + } + + return false; +} + /* PlayerSAO */ @@ -1434,3 +1460,7 @@ std::string PlayerSAO::getPropertyPacket() return gob_cmd_set_properties(m_prop); } +bool PlayerSAO::getCollisionBox(aabb3f *toset) { + //player collision handling is already done clientside no need to do it twice + return false; +} diff --git a/src/content_sao.h b/src/content_sao.h index e5b89d447..60ca8f319 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -78,6 +78,7 @@ public: void setSprite(v2s16 p, int num_frames, float framelength, bool select_horiz_by_yawpitch); std::string getName(); + bool getCollisionBox(aabb3f *toset); private: std::string getPropertyPacket(); void sendPosition(bool do_interpolate, bool is_movement_end); @@ -235,6 +236,8 @@ public: m_is_singleplayer = is_singleplayer; } + bool getCollisionBox(aabb3f *toset); + private: std::string getPropertyPacket(); diff --git a/src/environment.cpp b/src/environment.cpp index 7c93090b6..07cdb24d1 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -2096,7 +2096,7 @@ void ClientEnvironment::step(float dtime) Move the lplayer. This also does collision detection. */ - lplayer->move(dtime_part, *m_map, position_max_increment, + lplayer->move(dtime_part, this, position_max_increment, &player_collisions); } } diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 9c36e75e6..ee9b41c58 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "gamedef.h" #include "nodedef.h" #include "settings.h" +#include "environment.h" #include "map.h" #include "util/numeric.h" @@ -57,9 +58,10 @@ LocalPlayer::~LocalPlayer() { } -void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d, +void LocalPlayer::move(f32 dtime, ClientEnvironment *env, f32 pos_max_d, std::list *collision_info) { + Map *map = &env->getMap(); INodeDefManager *nodemgr = m_gamedef->ndef(); v3f position = getPosition(); @@ -97,15 +99,15 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d, if(in_liquid) { v3s16 pp = floatToInt(position + v3f(0,BS*0.1,0), BS); - in_liquid = nodemgr->get(map.getNode(pp).getContent()).isLiquid(); - liquid_viscosity = nodemgr->get(map.getNode(pp).getContent()).liquid_viscosity; + in_liquid = nodemgr->get(map->getNode(pp).getContent()).isLiquid(); + liquid_viscosity = nodemgr->get(map->getNode(pp).getContent()).liquid_viscosity; } // If not in liquid, the threshold of going in is at lower y else { v3s16 pp = floatToInt(position + v3f(0,BS*0.5,0), BS); - in_liquid = nodemgr->get(map.getNode(pp).getContent()).isLiquid(); - liquid_viscosity = nodemgr->get(map.getNode(pp).getContent()).liquid_viscosity; + in_liquid = nodemgr->get(map->getNode(pp).getContent()).isLiquid(); + liquid_viscosity = nodemgr->get(map->getNode(pp).getContent()).liquid_viscosity; } } catch(InvalidPositionException &e) @@ -118,7 +120,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d, */ try{ v3s16 pp = floatToInt(position + v3f(0,0,0), BS); - in_liquid_stable = nodemgr->get(map.getNode(pp).getContent()).isLiquid(); + in_liquid_stable = nodemgr->get(map->getNode(pp).getContent()).isLiquid(); } catch(InvalidPositionException &e) { @@ -132,8 +134,8 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d, try { v3s16 pp = floatToInt(position + v3f(0,0.5*BS,0), BS); v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS); - is_climbing = ((nodemgr->get(map.getNode(pp).getContent()).climbable || - nodemgr->get(map.getNode(pp2).getContent()).climbable) && !free_move); + is_climbing = ((nodemgr->get(map->getNode(pp).getContent()).climbable || + nodemgr->get(map->getNode(pp2).getContent()).climbable) && !free_move); } catch(InvalidPositionException &e) { @@ -197,7 +199,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d, v3f accel_f = v3f(0,0,0); - collisionMoveResult result = collisionMoveSimple(&map, m_gamedef, + collisionMoveResult result = collisionMoveSimple(env, m_gamedef, pos_max_d, playerbox, player_stepheight, dtime, position, m_speed, accel_f); @@ -219,7 +221,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d, */ v3s16 current_node = floatToInt(position - v3f(0,BS/2,0), BS); if(m_sneak_node_exists && - nodemgr->get(map.getNodeNoEx(m_old_node_below)).name == "air" && + nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" && m_old_node_below_type != "air") { // Old node appears to have been removed; that is, @@ -227,7 +229,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d, m_need_to_get_new_sneak_node = false; m_sneak_node_exists = false; } - else if(nodemgr->get(map.getNodeNoEx(current_node)).name != "air") + else if(nodemgr->get(map->getNodeNoEx(current_node)).name != "air") { // We are on something, so make sure to recalculate the sneak // node. @@ -267,10 +269,10 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d, try{ // The node to be sneaked on has to be walkable - if(nodemgr->get(map.getNode(p)).walkable == false) + if(nodemgr->get(map->getNode(p)).walkable == false) continue; // And the node above it has to be nonwalkable - if(nodemgr->get(map.getNode(p+v3s16(0,1,0))).walkable == true) + if(nodemgr->get(map->getNode(p+v3s16(0,1,0))).walkable == true) continue; } catch(InvalidPositionException &e) @@ -331,7 +333,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d, { camera_barely_in_ceiling = false; v3s16 camera_np = floatToInt(getEyePosition(), BS); - MapNode n = map.getNodeNoEx(camera_np); + MapNode n = map->getNodeNoEx(camera_np); if(n.getContent() != CONTENT_IGNORE){ if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){ camera_barely_in_ceiling = true; @@ -343,21 +345,21 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d, Update the node last under the player */ m_old_node_below = floatToInt(position - v3f(0,BS/2,0), BS); - m_old_node_below_type = nodemgr->get(map.getNodeNoEx(m_old_node_below)).name; + m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name; /* Check properties of the node on which the player is standing */ - const ContentFeatures &f = nodemgr->get(map.getNodeNoEx(getStandingNodePos())); + const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos())); // Determine if jumping is possible m_can_jump = touching_ground && !in_liquid; if(itemgroup_get(f.groups, "disable_jump")) m_can_jump = false; } -void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d) +void LocalPlayer::move(f32 dtime, ClientEnvironment *env, f32 pos_max_d) { - move(dtime, map, pos_max_d, NULL); + move(dtime, env, pos_max_d, NULL); } void LocalPlayer::applyControl(float dtime) diff --git a/src/localplayer.h b/src/localplayer.h index e46ca6147..17434d379 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "player.h" #include +class ClientEnvironment; + class LocalPlayer : public Player { public: @@ -38,9 +40,9 @@ public: v3f overridePosition; - void move(f32 dtime, Map &map, f32 pos_max_d, + void move(f32 dtime, ClientEnvironment *env, f32 pos_max_d, std::list *collision_info); - void move(f32 dtime, Map &map, f32 pos_max_d); + void move(f32 dtime, ClientEnvironment *env, f32 pos_max_d); void applyControl(float dtime); diff --git a/src/particles.cpp b/src/particles.cpp index 0445d7726..1d814f619 100644 --- a/src/particles.cpp +++ b/src/particles.cpp @@ -138,7 +138,7 @@ void Particle::step(float dtime, ClientEnvironment &env) v3f p_pos = m_pos*BS; v3f p_velocity = m_velocity*BS; v3f p_acceleration = m_acceleration*BS; - collisionMoveSimple(&env.getClientMap(), m_gamedef, + collisionMoveSimple(&env, m_gamedef, BS*0.5, box, 0, dtime, p_pos, p_velocity, p_acceleration);