chore: Physics Component abstraction and addition of tests (#1159)

* Make serialize actually virtual

yep

* Abstract to PhysicsComponent

Move shared functionality of all physics related classes to a base class.

Tested that there were no failed to unserialize errors when in main gameplay in Gnarled Forest or in a race.

Tested that 2 players were able to see each other in the above scenarios just fine as well.

* Update PhantomPhysicsComponent.cpp

* Add SimplePhysicsTest

* Add construction test

* Update SimplePhysicsComponentTests.cpp

* remove flags and fix override

* Update VendorComponent.h
This commit is contained in:
David Markowitz
2023-10-09 13:19:38 -07:00
committed by GitHub
parent d8ac148cee
commit ad003634f4
15 changed files with 242 additions and 279 deletions

View File

@@ -18,6 +18,7 @@ set(DGAME_DCOMPONENTS_SOURCES "BaseCombatAIComponent.cpp"
"MovingPlatformComponent.cpp"
"PetComponent.cpp"
"PhantomPhysicsComponent.cpp"
"PhysicsComponent.cpp"
"PlayerForcedMovementComponent.cpp"
"PossessableComponent.cpp"
"PossessorComponent.cpp"

View File

@@ -15,15 +15,12 @@
#include "LevelProgressionComponent.h"
#include "eStateChangeType.h"
ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : Component(entity) {
m_Position = {};
m_Rotation = NiQuaternion::IDENTITY;
ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : PhysicsComponent(entity) {
m_Velocity = {};
m_AngularVelocity = {};
m_InJetpackMode = false;
m_IsOnGround = true;
m_IsOnRail = false;
m_DirtyPosition = true;
m_DirtyVelocity = true;
m_DirtyAngularVelocity = true;
m_dpEntity = nullptr;
@@ -202,26 +199,14 @@ void ControllablePhysicsComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
}
void ControllablePhysicsComponent::SetPosition(const NiPoint3& pos) {
if (m_Static) {
return;
}
m_Position.x = pos.x;
m_Position.y = pos.y;
m_Position.z = pos.z;
m_DirtyPosition = true;
if (m_Static) return;
PhysicsComponent::SetPosition(pos);
if (m_dpEntity) m_dpEntity->SetPosition(pos);
}
void ControllablePhysicsComponent::SetRotation(const NiQuaternion& rot) {
if (m_Static) {
return;
}
m_Rotation = rot;
m_DirtyPosition = true;
if (m_Static) return;
PhysicsComponent::SetRotation(rot);
if (m_dpEntity) m_dpEntity->SetRotation(rot);
}

View File

@@ -6,7 +6,7 @@
#include "NiPoint3.h"
#include "NiQuaternion.h"
#include "tinyxml2.h"
#include "Component.h"
#include "PhysicsComponent.h"
#include "dpCollisionChecks.h"
#include "PhantomPhysicsComponent.h"
#include "eBubbleType.h"
@@ -19,7 +19,7 @@ enum class eStateChangeType : uint32_t;
/**
* Handles the movement of controllable Entities, e.g. enemies and players
*/
class ControllablePhysicsComponent : public Component {
class ControllablePhysicsComponent : public PhysicsComponent {
public:
static const eReplicaComponentType ComponentType = eReplicaComponentType::CONTROLLABLE_PHYSICS;
@@ -36,26 +36,14 @@ public:
* If the entity is static, this is a no-op.
* @param pos The position to set
*/
void SetPosition(const NiPoint3& pos);
/**
* Returns the current position of the entity
* @return The current position of the entity
*/
const NiPoint3& GetPosition() const { return m_Position; }
void SetPosition(const NiPoint3& pos) override;
/**
* Sets the rotation of this entity, ensures this change is serialized next tick. If the entity is static, this is
* a no-op.
* @param rot the rotation to set
*/
void SetRotation(const NiQuaternion& rot);
/**
* Returns the current rotation of this entity
* @return the current rotation of this entity
*/
const NiQuaternion& GetRotation() const { return m_Rotation; }
void SetRotation(const NiQuaternion& rot) override;
/**
* Sets the current velocity of this entity, ensures that this change is serialized next tick. If the entity is
@@ -322,21 +310,6 @@ private:
*/
dpEntity* m_dpEntity;
/**
* Whether or not the position is dirty, forcing a serialization update of the position
*/
bool m_DirtyPosition;
/**
* The current position of the entity
*/
NiPoint3 m_Position;
/**
* The current rotation of the entity
*/
NiQuaternion m_Rotation;
/**
* Whether or not the velocity is dirty, forcing a serialization of the velocity
*/

View File

@@ -27,14 +27,13 @@
#include "dpShapeBox.h"
#include "dpShapeSphere.h"
PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : Component(parent) {
PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : PhysicsComponent(parent) {
m_Position = m_Parent->GetDefaultPosition();
m_Rotation = m_Parent->GetDefaultRotation();
m_Scale = m_Parent->GetDefaultScale();
m_dpEntity = nullptr;
m_EffectInfoDirty = false;
m_PositionInfoDirty = false;
m_IsPhysicsEffectActive = false;
m_EffectType = ePhysicsEffectType::PUSH;
@@ -307,18 +306,7 @@ void PhantomPhysicsComponent::CreatePhysics() {
}
void PhantomPhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
outBitStream->Write(m_PositionInfoDirty || bIsInitialUpdate);
if (m_PositionInfoDirty || bIsInitialUpdate) {
outBitStream->Write(m_Position.x);
outBitStream->Write(m_Position.y);
outBitStream->Write(m_Position.z);
outBitStream->Write(m_Rotation.x);
outBitStream->Write(m_Rotation.y);
outBitStream->Write(m_Rotation.z);
outBitStream->Write(m_Rotation.w);
m_PositionInfoDirty = false;
}
PhysicsComponent::Serialize(outBitStream, bIsInitialUpdate);
outBitStream->Write(m_EffectInfoDirty || bIsInitialUpdate);
if (m_EffectInfoDirty || bIsInitialUpdate) {
@@ -426,13 +414,11 @@ void PhantomPhysicsComponent::SetMax(uint32_t max) {
}
void PhantomPhysicsComponent::SetPosition(const NiPoint3& pos) {
m_Position = pos;
PhysicsComponent::SetPosition(pos);
if (m_dpEntity) m_dpEntity->SetPosition(pos);
}
void PhantomPhysicsComponent::SetRotation(const NiQuaternion& rot) {
m_Rotation = rot;
PhysicsComponent::SetRotation(rot);
if (m_dpEntity) m_dpEntity->SetRotation(rot);
}

View File

@@ -11,8 +11,8 @@
#include <vector>
#include "CppScripts.h"
#include "InvalidScript.h"
#include "Component.h"
#include "eReplicaComponentType.h"
#include "PhysicsComponent.h"
class LDFBaseData;
class Entity;
@@ -25,7 +25,7 @@ enum class ePhysicsEffectType : uint32_t ;
* trigger gameplay events, for example the bus in Avant Gardens that moves around when the player touches its physics
* body. Optionally this object can also have effects, like the fans in AG.
*/
class PhantomPhysicsComponent : public Component {
class PhantomPhysicsComponent : public PhysicsComponent {
public:
static const eReplicaComponentType ComponentType = eReplicaComponentType::PHANTOM_PHYSICS;
@@ -75,29 +75,17 @@ public:
*/
void SetPhysicsEffectActive(bool val) { m_IsPhysicsEffectActive = val; m_EffectInfoDirty = true; }
/**
* Returns the position of this physics object
* @return the position of this physics object
*/
const NiPoint3& GetPosition() const { return m_Position; }
/**
* Sets the position of this physics object
* @param pos the position to set
*/
void SetPosition(const NiPoint3& pos);
/**
* Returns the rotation of this physics object
* @return the rotation of this physics object
*/
const NiQuaternion& GetRotation() const { return m_Rotation; }
void SetPosition(const NiPoint3& pos) override;
/**
* Sets the rotation of this physics object
* @param rot the rotation to set
*/
void SetRotation(const NiQuaternion& rot);
void SetRotation(const NiQuaternion& rot) override;
/**
* Returns the effect that's currently active, defaults to 0
@@ -134,27 +122,11 @@ public:
void SetMax(uint32_t max);
private:
/**
* The position of the physics object
*/
NiPoint3 m_Position;
/**
* The rotation of the physics object
*/
NiQuaternion m_Rotation;
/**
* A scale to apply to the size of the physics object
*/
float m_Scale;
/**
* Whether or not the position has changed and needs to be serialized
*/
bool m_PositionInfoDirty;
/**
* Whether or not the effect has changed and needs to be serialized
*/

View File

@@ -0,0 +1,21 @@
#include "PhysicsComponent.h"
PhysicsComponent::PhysicsComponent(Entity* parent) : Component(parent) {
m_Position = NiPoint3::ZERO;
m_Rotation = NiQuaternion::IDENTITY;
m_DirtyPosition = false;
}
void PhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
outBitStream->Write(bIsInitialUpdate || m_DirtyPosition);
if (bIsInitialUpdate || m_DirtyPosition) {
outBitStream->Write(m_Position.x);
outBitStream->Write(m_Position.y);
outBitStream->Write(m_Position.z);
outBitStream->Write(m_Rotation.x);
outBitStream->Write(m_Rotation.y);
outBitStream->Write(m_Rotation.z);
outBitStream->Write(m_Rotation.w);
if (!bIsInitialUpdate) m_DirtyPosition = false;
}
}

View File

@@ -0,0 +1,32 @@
#ifndef __PHYSICSCOMPONENT__H__
#define __PHYSICSCOMPONENT__H__
#include "Component.h"
#include "NiPoint3.h"
#include "NiQuaternion.h"
namespace Raknet {
class BitStream;
};
class PhysicsComponent : public Component {
public:
PhysicsComponent(Entity* parent);
virtual ~PhysicsComponent() = default;
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
const NiPoint3& GetPosition() const { return m_Position; }
virtual void SetPosition(const NiPoint3& pos) { if (m_Position == pos) return; m_Position = pos; m_DirtyPosition = true; }
const NiQuaternion& GetRotation() const { return m_Rotation; }
virtual void SetRotation(const NiQuaternion& rot) { if (m_Rotation == rot) return; m_Rotation = rot; m_DirtyPosition = true; }
protected:
NiPoint3 m_Position;
NiQuaternion m_Rotation;
bool m_DirtyPosition;
};
#endif //!__PHYSICSCOMPONENT__H__

View File

@@ -1,32 +1,16 @@
/*
* Darkflame Universe
* Copyright 2019
* Copyright 2023
*/
#include "RigidbodyPhantomPhysicsComponent.h"
#include "Entity.h"
RigidbodyPhantomPhysicsComponent::RigidbodyPhantomPhysicsComponent(Entity* parent) : Component(parent) {
RigidbodyPhantomPhysicsComponent::RigidbodyPhantomPhysicsComponent(Entity* parent) : PhysicsComponent(parent) {
m_Position = m_Parent->GetDefaultPosition();
m_Rotation = m_Parent->GetDefaultRotation();
m_IsDirty = true;
}
RigidbodyPhantomPhysicsComponent::~RigidbodyPhantomPhysicsComponent() {
}
void RigidbodyPhantomPhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
outBitStream->Write(m_IsDirty || bIsInitialUpdate);
if (m_IsDirty || bIsInitialUpdate) {
outBitStream->Write(m_Position.x);
outBitStream->Write(m_Position.y);
outBitStream->Write(m_Position.z);
outBitStream->Write(m_Rotation.x);
outBitStream->Write(m_Rotation.y);
outBitStream->Write(m_Rotation.z);
outBitStream->Write(m_Rotation.w);
m_IsDirty = false;
}
PhysicsComponent::Serialize(outBitStream, bIsInitialUpdate);
}

View File

@@ -1,71 +1,29 @@
/*
* Darkflame Universe
* Copyright 2019
* Copyright 2023
*/
#ifndef RIGIDBODYPHANTOMPHYSICS_H
#define RIGIDBODYPHANTOMPHYSICS_H
#ifndef __RIGIDBODYPHANTOMPHYSICS_H__
#define __RIGIDBODYPHANTOMPHYSICS_H__
#include "BitStream.h"
#include "dCommonVars.h"
#include "NiPoint3.h"
#include "NiQuaternion.h"
#include "Component.h"
#include "PhysicsComponent.h"
#include "eReplicaComponentType.h"
/**
* Component that handles rigid bodies that can be interacted with, mostly client-side rendered. An example is the
* bananas that fall from trees in GF.
*/
class RigidbodyPhantomPhysicsComponent : public Component {
class RigidbodyPhantomPhysicsComponent : public PhysicsComponent {
public:
static const eReplicaComponentType ComponentType = eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS;
RigidbodyPhantomPhysicsComponent(Entity* parent);
~RigidbodyPhantomPhysicsComponent() override;
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
/**
* Returns the position of this entity
* @return the position of this entity
*/
NiPoint3& GetPosition() { return m_Position; }
/**
* Sets the position of this entity
* @param pos the position to set
*/
void SetPosition(const NiPoint3& pos) { m_Position = pos; m_IsDirty = true; }
/**
* Returns the rotation of this entity
* @return the rotation of this entity
*/
NiQuaternion& GetRotation() { return m_Rotation; }
/**
* Sets the rotation for this entity
* @param rot the rotation to tset
*/
void SetRotation(const NiQuaternion& rot) { m_Rotation = rot; m_IsDirty = true; }
private:
/**
* The position of this entity
*/
NiPoint3 m_Position;
/**
* The rotation of this entity
*/
NiQuaternion m_Rotation;
/**
* Whether or not the component should be serialized
*/
bool m_IsDirty;
};
#endif // RIGIDBODYPHANTOMPHYSICS_H
#endif // __RIGIDBODYPHANTOMPHYSICS_H__

View File

@@ -13,10 +13,9 @@
#include "Entity.h"
SimplePhysicsComponent::SimplePhysicsComponent(uint32_t componentID, Entity* parent) : Component(parent) {
SimplePhysicsComponent::SimplePhysicsComponent(uint32_t componentID, Entity* parent) : PhysicsComponent(parent) {
m_Position = m_Parent->GetDefaultPosition();
m_Rotation = m_Parent->GetDefaultRotation();
m_IsDirty = true;
const auto& climbable_type = m_Parent->GetVar<std::u16string>(u"climbable");
if (climbable_type == u"wall") {
@@ -54,19 +53,7 @@ void SimplePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIs
} else {
outBitStream->Write0();
}
outBitStream->Write(m_IsDirty || bIsInitialUpdate);
if (m_IsDirty || bIsInitialUpdate) {
outBitStream->Write(m_Position.x);
outBitStream->Write(m_Position.y);
outBitStream->Write(m_Position.z);
outBitStream->Write(m_Rotation.x);
outBitStream->Write(m_Rotation.y);
outBitStream->Write(m_Rotation.z);
outBitStream->Write(m_Rotation.w);
m_IsDirty = false;
}
PhysicsComponent::Serialize(outBitStream, bIsInitialUpdate);
}
uint32_t SimplePhysicsComponent::GetPhysicsMotionState() const {

View File

@@ -10,7 +10,7 @@
#include "RakNetTypes.h"
#include "NiPoint3.h"
#include "NiQuaternion.h"
#include "Component.h"
#include "PhysicsComponent.h"
#include "eReplicaComponentType.h"
class Entity;
@@ -26,7 +26,7 @@ enum class eClimbableType : int32_t {
/**
* Component that serializes locations of entities to the client
*/
class SimplePhysicsComponent : public Component {
class SimplePhysicsComponent : public PhysicsComponent {
public:
static const eReplicaComponentType ComponentType = eReplicaComponentType::SIMPLE_PHYSICS;
@@ -35,30 +35,6 @@ public:
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
/**
* Returns the position of this entity
* @return the position of this entity
*/
NiPoint3& GetPosition() { return m_Position; }
/**
* Sets the position of this entity
* @param pos the position to set
*/
void SetPosition(const NiPoint3& pos) { m_Position = pos; m_IsDirty = true; }
/**
* Returns the rotation of this entity
* @return the rotation of this entity
*/
NiQuaternion& GetRotation() { return m_Rotation; }
/**
* Sets the rotation of this entity
* @param rot
*/
void SetRotation(const NiQuaternion& rot) { m_Rotation = rot; m_IsDirty = true; }
/**
* Returns the velocity of this entity
* @return the velocity of this entity
@@ -108,17 +84,6 @@ public:
void SetClimbableType(const eClimbableType& value) { m_ClimbableType = value; }
private:
/**
* The current position of the entity
*/
NiPoint3 m_Position = NiPoint3::ZERO;
/**
* The current rotation of the entity
*/
NiQuaternion m_Rotation = NiQuaternion::IDENTITY;
/**
* The current velocity of the entity
*/
@@ -134,11 +99,6 @@ private:
*/
bool m_DirtyVelocity = true;
/**
* Whether or not the position has changed
*/
bool m_IsDirty = true;
/**
* The current physics motion state
*/

View File

@@ -1,9 +1,7 @@
#include "VehiclePhysicsComponent.h"
#include "EntityManager.h"
VehiclePhysicsComponent::VehiclePhysicsComponent(Entity* parent) : Component(parent) {
m_Position = NiPoint3::ZERO;
m_Rotation = NiQuaternion::IDENTITY;
VehiclePhysicsComponent::VehiclePhysicsComponent(Entity* parent) : PhysicsComponent(parent) {
m_Velocity = NiPoint3::ZERO;
m_AngularVelocity = NiPoint3::ZERO;
m_IsOnGround = true;
@@ -14,22 +12,6 @@ VehiclePhysicsComponent::VehiclePhysicsComponent(Entity* parent) : Component(par
m_EndBehavior = GeneralUtils::GenerateRandomNumber<uint32_t>(0, 7);
}
VehiclePhysicsComponent::~VehiclePhysicsComponent() {
}
void VehiclePhysicsComponent::SetPosition(const NiPoint3& pos) {
if (pos == m_Position) return;
m_DirtyPosition = true;
m_Position = pos;
}
void VehiclePhysicsComponent::SetRotation(const NiQuaternion& rot) {
if (rot == m_Rotation) return;
m_DirtyPosition = true;
m_Rotation = rot;
}
void VehiclePhysicsComponent::SetVelocity(const NiPoint3& vel) {
if (vel == m_Velocity) return;
m_DirtyPosition = true;
@@ -60,10 +42,6 @@ void VehiclePhysicsComponent::SetRemoteInputInfo(const RemoteInputInfo& remoteIn
m_DirtyRemoteInput = true;
}
void VehiclePhysicsComponent::SetDirtyPosition(bool val) {
m_DirtyPosition = val;
}
void VehiclePhysicsComponent::SetDirtyVelocity(bool val) {
m_DirtyVelocity = val;
}

View File

@@ -2,7 +2,7 @@
#include "BitStream.h"
#include "Entity.h"
#include "Component.h"
#include "PhysicsComponent.h"
#include "eReplicaComponentType.h"
struct RemoteInputInfo {
@@ -26,41 +26,16 @@ struct RemoteInputInfo {
/**
* Physics component for vehicles.
*/
class VehiclePhysicsComponent : public Component {
class VehiclePhysicsComponent : public PhysicsComponent {
public:
static const eReplicaComponentType ComponentType = eReplicaComponentType::VEHICLE_PHYSICS;
VehiclePhysicsComponent(Entity* parentEntity);
~VehiclePhysicsComponent() override;
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
void Update(float deltaTime) override;
/**
* Sets the position
* @param pos the new position
*/
void SetPosition(const NiPoint3& pos);
/**
* Gets the position
* @return the position
*/
const NiPoint3& GetPosition() const { return m_Position; }
/**
* Sets the rotation
* @param rot the new rotation
*/
void SetRotation(const NiQuaternion& rot);
/**
* Gets the rotation
* @return the rotation
*/
const NiQuaternion& GetRotation() const { return m_Rotation; }
/**
* Sets the velocity
* @param vel the new velocity
@@ -115,10 +90,6 @@ public:
void SetRemoteInputInfo(const RemoteInputInfo&);
private:
bool m_DirtyPosition;
NiPoint3 m_Position;
NiQuaternion m_Rotation;
bool m_DirtyVelocity;
NiPoint3 m_Velocity;