Prevent objects from colliding with own child attachments (#7610)

Also, use a better distance calculation for 'collide with objects'.
Fixes the issue of a vehicle occasionally colliding with its own driver,
causing one of the velocity components to be set to zero.
This commit is contained in:
SmallJoker 2018-08-05 22:28:41 +02:00 committed by Paramat
parent 88efebdf86
commit ee63b94f2c
6 changed files with 28 additions and 14 deletions

@ -51,6 +51,7 @@ public:
virtual scene::ISceneNode *getSceneNode() { return NULL; } virtual scene::ISceneNode *getSceneNode() { return NULL; }
virtual scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode() { return NULL; } virtual scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode() { return NULL; }
virtual bool isLocalPlayer() const {return false;} virtual bool isLocalPlayer() const {return false;}
virtual ClientActiveObject *getParent() const { return nullptr; };
virtual void setAttachments() {} virtual void setAttachments() {}
virtual bool doShowSelectionBox(){return true;} virtual bool doShowSelectionBox(){return true;}

@ -360,11 +360,16 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
#ifndef SERVER #ifndef SERVER
ClientEnvironment *c_env = dynamic_cast<ClientEnvironment*>(env); ClientEnvironment *c_env = dynamic_cast<ClientEnvironment*>(env);
if (c_env != 0) { if (c_env != 0) {
f32 distance = speed_f->getLength(); // Calculate distance by speed, add own extent and 1.5m of tolerance
f32 distance = speed_f->getLength() * dtime +
box_0.getExtent().getLength() + 1.5f * BS;
std::vector<DistanceSortedActiveObject> clientobjects; std::vector<DistanceSortedActiveObject> clientobjects;
c_env->getActiveObjects(*pos_f, distance * 1.5f, clientobjects); c_env->getActiveObjects(*pos_f, distance, clientobjects);
for (auto &clientobject : clientobjects) { for (auto &clientobject : clientobjects) {
if (!self || (self != clientobject.obj)) { // Do collide with everything but itself and the parent CAO
if (!self || (self != clientobject.obj &&
self != clientobject.obj->getParent())) {
objects.push_back((ActiveObject*) clientobject.obj); objects.push_back((ActiveObject*) clientobject.obj);
} }
} }
@ -374,12 +379,17 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
{ {
ServerEnvironment *s_env = dynamic_cast<ServerEnvironment*>(env); ServerEnvironment *s_env = dynamic_cast<ServerEnvironment*>(env);
if (s_env != NULL) { if (s_env != NULL) {
f32 distance = speed_f->getLength(); // Calculate distance by speed, add own extent and 1.5m of tolerance
f32 distance = speed_f->getLength() * dtime +
box_0.getExtent().getLength() + 1.5f * BS;
std::vector<u16> s_objects; std::vector<u16> s_objects;
s_env->getObjectsInsideRadius(s_objects, *pos_f, distance * 1.5f); s_env->getObjectsInsideRadius(s_objects, *pos_f, distance);
for (u16 obj_id : s_objects) { for (u16 obj_id : s_objects) {
ServerActiveObject *current = s_env->getActiveObject(obj_id); ServerActiveObject *current = s_env->getActiveObject(obj_id);
if (!self || (self != current)) {
if (!self || (self != current &&
self != current->getParent())) {
objects.push_back((ActiveObject*)current); objects.push_back((ActiveObject*)current);
} }
} }

@ -139,8 +139,6 @@ public:
void processInitData(const std::string &data); void processInitData(const std::string &data);
ClientActiveObject *getParent() const;
bool getCollisionBox(aabb3f *toset) const; bool getCollisionBox(aabb3f *toset) const;
bool collideWithObjects() const; bool collideWithObjects() const;
@ -181,6 +179,8 @@ public:
void setChildrenVisible(bool toset); void setChildrenVisible(bool toset);
ClientActiveObject *getParent() const;
void setAttachments(); void setAttachments();
void removeFromScene(bool permanent); void removeFromScene(bool permanent);

@ -118,15 +118,14 @@ UnitSAO::UnitSAO(ServerEnvironment *env, v3f pos):
m_armor_groups["fleshy"] = 100; m_armor_groups["fleshy"] = 100;
} }
bool UnitSAO::isAttached() const ServerActiveObject *UnitSAO::getParent() const
{ {
if (!m_attachment_parent_id) if (!m_attachment_parent_id)
return false; return nullptr;
// Check if the parent still exists // Check if the parent still exists
ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id); ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id);
if (obj)
return true; return obj;
return false;
} }
void UnitSAO::setArmorGroups(const ItemGroupList &armor_groups) void UnitSAO::setArmorGroups(const ItemGroupList &armor_groups)

@ -42,7 +42,9 @@ public:
// Use a function, if isDead can be defined by other conditions // Use a function, if isDead can be defined by other conditions
bool isDead() const { return m_hp == 0; } bool isDead() const { return m_hp == 0; }
bool isAttached() const; inline bool isAttached() const
{ return getParent(); }
void setArmorGroups(const ItemGroupList &armor_groups); void setArmorGroups(const ItemGroupList &armor_groups);
const ItemGroupList &getArmorGroups(); const ItemGroupList &getArmorGroups();
void setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop); void setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop);
@ -57,6 +59,7 @@ public:
void addAttachmentChild(int child_id); void addAttachmentChild(int child_id);
void removeAttachmentChild(int child_id); void removeAttachmentChild(int child_id);
const std::unordered_set<int> &getAttachmentChildIds(); const std::unordered_set<int> &getAttachmentChildIds();
ServerActiveObject *getParent() const;
ObjectProperties* accessObjectProperties(); ObjectProperties* accessObjectProperties();
void notifyObjectPropertiesModified(); void notifyObjectPropertiesModified();
protected: protected:

@ -173,6 +173,7 @@ public:
{} {}
virtual const std::unordered_set<int> &getAttachmentChildIds() virtual const std::unordered_set<int> &getAttachmentChildIds()
{ static const std::unordered_set<int> rv; return rv; } { static const std::unordered_set<int> rv; return rv; }
virtual ServerActiveObject *getParent() const { return nullptr; }
virtual ObjectProperties* accessObjectProperties() virtual ObjectProperties* accessObjectProperties()
{ return NULL; } { return NULL; }
virtual void notifyObjectPropertiesModified() virtual void notifyObjectPropertiesModified()