Files
DarkflameServer/dGame/dComponents/Physics/PhysicsComponent.h
Aaron Kimbrell c826db94f5 feat(moving platform): the object goes with its mover on the server
LWOPlatform moves its object with SetPosition and SetRotation ignoring the dirty flags (ProcessStateChange 0x00cce380), turned between the two waypoints' rotations, and live serialized a moving platform's mover data without its physics. The server's object stayed where it spawned, so anything that asks where a platform is (the lightning orbs' knockback of issue 1352, phantoms riding a platform) had the start of its path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 14:14:44 -06:00

103 lines
3.9 KiB
C++

#ifndef __PHYSICSCOMPONENT__H__
#define __PHYSICSCOMPONENT__H__
#include "Component.h"
#include "NiPoint3.h"
#include "NiQuaternion.h"
#include "dCommonVars.h"
struct LwoNameValue;
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);
void LoadDataFromTemplate() override;
void LoadConfigData() override;
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; }
// As the client's SetPosition and SetRotation with bIgnoreDirtyFlags: moved without being serialized for it
void SetPositionAndRotationIgnoringDirtyFlags(const NiPoint3& pos, const NiQuaternion& rot) {
const bool dirty = m_DirtyPosition;
SetPosition(pos);
SetRotation(rot);
m_DirtyPosition = dirty;
}
int32_t GetCollisionGroup() const noexcept { return m_CollisionGroup; }
void SetCollisionGroup(int32_t group) noexcept { m_CollisionGroup = group; }
/**
* Whether a level object is carver_only, which the client never loads (LWOResMgr2Interface::Run skips its load
* when its config has carver_only set; LWOBasePhysComponent::LoadConfigData 0x00c495c9 reads it next to
* navmesh_carver). Live never sent one.
*/
[[nodiscard]] static bool IsCarverOnly(const LwoNameValue& settings);
/**
* For a level object the server doesn't spawn (carver_only): adds its shape to the world's movement blockers, the
* way its physics component would have (RegisterMovementBlocker), owned by the world.
* @return whether it blocks movement (its data makes it a wall and the server knows its shape)
*/
static bool AddLevelMovementBlocker(LWOOBJID id, LOT lot, const LwoNameValue& settings, const NiPoint3& position, const NiQuaternion& rotation, float scale);
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__