Further work on subcomponents

serialization is improved, next is re-implementing the actual functionality.
This commit is contained in:
David Markowitz 2023-08-01 01:19:07 -07:00
parent ba409b6ee2
commit 43657324e9
7 changed files with 268 additions and 63 deletions

View File

@ -16,7 +16,9 @@ enum class eMovementPlatformState : uint32_t
};
inline constexpr eMovementPlatformState operator|(eMovementPlatformState a, eMovementPlatformState b) {
return static_cast<eMovementPlatformState>(static_cast<uint32_t>(a) | static_cast<uint32_t>(b));
return static_cast<eMovementPlatformState>(
static_cast<std::underlying_type<eMovementPlatformState>::type>(a) |
static_cast<std::underlying_type<eMovementPlatformState>::type>(b));
};
#endif //!__EMOVEMENTPLATFORMSTATE__H__

View File

@ -0,0 +1,45 @@
#include "CDMovingPlatformComponentTable.h"
CDMovingPlatformComponentTable::CDMovingPlatformComponentTable() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MovementAIComponent");
while (!tableData.eof()) {
CDMovingPlatformTableEntry entry;
entry.platformIsSimpleMover = tableData.getIntField("platformIsSimpleMover", 0) == 1;
entry.platformStartAtEnd = tableData.getIntField("platformStartAtEnd", 0) == 1;
entry.platformMove.x = tableData.getFloatField("platformMoveX", 0.0f);
entry.platformMove.y = tableData.getFloatField("platformMoveY", 0.0f);
entry.platformMove.z = tableData.getFloatField("platformMoveZ", 0.0f);
entry.moveTime = tableData.getFloatField("platformMoveTime", -1.0f);
DluAssert(m_Platforms.insert(std::make_pair(tableData.getIntField("id", -1), entry)).second);
tableData.nextRow();
}
}
void CDMovingPlatformComponentTable::CachePlatformEntry(ComponentID id) {
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM MovementAIComponent WHERE id = ?;");
query.bind(1, static_cast<int32_t>(id));
auto tableData = query.execQuery();
while (!tableData.eof()) {
CDMovingPlatformTableEntry entry;
entry.platformIsSimpleMover = tableData.getIntField("platformIsSimpleMover", 0) == 1;
entry.platformStartAtEnd = tableData.getIntField("platformStartAtEnd", 0) == 1;
entry.platformMove.x = tableData.getFloatField("platformMoveX", 0.0f);
entry.platformMove.y = tableData.getFloatField("platformMoveY", 0.0f);
entry.platformMove.z = tableData.getFloatField("platformMoveZ", 0.0f);
entry.moveTime = tableData.getFloatField("platformMoveTime", -1.0f);
DluAssert(m_Platforms.insert(std::make_pair(tableData.getIntField("id", -1), entry)).second);
tableData.nextRow();
}
}
const std::optional<CDMovingPlatformTableEntry> CDMovingPlatformComponentTable::GetPlatformEntry(ComponentID id) {
auto itr = m_Platforms.find(id);
if (itr == m_Platforms.end()) {
CachePlatformEntry(id);
itr = m_Platforms.find(id);
}
return itr != m_Platforms.end() ? std::make_optional<CDMovingPlatformTableEntry>(itr->second) : std::nullopt;
}

View File

@ -0,0 +1,27 @@
#ifndef __CDMOVINGPLATFORMCOMPONENTTABLE__H__
#define __CDMOVINGPLATFORMCOMPONENTTABLE__H__
#include "CDTable.h"
#include "NiPoint3.h"
#include <optional>
typedef uint32_t ComponentID;
struct CDMovingPlatformTableEntry {
NiPoint3 platformMove;
float moveTime;
bool platformIsSimpleMover;
bool platformStartAtEnd;
};
class CDMovingPlatformComponentTable : public CDTable<CDMovingPlatformComponentTable> {
public:
CDMovingPlatformComponentTable();
void CachePlatformEntry(ComponentID id);
const std::optional<CDMovingPlatformTableEntry> GetPlatformEntry(ComponentID id);
private:
std::map<ComponentID, CDMovingPlatformTableEntry> m_Platforms;
};
#endif //!__CDMOVINGPLATFORMCOMPONENTTABLE__H__

View File

@ -16,6 +16,7 @@ set(DDATABASE_TABLES_SOURCES "CDActivitiesTable.cpp"
"CDLevelProgressionLookupTable.cpp"
"CDLootMatrixTable.cpp"
"CDLootTableTable.cpp"
"CDMovingPlatformComponentTable.cpp"
"CDMissionEmailTable.cpp"
"CDMissionNPCComponentTable.cpp"
"CDMissionsTable.cpp"

View File

@ -12,10 +12,15 @@
#include "GameMessages.h"
#include "CppScripts.h"
#include "SimplePhysicsComponent.h"
#include "CDClientManager.h"
#include "CDMovingPlatformComponentTable.h"
#include "Zone.h"
PlatformSubComponent::PlatformSubComponent() {
//------------- PlatformSubComponent begin --------------
PlatformSubComponent::PlatformSubComponent(MovingPlatformComponent* parentComponent) {
m_Position = NiPoint3::ZERO;
m_ParentComponent = parentComponent;
m_State = eMovementPlatformState::Stopped | eMovementPlatformState::ReachedDesiredWaypoint;
m_DesiredWaypointIndex = 0;
@ -31,8 +36,8 @@ PlatformSubComponent::PlatformSubComponent() {
}
void PlatformSubComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
outBitStream->Write(m_IsDirty);
if (!m_IsDirty) return;
outBitStream->Write(bIsInitialUpdate || m_IsDirty);
if (!(bIsInitialUpdate || m_IsDirty)) return;
outBitStream->Write(m_State);
outBitStream->Write(m_DesiredWaypointIndex);
outBitStream->Write(m_ShouldStopAtDesiredWaypoint);
@ -48,22 +53,105 @@ void PlatformSubComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsIn
if (!bIsInitialUpdate) m_IsDirty = false;
}
//------------- MovingPlatformComponent below --------------
//------------- PlatformSubComponent end --------------
//------------- MoverPlatformSubComponent begin --------------
MoverPlatformSubComponent::MoverPlatformSubComponent(MovingPlatformComponent* parentComponent) : PlatformSubComponent(parentComponent) {
}
//------------- MoverPlatformSubComponent end --------------
//------------- RotatorPlatformSubComponent begin --------------
RotatorPlatformSubComponent::RotatorPlatformSubComponent(MovingPlatformComponent* parentComponent) : PlatformSubComponent(parentComponent) {
}
//------------- RotatorPlatformSubComponent end --------------
//------------- SimpleMoverPlatformSubComponent begin --------------
void SimpleMoverPlatformSubComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
outBitStream->Write(bIsInitialUpdate || m_DirtyStartingPoint);
if (bIsInitialUpdate || m_DirtyStartingPoint) {
outBitStream->Write(m_HasStartingPoint);
if (m_HasStartingPoint) {
outBitStream->Write(m_StartingPoint.x);
outBitStream->Write(m_StartingPoint.y);
outBitStream->Write(m_StartingPoint.z);
outBitStream->Write(m_StartingRotation.w);
outBitStream->Write(m_StartingRotation.x);
outBitStream->Write(m_StartingRotation.y);
outBitStream->Write(m_StartingRotation.z);
}
if (!bIsInitialUpdate) m_DirtyStartingPoint = false;
}
outBitStream->Write(bIsInitialUpdate || m_IsDirty);
if (bIsInitialUpdate || m_IsDirty) {
outBitStream->Write(m_State);
outBitStream->Write(m_CurrentWaypointIndex);
outBitStream->Write(m_InReverse);
if (!bIsInitialUpdate) m_IsDirty = false;
}
}
void SimpleMoverPlatformSubComponent::LoadConfigData() {
if (m_ParentComponent->GetParent()->GetVar<bool>(u"dbonly")) return;
NiPoint3 platformMove(
m_ParentComponent->GetParent()->GetVar<float>(u"platformMoveX"),
m_ParentComponent->GetParent()->GetVar<float>(u"platformMoveY"),
m_ParentComponent->GetParent()->GetVar<float>(u"platformMoveZ")
);
m_PlatformMove = platformMove;
m_MoveTime = m_ParentComponent->GetParent()->GetVar<float>(u"platformMoveTime");
// idk either. client does it!
m_StartAtEnd = m_ParentComponent->GetParent()->GetVar<uint32_t>(u"attached_path_start") != 0;
m_StartAtEnd = m_ParentComponent->GetParent()->GetVar<bool>(u"platformStartAtEnd");
}
void SimpleMoverPlatformSubComponent::LoadDataFromTemplate() {
if (!m_ParentComponent->GetParent()->GetVar<bool>(u"dbonly")) return;
auto* movingPlatformTable = CDClientManager::Instance().GetTable<CDMovingPlatformComponentTable>();
if (movingPlatformTable == nullptr) return;
const auto& platformEntry = movingPlatformTable->GetPlatformEntry(m_ParentComponent->GetComponentId());
if (!platformEntry || !platformEntry->platformIsSimpleMover) return;
NiPoint3 platformMove = platformEntry->platformMove;
float moveTime = platformEntry->moveTime;
}
SimpleMoverPlatformSubComponent::SimpleMoverPlatformSubComponent(MovingPlatformComponent* parentComponent, const NiPoint3& platformMove, const bool startsInReverse) : PlatformSubComponent(parentComponent) {
m_PlatformMove = platformMove;
m_InReverse = startsInReverse;
m_HasStartingPoint = true;
m_DirtyStartingPoint = true;
m_IsDirty = true;
m_StartingPoint = m_ParentComponent->GetParent()->GetPosition();
m_StartingRotation = m_ParentComponent->GetParent()->GetRotation();
}
//------------- SimpleMoverPlatformSubComponent end --------------
//------------- MovingPlatformComponent begin --------------
MovingPlatformComponent::MovingPlatformComponent(Entity* parent, const std::string& pathName) : Component(parent) {
if (Game::zoneManager == nullptr) return;
auto path = Game::zoneManager->GetZone()->GetPath(pathName);
if (!path) return;
Game::logger->Log("MovingPlatformComponent", "Path found: %s", pathName.c_str());
}
void MovingPlatformComponent::LoadConfigData() {
if (m_Parent->GetVar<bool>(u"platformIsSimpleMover")) {
m_Platforms.push_back(std::make_unique<SimpleMoverPlatformSubComponent>());
AddMovingPlatform<SimpleMoverPlatformSubComponent>(NiPoint3::ZERO, false);
}
if (m_Parent->GetVar<bool>(u"platformIsMover")) {
m_Platforms.push_back(std::make_unique<MoverPlatformSubComponent>());
AddMovingPlatform<MoverPlatformSubComponent>();
}
if (m_Parent->GetVar<bool>(u"platformIsRotater")) {
m_Platforms.push_back(std::make_unique<RotatorPlatformSubComponent>());
AddMovingPlatform<RotatorPlatformSubComponent>();
}
m_DirtyPathInfo = true;
}
@ -80,11 +168,12 @@ void MovingPlatformComponent::Serialize(RakNet::BitStream* outBitStream, bool bI
for (const auto& c : m_PathName) {
outBitStream->Write(static_cast<uint16_t>(c));
}
outBitStream->Write<uint32_t>(1); // Starting waypoint
outBitStream->Write1(); // is in reverse
outBitStream->Write(m_StartingWaypointIndex);
outBitStream->Write(m_StartsIsInReverse);
}
if (!bIsInitialUpdate) m_DirtyPathInfo = false;
}
if (m_Platforms.empty()) return;
for (const auto& platform : m_Platforms) {
outBitStream->Write1(); // Has platform to write
@ -325,3 +414,5 @@ size_t MovingPlatformComponent::GetLastWaypointIndex() const {
return 0;
// return m_Path->pathWaypoints.size() - 1;
}
//------------- MovingPlatformComponent end --------------

View File

@ -28,9 +28,11 @@ enum class eMoverSubComponentType : uint32_t {
Rotator = 6
};
class MovingPlatformComponent;
class PlatformSubComponent {
public:
PlatformSubComponent();
PlatformSubComponent(MovingPlatformComponent* parentComponent);
virtual ~PlatformSubComponent() = default;
virtual void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate);
virtual eMoverSubComponentType GetPlatformType() { return eMoverSubComponentType::None; };
@ -40,6 +42,7 @@ protected:
#ifdef _MOVING_PLATFORM_TEST
public:
#endif
MovingPlatformComponent* m_ParentComponent = nullptr;
/**
* The state the platform is currently in
*/
@ -60,27 +63,38 @@ public:
class MoverPlatformSubComponent : public PlatformSubComponent {
public:
MoverPlatformSubComponent() : PlatformSubComponent() {};
inline static const eMoverSubComponentType SubComponentType = eMoverSubComponentType::Mover;
MoverPlatformSubComponent(MovingPlatformComponent* parentComponent);
~MoverPlatformSubComponent() override = default;
eMoverSubComponentType GetPlatformType() override { return eMoverSubComponentType::Mover; }
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override { PlatformSubComponent::Serialize(outBitStream, bIsInitialUpdate); };
};
class RotatorPlatformSubComponent : public PlatformSubComponent {
public:
RotatorPlatformSubComponent() : PlatformSubComponent() {};
inline static const eMoverSubComponentType SubComponentType = eMoverSubComponentType::Rotator;
RotatorPlatformSubComponent(MovingPlatformComponent* parentComponent);
~RotatorPlatformSubComponent() override = default;
eMoverSubComponentType GetPlatformType() override { return eMoverSubComponentType::Rotator; }
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override { PlatformSubComponent::Serialize(outBitStream, bIsInitialUpdate); };
};
// Only moves. Has NO path.
// Only moves. Has NO path. This moving platform gets its initial position and rotation from the server on serialization.
class SimpleMoverPlatformSubComponent : public PlatformSubComponent {
public:
SimpleMoverPlatformSubComponent() : PlatformSubComponent() {};
inline static const eMoverSubComponentType SubComponentType = eMoverSubComponentType::SimpleMover;
SimpleMoverPlatformSubComponent(MovingPlatformComponent* parentComponent, const NiPoint3& platformMove, const bool startAtEnd);
~SimpleMoverPlatformSubComponent() override = default;
eMoverSubComponentType GetPlatformType() override { return eMoverSubComponentType::SimpleMover; }
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override { PlatformSubComponent::Serialize(outBitStream, bIsInitialUpdate); };
void LoadConfigData();
void LoadDataFromTemplate();
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
bool m_HasStartingPoint = false;
bool m_DirtyStartingPoint = false;
NiPoint3 m_StartingPoint;
NiQuaternion m_StartingRotation;
NiPoint3 m_PlatformMove;
float m_MoveTime;
bool m_StartAtEnd;
};
/**
@ -96,6 +110,8 @@ public:
MovingPlatformComponent(Entity* parent, const std::string& pathName);
void LoadConfigData();
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
/**
@ -166,6 +182,19 @@ public:
*/
size_t GetLastWaypointIndex() const;
template<typename MovingPlatform, typename ...ConstructorValues>
void AddMovingPlatform(ConstructorValues... arguments) {
static_assert(std::is_base_of<PlatformSubComponent, MovingPlatform>::value, "MovingPlatform must derive from PlatformSubComponent");
auto hasPlatform = std::find_if(m_Platforms.begin(), m_Platforms.end(), [](const std::unique_ptr<PlatformSubComponent>& platform) {
return platform->GetPlatformType() == MovingPlatform::SubComponentType;
}) != m_Platforms.end();
if (!hasPlatform) {
m_Platforms.push_back(std::make_unique<MovingPlatform>(this, std::forward<ConstructorValues>(arguments)...));
}
}
int32_t GetComponentId() const { return componentId; }
#ifdef _MOVING_PLATFORM_TEST
/**
* Only used for testing. Do not call in production code. Let the constructor take care of this.
@ -192,6 +221,12 @@ private:
*/
bool m_PathingStopped = false;
uint32_t m_StartingWaypointIndex = 0;
bool m_StartsIsInReverse = false;
int32_t componentId = -1;;
/**
* The mover sub component that belongs to this platform
*/

View File

@ -7,6 +7,7 @@
#define _MOVING_PLATFORM_TEST
#include "MovingPlatformComponent.h"
#undef _MOVING_PLATFORM_TEST
#include "SimplePhysicsComponent.h"
#include "eReplicaComponentType.h"
class MovingPlatformComponentTests : public GameDependenciesTest {
@ -17,9 +18,19 @@ protected:
void SetUp() override {
SetUpDependencies();
baseEntity = std::make_unique<Entity>(15, GameDependenciesTest::info);
baseEntity->SetVar<bool>(u"dbonly", false);
baseEntity->SetVar<float>(u"platformMoveX", 23);
baseEntity->SetVar<float>(u"platformMoveY", 453);
baseEntity->SetVar<float>(u"platformMoveZ", 523);
baseEntity->SetVar<float>(u"platformMoveTime", 5724);
baseEntity->SetVar<bool>(u"platformStartAtEnd", true);
auto* movingPlatformComponent = new MovingPlatformComponent(baseEntity.get(), "");
auto* simplePhysicsComponent = new SimplePhysicsComponent(1, baseEntity.get());
baseEntity->AddComponent(eReplicaComponentType::MOVING_PLATFORM, movingPlatformComponent);
auto moverPlatformSubComponent = std::make_unique<MoverPlatformSubComponent>();
baseEntity->AddComponent(eReplicaComponentType::SIMPLE_PHYSICS, simplePhysicsComponent);
baseEntity->SetPosition(NiPoint3(25, 26, 27));
baseEntity->SetRotation(NiQuaternion(28, 29, 30, 31));
auto moverPlatformSubComponent = std::make_unique<MoverPlatformSubComponent>(movingPlatformComponent);
moverPlatformSubComponent->m_State = eMovementPlatformState::Stopped | eMovementPlatformState::ReachedDesiredWaypoint;
moverPlatformSubComponent->m_DesiredWaypointIndex = 1;
moverPlatformSubComponent->m_PercentBetweenPoints = 2;
@ -32,7 +43,7 @@ protected:
moverPlatformSubComponent->m_InReverse = true;
moverPlatformSubComponent->m_ShouldStopAtDesiredWaypoint = true;
auto rotatorPlatformSubComponent = std::make_unique<RotatorPlatformSubComponent>();
auto rotatorPlatformSubComponent = std::make_unique<RotatorPlatformSubComponent>(movingPlatformComponent);
rotatorPlatformSubComponent->m_State = eMovementPlatformState::Travelling;
rotatorPlatformSubComponent->m_DesiredWaypointIndex = 12;
rotatorPlatformSubComponent->m_PercentBetweenPoints = 13;
@ -45,18 +56,20 @@ protected:
rotatorPlatformSubComponent->m_InReverse = true;
rotatorPlatformSubComponent->m_ShouldStopAtDesiredWaypoint = true;
auto simpleMoverPlatformSubComponent = std::make_unique<SimpleMoverPlatformSubComponent>();
auto simpleMoverPlatformSubComponent = std::make_unique<SimpleMoverPlatformSubComponent>(movingPlatformComponent, NiPoint3(), true);
simpleMoverPlatformSubComponent->m_State = eMovementPlatformState::Waiting | eMovementPlatformState::ReachedDesiredWaypoint | eMovementPlatformState::ReachedFinalWaypoint;
simpleMoverPlatformSubComponent->m_DesiredWaypointIndex = 23;
simpleMoverPlatformSubComponent->m_PercentBetweenPoints = 24;
simpleMoverPlatformSubComponent->m_Position = NiPoint3(25, 26, 27);
simpleMoverPlatformSubComponent->m_CurrentWaypointIndex = 28;
simpleMoverPlatformSubComponent->m_NextWaypointIndex = 29;
simpleMoverPlatformSubComponent->m_IdleTimeElapsed = 30;
simpleMoverPlatformSubComponent->m_MoveTimeElapsed = 33;
simpleMoverPlatformSubComponent->m_IsDirty = true;
simpleMoverPlatformSubComponent->m_InReverse = true;
simpleMoverPlatformSubComponent->m_DirtyStartingPoint = true;
simpleMoverPlatformSubComponent->m_HasStartingPoint = true;
simpleMoverPlatformSubComponent->m_ShouldStopAtDesiredWaypoint = true;
simpleMoverPlatformSubComponent->LoadConfigData();
movingPlatformComponent->_AddPlatformSubComponent(std::move(moverPlatformSubComponent));
movingPlatformComponent->_AddPlatformSubComponent(std::move(rotatorPlatformSubComponent));
@ -95,11 +108,11 @@ protected:
uint32_t pathStartIndex;
bitStream.Read(pathStartIndex);
ASSERT_EQ(pathStartIndex, 1);
ASSERT_EQ(pathStartIndex, 0);
bool isInReverse;
bitStream.Read(isInReverse);
ASSERT_TRUE(isInReverse);
ASSERT_FALSE(isInReverse);
bool hasPlatformData;
bitStream.Read(hasPlatformData);
@ -217,52 +230,43 @@ protected:
bitStream.Read(platformType3);
ASSERT_EQ(platformType3, eMoverSubComponentType::SimpleMover);
bool isDirty3;
bitStream.Read(isDirty3);
ASSERT_TRUE(isDirty3);
bool dirtyStartingPoint;
bitStream.Read(dirtyStartingPoint);
ASSERT_TRUE(dirtyStartingPoint);
bool hasStartingPoint;
bitStream.Read(hasStartingPoint);
ASSERT_TRUE(hasStartingPoint);
NiPoint3 startingPoint;
bitStream.Read(startingPoint.x);
bitStream.Read(startingPoint.y);
bitStream.Read(startingPoint.z);
ASSERT_EQ(startingPoint, NiPoint3(25, 26, 27));
NiQuaternion startingRotation;
bitStream.Read(startingRotation.w);
bitStream.Read(startingRotation.x);
bitStream.Read(startingRotation.y);
bitStream.Read(startingRotation.z);
ASSERT_EQ(startingRotation, NiQuaternion(28, 29, 30, 31));
bool isDirty4;
bitStream.Read(isDirty4);
ASSERT_TRUE(isDirty4);
eMovementPlatformState state3;
bitStream.Read(state3);
ASSERT_EQ(state3, eMovementPlatformState::Waiting | eMovementPlatformState::ReachedDesiredWaypoint | eMovementPlatformState::ReachedFinalWaypoint);
int32_t desiredWaypointIndex3;
bitStream.Read(desiredWaypointIndex3);
ASSERT_EQ(desiredWaypointIndex3, 23);
bool shouldStopAtDesiredWaypoint3;
bitStream.Read(shouldStopAtDesiredWaypoint3);
ASSERT_TRUE(shouldStopAtDesiredWaypoint3);
int32_t currentWaypointIndex3;
bitStream.Read(currentWaypointIndex3);
ASSERT_EQ(currentWaypointIndex3, 28);
bool isInReverse4;
bitStream.Read(isInReverse4);
ASSERT_TRUE(isInReverse4);
float percentBetweenPoints3;
bitStream.Read(percentBetweenPoints3);
ASSERT_EQ(percentBetweenPoints3, 24);
NiPoint3 position3;
bitStream.Read(position3.x);
bitStream.Read(position3.y);
bitStream.Read(position3.z);
ASSERT_EQ(position3, NiPoint3(25, 26, 27));
uint32_t currentWaypointIndex3;
bitStream.Read(currentWaypointIndex3);
ASSERT_EQ(currentWaypointIndex3, 28);
uint32_t nextWaypointIndex3;
bitStream.Read(nextWaypointIndex3);
ASSERT_EQ(nextWaypointIndex3, 29);
float idleTimeElapsed3;
bitStream.Read(idleTimeElapsed3);
ASSERT_EQ(idleTimeElapsed3, 30);
float moveTimeElapsed3;
bitStream.Read(moveTimeElapsed3);
ASSERT_EQ(moveTimeElapsed3, 33);
bool hasPlatformSubComponents2;
bitStream.Read(hasPlatformSubComponents2);
ASSERT_FALSE(hasPlatformSubComponents2);