From ee63b94f2c9e176f549c4446391e4c59f5a5be53 Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Sun, 5 Aug 2018 22:28:41 +0200 Subject: [PATCH] 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. --- src/clientobject.h | 1 + src/collision.cpp | 22 ++++++++++++++++------ src/content_cao.h | 4 ++-- src/content_sao.cpp | 9 ++++----- src/content_sao.h | 5 ++++- src/serverobject.h | 1 + 6 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/clientobject.h b/src/clientobject.h index c85e1ec91..9377d1e67 100644 --- a/src/clientobject.h +++ b/src/clientobject.h @@ -51,6 +51,7 @@ public: virtual scene::ISceneNode *getSceneNode() { return NULL; } virtual scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode() { return NULL; } virtual bool isLocalPlayer() const {return false;} + virtual ClientActiveObject *getParent() const { return nullptr; }; virtual void setAttachments() {} virtual bool doShowSelectionBox(){return true;} diff --git a/src/collision.cpp b/src/collision.cpp index 99874dbfd..48a681dca 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -360,11 +360,16 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, #ifndef SERVER ClientEnvironment *c_env = dynamic_cast(env); 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 clientobjects; - c_env->getActiveObjects(*pos_f, distance * 1.5f, clientobjects); + c_env->getActiveObjects(*pos_f, distance, 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); } } @@ -374,12 +379,17 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, { ServerEnvironment *s_env = dynamic_cast(env); 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 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) { ServerActiveObject *current = s_env->getActiveObject(obj_id); - if (!self || (self != current)) { + + if (!self || (self != current && + self != current->getParent())) { objects.push_back((ActiveObject*)current); } } diff --git a/src/content_cao.h b/src/content_cao.h index cd58681bb..9e688d78d 100644 --- a/src/content_cao.h +++ b/src/content_cao.h @@ -139,8 +139,6 @@ public: void processInitData(const std::string &data); - ClientActiveObject *getParent() const; - bool getCollisionBox(aabb3f *toset) const; bool collideWithObjects() const; @@ -181,6 +179,8 @@ public: void setChildrenVisible(bool toset); + ClientActiveObject *getParent() const; + void setAttachments(); void removeFromScene(bool permanent); diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 4ef52c7f2..f32294191 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -118,15 +118,14 @@ UnitSAO::UnitSAO(ServerEnvironment *env, v3f pos): m_armor_groups["fleshy"] = 100; } -bool UnitSAO::isAttached() const +ServerActiveObject *UnitSAO::getParent() const { if (!m_attachment_parent_id) - return false; + return nullptr; // Check if the parent still exists ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id); - if (obj) - return true; - return false; + + return obj; } void UnitSAO::setArmorGroups(const ItemGroupList &armor_groups) diff --git a/src/content_sao.h b/src/content_sao.h index 8510015c5..e45a4028e 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -42,7 +42,9 @@ public: // Use a function, if isDead can be defined by other conditions bool isDead() const { return m_hp == 0; } - bool isAttached() const; + inline bool isAttached() const + { return getParent(); } + void setArmorGroups(const ItemGroupList &armor_groups); const ItemGroupList &getArmorGroups(); 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 removeAttachmentChild(int child_id); const std::unordered_set &getAttachmentChildIds(); + ServerActiveObject *getParent() const; ObjectProperties* accessObjectProperties(); void notifyObjectPropertiesModified(); protected: diff --git a/src/serverobject.h b/src/serverobject.h index ba205f6a5..04d52425d 100644 --- a/src/serverobject.h +++ b/src/serverobject.h @@ -173,6 +173,7 @@ public: {} virtual const std::unordered_set &getAttachmentChildIds() { static const std::unordered_set rv; return rv; } + virtual ServerActiveObject *getParent() const { return nullptr; } virtual ObjectProperties* accessObjectProperties() { return NULL; } virtual void notifyObjectPropertiesModified()