From 4eb3520be8d95caf0f44d3c8a46550456b3f0be1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 13 Dec 2017 10:36:27 +0100 Subject: [PATCH 1/4] Sdk/PhysicsComponent3D: Add node synchronization control --- .../NDK/Components/PhysicsComponent3D.hpp | 5 ++- .../NDK/Components/PhysicsComponent3D.inl | 40 ++++++++++++++++--- SDK/src/NDK/Systems/PhysicsSystem3D.cpp | 20 ++++++---- 3 files changed, 51 insertions(+), 14 deletions(-) diff --git a/SDK/include/NDK/Components/PhysicsComponent3D.hpp b/SDK/include/NDK/Components/PhysicsComponent3D.hpp index 292c5f9ab..fe5e2f28a 100644 --- a/SDK/include/NDK/Components/PhysicsComponent3D.hpp +++ b/SDK/include/NDK/Components/PhysicsComponent3D.hpp @@ -19,7 +19,7 @@ namespace Ndk friend class PhysicsSystem3D; public: - PhysicsComponent3D() = default; + inline PhysicsComponent3D(); PhysicsComponent3D(const PhysicsComponent3D& physics); ~PhysicsComponent3D() = default; @@ -28,6 +28,7 @@ namespace Ndk void AddTorque(const Nz::Vector3f& torque, Nz::CoordSys coordSys = Nz::CoordSys_Global); void EnableAutoSleep(bool autoSleep); + void EnableNodeSynchronization(bool nodeSynchronization); Nz::Boxf GetAABB() const; Nz::Vector3f GetAngularDamping() const; @@ -43,6 +44,7 @@ namespace Ndk bool IsAutoSleepEnabled() const; bool IsMoveable() const; + bool IsNodeSynchronizationEnabled() const; bool IsSleeping() const; void SetAngularDamping(const Nz::Vector3f& angularDamping); @@ -69,6 +71,7 @@ namespace Ndk void OnEntityEnabled() override; std::unique_ptr m_object; + bool m_nodeSynchronizationEnabled; }; } diff --git a/SDK/include/NDK/Components/PhysicsComponent3D.inl b/SDK/include/NDK/Components/PhysicsComponent3D.inl index 741655387..319bb88dd 100644 --- a/SDK/include/NDK/Components/PhysicsComponent3D.inl +++ b/SDK/include/NDK/Components/PhysicsComponent3D.inl @@ -7,13 +7,18 @@ namespace Ndk { + inline PhysicsComponent3D::PhysicsComponent3D() : + m_nodeSynchronizationEnabled(true) + { + } + /*! * \brief Constructs a PhysicsComponent3D object by copy semantic * * \param physics PhysicsComponent3D to copy */ - - inline PhysicsComponent3D::PhysicsComponent3D(const PhysicsComponent3D& physics) + inline PhysicsComponent3D::PhysicsComponent3D(const PhysicsComponent3D& physics) : + m_nodeSynchronizationEnabled(physics.m_nodeSynchronizationEnabled) { // No copy of physical object (because we only create it when attached to an entity) NazaraUnused(physics); @@ -75,7 +80,6 @@ namespace Ndk * * \remark Produces a NazaraAssert if the physics object is invalid */ - inline void PhysicsComponent3D::EnableAutoSleep(bool autoSleep) { NazaraAssert(m_object, "Invalid physics object"); @@ -83,6 +87,22 @@ namespace Ndk m_object->EnableAutoSleep(autoSleep); } + /*! + * \brief Enables position/rotation synchronization with the NodeComponent + * + * By default, at every update of the PhysicsSystem3D, the NodeComponent's position and rotation (if any) will be synchronized with + * the values of the PhysicsComponent3D. This function allows to enable/disable this behavior on a per-entity basis. + * + * \param nodeSynchronization Should synchronization occur between NodeComponent and PhysicsComponent3D + */ + inline void PhysicsComponent3D::EnableNodeSynchronization(bool nodeSynchronization) + { + m_nodeSynchronizationEnabled = nodeSynchronization; + + if (m_entity) + m_entity->Invalidate(); + } + /*! * \brief Gets the AABB of the physics object * \return AABB of the object @@ -178,7 +198,7 @@ namespace Ndk * \brief Gets the gravity center of the physics object * \return Gravity center of the object * - * \param coordSys System coordinates to consider + * \param coordSys System coordinates to consider * * \remark Produces a NazaraAssert if the physics object is invalid */ @@ -258,13 +278,23 @@ namespace Ndk return m_object->IsMoveable(); } + /*! + * \brief Checks if position & rotation are synchronized with NodeComponent + * \return true If synchronization is enabled + * + * \see EnableNodeSynchronization + */ + inline bool PhysicsComponent3D::IsNodeSynchronizationEnabled() const + { + return m_nodeSynchronizationEnabled; + } + /*! * \brief Checks whether the entity is currently sleeping * \return true If it is the case * * \remark Produces a NazaraAssert if the physics object is invalid */ - inline bool PhysicsComponent3D::IsSleeping() const { NazaraAssert(m_object, "Invalid physics object"); diff --git a/SDK/src/NDK/Systems/PhysicsSystem3D.cpp b/SDK/src/NDK/Systems/PhysicsSystem3D.cpp index efb2a0554..8aec2d8e2 100644 --- a/SDK/src/NDK/Systems/PhysicsSystem3D.cpp +++ b/SDK/src/NDK/Systems/PhysicsSystem3D.cpp @@ -47,16 +47,20 @@ namespace Ndk void PhysicsSystem3D::OnEntityValidation(Entity* entity, bool justAdded) { - // It's possible our entity got revalidated because of the addition/removal of a PhysicsComponent3D - if (!justAdded) + if (entity->HasComponent()) { - // We take the opposite array from which the entity should belong to - auto& entities = (entity->HasComponent()) ? m_staticObjects : m_dynamicObjects; - entities.Remove(entity); - } + if (entity->GetComponent().IsNodeSynchronizationEnabled()) + m_dynamicObjects.Insert(entity); + else + m_dynamicObjects.Remove(entity); - auto& entities = (entity->HasComponent()) ? m_dynamicObjects : m_staticObjects; - entities.Insert(entity); + m_staticObjects.Remove(entity); + } + else + { + m_dynamicObjects.Remove(entity); + m_staticObjects.Insert(entity); + } if (!m_world) CreatePhysWorld(); From 192321b448794302f656e90410286a0cf88b4c3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 13 Dec 2017 12:55:03 +0100 Subject: [PATCH 2/4] Network: Fix uninitialized values (found by valgrind) --- include/Nazara/Network/ENetPeer.inl | 3 ++- src/Nazara/Network/Linux/SocketPollerImpl.cpp | 3 ++- src/Nazara/Network/Posix/SocketImpl.cpp | 12 +++++++++++- src/Nazara/Network/Win32/SocketImpl.cpp | 10 ++++++++++ 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl index c3ede0978..2a833e530 100644 --- a/include/Nazara/Network/ENetPeer.inl +++ b/include/Nazara/Network/ENetPeer.inl @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2017 Jérôme Leclercq // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -8,6 +8,7 @@ namespace Nz { inline ENetPeer::ENetPeer(ENetHost* host, UInt16 peerId) : m_host(host), + m_state(ENetPeerState::Disconnected), m_incomingSessionID(0xFF), m_outgoingSessionID(0xFF), m_incomingPeerID(peerId), diff --git a/src/Nazara/Network/Linux/SocketPollerImpl.cpp b/src/Nazara/Network/Linux/SocketPollerImpl.cpp index d3287a815..b35a37ca5 100644 --- a/src/Nazara/Network/Linux/SocketPollerImpl.cpp +++ b/src/Nazara/Network/Linux/SocketPollerImpl.cpp @@ -48,7 +48,8 @@ namespace Nz NazaraAssert(!IsRegistered(socket), "Socket is already registered"); epoll_event entry; - entry.events = 0; + std::memset(&entry, 0, sizeof(epoll_event)); + entry.data.fd = socket; if (eventFlags & SocketPollEvent_Read) diff --git a/src/Nazara/Network/Posix/SocketImpl.cpp b/src/Nazara/Network/Posix/SocketImpl.cpp index 9d1f7bd0c..eddbf2063 100644 --- a/src/Nazara/Network/Posix/SocketImpl.cpp +++ b/src/Nazara/Network/Posix/SocketImpl.cpp @@ -25,6 +25,8 @@ namespace Nz NazaraAssert(handle != InvalidHandle, "Invalid handle"); IpAddressImpl::SockAddrBuffer nameBuffer; + std::fill(nameBuffer.begin(), nameBuffer.end(), 0); + socklen_t bufferLength = sizeof(sockaddr_in); SocketHandle newClient = accept(handle, reinterpret_cast(&nameBuffer), &bufferLength); @@ -376,7 +378,9 @@ namespace Nz NazaraAssert(handle != InvalidHandle, "Invalid handle"); IpAddressImpl::SockAddrBuffer nameBuffer; - socklen_t bufferLength = sizeof(sockaddr_in); + std::fill(nameBuffer.begin(), nameBuffer.end(), 0); + + socklen_t bufferLength = sizeof(nameBuffer.size()); if (getpeername(handle, reinterpret_cast(nameBuffer.data()), &bufferLength) == SOCKET_ERROR) { @@ -416,6 +420,8 @@ namespace Nz NazaraAssert(handle != InvalidHandle, "Invalid handle"); IpAddressImpl::SockAddrBuffer nameBuffer; + std::fill(nameBuffer.begin(), nameBuffer.end(), 0); + socklen_t bufferLength = sizeof(sockaddr_in); if (getsockname(handle, reinterpret_cast(nameBuffer.data()), &bufferLength) == SOCKET_ERROR) @@ -509,6 +515,8 @@ namespace Nz NazaraAssert(buffer && length > 0, "Invalid buffer"); IpAddressImpl::SockAddrBuffer nameBuffer; + std::fill(nameBuffer.begin(), nameBuffer.end(), 0); + socklen_t bufferLength = static_cast(nameBuffer.size()); IpAddress senderIp; @@ -580,6 +588,8 @@ namespace Nz msgHdr.msg_iovlen = static_cast(bufferCount); IpAddressImpl::SockAddrBuffer nameBuffer; + std::fill(nameBuffer.begin(), nameBuffer.end(), 0); + if (from) { msgHdr.msg_name = nameBuffer.data(); diff --git a/src/Nazara/Network/Win32/SocketImpl.cpp b/src/Nazara/Network/Win32/SocketImpl.cpp index fbc8beec3..b410af93c 100644 --- a/src/Nazara/Network/Win32/SocketImpl.cpp +++ b/src/Nazara/Network/Win32/SocketImpl.cpp @@ -33,6 +33,8 @@ namespace Nz NazaraAssert(handle != InvalidHandle, "Invalid handle"); IpAddressImpl::SockAddrBuffer nameBuffer; + std::fill(nameBuffer.begin(), nameBuffer.end(), 0); + int bufferLength = static_cast(nameBuffer.size()); SocketHandle newClient = accept(handle, reinterpret_cast(&nameBuffer), &bufferLength); @@ -392,6 +394,8 @@ namespace Nz NazaraAssert(handle != InvalidHandle, "Invalid handle"); IpAddressImpl::SockAddrBuffer nameBuffer; + std::fill(nameBuffer.begin(), nameBuffer.end(), 0); + int bufferLength = static_cast(nameBuffer.size()); if (getpeername(handle, reinterpret_cast(nameBuffer.data()), &bufferLength) == SOCKET_ERROR) @@ -413,6 +417,8 @@ namespace Nz NazaraAssert(handle != InvalidHandle, "Invalid handle"); IpAddressImpl::SockAddrBuffer nameBuffer; + std::fill(nameBuffer.begin(), nameBuffer.end(), 0); + int bufferLength = static_cast(nameBuffer.size()); if (getsockname(handle, reinterpret_cast(nameBuffer.data()), &bufferLength) == SOCKET_ERROR) @@ -537,6 +543,8 @@ namespace Nz NazaraAssert(buffer && length > 0, "Invalid buffer"); IpAddressImpl::SockAddrBuffer nameBuffer; + std::fill(nameBuffer.begin(), nameBuffer.end(), 0); + int bufferLength = static_cast(nameBuffer.size()); IpAddress senderIp; @@ -592,6 +600,8 @@ namespace Nz NazaraAssert(buffers && bufferCount > 0, "Invalid buffers"); IpAddressImpl::SockAddrBuffer nameBuffer; + std::fill(nameBuffer.begin(), nameBuffer.end(), 0); + int bufferLength = static_cast(nameBuffer.size()); IpAddress senderIp; From 9272efa1598ad230d5ef98967a51391f158f4c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 13 Dec 2017 17:42:45 +0100 Subject: [PATCH 3/4] Core/Thread: Fix possible infinite recursion --- include/Nazara/Core/Thread.hpp | 2 +- src/Nazara/Core/Thread.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/Nazara/Core/Thread.hpp b/include/Nazara/Core/Thread.hpp index c622fd309..9c77d7301 100644 --- a/include/Nazara/Core/Thread.hpp +++ b/include/Nazara/Core/Thread.hpp @@ -64,7 +64,7 @@ namespace Nz NAZARA_CORE_API friend std::ostream& operator<<(std::ostream& o, const Id& id); private: - Id(ThreadImpl* thread); + explicit Id(ThreadImpl* thread); ThreadImpl* m_id = nullptr; }; diff --git a/src/Nazara/Core/Thread.cpp b/src/Nazara/Core/Thread.cpp index 8f9f0b5b6..5380188d1 100644 --- a/src/Nazara/Core/Thread.cpp +++ b/src/Nazara/Core/Thread.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #if defined(NAZARA_PLATFORM_WINDOWS) #include From 5aab9b248d270b832f9e2bf0c90b193f0955bbb2 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 13 Dec 2017 22:17:50 +0100 Subject: [PATCH 4/4] Sdk/PhysicsComponent3D: Fix cloning by preserving physics states --- .../NDK/Components/PhysicsComponent3D.hpp | 15 +++++++ .../NDK/Components/PhysicsComponent3D.inl | 40 +++++++++++++++++-- SDK/src/NDK/Components/PhysicsComponent3D.cpp | 14 ++++++- src/Nazara/Physics3D/RigidBody3D.cpp | 27 +++++++++---- 4 files changed, 83 insertions(+), 13 deletions(-) diff --git a/SDK/include/NDK/Components/PhysicsComponent3D.hpp b/SDK/include/NDK/Components/PhysicsComponent3D.hpp index fe5e2f28a..e7985ca3d 100644 --- a/SDK/include/NDK/Components/PhysicsComponent3D.hpp +++ b/SDK/include/NDK/Components/PhysicsComponent3D.hpp @@ -60,7 +60,10 @@ namespace Ndk static ComponentIndex componentIndex; private: + void ApplyPhysicsState(Nz::RigidBody3D& rigidBody) const; + void CopyPhysicsState(const Nz::RigidBody3D& rigidBody); Nz::RigidBody3D& GetRigidBody(); + const Nz::RigidBody3D& GetRigidBody() const; void OnAttached() override; void OnComponentAttached(BaseComponent& component) override; @@ -70,7 +73,19 @@ namespace Ndk void OnEntityDisabled() override; void OnEntityEnabled() override; + struct PendingPhysObjectStates + { + Nz::Vector3f angularDamping; + Nz::Vector3f massCenter; + bool autoSleep; + bool valid = false; + float gravityFactor; + float linearDamping; + float mass; + }; + std::unique_ptr m_object; + PendingPhysObjectStates m_pendingStates; bool m_nodeSynchronizationEnabled; }; } diff --git a/SDK/include/NDK/Components/PhysicsComponent3D.inl b/SDK/include/NDK/Components/PhysicsComponent3D.inl index 319bb88dd..4fceefdff 100644 --- a/SDK/include/NDK/Components/PhysicsComponent3D.inl +++ b/SDK/include/NDK/Components/PhysicsComponent3D.inl @@ -20,8 +20,8 @@ namespace Ndk inline PhysicsComponent3D::PhysicsComponent3D(const PhysicsComponent3D& physics) : m_nodeSynchronizationEnabled(physics.m_nodeSynchronizationEnabled) { - // No copy of physical object (because we only create it when attached to an entity) - NazaraUnused(physics); + // We can't make a copy of the RigidBody3D, as we are not attached yet (and will possibly be attached to another world) + CopyPhysicsState(physics.GetRigidBody()); } /*! @@ -383,7 +383,8 @@ namespace Ndk inline void PhysicsComponent3D::SetMass(float mass) { NazaraAssert(m_object, "Invalid physics object"); - NazaraAssert(mass > 0.f, "Mass should be positive"); + NazaraAssert(mass >= 0.f, "Mass must be positive and finite"); + NazaraAssert(std::isfinite(mass), "Mass must be positive and finite"); m_object->SetMass(mass); } @@ -433,13 +434,44 @@ namespace Ndk m_object->SetRotation(rotation); } + inline void PhysicsComponent3D::ApplyPhysicsState(Nz::RigidBody3D& rigidBody) const + { + assert(m_pendingStates.valid); + + rigidBody.EnableAutoSleep(m_pendingStates.autoSleep); + rigidBody.SetAngularDamping(m_pendingStates.angularDamping); + rigidBody.SetGravityFactor(m_pendingStates.gravityFactor); + rigidBody.SetLinearDamping(m_pendingStates.linearDamping); + rigidBody.SetMass(m_pendingStates.mass); + rigidBody.SetMassCenter(m_pendingStates.massCenter); + } + + inline void PhysicsComponent3D::CopyPhysicsState(const Nz::RigidBody3D& rigidBody) + { + m_pendingStates.autoSleep = rigidBody.IsAutoSleepEnabled(); + m_pendingStates.angularDamping = rigidBody.GetAngularDamping(); + m_pendingStates.gravityFactor = rigidBody.GetGravityFactor(); + m_pendingStates.linearDamping = rigidBody.GetLinearDamping(); + m_pendingStates.mass = rigidBody.GetMass(); + m_pendingStates.massCenter = rigidBody.GetMassCenter(Nz::CoordSys_Local); + m_pendingStates.valid = true; + } + /*! * \brief Gets the underlying physics object * \return A reference to the physics object */ - inline Nz::RigidBody3D& PhysicsComponent3D::GetRigidBody() { return *m_object.get(); } + + /*! + * \brief Gets the underlying physics object + * \return A reference to the physics object + */ + inline const Nz::RigidBody3D& PhysicsComponent3D::GetRigidBody() const + { + return *m_object.get(); + } } diff --git a/SDK/src/NDK/Components/PhysicsComponent3D.cpp b/SDK/src/NDK/Components/PhysicsComponent3D.cpp index be7ea9f86..b93068fa7 100644 --- a/SDK/src/NDK/Components/PhysicsComponent3D.cpp +++ b/SDK/src/NDK/Components/PhysicsComponent3D.cpp @@ -41,7 +41,11 @@ namespace Ndk matrix.MakeIdentity(); m_object = std::make_unique(&world, geom, matrix); - m_object->SetMass(1.f); + + if (m_pendingStates.valid) + ApplyPhysicsState(*m_object); + else + m_object->SetMass(1.f); } /*! @@ -57,6 +61,7 @@ namespace Ndk if (IsComponent(component)) { NazaraAssert(m_object, "Invalid object"); + m_object->SetGeom(static_cast(component).GetGeom()); } } @@ -74,6 +79,7 @@ namespace Ndk if (IsComponent(component)) { NazaraAssert(m_object, "Invalid object"); + m_object->SetGeom(Nz::NullCollider3D::New()); } } @@ -84,7 +90,11 @@ namespace Ndk void PhysicsComponent3D::OnDetached() { - m_object.reset(); + if (m_object) + { + CopyPhysicsState(*m_object); + m_object.reset(); + } } void PhysicsComponent3D::OnEntityDestruction() diff --git a/src/Nazara/Physics3D/RigidBody3D.cpp b/src/Nazara/Physics3D/RigidBody3D.cpp index 60db49240..2718f93f8 100644 --- a/src/Nazara/Physics3D/RigidBody3D.cpp +++ b/src/Nazara/Physics3D/RigidBody3D.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include namespace Nz @@ -31,6 +32,7 @@ namespace Nz m_body = NewtonCreateDynamicBody(m_world->GetHandle(), m_geom->GetHandle(m_world), m_matrix); NewtonBodySetUserData(m_body, this); + NewtonBodySetTransformCallback(m_body, &TransformCallback); } RigidBody3D::RigidBody3D(const RigidBody3D& object) : @@ -47,6 +49,7 @@ namespace Nz m_body = NewtonCreateDynamicBody(m_world->GetHandle(), m_geom->GetHandle(m_world), m_matrix); NewtonBodySetUserData(m_body, this); + NewtonBodySetTransformCallback(m_body, &TransformCallback); SetMass(object.m_mass); SetAngularDamping(object.GetAngularDamping()); @@ -293,16 +296,27 @@ namespace Nz void RigidBody3D::SetMass(float mass) { + NazaraAssert(mass >= 0.f, "Mass must be positive and finite"); + NazaraAssert(std::isfinite(mass), "Mass must be positive and finite"); + if (m_mass > 0.f) { - // If we already have a mass, we already have an inertial matrix as well, just rescale it - float Ix, Iy, Iz; - NewtonBodyGetMassMatrix(m_body, &m_mass, &Ix, &Iy, &Iz); + if (mass > 0.f) + { + // If we already have a mass, we already have an inertial matrix as well, just rescale it + float Ix, Iy, Iz; + NewtonBodyGetMassMatrix(m_body, &m_mass, &Ix, &Iy, &Iz); - float scale = mass/m_mass; - NewtonBodySetMassMatrix(m_body, mass, Ix*scale, Iy*scale, Iz*scale); + float scale = mass / m_mass; + NewtonBodySetMassMatrix(m_body, mass, Ix*scale, Iy*scale, Iz*scale); + } + else + { + NewtonBodySetMassMatrix(m_body, 0.f, 0.f, 0.f, 0.f); + NewtonBodySetForceAndTorqueCallback(m_body, nullptr); + } } - else if (mass > 0.f) + else { Vector3f inertia, origin; m_geom->ComputeInertialMatrix(&inertia, &origin); @@ -310,7 +324,6 @@ namespace Nz NewtonBodySetCentreOfMass(m_body, &origin.x); NewtonBodySetMassMatrix(m_body, mass, inertia.x*mass, inertia.y*mass, inertia.z*mass); NewtonBodySetForceAndTorqueCallback(m_body, &ForceAndTorqueCallback); - NewtonBodySetTransformCallback(m_body, &TransformCallback); } m_mass = mass;