Files
DarkflameServer/dGame/dComponents/PhysicsComponent.h
Aaron Kimbrell 175d2930b7 feat(physics): real sizes for the navmesh carvers the server didn't know
Walls whose asset shape the server doesn't know are left out of the movement
blockers (a stand in cube would be a guess), which left out every navmesh
carver in Robot City (hedges, hedge corners, potted bushes, greebles, robot
statues) and the Ninjago Monastery benches. Their sizes now come from the
client's own collision shapes (res/physics): the bounds of all of a shape's
parts, with the offset of the box from the object's position. The hedge
corner is an L, so its box also covers the inside of the corner.

The same bounds match two shapes the server already had (misc_phys_10x1x5:
10 x 5 x 1; Trigger_Rectangle_Box: 8 x 8 x 4).

CreatePhysicsEntity's shape lookup becomes CreateAssetShape, which needs no
component, for walls without an object.

Still unknown: the Ninjago Monastery cave's primitive model carver (a 77.6
cube whose origin, centre or base, isn't known).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:48:56 -05:00

76 lines
2.7 KiB
C++

#ifndef __PHYSICSCOMPONENT__H__
#define __PHYSICSCOMPONENT__H__
#include "Component.h"
#include "NiPoint3.h"
#include "NiQuaternion.h"
#include "dCommonVars.h"
namespace GameMessages {
struct GetObjectReportInfo;
struct GetPosition;
};
namespace Raknet {
class BitStream;
};
enum class eReplicaComponentType : uint32_t;
class dpEntity;
class PhysicsComponent : public Component {
public:
PhysicsComponent(Entity* parent, const int32_t componentID);
virtual ~PhysicsComponent();
void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override;
const NiPoint3& GetPosition() const noexcept { 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; }
int32_t GetCollisionGroup() const noexcept { return m_CollisionGroup; }
void SetCollisionGroup(int32_t group) noexcept { m_CollisionGroup = group; }
protected:
bool OnGetObjectReportInfo(GameMessages::GetObjectReportInfo& msg);
// isFallback, when given, says whether the asset had no known shape and got a stand in cube
dpEntity* CreatePhysicsEntity(eReplicaComponentType type, bool* isFallback = nullptr);
/**
* The shape of the physics asset of a LOT's physics component of the given type, for an object placed with this
* scale and rotation, or nullptr when it has none. Some shapes move position (in and out) to line up with the
* client's. isFallback, when given, says whether the asset had no known shape and got a stand in cube.
*/
static dpEntity* CreateAssetShape(LWOOBJID id, LOT lot, eReplicaComponentType type, int32_t collisionGroup, float scale, const NiQuaternion& rotation, NiPoint3& position, 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;
void SpawnVertices(dpEntity* entity) const;
bool OnGetPosition(GameMessages::GetPosition& msg);
NiPoint3 m_Position;
NiQuaternion m_Rotation = QuatUtils::IDENTITY;
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__