mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 02:43:44 +00:00
feat(physics): simple and phantom physics objects register as movement blockers
A fixed simple physics object, or a phantom volume, that its data marks as a wall for enemies (a navmesh carver, or solid with a group only enemies touch) adds its shape to the world's movement blockers, and takes it out again when it goes away. Only shapes the server knows are used; an unknown asset's stand in cube would be a guess, so it is logged and left out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -50,6 +50,9 @@ PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent, const int32_t c
|
||||
m_IsDirectional = false;
|
||||
m_Direction = NiPoint3(); // * m_DirectionalMultiplier
|
||||
|
||||
// A phantom volume enemies can't walk into when it carves the navmesh (e.g. the Sentinel camp walls)
|
||||
RegisterMovementBlocker(ComponentType, false, m_Scale);
|
||||
|
||||
if (m_Parent->GetVar<bool>(u"create_physics")) {
|
||||
m_dpEntity = CreatePhysicsLnv(m_Scale, ComponentType);
|
||||
}
|
||||
|
||||
@@ -12,11 +12,14 @@
|
||||
|
||||
#include "dpEntity.h"
|
||||
#include "dpWorld.h"
|
||||
#include "dpMovementBlockers.h"
|
||||
#include "dpShapeBox.h"
|
||||
#include "dpShapeSphere.h"
|
||||
|
||||
#include "EntityInfo.h"
|
||||
#include "Amf3.h"
|
||||
#include "Entity.h"
|
||||
#include "Logger.h"
|
||||
|
||||
PhysicsComponent::PhysicsComponent(Entity* parent, const int32_t componentID) : Component(parent, componentID) {
|
||||
m_Position = NiPoint3Constant::ZERO;
|
||||
@@ -37,6 +40,37 @@ PhysicsComponent::PhysicsComponent(Entity* parent, const int32_t componentID) :
|
||||
RegisterMsg(&PhysicsComponent::OnGetPosition);
|
||||
}
|
||||
|
||||
PhysicsComponent::~PhysicsComponent() {
|
||||
if (!m_MovementBlocker) return;
|
||||
dpWorld::RemoveMovementBlocker(m_MovementBlocker);
|
||||
delete m_MovementBlocker;
|
||||
}
|
||||
|
||||
void PhysicsComponent::RegisterMovementBlocker(const eReplicaComponentType type, const bool solid, const float scale) {
|
||||
if (m_MovementBlocker) return;
|
||||
const auto filter = dpMovementBlockers::BlockingFilter(m_Parent->GetVar<bool>(u"navmesh_carver"), solid, static_cast<uint32_t>(m_CollisionGroup));
|
||||
if (!filter) return;
|
||||
|
||||
// Some shapes move the object's position to line up with the client's; that is for the shape only
|
||||
const auto placed = m_Position;
|
||||
bool isFallback = false;
|
||||
auto* const blocker = CreatePhysicsEntity(type, &isFallback);
|
||||
const auto shapePosition = m_Position;
|
||||
m_Position = placed;
|
||||
if (!blocker) return;
|
||||
if (isFallback) {
|
||||
LOG_DEBUG("%llu (LOT %i) should block movement, but the server doesn't know its shape", m_Parent->GetObjectID(), m_Parent->GetLOT());
|
||||
delete blocker;
|
||||
return;
|
||||
}
|
||||
|
||||
blocker->SetScale(scale);
|
||||
blocker->SetRotation(m_Rotation);
|
||||
blocker->SetPosition(shapePosition);
|
||||
m_MovementBlocker = blocker;
|
||||
dpWorld::AddMovementBlocker(m_MovementBlocker, *filter);
|
||||
}
|
||||
|
||||
bool PhysicsComponent::OnGetPosition(GameMessages::GetPosition& msg) {
|
||||
msg.pos = GetPosition();
|
||||
return true;
|
||||
@@ -56,7 +90,8 @@ void PhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitia
|
||||
}
|
||||
}
|
||||
|
||||
dpEntity* PhysicsComponent::CreatePhysicsEntity(eReplicaComponentType type) {
|
||||
dpEntity* PhysicsComponent::CreatePhysicsEntity(eReplicaComponentType type, bool* isFallback) {
|
||||
if (isFallback) *isFallback = false;
|
||||
CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable<CDComponentsRegistryTable>();
|
||||
auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), type);
|
||||
|
||||
@@ -115,6 +150,7 @@ dpEntity* PhysicsComponent::CreatePhysicsEntity(eReplicaComponentType type) {
|
||||
|
||||
//add fallback cube:
|
||||
toReturn = new dpEntity(m_Parent->GetObjectID(), 2.0f, 2.0f, 2.0f);
|
||||
if (isFallback) *isFallback = true;
|
||||
}
|
||||
// Only touch what the client lets this group touch (e.g. POI walls ignore enemies, threat clearing walls ignore players)
|
||||
toReturn->SetCollisionGroup(static_cast<uint32_t>(m_CollisionGroup));
|
||||
|
||||
@@ -21,7 +21,7 @@ class dpEntity;
|
||||
class PhysicsComponent : public Component {
|
||||
public:
|
||||
PhysicsComponent(Entity* parent, const int32_t componentID);
|
||||
virtual ~PhysicsComponent() = default;
|
||||
virtual ~PhysicsComponent();
|
||||
|
||||
void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override;
|
||||
|
||||
@@ -36,7 +36,15 @@ public:
|
||||
protected:
|
||||
bool OnGetObjectReportInfo(GameMessages::GetObjectReportInfo& msg);
|
||||
|
||||
dpEntity* CreatePhysicsEntity(eReplicaComponentType type);
|
||||
// isFallback, when given, says whether the asset had no known shape and got a stand in cube
|
||||
dpEntity* CreatePhysicsEntity(eReplicaComponentType type, bool* isFallback = nullptr);
|
||||
|
||||
/**
|
||||
* Makes this object a wall the server's movers can't walk through when its data says it is one
|
||||
* (dpMovementBlockers::BlockingFilter: a navmesh carver, or a solid object only enemies collide with). Only
|
||||
* shapes the server knows are used; a stand in cube would be a guess.
|
||||
*/
|
||||
void RegisterMovementBlocker(eReplicaComponentType type, bool solid, float scale);
|
||||
|
||||
dpEntity* CreatePhysicsLnv(const float scale, const eReplicaComponentType type) const;
|
||||
|
||||
@@ -51,6 +59,9 @@ protected:
|
||||
bool m_DirtyPosition;
|
||||
|
||||
int32_t m_CollisionGroup{};
|
||||
|
||||
// This object's shape as a movement blocker, owned here and not stepped with the physics world
|
||||
dpEntity* m_MovementBlocker{};
|
||||
};
|
||||
|
||||
#endif //!__PHYSICSCOMPONENT__H__
|
||||
|
||||
@@ -33,6 +33,9 @@ SimplePhysicsComponent::SimplePhysicsComponent(Entity* parent, const int32_t com
|
||||
}
|
||||
// Without a motionType the object is fixed (live: Fixed on 38,970 of 40,786 constructions, never the invalid 0)
|
||||
if (m_Parent->HasVar(u"motionType")) m_PhysicsMotionState = m_Parent->GetVarAs<uint32_t>(u"motionType");
|
||||
|
||||
// A fixed solid object can be a wall enemies walk into (an enemy only blocker, or a navmesh carver)
|
||||
if (m_PhysicsMotionState == MOTION_TYPE_FIXED) RegisterMovementBlocker(eReplicaComponentType::SIMPLE_PHYSICS, true, m_Parent->GetDefaultScale());
|
||||
}
|
||||
|
||||
SimplePhysicsComponent::~SimplePhysicsComponent() {
|
||||
|
||||
Reference in New Issue
Block a user