Compare commits

..

4 Commits

Author SHA1 Message Date
David Markowitz
ea2ef0aea3 Merge branch 'main' into fix-issue 2024-02-20 05:03:13 -08:00
David Markowitz
f38537aece fix: incorrectly inverted statement (#1459)
if we DONT find it, we want to kill/delete it.  not the other way around where if we find it we try to delete it again.

tested that you no longer crash when trying to login
tested that bird monument issues are fixed
2024-02-20 05:51:02 -06:00
David Markowitz
202ac1e204 fix: incorrectly inverted statement
if we DONT find it, we want to kill/delete it.  not the other way around where if we find it we try to delete it again.

tested that you no longer crash when trying to login
tested that bird monument issues are fixed
2024-02-20 02:34:36 -08:00
jadebenn
b6af92ef81 refactor: Rewrite BehaviorMessage classes to use member initialization, preferred member naming conventions, and const-ref getters (#1456)
* Split out BehaviorMessage class changes from PR #1452

* remove <string_view> inclusion in ActionContext.h

* add the arguments nullptr check back in

* remove redundant std::string constructor calls

* Update AddStripMessage.cpp - change push_back to emplace_back
2024-02-18 00:38:26 -06:00
68 changed files with 847 additions and 1596 deletions

View File

@@ -127,12 +127,12 @@ public:
/**
* Returns the Associative portion of the object
*/
[[nodiscard]] inline AMFAssociative& GetAssociative() noexcept { return this->associative; }
[[nodiscard]] inline const AMFAssociative& GetAssociative() const noexcept { return this->associative; }
/**
* Returns the dense portion of the object
*/
[[nodiscard]] inline AMFDense& GetDense() noexcept { return this->dense; }
[[nodiscard]] inline const AMFDense& GetDense() const noexcept { return this->dense; }
/**
* Inserts an AMFValue into the associative portion with the given key.
@@ -297,7 +297,7 @@ public:
if (!this->dense.empty()) Remove(this->dense.size() - 1);
}
[[nodiscard]] AMFArrayValue* GetArray(const std::string& key) {
[[nodiscard]] AMFArrayValue* GetArray(const std::string& key) const {
AMFAssociative::const_iterator it = this->associative.find(key);
if (it != this->associative.end()) {
return dynamic_cast<AMFArrayValue*>(it->second);
@@ -305,7 +305,7 @@ public:
return nullptr;
}
[[nodiscard]] AMFArrayValue* GetArray(const size_t index) {
[[nodiscard]] AMFArrayValue* GetArray(const size_t index) const {
return index >= this->dense.size() ? nullptr : dynamic_cast<AMFArrayValue*>(this->dense.at(index));
}

View File

@@ -2,7 +2,6 @@
#define __DLUASSERT__H__
#include <assert.h>
#define _DEBUG
#ifdef _DEBUG
# define DluAssert(expression) assert(expression)

View File

@@ -31,7 +31,6 @@ constexpr const char* GetFileNameFromAbsolutePath(const char* path) {
// is used in the instruction instead of the start of the absolute path.
#define LOG(message, ...) do { auto str = FILENAME_AND_LINE; Game::logger->Log(str, message, ##__VA_ARGS__); } while(0)
#define LOG_DEBUG(message, ...) do { auto str = FILENAME_AND_LINE; Game::logger->LogDebug(str, message, ##__VA_ARGS__); } while(0)
#define LOG_TEST(message, ...) do { auto str = FILENAME_AND_LINE; Game::logger->LogDebug(str, message, ##__VA_ARGS__); Game::logger->Flush();} while(0)
// Writer class for writing data to files.
class Writer {

View File

@@ -0,0 +1,16 @@
#ifndef __EMOVEMENTPLATFORMSTATE__H__
#define __EMOVEMENTPLATFORMSTATE__H__
#include <cstdint>
/**
* The different types of platform movement state, supposedly a bitmap
*/
enum class eMovementPlatformState : uint32_t
{
Moving = 0b00010,
Stationary = 0b11001,
Stopped = 0b01100
};
#endif //!__EMOVEMENTPLATFORMSTATE__H__

View File

@@ -40,7 +40,6 @@
#include "CDRailActivatorComponent.h"
#include "CDRewardCodesTable.h"
#include "CDPetComponentTable.h"
#include "CDMovingPlatformComponentTable.h"
#include <exception>
@@ -111,7 +110,6 @@ DEFINE_TABLE_STORAGE(CDScriptComponentTable);
DEFINE_TABLE_STORAGE(CDSkillBehaviorTable);
DEFINE_TABLE_STORAGE(CDVendorComponentTable);
DEFINE_TABLE_STORAGE(CDZoneTableTable);
DEFINE_TABLE_STORAGE(CDMovingPlatformComponentTable);
void CDClientManager::LoadValuesFromDatabase() {
if (!CDClientDatabase::isConnected) throw CDClientConnectionException();

View File

@@ -1,48 +0,0 @@
#include "CDMovingPlatformComponentTable.h"
CDMovingPlatformComponentTable::CDMovingPlatformComponentTable() {
auto& entries = GetEntriesMutable();
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MovingPlatforms");
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(entries.insert(std::make_pair(tableData.getIntField("id", -1), entry)).second);
tableData.nextRow();
}
}
void CDMovingPlatformComponentTable::CachePlatformEntry(ComponentID id) {
auto& entries = GetEntriesMutable();
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM MovingPlatforms 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(entries.insert(std::make_pair(tableData.getIntField("id", -1), entry)).second);
tableData.nextRow();
}
}
const std::optional<CDMovingPlatformTableEntry> CDMovingPlatformComponentTable::GetPlatformEntry(ComponentID id) {
auto& entries = GetEntriesMutable();
auto itr = entries.find(id);
if (itr == entries.end()) {
CachePlatformEntry(id);
itr = entries.find(id);
}
return itr != entries.end() ? std::make_optional<CDMovingPlatformTableEntry>(itr->second) : std::nullopt;
}

View File

@@ -1,25 +0,0 @@
#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, std::map<ComponentID, CDMovingPlatformTableEntry>> {
public:
CDMovingPlatformComponentTable();
void CachePlatformEntry(ComponentID id);
const std::optional<CDMovingPlatformTableEntry> GetPlatformEntry(ComponentID id);
};
#endif //!__CDMOVINGPLATFORMCOMPONENTTABLE__H__

View File

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

View File

@@ -315,7 +315,7 @@ Entity* EntityManager::GetSpawnPointEntity(const std::string& spawnName) const {
// Check if the spawn point entity is valid just in case
return spawnPoint == m_SpawnPoints.end() ? nullptr : GetEntity(spawnPoint->second);
}
#include <thread>
const std::unordered_map<std::string, LWOOBJID>& EntityManager::GetSpawnPointEntities() const {
return m_SpawnPoints;
}
@@ -575,13 +575,13 @@ void EntityManager::ScheduleForKill(Entity* entity) {
const auto objectId = entity->GetObjectID();
if (std::find(m_EntitiesToKill.begin(), m_EntitiesToKill.end(), objectId) != m_EntitiesToKill.end()) {
if (std::find(m_EntitiesToKill.begin(), m_EntitiesToKill.end(), objectId) == m_EntitiesToKill.end()) {
m_EntitiesToKill.push_back(objectId);
}
}
void EntityManager::ScheduleForDeletion(LWOOBJID entity) {
if (std::find(m_EntitiesToDelete.begin(), m_EntitiesToDelete.end(), entity) != m_EntitiesToDelete.end()) {
if (std::find(m_EntitiesToDelete.begin(), m_EntitiesToDelete.end(), entity) == m_EntitiesToDelete.end()) {
m_EntitiesToDelete.push_back(entity);
}
}

View File

@@ -12,402 +12,109 @@
#include "GameMessages.h"
#include "CppScripts.h"
#include "SimplePhysicsComponent.h"
#include "CDClientManager.h"
#include "CDMovingPlatformComponentTable.h"
#include "Zone.h"
#include "StringifiedEnum.h"
//------------- PlatformSubComponent begin --------------
MoverSubComponent::MoverSubComponent(const NiPoint3& startPos) {
mPosition = {};
PlatformSubComponent::PlatformSubComponent(MovingPlatformComponent* parentComponent) {
DluAssert(parentComponent != nullptr);
m_ParentComponent = parentComponent;
m_Position = parentComponent->GetParent()->GetPosition();
m_Rotation = parentComponent->GetParent()->GetRotation();
mState = eMovementPlatformState::Stopped;
mDesiredWaypointIndex = 0; // -1;
mInReverse = false;
mShouldStopAtDesiredWaypoint = false;
m_State = eMovementPlatformState::Stopped | eMovementPlatformState::ReachedDesiredWaypoint;
m_DesiredWaypointIndex = -1;
m_PercentUntilNextWaypoint = 0.0f;
m_CurrentWaypointIndex = 0;
m_NextWaypointIndex = -1;
m_IdleTimeElapsed = 0.0f;
m_Speed = 0.0f;
m_WaitTime = 0.0f;
m_MoveTimeElapsed = 0.0f;
m_IsDirty = false;
m_InReverse = false;
m_ShouldStopAtDesiredWaypoint = false;
m_LinearVelocity = NiPoint3Constant::ZERO;
m_AngularVelocity = NiPoint3Constant::ZERO;
m_TimeBasedMovement = false;
m_Path = nullptr;
mPercentBetweenPoints = 0.0f;
mCurrentWaypointIndex = 0;
mNextWaypointIndex = 0; //mCurrentWaypointIndex + 1;
mIdleTimeElapsed = 0.0f;
}
void PlatformSubComponent::Update(float deltaTime) {
if (m_State == 0 || !m_Path) return;
if (m_State & eMovementPlatformState::Travelling) {
m_MoveTimeElapsed += deltaTime;
MoverSubComponent::~MoverSubComponent() = default;
// Only need to recalculate the linear velocity if the speed is changing between waypoints
// Unfortunately for the poor client, they chose to, instead of change the speed once at the start of the waypoint,
// the speed is changed over the course of the waypoint. This means we have to recalculate the linear velocity every frame.
// yay.
if (m_Speed == 0.0f || (GetCurrentWaypoint().movingPlatform.speed != GetNextWaypoint().movingPlatform.speed)) {
UpdateLinearVelocity();
m_IsDirty = true;
}
m_Position += m_LinearVelocity * deltaTime;
if (CalculatePercentToNextWaypoint() > 0.99) {
m_MoveTimeElapsed = 0;
m_ParentComponent->GetParent()->SetPosition(m_Position);
m_InReverse ? AdvanceToNextReverseWaypoint() : AdvanceToNextWaypoint();
m_IsDirty = true;
Game::entityManager->SerializeEntity(m_ParentComponent->GetParent());
}
}
void MoverSubComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
outBitStream->Write<bool>(true);
outBitStream->Write(mState);
outBitStream->Write<int32_t>(mDesiredWaypointIndex);
outBitStream->Write(mShouldStopAtDesiredWaypoint);
outBitStream->Write(mInReverse);
outBitStream->Write<float_t>(mPercentBetweenPoints);
outBitStream->Write<float_t>(mPosition.x);
outBitStream->Write<float_t>(mPosition.y);
outBitStream->Write<float_t>(mPosition.z);
outBitStream->Write<uint32_t>(mCurrentWaypointIndex);
outBitStream->Write<uint32_t>(mNextWaypointIndex);
outBitStream->Write<float_t>(mIdleTimeElapsed);
outBitStream->Write<float_t>(0.0f); // Move time elapsed
}
float PlatformSubComponent::CalculatePercentToNextWaypoint() {
if (m_TimeBasedMovement) return 0;
float distanceToNextWaypoint = (GetNextWaypoint().position - GetCurrentWaypoint().position).Length();
if (distanceToNextWaypoint == 0.0f) return 0;
float distanceToCurrentWaypoint = (m_Position - GetCurrentWaypoint().position).Length();
return distanceToCurrentWaypoint / distanceToNextWaypoint;
}
void PlatformSubComponent::UpdateAngularVelocity() {
// Update the angular velocity
// This one is sure to be fun...
}
void PlatformSubComponent::UpdateLinearVelocity() {
m_LinearVelocity = CalculateLinearVelocity();
}
void PlatformSubComponent::AdvanceToNextWaypoint() {
m_CurrentWaypointIndex = m_NextWaypointIndex;
m_ParentComponent->GetParent()->SetPosition(GetCurrentWaypoint().position);
m_ParentComponent->GetParent()->SetRotation(GetCurrentWaypoint().rotation);
int32_t nextWaypointIndex = FindNextWaypointIndex();
m_NextWaypointIndex = nextWaypointIndex;
m_DesiredWaypointIndex = nextWaypointIndex;
UpdateLinearVelocity();
UpdateAngularVelocity();
m_IsDirty = true;
}
void PlatformSubComponent::AdvanceToNextReverseWaypoint() {
m_ParentComponent->GetParent()->SetPosition(GetCurrentWaypoint().position);
m_ParentComponent->GetParent()->SetRotation(GetCurrentWaypoint().rotation);
m_CurrentWaypointIndex = m_NextWaypointIndex;
int32_t nextWaypointIndex = FindNextReversedWaypointIndex();
m_NextWaypointIndex = nextWaypointIndex;
m_DesiredWaypointIndex = nextWaypointIndex;
UpdateLinearVelocity();
UpdateAngularVelocity();
m_IsDirty = true;
}
void PlatformSubComponent::SetupPath(const std::string& pathName, uint32_t startingWaypointIndex, bool startsInReverse) {
m_Path = Game::zoneManager->GetZone()->GetPath(pathName);
LOG("setting up path %s", pathName.c_str());
if (!m_Path) {
LOG("Failed to find path (%s)", pathName.c_str());
return;
}
m_InReverse = startsInReverse;
m_CurrentWaypointIndex = startingWaypointIndex;
m_TimeBasedMovement = m_Path->movingPlatform.timeBasedMovement;
m_NextWaypointIndex = m_InReverse ? FindNextReversedWaypointIndex() : FindNextWaypointIndex();
}
const PathWaypoint& PlatformSubComponent::GetNextWaypoint() const {
DluAssert(m_Path != nullptr);
return m_Path->pathWaypoints.at(m_NextWaypointIndex);
}
const int32_t PlatformSubComponent::FindNextWaypointIndex() {
DluAssert(m_Path != nullptr);
uint32_t numWaypoints = m_Path->pathWaypoints.size();
uint32_t nextWaypointIndex = m_CurrentWaypointIndex + 1;
if (numWaypoints <= nextWaypointIndex) {
PathBehavior behavior = m_Path->pathBehavior;
if (behavior == PathBehavior::Once) {
nextWaypointIndex = m_Path->pathWaypoints.size() - 1;
} else if (behavior == PathBehavior::Bounce) {
nextWaypointIndex = m_Path->pathWaypoints.size() - 2;
m_InReverse = true;
} else {
nextWaypointIndex = 0;
}
}
return nextWaypointIndex;
}
const int32_t PlatformSubComponent::FindNextReversedWaypointIndex() {
DluAssert(m_Path != nullptr);
uint32_t numWaypoints = m_Path->pathWaypoints.size();
int32_t nextWaypointIndex = m_CurrentWaypointIndex - 1;
if (nextWaypointIndex < 0) {
PathBehavior behavior = m_Path->pathBehavior;
if (behavior == PathBehavior::Once) {
nextWaypointIndex = 0;
} else if (behavior == PathBehavior::Bounce) {
nextWaypointIndex = 1;
m_InReverse = false;
} else {
nextWaypointIndex = m_Path->pathWaypoints.size() - 1;
}
}
return nextWaypointIndex;
}
const PathWaypoint& PlatformSubComponent::GetCurrentWaypoint() const {
DluAssert(m_Path != nullptr);
return m_Path->pathWaypoints.at(m_CurrentWaypointIndex);
}
float PlatformSubComponent::CalculateSpeed() const {
float speed;
if (m_TimeBasedMovement) {
float unitizedDirection = 1.0f / (GetNextWaypoint().position - GetCurrentWaypoint().position).Length();
speed = unitizedDirection / GetCurrentWaypoint().movingPlatform.speed;
} else {
LOG("%i %i", m_CurrentWaypointIndex, m_NextWaypointIndex);
Game::logger->Flush();
speed = (GetNextWaypoint().movingPlatform.speed - GetCurrentWaypoint().movingPlatform.speed) * m_PercentUntilNextWaypoint + GetCurrentWaypoint().movingPlatform.speed;
}
return speed;
}
NiPoint3 PlatformSubComponent::CalculateLinearVelocity() {
return (GetNextWaypoint().position - GetCurrentWaypoint().position).Unitize() * CalculateSpeed();
}
void PlatformSubComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
outBitStream->Write(bIsInitialUpdate || m_IsDirty);
if (!(bIsInitialUpdate || m_IsDirty)) return;
outBitStream->Write(m_State);
outBitStream->Write(m_DesiredWaypointIndex);
outBitStream->Write(m_ShouldStopAtDesiredWaypoint);
outBitStream->Write(m_InReverse);
outBitStream->Write(m_PercentUntilNextWaypoint);
outBitStream->Write(m_Position.x);
outBitStream->Write(m_Position.y);
outBitStream->Write(m_Position.z);
outBitStream->Write(m_CurrentWaypointIndex);
outBitStream->Write(m_NextWaypointIndex);
outBitStream->Write(m_IdleTimeElapsed);
outBitStream->Write(m_MoveTimeElapsed);
if (!bIsInitialUpdate) m_IsDirty = false;
}
void PlatformSubComponent::StartPathing() {
m_State |= eMovementPlatformState::Travelling;
m_State &= ~eMovementPlatformState::Stopped;
m_State &= ~eMovementPlatformState::Waiting;
m_IsDirty = true;
m_CurrentWaypointIndex = m_ParentComponent->GetStartingWaypointIndex();
m_InReverse = m_ParentComponent->GetStartsIsInReverse();
m_NextWaypointIndex = m_InReverse ? m_CurrentWaypointIndex - 1 : m_CurrentWaypointIndex + 1;
Game::entityManager->SerializeEntity(m_ParentComponent->GetParent());
}
void PlatformSubComponent::ResumePathing() {
if (m_State & eMovementPlatformState::Stopped && (m_State & eMovementPlatformState::ReachedDesiredWaypoint) == 0) {
StartPathing();
}
if (m_State & eMovementPlatformState::Travelling == 0) {
m_State |= eMovementPlatformState::Waiting;
m_State &= ~eMovementPlatformState::Stopped;
m_State &= ~eMovementPlatformState::Travelling;
m_IsDirty = true;
} else {
m_State &= eMovementPlatformState::Waiting;
m_State &= eMovementPlatformState::Travelling;
m_State &= eMovementPlatformState::Stopped;
m_IsDirty = true;
UpdateLinearVelocity();
UpdateAngularVelocity();
}
}
void PlatformSubComponent::StopPathing() {
m_State |= eMovementPlatformState::Stopped;
m_State &= ~eMovementPlatformState::Travelling;
m_State &= ~eMovementPlatformState::Waiting;
m_LinearVelocity = NiPoint3Constant::ZERO;
m_AngularVelocity = NiPoint3Constant::ZERO;
}
//------------- PlatformSubComponent end --------------
//------------- MoverPlatformSubComponent begin --------------
MoverPlatformSubComponent::MoverPlatformSubComponent(MovingPlatformComponent* parentComponent) : PlatformSubComponent(parentComponent) {
}
void MoverPlatformSubComponent::LoadConfigData() {
m_AllowPositionSnapping = m_ParentComponent->GetParent()->GetVar<bool>(u"allowPosSnap");
if(m_ParentComponent->GetParent()->HasVar(u"maxLerpDist")){
m_MaxLerpDistnace = m_ParentComponent->GetParent()->GetVar<float>(u"maxLerpDist");
m_MaxLerpDistnace = m_MaxLerpDistnace * m_MaxLerpDistnace;
}
}
//------------- MoverPlatformSubComponent end --------------
//------------- RotatorPlatformSubComponent begin --------------
RotatorPlatformSubComponent::RotatorPlatformSubComponent(MovingPlatformComponent* parentComponent) : PlatformSubComponent(parentComponent) {
}
void RotatorPlatformSubComponent::LoadConfigData() {
if(m_ParentComponent->GetParent()->HasVar(u"rotX")){
m_Rotation.x = m_ParentComponent->GetParent()->GetVar<float>(u"rotX") * M_PI;
}
if(m_ParentComponent->GetParent()->HasVar(u"rotY")){
m_Rotation.y = m_ParentComponent->GetParent()->GetVar<float>(u"rotY") * M_PI;
}
if(m_ParentComponent->GetParent()->HasVar(u"rotZ")){
m_Rotation.z = m_ParentComponent->GetParent()->GetVar<float>(u"rotZ") * M_PI;
}
if(m_ParentComponent->GetParent()->HasVar(u"allowRotSnap")){
m_AllowRotationSnapping = m_ParentComponent->GetParent()->GetVar<bool>(u"allowRotSnap");
}
if(m_AllowRotationSnapping) {
if(m_ParentComponent->GetParent()->HasVar(u"maxLerpAngle")){
m_MaxLerpAngle = (m_ParentComponent->GetParent()->GetVar<float>(u"maxLerpAngle") * M_PI) / 180;
}
}
}
//------------- 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");
m_StartAtEnd = m_ParentComponent->GetParent()->GetVar<bool>(u"platformStartAtEnd");
}
void SimpleMoverPlatformSubComponent::LoadDataFromTemplate() {
if (!m_ParentComponent->GetParent()->GetVar<bool>(u"dbonly")) return;
auto* movingPlatformTable = CDClientManager::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;
m_PlatformMove = platformMove;
m_MoveTime = 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 below --------------
MovingPlatformComponent::MovingPlatformComponent(Entity* parent, const std::string& pathName) : Component(parent) {
m_MoverSubComponentType = eMoverSubComponentType::mover;
m_MoverSubComponent = new MoverSubComponent(m_Parent->GetDefaultPosition());
m_PathName = GeneralUtils::ASCIIToUTF16(pathName);
m_Path = Game::zoneManager->GetZone()->GetPath(pathName);
m_NoAutoStart = false;
if (m_Path == nullptr) {
LOG("Path not found: %s", pathName.c_str());
}
}
void MovingPlatformComponent::LoadDataFromTemplate() {
std::for_each(m_Platforms.begin(), m_Platforms.end(), [](const std::unique_ptr<PlatformSubComponent>& platform) { platform->LoadDataFromTemplate(); });
}
void MovingPlatformComponent::LoadConfigData() {
if (m_Parent->GetVar<bool>(u"platformIsMover")) {
AddMovingPlatform<MoverPlatformSubComponent>();
}
if (m_Parent->GetVar<bool>(u"platformIsSimpleMover")) {
AddMovingPlatform<SimpleMoverPlatformSubComponent>(NiPoint3Constant::ZERO, false);
}
if (m_Parent->GetVar<bool>(u"platformIsRotater")) {
AddMovingPlatform<RotatorPlatformSubComponent>();
}
m_StartingWaypointIndex = m_Parent->GetVar<uint32_t>(u"attached_path_start");
m_StartsIsInReverse = false;
m_DirtyPathInfo = true;
m_StartOnload = m_Parent->GetVar<bool>(u"startPathingOnLoad");
}
void MovingPlatformComponent::Update(float deltaTime) {
std::for_each(m_Platforms.begin(), m_Platforms.end(), [deltaTime](const std::unique_ptr<PlatformSubComponent>& platform) { platform->Update(deltaTime); });
MovingPlatformComponent::~MovingPlatformComponent() {
delete static_cast<MoverSubComponent*>(m_MoverSubComponent);
}
void MovingPlatformComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
// For some reason we need to write this here instead of later on.
outBitStream->Write(!m_Platforms.empty());
// Here we don't serialize the moving platform to let the client simulate the movement
outBitStream->Write(bIsInitialUpdate || m_DirtyPathInfo);
if (bIsInitialUpdate || m_DirtyPathInfo) {
outBitStream->Write(!m_PathName.empty());
if (!m_PathName.empty()) {
outBitStream->Write(static_cast<uint16_t>(m_PathName.size()));
for (const auto& c : m_PathName) {
outBitStream->Write(static_cast<uint16_t>(c));
}
outBitStream->Write(m_StartingWaypointIndex);
outBitStream->Write(m_StartsIsInReverse);
if (!m_Serialize) {
outBitStream->Write<bool>(false);
outBitStream->Write<bool>(false);
return;
}
outBitStream->Write<bool>(true);
auto hasPath = !m_PathingStopped && !m_PathName.empty();
outBitStream->Write(hasPath);
if (hasPath) {
// Is on rail
outBitStream->Write1();
outBitStream->Write<uint16_t>(m_PathName.size());
for (const auto& c : m_PathName) {
outBitStream->Write<uint16_t>(c);
}
if (!bIsInitialUpdate) m_DirtyPathInfo = false;
}
if (m_Platforms.empty()) return;
for (const auto& platform : m_Platforms) {
outBitStream->Write1(); // Has platform to write
outBitStream->Write(platform->GetPlatformType());
platform->Serialize(outBitStream, bIsInitialUpdate);
// Starting point
outBitStream->Write<uint32_t>(0);
// Reverse
outBitStream->Write<bool>(false);
}
const auto hasPlatform = m_MoverSubComponent != nullptr;
outBitStream->Write<bool>(hasPlatform);
if (hasPlatform) {
auto* mover = static_cast<MoverSubComponent*>(m_MoverSubComponent);
outBitStream->Write(m_MoverSubComponentType);
if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) {
// TODO
} else {
mover->Serialize(outBitStream, bIsInitialUpdate);
}
}
outBitStream->Write0(); // No more platforms to write
}
void MovingPlatformComponent::OnQuickBuildInitilized() {
@@ -415,45 +122,232 @@ void MovingPlatformComponent::OnQuickBuildInitilized() {
}
void MovingPlatformComponent::OnCompleteQuickBuild() {
if (m_NoAutoStart) return;
if (m_NoAutoStart)
return;
StartPathing();
}
void MovingPlatformComponent::SetMovementState(eMovementPlatformState value) {
auto* subComponent = static_cast<MoverSubComponent*>(m_MoverSubComponent);
subComponent->mState = value;
Game::entityManager->SerializeEntity(m_Parent);
}
void MovingPlatformComponent::GotoWaypoint(uint32_t index, bool stopAtWaypoint) {
auto* subComponent = static_cast<MoverSubComponent*>(m_MoverSubComponent);
subComponent->mDesiredWaypointIndex = index;
subComponent->mNextWaypointIndex = index;
subComponent->mShouldStopAtDesiredWaypoint = stopAtWaypoint;
StartPathing();
}
void MovingPlatformComponent::StartPathing() {
std::for_each(m_Platforms.begin(), m_Platforms.end(), [](const std::unique_ptr<PlatformSubComponent>& platform) {
platform->StartPathing();
//GameMessages::SendStartPathing(m_Parent);
m_PathingStopped = false;
auto* subComponent = static_cast<MoverSubComponent*>(m_MoverSubComponent);
subComponent->mShouldStopAtDesiredWaypoint = true;
subComponent->mState = eMovementPlatformState::Stationary;
NiPoint3 targetPosition;
if (m_Path != nullptr) {
const auto& currentWaypoint = m_Path->pathWaypoints[subComponent->mCurrentWaypointIndex];
const auto& nextWaypoint = m_Path->pathWaypoints[subComponent->mNextWaypointIndex];
subComponent->mPosition = currentWaypoint.position;
subComponent->mSpeed = currentWaypoint.movingPlatform.speed;
subComponent->mWaitTime = currentWaypoint.movingPlatform.wait;
targetPosition = nextWaypoint.position;
} else {
subComponent->mPosition = m_Parent->GetPosition();
subComponent->mSpeed = 1.0f;
subComponent->mWaitTime = 2.0f;
targetPosition = m_Parent->GetPosition() + NiPoint3(0.0f, 10.0f, 0.0f);
}
m_Parent->AddCallbackTimer(subComponent->mWaitTime, [this] {
SetMovementState(eMovementPlatformState::Moving);
});
const auto travelTime = Vector3::Distance(targetPosition, subComponent->mPosition) / subComponent->mSpeed + 1.5f;
const auto travelNext = subComponent->mWaitTime + travelTime;
m_Parent->AddCallbackTimer(travelTime, [subComponent, this] {
for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) {
script->OnWaypointReached(m_Parent, subComponent->mNextWaypointIndex);
}
});
m_Parent->AddCallbackTimer(travelNext, [this] {
ContinuePathing();
});
//GameMessages::SendPlatformResync(m_Parent, UNASSIGNED_SYSTEM_ADDRESS);
Game::entityManager->SerializeEntity(m_Parent);
}
void MovingPlatformComponent::ContinuePathing() {
auto* subComponent = static_cast<MoverSubComponent*>(m_MoverSubComponent);
subComponent->mState = eMovementPlatformState::Stationary;
subComponent->mCurrentWaypointIndex = subComponent->mNextWaypointIndex;
NiPoint3 targetPosition;
uint32_t pathSize;
PathBehavior behavior;
if (m_Path != nullptr) {
const auto& currentWaypoint = m_Path->pathWaypoints[subComponent->mCurrentWaypointIndex];
const auto& nextWaypoint = m_Path->pathWaypoints[subComponent->mNextWaypointIndex];
subComponent->mPosition = currentWaypoint.position;
subComponent->mSpeed = currentWaypoint.movingPlatform.speed;
subComponent->mWaitTime = currentWaypoint.movingPlatform.wait; // + 2;
pathSize = m_Path->pathWaypoints.size() - 1;
behavior = static_cast<PathBehavior>(m_Path->pathBehavior);
targetPosition = nextWaypoint.position;
} else {
subComponent->mPosition = m_Parent->GetPosition();
subComponent->mSpeed = 1.0f;
subComponent->mWaitTime = 2.0f;
targetPosition = m_Parent->GetPosition() + NiPoint3(0.0f, 10.0f, 0.0f);
pathSize = 1;
behavior = PathBehavior::Loop;
}
if (m_Parent->GetLOT() == 9483) {
behavior = PathBehavior::Bounce;
} else {
return;
}
if (subComponent->mCurrentWaypointIndex >= pathSize) {
subComponent->mCurrentWaypointIndex = pathSize;
switch (behavior) {
case PathBehavior::Once:
Game::entityManager->SerializeEntity(m_Parent);
return;
case PathBehavior::Bounce:
subComponent->mInReverse = true;
break;
case PathBehavior::Loop:
subComponent->mNextWaypointIndex = 0;
break;
default:
break;
}
} else if (subComponent->mCurrentWaypointIndex == 0) {
subComponent->mInReverse = false;
}
if (subComponent->mInReverse) {
subComponent->mNextWaypointIndex = subComponent->mCurrentWaypointIndex - 1;
} else {
subComponent->mNextWaypointIndex = subComponent->mCurrentWaypointIndex + 1;
}
/*
subComponent->mNextWaypointIndex = 0;
subComponent->mCurrentWaypointIndex = 1;
*/
//GameMessages::SendPlatformResync(m_Parent, UNASSIGNED_SYSTEM_ADDRESS);
if (subComponent->mCurrentWaypointIndex == subComponent->mDesiredWaypointIndex) {
// TODO: Send event?
StopPathing();
return;
}
m_Parent->CancelCallbackTimers();
m_Parent->AddCallbackTimer(subComponent->mWaitTime, [this] {
SetMovementState(eMovementPlatformState::Moving);
});
auto travelTime = Vector3::Distance(targetPosition, subComponent->mPosition) / subComponent->mSpeed + 1.5;
if (m_Parent->GetLOT() == 9483) {
travelTime += 20;
}
const auto travelNext = subComponent->mWaitTime + travelTime;
m_Parent->AddCallbackTimer(travelTime, [subComponent, this] {
for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) {
script->OnWaypointReached(m_Parent, subComponent->mNextWaypointIndex);
}
});
m_Parent->AddCallbackTimer(travelNext, [this] {
ContinuePathing();
});
Game::entityManager->SerializeEntity(m_Parent);
}
void MovingPlatformComponent::StopPathing() {
//m_Parent->CancelCallbackTimers();
auto* subComponent = static_cast<MoverSubComponent*>(m_MoverSubComponent);
m_PathingStopped = true;
subComponent->mState = eMovementPlatformState::Stopped;
subComponent->mDesiredWaypointIndex = -1;
subComponent->mShouldStopAtDesiredWaypoint = false;
Game::entityManager->SerializeEntity(m_Parent);
//GameMessages::SendPlatformResync(m_Parent, UNASSIGNED_SYSTEM_ADDRESS);
}
void MovingPlatformComponent::SetSerialized(bool value) {
m_Serialize = value;
}
bool MovingPlatformComponent::GetNoAutoStart() const {
return false;
return m_NoAutoStart;
}
void MovingPlatformComponent::SetNoAutoStart(const bool value) {
m_NoAutoStart = value;
}
void MovingPlatformComponent::WarpToWaypoint(size_t index) {
const auto& waypoint = m_Path->pathWaypoints[index];
m_Parent->SetPosition(waypoint.position);
m_Parent->SetRotation(waypoint.rotation);
Game::entityManager->SerializeEntity(m_Parent);
}
size_t MovingPlatformComponent::GetLastWaypointIndex() const {
return 0;
return m_Path->pathWaypoints.size() - 1;
}
//------------- MovingPlatformComponent end --------------
MoverSubComponent* MovingPlatformComponent::GetMoverSubComponent() const {
return static_cast<MoverSubComponent*>(m_MoverSubComponent);
}

View File

@@ -6,166 +6,96 @@
#ifndef MOVINGPLATFORMCOMPONENT_H
#define MOVINGPLATFORMCOMPONENT_H
#include "RakNetTypes.h"
#include "NiPoint3.h"
#include <memory>
#include <string>
#include <vector>
#include "dCommonVars.h"
#include "EntityManager.h"
#include "Component.h"
#include "eMovementPlatformState.h"
#include "eReplicaComponentType.h"
class PathWaypoint;
class Path;
/**
* The different types of platform movement state
*/
enum eMovementPlatformState : uint32_t
{
Waiting = 1 << 0U,
Travelling = 1 << 1U,
Stopped = 1 << 2U,
ReachedDesiredWaypoint = 1 << 3U,
ReachedFinalWaypoint = 1 << 4U,
};
/**
* Different types of available platforms
*/
/**
* Different types of available platforms
*/
enum class eMoverSubComponentType : uint32_t {
None = 0,
Mover = 4,
SimpleMover = 5,
Rotator = 6
mover = 4,
/**
* Used in NJ
*/
simpleMover = 5,
};
class MovingPlatformComponent;
// In the context of a platform that is TimeBasedMovement,
// the speed member from the Path is used as the time to go between waypoints.
class PlatformSubComponent {
/**
* Sub component for moving platforms that determine the actual current movement state
*/
class MoverSubComponent {
public:
PlatformSubComponent(MovingPlatformComponent* parentComponent);
virtual ~PlatformSubComponent() = default;
virtual void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate);
virtual eMoverSubComponentType GetPlatformType() { return eMoverSubComponentType::None; };
bool GetIsDirty() const { return m_IsDirty; }
virtual void LoadDataFromTemplate() {};
virtual void LoadConfigData() {};
virtual void StartPathing();
virtual void ResumePathing();
virtual void StopPathing();
virtual void Update(float deltaTime);
float CalculateSpeed() const;
const PathWaypoint& GetNextWaypoint() const;
const PathWaypoint& GetCurrentWaypoint() const;
const int32_t FindNextWaypointIndex();
const int32_t FindNextReversedWaypointIndex();
void SetupPath(const std::string& pathName, uint32_t startingWaypointIndex, bool startsInReverse);
void AdvanceToNextWaypoint();
void AdvanceToNextReverseWaypoint();
NiPoint3 CalculateLinearVelocity();
void UpdateLinearVelocity();
void UpdateAngularVelocity();
float CalculatePercentToNextWaypoint();
MoverSubComponent(const NiPoint3& startPos);
~MoverSubComponent();
// Write all the getters for the below members
bool GetTimeBasedMovement() const { return m_TimeBasedMovement; }
const Path* GetPath() const { return m_Path; }
float GetSpeed() const { return m_Speed; }
float GetWaitTime() const { return m_WaitTime; }
float GetMoveTimeElapsed() const { return m_MoveTimeElapsed; }
float GetPercentUntilNextWaypoint() const { return m_PercentUntilNextWaypoint; }
int32_t GetCurrentWaypointIndex() const { return m_CurrentWaypointIndex; }
int32_t GetNextWaypointIndex() const { return m_NextWaypointIndex; }
bool GetInReverse() const { return m_InReverse; }
bool GetShouldStopAtDesiredWaypoint() const { return m_ShouldStopAtDesiredWaypoint; }
int32_t GetDesiredWaypointIndex() const { return m_DesiredWaypointIndex; }
uint32_t GetState() const { return m_State; }
const NiPoint3& GetPosition() const { return m_Position; }
const NiQuaternion& GetRotation() const { return m_Rotation; }
const NiPoint3& GetLinearVelocity() const { return m_LinearVelocity; }
const NiPoint3& GetAngularVelocity() const { return m_AngularVelocity; }
const MovingPlatformComponent* GetParentComponent() const { return m_ParentComponent; }
const float GetIdleTimeElapsed() const { return m_IdleTimeElapsed; }
protected:
MovingPlatformComponent* m_ParentComponent;
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate);
/**
* The state the platform is currently in
*/
uint32_t m_State;
int32_t m_DesiredWaypointIndex;
float m_PercentUntilNextWaypoint;
NiPoint3 m_Position;
int32_t m_CurrentWaypointIndex;
int32_t m_NextWaypointIndex;
float m_IdleTimeElapsed;
float m_Speed;
float m_WaitTime;
float m_MoveTimeElapsed;
bool m_IsDirty;
bool m_InReverse;
bool m_ShouldStopAtDesiredWaypoint;
NiPoint3 m_LinearVelocity;
NiPoint3 m_AngularVelocity;
bool m_TimeBasedMovement;
const Path* m_Path;
NiQuaternion m_Rotation;
eMovementPlatformState mState = eMovementPlatformState::Stationary;
/**
* The waypoint this platform currently wants to traverse to
*/
int32_t mDesiredWaypointIndex = 0;
/**
* Whether the platform is currently reversing away from the desired waypoint
*/
bool mInReverse = false;
/**
* Whether the platform should stop moving when reaching the desired waypoint
*/
bool mShouldStopAtDesiredWaypoint = false;
/**
* The percentage of the way between the last point and the desired point
*/
float mPercentBetweenPoints = 0;
/**
* The current position of the platofrm
*/
NiPoint3 mPosition{};
/**
* The waypoint the platform is (was) at
*/
uint32_t mCurrentWaypointIndex;
/**
* The waypoint the platform is attempting to go to
*/
uint32_t mNextWaypointIndex;
/**
* The timer that handles the time before stopping idling and continue platform movement
*/
float mIdleTimeElapsed = 0;
/**
* The speed the platform is currently moving at
*/
float mSpeed = 0;
/**
* The time to wait before continuing movement
*/
float mWaitTime = 0;
};
class MoverPlatformSubComponent : public PlatformSubComponent {
public:
inline static const eMoverSubComponentType SubComponentType = eMoverSubComponentType::Mover;
MoverPlatformSubComponent(MovingPlatformComponent* parentComponent);
~MoverPlatformSubComponent() override = default;
eMoverSubComponentType GetPlatformType() override { return eMoverSubComponentType::Mover; }
void LoadConfigData() override;
private:
bool m_AllowPositionSnapping = true;
float m_MaxLerpDistnace = 16.0f;
};
class RotatorPlatformSubComponent : public PlatformSubComponent {
public:
inline static const eMoverSubComponentType SubComponentType = eMoverSubComponentType::Rotator;
RotatorPlatformSubComponent(MovingPlatformComponent* parentComponent);
~RotatorPlatformSubComponent() override = default;
eMoverSubComponentType GetPlatformType() override { return eMoverSubComponentType::Rotator; }
void LoadConfigData() override;
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override { PlatformSubComponent::Serialize(outBitStream, bIsInitialUpdate); };
private:
NiPoint3 m_Rotation = NiPoint3Constant::ZERO;
float m_Rate = 0.0f;
NiPoint3 m_AngularVelocity = NiPoint3Constant::ZERO;
bool m_AllowRotationSnapping = true;
float m_MaxLerpAngle = 0.1396263;
bool m_DirtyAngularVelocity = false;
float m_UnknownFloat = 0.0f;
};
// Only moves. Has NO path. This moving platform gets its initial position and rotation from the server on serialization.
class SimpleMoverPlatformSubComponent : public PlatformSubComponent {
public:
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 LoadConfigData() override;
void LoadDataFromTemplate() override;
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;
};
/**
* Represents entities that may be moving platforms, indicating how they should move through the world.
@@ -179,10 +109,7 @@ public:
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::MOVING_PLATFORM;
MovingPlatformComponent(Entity* parent, const std::string& pathName);
void LoadDataFromTemplate();
void LoadConfigData();
void Update(float deltaTime) override;
~MovingPlatformComponent() override;
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
@@ -228,7 +155,7 @@ public:
* Determines if the entity should be serialized on the next update
* @param value whether to serialize the entity or not
*/
void SetSerialized(bool value) {};
void SetSerialized(bool value);
/**
* Returns if this platform will start automatically after spawn
@@ -254,44 +181,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)...));
}
}
bool HasPlatform() { return !m_Platforms.empty(); }
const PlatformSubComponent& GetPlatform() const {
return *m_Platforms.at(0);
}
int32_t GetComponentId() const { return componentId; }
// Make
const std::u16string& GetPathName() const { return m_PathName; }
void SetPathName(const std::u16string& pathName) { m_PathName = pathName; }
bool GetPathingStopped() const { return m_PathingStopped; }
void SetPathingStopped(bool value) { m_PathingStopped = value; }
uint32_t GetStartingWaypointIndex() const { return m_StartingWaypointIndex; }
void SetStartingWaypointIndex(uint32_t value) { m_StartingWaypointIndex = value; }
bool GetStartsIsInReverse() const { return m_StartsIsInReverse; }
void SetStartsIsInReverse(bool value) { m_StartsIsInReverse = value; }
bool GetStartOnload() const { return m_StartOnload; }
void SetStartOnload(bool value) { m_StartOnload = value; }
bool GetDirtyPathInfo() const { return m_DirtyPathInfo; }
/**
* Returns the sub component that actually defines how the platform moves around (speeds, etc).
* @return the sub component that actually defines how the platform moves around
*/
MoverSubComponent* GetMoverSubComponent() const;
private:
/**
* The path this platform is currently on
*/
const Path* m_Path = nullptr;
/**
* The name of the path this platform is currently on
*/
@@ -302,24 +204,25 @@ private:
*/
bool m_PathingStopped = false;
uint32_t m_StartingWaypointIndex = 0;
bool m_StartsIsInReverse = false;
int32_t componentId = -1;
/**
* The type of the subcomponent
*/
eMoverSubComponentType m_MoverSubComponentType;
/**
* The mover sub component that belongs to this platform
*/
std::vector<std::unique_ptr<PlatformSubComponent>> m_Platforms;
void* m_MoverSubComponent;
/**
* Whether the platform shouldn't auto start
*/
bool m_NoAutoStart;
bool m_DirtyPathInfo = false;
bool m_StartOnload = false;
/**
* Whether to serialize the entity on the next update
*/
bool m_Serialize = false;
};
#endif // MOVINGPLATFORMCOMPONENT_H

View File

@@ -25,6 +25,7 @@
#include "ChatPackets.h"
#include "MultiZoneEntranceComponent.h"
#include "eUnequippableActiveType.h"
#include "eMovementPlatformState.h"
#include "LeaderboardManager.h"
#include "Amf3.h"
#include "Loot.h"
@@ -358,43 +359,55 @@ void GameMessages::SendResetMissions(Entity* entity, const SystemAddress& sysAdd
SEND_PACKET;
}
void GameMessages::SendPlatformResync(Entity* entity, const SystemAddress& sysAddr,
eMovementPlatformState movementState, bool bStopAtDesiredWaypoint,
int iIndex, int iDesiredWaypointIndex, int nextIndex) {
void GameMessages::SendPlatformResync(Entity* entity, const SystemAddress& sysAddr, bool bStopAtDesiredWaypoint,
int iIndex, int iDesiredWaypointIndex, int nextIndex,
eMovementPlatformState movementState) {
CBITSTREAM;
CMSGHEADER;
const auto lot = entity->GetLOT();
if (lot == 12341 || lot == 5027 || lot == 5028 || lot == 14335 || lot == 14447 || lot == 14449) {
iDesiredWaypointIndex = 0;
iIndex = 0;
nextIndex = 0;
bStopAtDesiredWaypoint = true;
movementState = eMovementPlatformState::Stationary;
}
bitStream.Write(entity->GetObjectID());
bitStream.Write(eGameMessageType::PLATFORM_RESYNC);
auto* movingPlatformComponent = entity->GetComponent<MovingPlatformComponent>();
if (!movingPlatformComponent) return;
if (!movingPlatformComponent->HasPlatform()) return;
auto& subComponent = movingPlatformComponent->GetPlatform();
bool bReverse = false;
int eCommand = 0;
int eUnexpectedCommand = 0;
float fIdleTimeElapsed = 0.0f;
float fMoveTimeElapsed = 0.0f;
float fPercentBetweenPoints = 0.0f;
NiPoint3 ptUnexpectedLocation = NiPoint3Constant::ZERO;
NiQuaternion qUnexpectedRotation = NiQuaternionConstant::IDENTITY;
bitStream.Write(subComponent.GetInReverse());
bitStream.Write(subComponent.GetShouldStopAtDesiredWaypoint());
bitStream.Write<int32_t>(0);
bitStream.Write(subComponent.GetState());
bitStream.Write<int32_t>(0);
bitStream.Write(subComponent.GetIdleTimeElapsed());
bitStream.Write(subComponent.GetMoveTimeElapsed());
bitStream.Write(subComponent.GetPercentUntilNextWaypoint());
bitStream.Write(subComponent.GetDesiredWaypointIndex());
bitStream.Write(subComponent.GetCurrentWaypointIndex());
bitStream.Write(subComponent.GetNextWaypointIndex());
bitStream.Write(subComponent.GetPosition().x);
bitStream.Write(subComponent.GetPosition().y);
bitStream.Write(subComponent.GetPosition().z);
bitStream.Write(bReverse);
bitStream.Write(bStopAtDesiredWaypoint);
bitStream.Write(eCommand);
bitStream.Write(static_cast<int32_t>(movementState));
bitStream.Write(eUnexpectedCommand);
bitStream.Write(fIdleTimeElapsed);
bitStream.Write(fMoveTimeElapsed);
bitStream.Write(fPercentBetweenPoints);
bitStream.Write(iDesiredWaypointIndex);
bitStream.Write(iIndex);
bitStream.Write(nextIndex);
bitStream.Write(ptUnexpectedLocation.x);
bitStream.Write(ptUnexpectedLocation.y);
bitStream.Write(ptUnexpectedLocation.z);
bitStream.Write(subComponent.GetRotation() != NiQuaternionConstant::IDENTITY);
if (subComponent.GetRotation() != NiQuaternionConstant::IDENTITY) {
bitStream.Write(subComponent.GetRotation().x);
bitStream.Write(subComponent.GetRotation().y);
bitStream.Write(subComponent.GetRotation().z);
bitStream.Write(subComponent.GetRotation().w);
bitStream.Write(qUnexpectedRotation != NiQuaternionConstant::IDENTITY);
if (qUnexpectedRotation != NiQuaternionConstant::IDENTITY) {
bitStream.Write(qUnexpectedRotation.x);
bitStream.Write(qUnexpectedRotation.y);
bitStream.Write(qUnexpectedRotation.z);
bitStream.Write(qUnexpectedRotation.w);
}
SEND_PACKET_BROADCAST;
@@ -2491,7 +2504,7 @@ void GameMessages::HandleControlBehaviors(RakNet::BitStream* inStream, Entity* e
auto owner = PropertyManagementComponent::Instance()->GetOwner();
if (!owner) return;
ControlBehaviors::Instance().ProcessCommand(entity, sysAddr, static_cast<AMFArrayValue*>(amfArguments.get()), command, owner);
ControlBehaviors::Instance().ProcessCommand(entity, static_cast<AMFArrayValue*>(amfArguments.get()), command, owner);
}
void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) {
@@ -4949,7 +4962,8 @@ void GameMessages::HandleFireEventServerSide(RakNet::BitStream* inStream, Entity
}
void GameMessages::HandleRequestPlatformResync(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) {
GameMessages::SendPlatformResync(entity, sysAddr, eMovementPlatformState::Travelling);
if (entity->GetLOT() == 6267 || entity->GetLOT() == 16141) return;
GameMessages::SendPlatformResync(entity, sysAddr);
}
void GameMessages::HandleQuickBuildCancel(RakNet::BitStream* inStream, Entity* entity) {

View File

@@ -5,6 +5,7 @@
#include <map>
#include <string>
#include <vector>
#include "eMovementPlatformState.h"
#include "NiPoint3.h"
#include "eEndBehavior.h"
#include "eCyclingMode.h"
@@ -20,7 +21,6 @@ class Leaderboard;
class PropertySelectQueryProperty;
class TradeItem;
enum eMovementPlatformState : uint32_t;
enum class eAnimationFlags : uint32_t;
enum class eUnequippableActiveType;
@@ -71,9 +71,9 @@ namespace GameMessages {
void SendPlayNDAudioEmitter(Entity* entity, const SystemAddress& sysAddr, std::string audioGUID);
void SendStartPathing(Entity* entity);
void SendPlatformResync(Entity* entity, const SystemAddress& sysAddr,
eMovementPlatformState movementState, bool bStopAtDesiredWaypoint = false,
int iIndex = 0, int iDesiredWaypointIndex = 1, int nextIndex = 1);
void SendPlatformResync(Entity* entity, const SystemAddress& sysAddr, bool bStopAtDesiredWaypoint = false,
int iIndex = 0, int iDesiredWaypointIndex = 1, int nextIndex = 1,
eMovementPlatformState movementState = eMovementPlatformState::Moving);
void SendResetMissions(Entity* entity, const SystemAddress& sysAddr, const int32_t missionid = -1);
void SendRestoreToPostLoadStats(Entity* entity, const SystemAddress& sysAddr);

View File

@@ -2,8 +2,8 @@
BlockDefinition BlockDefinition::blockDefinitionDefault{};
BlockDefinition::BlockDefinition(std::string defaultValue, float minimumValue, float maximumValue) {
this->defaultValue = defaultValue;
this->minimumValue = minimumValue;
this->maximumValue = maximumValue;
BlockDefinition::BlockDefinition(const std::string& defaultValue, const float minimumValue, const float maximumValue)
: m_DefaultValue{ defaultValue }
, m_MinimumValue{ minimumValue }
, m_MaximumValue{ maximumValue } {
}

View File

@@ -7,19 +7,20 @@ class AMFArrayValue;
class BlockDefinition {
public:
BlockDefinition(std::string defaultValue = "", float minimumValue = 0.0f, float maximumValue = 0.0f);
BlockDefinition(const std::string& defaultValue = "", const float minimumValue = 0.0f, const float maximumValue = 0.0f);
static BlockDefinition blockDefinitionDefault;
std::string& GetDefaultValue() { return defaultValue; };
float GetMinimumValue() { return minimumValue; };
float GetMaximumValue() { return maximumValue; };
void SetDefaultValue(std::string value) { defaultValue = value; };
void SetMinimumValue(float value) { minimumValue = value; };
void SetMaximumValue(float value) { maximumValue = value; };
[[nodiscard]] const std::string& GetDefaultValue() const { return m_DefaultValue; }
[[nodiscard]] float GetMinimumValue() const noexcept { return m_MinimumValue; }
[[nodiscard]] float GetMaximumValue() const noexcept { return m_MaximumValue; }
void SetDefaultValue(const std::string& value) { m_DefaultValue = value; }
void SetMinimumValue(const float value) noexcept { m_MinimumValue = value; }
void SetMaximumValue(const float value) noexcept { m_MaximumValue = value; }
private:
std::string defaultValue;
float minimumValue;
float maximumValue;
std::string m_DefaultValue;
float m_MinimumValue;
float m_MaximumValue;
};
#endif //!__BLOCKDEFINITION__H__

View File

@@ -1,46 +1,34 @@
#include "Action.h"
#include "Amf3.h"
Action::Action() {
type = "";
valueParameterName = "";
valueParameterString = "";
valueParameterDouble = 0.0;
}
Action::Action(AMFArrayValue* arguments) {
type = "";
valueParameterName = "";
valueParameterString = "";
valueParameterDouble = 0.0;
for (auto& [paramName, paramValue] : arguments->GetAssociative()) {
Action::Action(const AMFArrayValue* arguments) {
for (const auto& [paramName, paramValue] : arguments->GetAssociative()) {
if (paramName == "Type") {
if (paramValue->GetValueType() != eAmf::String) continue;
type = static_cast<AMFStringValue*>(paramValue)->GetValue();
m_Type = static_cast<AMFStringValue*>(paramValue)->GetValue();
} else {
valueParameterName = paramName;
m_ValueParameterName = paramName;
// Message is the only known string parameter
if (valueParameterName == "Message") {
if (m_ValueParameterName == "Message") {
if (paramValue->GetValueType() != eAmf::String) continue;
valueParameterString = static_cast<AMFStringValue*>(paramValue)->GetValue();
m_ValueParameterString = static_cast<AMFStringValue*>(paramValue)->GetValue();
} else {
if (paramValue->GetValueType() != eAmf::Double) continue;
valueParameterDouble = static_cast<AMFDoubleValue*>(paramValue)->GetValue();
m_ValueParameterDouble = static_cast<AMFDoubleValue*>(paramValue)->GetValue();
}
}
}
}
void Action::SendBehaviorBlocksToClient(AMFArrayValue& args) const {
auto* actionArgs = args.PushArray();
actionArgs->Insert("Type", type);
auto* const actionArgs = args.PushArray();
actionArgs->Insert("Type", m_Type);
auto valueParameterName = GetValueParameterName();
if (valueParameterName.empty()) return;
if (m_ValueParameterName.empty()) return;
if (valueParameterName == "Message") {
actionArgs->Insert(valueParameterName, valueParameterString);
if (m_ValueParameterName == "Message") {
actionArgs->Insert(m_ValueParameterName, m_ValueParameterString);
} else {
actionArgs->Insert(valueParameterName, valueParameterDouble);
actionArgs->Insert(m_ValueParameterName, m_ValueParameterDouble);
}
}

View File

@@ -11,19 +11,20 @@ class AMFArrayValue;
*/
class Action {
public:
Action();
Action(AMFArrayValue* arguments);
const std::string& GetType() const { return type; };
const std::string& GetValueParameterName() const { return valueParameterName; };
const std::string& GetValueParameterString() const { return valueParameterString; };
const double GetValueParameterDouble() const { return valueParameterDouble; };
Action() = default;
Action(const AMFArrayValue* arguments);
[[nodiscard]] const std::string& GetType() const { return m_Type; };
[[nodiscard]] const std::string& GetValueParameterName() const { return m_ValueParameterName; };
[[nodiscard]] const std::string& GetValueParameterString() const { return m_ValueParameterString; };
[[nodiscard]] double GetValueParameterDouble() const noexcept { return m_ValueParameterDouble; };
void SendBehaviorBlocksToClient(AMFArrayValue& args) const;
private:
std::string type;
std::string valueParameterName;
std::string valueParameterString;
double valueParameterDouble;
double m_ValueParameterDouble{ 0.0 };
std::string m_Type{ "" };
std::string m_ValueParameterName{ "" };
std::string m_ValueParameterString{ "" };
};
#endif //!__ACTION__H__

View File

@@ -4,27 +4,20 @@
#include "Amf3.h"
ActionContext::ActionContext() {
stripId = 0;
stateId = BehaviorState::HOME_STATE;
ActionContext::ActionContext(const AMFArrayValue* arguments, const std::string& customStateKey, const std::string& customStripKey)
: m_StripId{ GetStripIdFromArgument(arguments, customStripKey) }
, m_StateId{ GetBehaviorStateFromArgument(arguments, customStateKey) } {
}
ActionContext::ActionContext(AMFArrayValue* arguments, std::string customStateKey, std::string customStripKey) {
stripId = 0;
stateId = BehaviorState::HOME_STATE;
stripId = GetStripIdFromArgument(arguments, customStripKey);
stateId = GetBehaviorStateFromArgument(arguments, customStateKey);
}
BehaviorState ActionContext::GetBehaviorStateFromArgument(AMFArrayValue* arguments, const std::string& key) {
auto* stateIDValue = arguments->Get<double>(key);
BehaviorState ActionContext::GetBehaviorStateFromArgument(const AMFArrayValue* arguments, const std::string& key) const {
const auto* const stateIDValue = arguments->Get<double>(key);
if (!stateIDValue) throw std::invalid_argument("Unable to find behavior state from argument \"" + key + "\"");
return static_cast<BehaviorState>(stateIDValue->GetValue());
}
StripId ActionContext::GetStripIdFromArgument(AMFArrayValue* arguments, const std::string& key) {
auto* stripIdValue = arguments->Get<double>(key);
StripId ActionContext::GetStripIdFromArgument(const AMFArrayValue* arguments, const std::string& key) const {
const auto* const stripIdValue = arguments->Get<double>(key);
if (!stripIdValue) throw std::invalid_argument("Unable to find strip ID from argument \"" + key + "\"");
return static_cast<StripId>(stripIdValue->GetValue());

View File

@@ -12,15 +12,16 @@ class AMFArrayValue;
*/
class ActionContext {
public:
ActionContext();
ActionContext(AMFArrayValue* arguments, std::string customStateKey = "stateID", std::string customStripKey = "stripID");
const StripId GetStripId() const { return stripId; };
const BehaviorState GetStateId() const { return stateId; };
ActionContext() noexcept = default;
ActionContext(const AMFArrayValue* arguments, const std::string& customStateKey = "stateID", const std::string& customStripKey = "stripID");
[[nodiscard]] StripId GetStripId() const noexcept { return m_StripId; };
[[nodiscard]] BehaviorState GetStateId() const noexcept { return m_StateId; };
private:
BehaviorState GetBehaviorStateFromArgument(AMFArrayValue* arguments, const std::string& key);
StripId GetStripIdFromArgument(AMFArrayValue* arguments, const std::string& key);
StripId stripId;
BehaviorState stateId;
[[nodiscard]] BehaviorState GetBehaviorStateFromArgument(const AMFArrayValue* arguments, const std::string& key) const;
[[nodiscard]] StripId GetStripIdFromArgument(const AMFArrayValue* arguments, const std::string& key) const;
StripId m_StripId{ 0 };
BehaviorState m_StateId{ BehaviorState::HOME_STATE };
};
#endif //!__ACTIONCONTEXT__H__

View File

@@ -1,13 +1,14 @@
#include "AddActionMessage.h"
AddActionMessage::AddActionMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) {
actionContext = ActionContext(arguments);
actionIndex = GetActionIndexFromArgument(arguments);
AddActionMessage::AddActionMessage(const AMFArrayValue* arguments)
: BehaviorMessageBase{ arguments }
, m_ActionIndex{ GetActionIndexFromArgument(arguments) }
, m_ActionContext{ arguments } {
auto* actionValue = arguments->GetArray("action");
const auto* const actionValue = arguments->GetArray("action");
if (!actionValue) return;
action = Action(actionValue);
m_Action = Action{ actionValue };
LOG_DEBUG("actionIndex %i stripId %i stateId %i type %s valueParameterName %s valueParameterString %s valueParameterDouble %f behaviorId %i", actionIndex, actionContext.GetStripId(), actionContext.GetStateId(), action.GetType().c_str(), action.GetValueParameterName().c_str(), action.GetValueParameterString().c_str(), action.GetValueParameterDouble(), behaviorId);
LOG_DEBUG("actionIndex %i stripId %i stateId %i type %s valueParameterName %s valueParameterString %s valueParameterDouble %f m_BehaviorId %i", m_ActionIndex, m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_Action.GetType().c_str(), m_Action.GetValueParameterName().c_str(), m_Action.GetValueParameterString().c_str(), m_Action.GetValueParameterDouble(), m_BehaviorId);
}

View File

@@ -13,14 +13,18 @@ class AMFArrayValue;
*/
class AddActionMessage : public BehaviorMessageBase {
public:
AddActionMessage(AMFArrayValue* arguments);
int32_t GetActionIndex() const { return actionIndex; };
Action GetAction() const { return action; };
ActionContext GetActionContext() const { return actionContext; };
AddActionMessage(const AMFArrayValue* arguments);
[[nodiscard]] int32_t GetActionIndex() const noexcept { return m_ActionIndex; };
[[nodiscard]] const Action& GetAction() const noexcept { return m_Action; };
[[nodiscard]] const ActionContext& GetActionContext() const noexcept { return m_ActionContext; };
private:
int32_t actionIndex = -1;
ActionContext actionContext;
Action action;
int32_t m_ActionIndex{ -1 };
ActionContext m_ActionContext;
Action m_Action;
};
#endif //!__ADDACTIONMESSAGE__H__

View File

@@ -1,11 +1,9 @@
#include "AddMessage.h"
AddMessage::AddMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) {
behaviorIndex = 0;
auto* behaviorIndexValue = arguments->Get<double>("BehaviorIndex");
AddMessage::AddMessage(const AMFArrayValue* arguments) : BehaviorMessageBase{ arguments } {
const auto* const behaviorIndexValue = arguments->Get<double>("BehaviorIndex");
if (!behaviorIndexValue) return;
behaviorIndex = static_cast<uint32_t>(behaviorIndexValue->GetValue());
LOG_DEBUG("behaviorId %i index %i", behaviorId, behaviorIndex);
m_BehaviorIndex = static_cast<uint32_t>(behaviorIndexValue->GetValue());
LOG_DEBUG("behaviorId %i index %i", m_BehaviorId, m_BehaviorIndex);
}

View File

@@ -9,10 +9,11 @@
*/
class AddMessage : public BehaviorMessageBase {
public:
AddMessage(AMFArrayValue* arguments);
const uint32_t GetBehaviorIndex() const { return behaviorIndex; };
AddMessage(const AMFArrayValue* arguments);
[[nodiscard]] uint32_t GetBehaviorIndex() const noexcept { return m_BehaviorIndex; };
private:
uint32_t behaviorIndex;
uint32_t m_BehaviorIndex{ 0 };
};
#endif //!__ADDMESSAGE__H__

View File

@@ -2,27 +2,24 @@
#include "Action.h"
AddStripMessage::AddStripMessage(AMFArrayValue* const arguments) : BehaviorMessageBase{ arguments } {
actionContext = ActionContext(arguments);
position = StripUiPosition(arguments);
AddStripMessage::AddStripMessage(const AMFArrayValue* arguments)
: BehaviorMessageBase{ arguments }
, m_Position{ arguments }
, m_ActionContext{ arguments } {
auto* strip = arguments->GetArray("strip");
const auto* const strip = arguments->GetArray("strip");
if (!strip) return;
auto* actions = strip->GetArray("actions");
const auto* const actions = strip->GetArray("actions");
if (!actions) return;
for (uint32_t actionNumber = 0; actionNumber < actions->GetDense().size(); actionNumber++) {
auto* actionValue = actions->GetArray(actionNumber);
const auto* const actionValue = actions->GetArray(actionNumber);
if (!actionValue) continue;
actionsToAdd.push_back(Action(actionValue));
m_ActionsToAdd.emplace_back(actionValue);
LOG_DEBUG("xPosition %f yPosition %f stripId %i stateId %i behaviorId %i t %s valueParameterName %s valueParameterString %s valueParameterDouble %f", position.GetX(), position.GetY(), actionContext.GetStripId(), actionContext.GetStateId(), behaviorId, actionsToAdd.back().GetType().c_str(), actionsToAdd.back().GetValueParameterName().c_str(), actionsToAdd.back().GetValueParameterString().c_str(), actionsToAdd.back().GetValueParameterDouble());
LOG_DEBUG("xPosition %f yPosition %f stripId %i stateId %i behaviorId %i t %s valueParameterName %s valueParameterString %s valueParameterDouble %f", m_Position.GetX(), m_Position.GetY(), m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_BehaviorId, m_ActionsToAdd.back().GetType().c_str(), m_ActionsToAdd.back().GetValueParameterName().c_str(), m_ActionsToAdd.back().GetValueParameterString().c_str(), m_ActionsToAdd.back().GetValueParameterDouble());
}
LOG_DEBUG("number of actions %i", actionsToAdd.size());
}
std::vector<Action> AddStripMessage::GetActionsToAdd() const {
return actionsToAdd;
LOG_DEBUG("number of actions %i", m_ActionsToAdd.size());
}

View File

@@ -18,14 +18,18 @@ class AMFArrayValue;
*/
class AddStripMessage : public BehaviorMessageBase {
public:
AddStripMessage(AMFArrayValue* const arguments);
StripUiPosition GetPosition() const { return position; };
ActionContext GetActionContext() const { return actionContext; };
std::vector<Action> GetActionsToAdd() const;
AddStripMessage(const AMFArrayValue* arguments);
[[nodiscard]] const StripUiPosition& GetPosition() const noexcept { return m_Position; }
[[nodiscard]] const ActionContext& GetActionContext() const noexcept { return m_ActionContext; }
[[nodiscard]] const std::vector<Action>& GetActionsToAdd() const noexcept { return m_ActionsToAdd; }
private:
StripUiPosition position;
ActionContext actionContext;
std::vector<Action> actionsToAdd;
StripUiPosition m_Position;
ActionContext m_ActionContext;
std::vector<Action> m_ActionsToAdd;
};
#endif //!__ADDSTRIPMESSAGE__H__

View File

@@ -4,25 +4,22 @@
#include "BehaviorStates.h"
#include "dCommonVars.h"
BehaviorMessageBase::BehaviorMessageBase(AMFArrayValue* arguments) {
this->behaviorId = GetBehaviorIdFromArgument(arguments);
}
int32_t BehaviorMessageBase::GetBehaviorIdFromArgument(AMFArrayValue* const arguments) {
const char* const key = "BehaviorID";
int32_t BehaviorMessageBase::GetBehaviorIdFromArgument(const AMFArrayValue* arguments) {
static constexpr const char* key = "BehaviorID";
const auto* const behaviorIDValue = arguments->Get<std::string>(key);
int32_t behaviorId = DefaultBehaviorId;
if (behaviorIDValue && behaviorIDValue->GetValueType() == eAmf::String) {
this->behaviorId =
GeneralUtils::TryParse<int32_t>(behaviorIDValue->GetValue()).value_or(this->behaviorId);
behaviorId =
GeneralUtils::TryParse<int32_t>(behaviorIDValue->GetValue()).value_or(behaviorId);
} else if (arguments->Get(key) && arguments->Get(key)->GetValueType() != eAmf::Undefined) {
throw std::invalid_argument("Unable to find behavior ID");
}
return this->behaviorId;
return behaviorId;
}
int32_t BehaviorMessageBase::GetActionIndexFromArgument(AMFArrayValue* const arguments, const std::string& keyName) const {
int32_t BehaviorMessageBase::GetActionIndexFromArgument(const AMFArrayValue* arguments, const std::string& keyName) const {
const auto* const actionIndexAmf = arguments->Get<double>(keyName);
if (!actionIndexAmf) throw std::invalid_argument("Unable to find actionIndex");

View File

@@ -15,14 +15,15 @@ enum class BehaviorState : uint32_t;
*/
class BehaviorMessageBase {
public:
static constexpr int32_t DefaultBehaviorId = -1;
[[nodiscard]] int32_t GetBehaviorId() const { return behaviorId; };
[[nodiscard]] bool IsDefaultBehaviorId() { return behaviorId == DefaultBehaviorId; };
BehaviorMessageBase(AMFArrayValue* const arguments);
static constexpr int32_t DefaultBehaviorId{ -1 };
BehaviorMessageBase(const AMFArrayValue* arguments) : m_BehaviorId{ GetBehaviorIdFromArgument(arguments) } {}
[[nodiscard]] int32_t GetBehaviorId() const noexcept { return m_BehaviorId; }
[[nodiscard]] bool IsDefaultBehaviorId() const noexcept { return m_BehaviorId == DefaultBehaviorId; }
protected:
[[nodiscard]] int32_t GetBehaviorIdFromArgument(AMFArrayValue* const arguments);
[[nodiscard]] int32_t GetActionIndexFromArgument(AMFArrayValue* const arguments, const std::string& keyName = "actionIndex") const;
int32_t behaviorId = DefaultBehaviorId;
[[nodiscard]] int32_t GetBehaviorIdFromArgument(const AMFArrayValue* arguments);
[[nodiscard]] int32_t GetActionIndexFromArgument(const AMFArrayValue* arguments, const std::string& keyName = "actionIndex") const;
int32_t m_BehaviorId{ DefaultBehaviorId };
};
#endif //!__BEHAVIORMESSAGEBASE__H__

View File

@@ -1,11 +1,11 @@
#include "MergeStripsMessage.h"
MergeStripsMessage::MergeStripsMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) {
sourceActionContext = ActionContext(arguments, "srcStateID", "srcStripID");
MergeStripsMessage::MergeStripsMessage(const AMFArrayValue* arguments)
: BehaviorMessageBase{ arguments }
, m_DstActionIndex{ GetActionIndexFromArgument(arguments, "dstActionIndex") }
, m_SourceActionContext{ arguments, "srcStateID", "srcStripID" }
, m_DestinationActionContext{ arguments, "dstStateID", "dstStripID" } {
destinationActionContext = ActionContext(arguments, "dstStateID", "dstStripID");
dstActionIndex = GetActionIndexFromArgument(arguments, "dstActionIndex");
LOG_DEBUG("srcstripId %i dststripId %i srcstateId %i dststateId %i dstactionIndex %i behaviorId %i", sourceActionContext.GetStripId(), destinationActionContext.GetStripId(), sourceActionContext.GetStateId(), destinationActionContext.GetStateId(), dstActionIndex, behaviorId);
LOG_DEBUG("srcstripId %i dststripId %i srcstateId %i dststateId %i dstactionIndex %i behaviorId %i", m_SourceActionContext.GetStripId(), m_DestinationActionContext.GetStripId(), m_SourceActionContext.GetStateId(), m_DestinationActionContext.GetStateId(), m_DstActionIndex, m_BehaviorId);
}

View File

@@ -13,17 +13,23 @@ class AMFArrayValue;
*/
class MergeStripsMessage : public BehaviorMessageBase {
public:
MergeStripsMessage(AMFArrayValue* arguments);
int32_t GetDstActionIndex() const { return dstActionIndex; };
ActionContext GetSourceActionContext() const { return sourceActionContext; };
ActionContext GetDestinationActionContext() const { return destinationActionContext; };
const std::vector<Action>& GetMigratedActions() const { return migratedActions; };
void SetMigratedActions(std::vector<Action>::const_iterator start, std::vector<Action>::const_iterator end) { migratedActions.assign(start, end); };
MergeStripsMessage(const AMFArrayValue* arguments);
[[nodiscard]] int32_t GetDstActionIndex() const noexcept { return m_DstActionIndex; }
[[nodiscard]] const ActionContext& GetSourceActionContext() const noexcept { return m_SourceActionContext; }
[[nodiscard]] const ActionContext& GetDestinationActionContext() const noexcept { return m_DestinationActionContext; }
[[nodiscard]] const std::vector<Action>& GetMigratedActions() const noexcept { return m_MigratedActions; }
void SetMigratedActions(std::vector<Action>::const_iterator start, std::vector<Action>::const_iterator end) { m_MigratedActions.assign(start, end); };
private:
std::vector<Action> migratedActions;
ActionContext sourceActionContext;
ActionContext destinationActionContext;
int32_t dstActionIndex;
int32_t m_DstActionIndex;
std::vector<Action> m_MigratedActions;
ActionContext m_SourceActionContext;
ActionContext m_DestinationActionContext;
};
#endif //!__MERGESTRIPSMESSAGE__H__

View File

@@ -1,11 +1,11 @@
#include "MigrateActionsMessage.h"
MigrateActionsMessage::MigrateActionsMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) {
sourceActionContext = ActionContext(arguments, "srcStateID", "srcStripID");
srcActionIndex = GetActionIndexFromArgument(arguments, "srcActionIndex");
MigrateActionsMessage::MigrateActionsMessage(const AMFArrayValue* arguments)
: BehaviorMessageBase{ arguments }
, m_SrcActionIndex{ GetActionIndexFromArgument(arguments, "srcActionIndex") }
, m_DstActionIndex{ GetActionIndexFromArgument(arguments, "dstActionIndex") }
, m_SourceActionContext{ arguments, "srcStateID", "srcStripID" }
, m_DestinationActionContext{ arguments, "dstStateID", "dstStripID" } {
destinationActionContext = ActionContext(arguments, "dstStateID", "dstStripID");
dstActionIndex = GetActionIndexFromArgument(arguments, "dstActionIndex");
LOG_DEBUG("srcactionIndex %i dstactionIndex %i srcstripId %i dststripId %i srcstateId %i dststateId %i behaviorId %i", srcActionIndex, dstActionIndex, sourceActionContext.GetStripId(), destinationActionContext.GetStripId(), sourceActionContext.GetStateId(), destinationActionContext.GetStateId(), behaviorId);
LOG_DEBUG("srcactionIndex %i dstactionIndex %i srcstripId %i dststripId %i srcstateId %i dststateId %i behaviorId %i", m_SrcActionIndex, m_DstActionIndex, m_SourceActionContext.GetStripId(), m_DestinationActionContext.GetStripId(), m_SourceActionContext.GetStateId(), m_DestinationActionContext.GetStateId(), m_BehaviorId);
}

View File

@@ -13,19 +13,26 @@ class AMFArrayValue;
*/
class MigrateActionsMessage : public BehaviorMessageBase {
public:
MigrateActionsMessage(AMFArrayValue* arguments);
int32_t GetSrcActionIndex() const { return srcActionIndex; };
int32_t GetDstActionIndex() const { return dstActionIndex; };
ActionContext GetSourceActionContext() const { return sourceActionContext; };
ActionContext GetDestinationActionContext() const { return destinationActionContext; };
const std::vector<Action>& GetMigratedActions() const { return migratedActions; };
void SetMigratedActions(std::vector<Action>::const_iterator start, std::vector<Action>::const_iterator end) { migratedActions.assign(start, end); };
MigrateActionsMessage(const AMFArrayValue* arguments);
[[nodiscard]] int32_t GetSrcActionIndex() const noexcept { return m_SrcActionIndex; }
[[nodiscard]] int32_t GetDstActionIndex() const noexcept { return m_DstActionIndex; }
[[nodiscard]] const ActionContext& GetSourceActionContext() const noexcept { return m_SourceActionContext; }
[[nodiscard]] const ActionContext& GetDestinationActionContext() const noexcept { return m_DestinationActionContext; }
[[nodiscard]] const std::vector<Action>& GetMigratedActions() const noexcept { return m_MigratedActions; }
void SetMigratedActions(std::vector<Action>::const_iterator start, std::vector<Action>::const_iterator end) { m_MigratedActions.assign(start, end); }
private:
std::vector<Action> migratedActions;
ActionContext sourceActionContext;
ActionContext destinationActionContext;
int32_t srcActionIndex;
int32_t dstActionIndex;
int32_t m_SrcActionIndex;
int32_t m_DstActionIndex;
std::vector<Action> m_MigratedActions;
ActionContext m_SourceActionContext;
ActionContext m_DestinationActionContext;
};
#endif //!__MIGRATEACTIONSMESSAGE__H__

View File

@@ -1,9 +1,9 @@
#include "MoveToInventoryMessage.h"
MoveToInventoryMessage::MoveToInventoryMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) {
auto* behaviorIndexValue = arguments->Get<double>("BehaviorIndex");
MoveToInventoryMessage::MoveToInventoryMessage(const AMFArrayValue* arguments) : BehaviorMessageBase{ arguments } {
const auto* const behaviorIndexValue = arguments->Get<double>("BehaviorIndex");
if (!behaviorIndexValue) return;
behaviorIndex = static_cast<uint32_t>(behaviorIndexValue->GetValue());
LOG_DEBUG("behaviorId %i behaviorIndex %i", behaviorId, behaviorIndex);
m_BehaviorIndex = static_cast<uint32_t>(behaviorIndexValue->GetValue());
LOG_DEBUG("behaviorId %i behaviorIndex %i", m_BehaviorId, m_BehaviorIndex);
}

View File

@@ -7,15 +7,15 @@ class AMFArrayValue;
/**
* @brief Sent when a player moves a Behavior A at position B to their inventory.
*
*/
#pragma warning("This Control Behavior Message does not have a test yet. Non-developers can ignore this warning.")
class MoveToInventoryMessage : public BehaviorMessageBase {
public:
MoveToInventoryMessage(AMFArrayValue* arguments);
const uint32_t GetBehaviorIndex() const { return behaviorIndex; };
MoveToInventoryMessage(const AMFArrayValue* arguments);
[[nodiscard]] uint32_t GetBehaviorIndex() const noexcept { return m_BehaviorIndex; };
private:
uint32_t behaviorIndex;
uint32_t m_BehaviorIndex;
};
#endif //!__MOVETOINVENTORYMESSAGE__H__

View File

@@ -1,10 +1,10 @@
#include "RearrangeStripMessage.h"
RearrangeStripMessage::RearrangeStripMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) {
actionContext = ActionContext(arguments);
srcActionIndex = GetActionIndexFromArgument(arguments, "srcActionIndex");
RearrangeStripMessage::RearrangeStripMessage(const AMFArrayValue* arguments)
: BehaviorMessageBase{ arguments }
, m_SrcActionIndex{ GetActionIndexFromArgument(arguments, "srcActionIndex") }
, m_DstActionIndex{ GetActionIndexFromArgument(arguments, "dstActionIndex") }
, m_ActionContext{ arguments } {
dstActionIndex = GetActionIndexFromArgument(arguments, "dstActionIndex");
LOG_DEBUG("srcactionIndex %i dstactionIndex %i stripId %i behaviorId %i stateId %i", srcActionIndex, dstActionIndex, actionContext.GetStripId(), behaviorId, actionContext.GetStateId());
LOG_DEBUG("srcactionIndex %i dstactionIndex %i stripId %i behaviorId %i stateId %i", m_SrcActionIndex, m_DstActionIndex, m_ActionContext.GetStripId(), m_BehaviorId, m_ActionContext.GetStateId());
}

View File

@@ -10,14 +10,17 @@
*/
class RearrangeStripMessage : public BehaviorMessageBase {
public:
RearrangeStripMessage(AMFArrayValue* arguments);
int32_t GetSrcActionIndex() const { return srcActionIndex; };
int32_t GetDstActionIndex() const { return dstActionIndex; };
ActionContext GetActionContext() const { return actionContext; };
RearrangeStripMessage(const AMFArrayValue* arguments);
[[nodiscard]] int32_t GetSrcActionIndex() const noexcept { return m_SrcActionIndex; }
[[nodiscard]] int32_t GetDstActionIndex() const noexcept { return m_DstActionIndex; }
[[nodiscard]] const ActionContext& GetActionContext() const noexcept { return m_ActionContext; }
private:
ActionContext actionContext;
int32_t srcActionIndex;
int32_t dstActionIndex;
int32_t m_SrcActionIndex;
int32_t m_DstActionIndex;
ActionContext m_ActionContext;
};
#endif //!__REARRANGESTRIPMESSAGE__H__

View File

@@ -1,8 +1,9 @@
#include "RemoveActionsMessage.h"
RemoveActionsMessage::RemoveActionsMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) {
actionContext = ActionContext(arguments);
actionIndex = GetActionIndexFromArgument(arguments);
RemoveActionsMessage::RemoveActionsMessage(const AMFArrayValue* arguments)
: BehaviorMessageBase{ arguments }
, m_ActionIndex{ GetActionIndexFromArgument(arguments) }
, m_ActionContext{ arguments } {
LOG_DEBUG("behaviorId %i actionIndex %i stripId %i stateId %i", behaviorId, actionIndex, actionContext.GetStripId(), actionContext.GetStateId());
LOG_DEBUG("behaviorId %i actionIndex %i stripId %i stateId %i", m_BehaviorId, m_ActionIndex, m_ActionContext.GetStripId(), m_ActionContext.GetStateId());
}

View File

@@ -12,12 +12,15 @@ class AMFArrayValue;
*/
class RemoveActionsMessage : public BehaviorMessageBase {
public:
RemoveActionsMessage(AMFArrayValue* arguments);
int32_t GetActionIndex() const { return actionIndex; };
ActionContext GetActionContext() const { return actionContext; };
RemoveActionsMessage(const AMFArrayValue* arguments);
[[nodiscard]] int32_t GetActionIndex() const noexcept { return m_ActionIndex; }
[[nodiscard]] const ActionContext& GetActionContext() const noexcept { return m_ActionContext; }
private:
ActionContext actionContext;
int32_t actionIndex;
int32_t m_ActionIndex;
ActionContext m_ActionContext;
};
#endif //!__REMOVEACTIONSMESSAGE__H__

View File

@@ -1,7 +1,8 @@
#include "RemoveStripMessage.h"
RemoveStripMessage::RemoveStripMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) {
actionContext = ActionContext(arguments);
RemoveStripMessage::RemoveStripMessage(const AMFArrayValue* arguments)
: BehaviorMessageBase{ arguments }
, m_ActionContext{ arguments } {
LOG_DEBUG("stripId %i stateId %i behaviorId %i", actionContext.GetStripId(), actionContext.GetStateId(), behaviorId);
LOG_DEBUG("stripId %i stateId %i behaviorId %i", m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_BehaviorId);
}

View File

@@ -10,10 +10,12 @@
*/
class RemoveStripMessage : public BehaviorMessageBase {
public:
RemoveStripMessage(AMFArrayValue* arguments);
ActionContext GetActionContext() const { return actionContext; };
RemoveStripMessage(const AMFArrayValue* arguments);
const ActionContext& GetActionContext() const noexcept { return m_ActionContext; }
private:
ActionContext actionContext;
ActionContext m_ActionContext;
};
#endif //!__REMOVESTRIPMESSAGE__H__

View File

@@ -1,9 +1,9 @@
#include "RenameMessage.h"
RenameMessage::RenameMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) {
auto* nameAmf = arguments->Get<std::string>("Name");
RenameMessage::RenameMessage(const AMFArrayValue* arguments) : BehaviorMessageBase{ arguments } {
const auto* const nameAmf = arguments->Get<std::string>("Name");
if (!nameAmf) return;
name = nameAmf->GetValue();
LOG_DEBUG("behaviorId %i n %s", behaviorId, name.c_str());
m_Name = nameAmf->GetValue();
LOG_DEBUG("behaviorId %i n %s", m_BehaviorId, m_Name.c_str());
}

View File

@@ -7,14 +7,14 @@ class AMFArrayValue;
/**
* @brief Sent when a player renames this behavior
*
*/
class RenameMessage : public BehaviorMessageBase {
public:
RenameMessage(AMFArrayValue* arguments);
const std::string& GetName() const { return name; };
RenameMessage(const AMFArrayValue* arguments);
[[nodiscard]] const std::string& GetName() const { return m_Name; };
private:
std::string name;
std::string m_Name;
};
#endif //!__RENAMEMESSAGE__H__

View File

@@ -1,11 +1,11 @@
#include "SplitStripMessage.h"
SplitStripMessage::SplitStripMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) {
sourceActionContext = ActionContext(arguments, "srcStateID", "srcStripID");
srcActionIndex = GetActionIndexFromArgument(arguments, "srcActionIndex");
SplitStripMessage::SplitStripMessage(const AMFArrayValue* arguments)
: BehaviorMessageBase{ arguments }
, m_SrcActionIndex{ GetActionIndexFromArgument(arguments, "srcActionIndex") }
, m_SourceActionContext{ arguments, "srcStateID", "srcStripID" }
, m_DestinationActionContext{ arguments, "dstStateID", "dstStripID" }
, m_DestinationPosition{ arguments, "dstStripUI" } {
destinationActionContext = ActionContext(arguments, "dstStateID", "dstStripID");
destinationPosition = StripUiPosition(arguments, "dstStripUI");
LOG_DEBUG("behaviorId %i xPosition %f yPosition %f sourceStrip %i destinationStrip %i sourceState %i destinationState %i srcActindex %i", behaviorId, destinationPosition.GetX(), destinationPosition.GetY(), sourceActionContext.GetStripId(), destinationActionContext.GetStripId(), sourceActionContext.GetStateId(), destinationActionContext.GetStateId(), srcActionIndex);
LOG_DEBUG("behaviorId %i xPosition %f yPosition %f sourceStrip %i destinationStrip %i sourceState %i destinationState %i srcActindex %i", m_BehaviorId, m_DestinationPosition.GetX(), m_DestinationPosition.GetY(), m_SourceActionContext.GetStripId(), m_DestinationActionContext.GetStripId(), m_SourceActionContext.GetStateId(), m_DestinationActionContext.GetStateId(), m_SrcActionIndex);
}

View File

@@ -14,20 +14,27 @@ class AMFArrayValue;
*/
class SplitStripMessage : public BehaviorMessageBase {
public:
SplitStripMessage(AMFArrayValue* arguments);
ActionContext GetSourceActionContext() const { return sourceActionContext; };
ActionContext GetDestinationActionContext() const { return destinationActionContext; };
int32_t GetSrcActionIndex() const { return srcActionIndex; };
StripUiPosition GetPosition() const { return destinationPosition; };
const std::vector<Action>& GetTransferredActions() const { return transferredActions; };
void SetTransferredActions(std::vector<Action>::const_iterator begin, std::vector<Action>::const_iterator end) { transferredActions.assign(begin, end); };
private:
ActionContext sourceActionContext;
ActionContext destinationActionContext;
int32_t srcActionIndex;
StripUiPosition destinationPosition;
SplitStripMessage(const AMFArrayValue* arguments);
[[nodiscard]] int32_t GetSrcActionIndex() const noexcept { return m_SrcActionIndex; }
std::vector<Action> transferredActions;
[[nodiscard]] const ActionContext& GetSourceActionContext() const noexcept { return m_SourceActionContext; }
[[nodiscard]] const ActionContext& GetDestinationActionContext() const noexcept { return m_DestinationActionContext; }
[[nodiscard]] const StripUiPosition& GetPosition() const noexcept { return m_DestinationPosition; }
[[nodiscard]] const std::vector<Action>& GetTransferredActions() const noexcept { return m_TransferredActions; }
void SetTransferredActions(std::vector<Action>::const_iterator begin, std::vector<Action>::const_iterator end) { m_TransferredActions.assign(begin, end); };
private:
int32_t m_SrcActionIndex;
ActionContext m_SourceActionContext;
ActionContext m_DestinationActionContext;
StripUiPosition m_DestinationPosition;
std::vector<Action> m_TransferredActions;
};
#endif //!__SPLITSTRIPMESSAGE__H__

View File

@@ -2,27 +2,22 @@
#include "Amf3.h"
StripUiPosition::StripUiPosition() {
xPosition = 0.0;
yPosition = 0.0;
}
StripUiPosition::StripUiPosition(AMFArrayValue* arguments, std::string uiKeyName) {
xPosition = 0.0;
yPosition = 0.0;
auto* uiArray = arguments->GetArray(uiKeyName);
StripUiPosition::StripUiPosition(const AMFArrayValue* arguments, const std::string& uiKeyName) {
const auto* const uiArray = arguments->GetArray(uiKeyName);
if (!uiArray) return;
auto* xPositionValue = uiArray->Get<double>("x");
auto* yPositionValue = uiArray->Get<double>("y");
if (!xPositionValue || !yPositionValue) return;
const auto* const xPositionValue = uiArray->Get<double>("x");
if (!xPositionValue) return;
yPosition = yPositionValue->GetValue();
xPosition = xPositionValue->GetValue();
const auto* const yPositionValue = uiArray->Get<double>("y");
if (!yPositionValue) return;
m_YPosition = yPositionValue->GetValue();
m_XPosition = xPositionValue->GetValue();
}
void StripUiPosition::SendBehaviorBlocksToClient(AMFArrayValue& args) const {
auto* uiArgs = args.InsertArray("ui");
uiArgs->Insert("x", xPosition);
uiArgs->Insert("y", yPosition);
auto* const uiArgs = args.InsertArray("ui");
uiArgs->Insert("x", m_XPosition);
uiArgs->Insert("y", m_YPosition);
}

View File

@@ -9,14 +9,15 @@ class AMFArrayValue;
*/
class StripUiPosition {
public:
StripUiPosition();
StripUiPosition(AMFArrayValue* arguments, std::string uiKeyName = "ui");
StripUiPosition() noexcept = default;
StripUiPosition(const AMFArrayValue* arguments, const std::string& uiKeyName = "ui");
void SendBehaviorBlocksToClient(AMFArrayValue& args) const;
double GetX() const { return xPosition; };
double GetY() const { return yPosition; };
[[nodiscard]] double GetX() const noexcept { return m_XPosition; }
[[nodiscard]] double GetY() const noexcept { return m_YPosition; }
private:
double xPosition;
double yPosition;
double m_XPosition{ 0.0 };
double m_YPosition{ 0.0 };
};
#endif //!__STRIPUIPOSITION__H__

View File

@@ -2,14 +2,15 @@
#include "Action.h"
UpdateActionMessage::UpdateActionMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) {
actionContext = ActionContext(arguments);
UpdateActionMessage::UpdateActionMessage(const AMFArrayValue* arguments)
: BehaviorMessageBase{ arguments }
, m_ActionIndex{ GetActionIndexFromArgument(arguments) }
, m_ActionContext{ arguments } {
auto* actionValue = arguments->GetArray("action");
const auto* const actionValue = arguments->GetArray("action");
if (!actionValue) return;
m_Action = Action{ actionValue };
action = Action(actionValue);
actionIndex = GetActionIndexFromArgument(arguments);
LOG_DEBUG("type %s valueParameterName %s valueParameterString %s valueParameterDouble %f behaviorId %i actionIndex %i stripId %i stateId %i", action.GetType().c_str(), action.GetValueParameterName().c_str(), action.GetValueParameterString().c_str(), action.GetValueParameterDouble(), behaviorId, actionIndex, actionContext.GetStripId(), actionContext.GetStateId());
LOG_DEBUG("type %s valueParameterName %s valueParameterString %s valueParameterDouble %f behaviorId %i actionIndex %i stripId %i stateId %i", m_Action.GetType().c_str(), m_Action.GetValueParameterName().c_str(), m_Action.GetValueParameterString().c_str(), m_Action.GetValueParameterDouble(), m_BehaviorId, m_ActionIndex, m_ActionContext.GetStripId(), m_ActionContext.GetStateId());
}

View File

@@ -13,14 +13,18 @@ class AMFArrayValue;
*/
class UpdateActionMessage : public BehaviorMessageBase {
public:
UpdateActionMessage(AMFArrayValue* arguments);
int32_t GetActionIndex() const { return actionIndex; };
ActionContext GetActionContext() const { return actionContext; };
Action GetAction() const { return action; };
UpdateActionMessage(const AMFArrayValue* arguments);
[[nodiscard]] int32_t GetActionIndex() const noexcept { return m_ActionIndex; }
[[nodiscard]] const ActionContext& GetActionContext() const noexcept { return m_ActionContext; }
[[nodiscard]] const Action& GetAction() const noexcept { return m_Action; }
private:
int32_t actionIndex;
ActionContext actionContext;
Action action;
int32_t m_ActionIndex;
ActionContext m_ActionContext;
Action m_Action;
};
#endif //!__UPDATEACTIONMESSAGE__H__

View File

@@ -1,8 +1,9 @@
#include "UpdateStripUiMessage.h"
UpdateStripUiMessage::UpdateStripUiMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) {
position = StripUiPosition(arguments);
actionContext = ActionContext(arguments);
UpdateStripUiMessage::UpdateStripUiMessage(const AMFArrayValue* arguments)
: BehaviorMessageBase{ arguments }
, m_Position{ arguments }
, m_ActionContext{ arguments } {
LOG_DEBUG("xPosition %f yPosition %f stripId %i stateId %i behaviorId %i", position.GetX(), position.GetY(), actionContext.GetStripId(), actionContext.GetStateId(), behaviorId);
LOG_DEBUG("xPosition %f yPosition %f stripId %i stateId %i behaviorId %i", m_Position.GetX(), m_Position.GetY(), m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_BehaviorId);
}

View File

@@ -13,12 +13,15 @@ class AMFArrayValue;
*/
class UpdateStripUiMessage : public BehaviorMessageBase {
public:
UpdateStripUiMessage(AMFArrayValue* arguments);
StripUiPosition GetPosition() const { return position; };
ActionContext GetActionContext() const { return actionContext; };
UpdateStripUiMessage(const AMFArrayValue* arguments);
[[nodiscard]] const StripUiPosition& GetPosition() const noexcept { return m_Position; };
[[nodiscard]] const ActionContext& GetActionContext() const noexcept { return m_ActionContext; };
private:
StripUiPosition position;
ActionContext actionContext;
StripUiPosition m_Position;
ActionContext m_ActionContext;
};
#endif //!__UPDATESTRIPUIMESSAGE__H__

View File

@@ -63,7 +63,7 @@ void ControlBehaviors::SendBehaviorListToClient(const ControlBehaviorContext& co
// TODO This is also supposed to serialize the state of the behaviors in progress but those aren't implemented yet
void ControlBehaviors::SendBehaviorBlocksToClient(ControlBehaviorContext& context) {
if (!context) return;
BehaviorMessageBase behaviorMsg(context.arguments);
BehaviorMessageBase behaviorMsg{ context.arguments };
context.modelComponent->VerifyBehaviors();
AMFArrayValue behavior;
@@ -71,8 +71,8 @@ void ControlBehaviors::SendBehaviorBlocksToClient(ControlBehaviorContext& contex
GameMessages::SendUIMessageServerToSingleClient(context.modelOwner, context.modelOwner->GetSystemAddress(), "UpdateBehaviorBlocks", behavior);
}
void ControlBehaviors::UpdateAction(AMFArrayValue* arguments) {
UpdateActionMessage updateActionMessage(arguments);
void ControlBehaviors::UpdateAction(const AMFArrayValue* arguments) {
UpdateActionMessage updateActionMessage{ arguments };
auto blockDefinition = GetBlockInfo(updateActionMessage.GetAction().GetType());
if (!blockDefinition) {
@@ -95,18 +95,18 @@ void ControlBehaviors::UpdateAction(AMFArrayValue* arguments) {
}
}
void ControlBehaviors::ProcessCommand(Entity* modelEntity, const SystemAddress& sysAddr, AMFArrayValue* arguments, std::string command, Entity* modelOwner) {
void ControlBehaviors::ProcessCommand(Entity* modelEntity, AMFArrayValue* arguments, std::string& command, Entity* modelOwner) {
if (!isInitialized || !modelEntity || !modelOwner || !arguments) return;
auto* modelComponent = modelEntity->GetComponent<ModelComponent>();
auto* const modelComponent = modelEntity->GetComponent<ModelComponent>();
if (!modelComponent) return;
ControlBehaviorContext context(arguments, modelComponent, modelOwner);
ControlBehaviorContext context{ arguments, modelComponent, modelOwner };
if (command == "sendBehaviorListToClient") {
SendBehaviorListToClient(context);
} else if (command == "modelTypeChanged") {
auto* modelType = arguments->Get<double>("ModelType");
auto* const modelType = arguments->Get<double>("ModelType");
if (!modelType) return;
modelEntity->SetVar<int>(u"modelType", modelType->GetValue());
@@ -131,7 +131,7 @@ void ControlBehaviors::ProcessCommand(Entity* modelEntity, const SystemAddress&
} else if (command == "rearrangeStrip") {
context.modelComponent->HandleControlBehaviorsMsg<RearrangeStripMessage>(arguments);
} else if (command == "add") {
AddMessage msg(context.arguments);
AddMessage msg{ context.arguments };
context.modelComponent->AddBehavior(msg);
SendBehaviorListToClient(context);
} else if (command == "removeActions") {
@@ -144,7 +144,7 @@ void ControlBehaviors::ProcessCommand(Entity* modelEntity, const SystemAddress&
} else if (command == "sendBehaviorBlocksToClient") {
SendBehaviorBlocksToClient(context);
} else if (command == "moveToInventory") {
MoveToInventoryMessage msg(arguments);
MoveToInventoryMessage msg{ arguments };
context.modelComponent->MoveToInventory(msg);
auto* characterComponent = modelOwner->GetComponent<CharacterComponent>();
if (!characterComponent) return;
@@ -239,7 +239,7 @@ ControlBehaviors::ControlBehaviors() {
if (values) {
auto* value = values->FirstChildElement("Value");
while (value) {
if (value->GetText() == blockDefinition.GetDefaultValue()) blockDefinition.GetDefaultValue() = std::to_string(blockDefinition.GetMaximumValue());
if (value->GetText() == blockDefinition.GetDefaultValue()) blockDefinition.SetDefaultValue(std::to_string(blockDefinition.GetMaximumValue()));
blockDefinition.SetMaximumValue(blockDefinition.GetMaximumValue() + 1);
value = value->NextSiblingElement("Value");
}
@@ -283,7 +283,7 @@ ControlBehaviors::ControlBehaviors() {
}
}
std::optional<BlockDefinition> ControlBehaviors::GetBlockInfo(const BlockName& blockName) {
std::optional<BlockDefinition> ControlBehaviors::GetBlockInfo(const std::string& blockName) {
auto blockDefinition = blockTypes.find(blockName);
return blockDefinition != blockTypes.end() ? std::optional(blockDefinition->second) : std::nullopt;
}

View File

@@ -19,15 +19,17 @@ class SystemAddress;
typedef std::string BlockName; //! A block name
struct ControlBehaviorContext {
ControlBehaviorContext(AMFArrayValue* args, ModelComponent* modelComponent, Entity* modelOwner) : arguments(args), modelComponent(modelComponent), modelOwner(modelOwner) {};
ControlBehaviorContext(AMFArrayValue* args, ModelComponent* modelComponent, Entity* modelOwner) noexcept
: arguments{ args }, modelComponent{ modelComponent }, modelOwner{ modelOwner } {
};
operator bool() const {
return arguments != nullptr && modelComponent != nullptr && modelOwner != nullptr;
}
AMFArrayValue* arguments;
Entity* modelOwner;
ModelComponent* modelComponent;
Entity* modelOwner;
};
class ControlBehaviors: public Singleton<ControlBehaviors> {
@@ -37,12 +39,11 @@ public:
* @brief Main driver for processing Property Behavior commands
*
* @param modelEntity The model that sent this command
* @param sysAddr The SystemAddress to respond to
* @param arguments The arguments formatted as an AMFArrayValue
* @param command The command to perform
* @param modelOwner The owner of the model which sent this command
*/
void ProcessCommand(Entity* modelEntity, const SystemAddress& sysAddr, AMFArrayValue* arguments, std::string command, Entity* modelOwner);
void ProcessCommand(Entity* modelEntity, AMFArrayValue* arguments, std::string& command, Entity* modelOwner);
/**
* @brief Gets a blocks parameter values by the name
@@ -52,13 +53,13 @@ public:
*
* @return A pair of the block parameter name to its typing
*/
std::optional<BlockDefinition> GetBlockInfo(const BlockName& blockName);
[[nodiscard]] std::optional<BlockDefinition> GetBlockInfo(const std::string& blockName);
private:
void RequestUpdatedID(ControlBehaviorContext& context);
void SendBehaviorListToClient(const ControlBehaviorContext& context);
void SendBehaviorBlocksToClient(ControlBehaviorContext& context);
void UpdateAction(AMFArrayValue* arguments);
std::map<BlockName, BlockDefinition> blockTypes{};
void UpdateAction(const AMFArrayValue* arguments);
std::map<BlockName, BlockDefinition, std::less<>> blockTypes{};
// If false, property behaviors will not be able to be edited.
bool isInitialized = false;

View File

@@ -83,10 +83,6 @@ void PropertyBehavior::HandleMsg(AddMessage& msg) {
isLoot = m_BehaviorId != 7965;
};
void PropertyBehavior::SetBehaviorId(int32_t behaviorId) {
m_BehaviorId = behaviorId;
}
void PropertyBehavior::SendBehaviorListToClient(AMFArrayValue& args) const {
args.Insert("id", std::to_string(m_BehaviorId));
args.Insert("name", m_Name);
@@ -111,19 +107,18 @@ void PropertyBehavior::VerifyLastEditedState() {
}
void PropertyBehavior::SendBehaviorBlocksToClient(AMFArrayValue& args) const {
auto* stateArray = args.InsertArray("states");
auto* const stateArray = args.InsertArray("states");
auto lastState = BehaviorState::HOME_STATE;
for (auto& [stateId, state] : m_States) {
for (const auto& [stateId, state] : m_States) {
if (state.IsEmpty()) continue;
LOG_DEBUG("Serializing state %i", stateId);
auto* stateArgs = stateArray->PushArray();
auto* const stateArgs = stateArray->PushArray();
stateArgs->Insert("id", static_cast<double>(stateId));
state.SendBehaviorBlocksToClient(*stateArgs);
}
auto* executionState = args.InsertArray("executionState");
auto* const executionState = args.InsertArray("executionState");
executionState->Insert("stateID", static_cast<double>(m_LastEditedState));
executionState->InsertArray("strips");

View File

@@ -13,7 +13,8 @@ class AMFArrayValue;
class PropertyBehavior {
public:
PropertyBehavior();
template<typename Msg>
template <typename Msg>
void HandleMsg(Msg& msg);
// If the last edited state has no strips, this method will set the last edited state to the first state that has strips.
@@ -21,8 +22,9 @@ public:
void SendBehaviorListToClient(AMFArrayValue& args) const;
void SendBehaviorBlocksToClient(AMFArrayValue& args) const;
int32_t GetBehaviorId() const { return m_BehaviorId; }
void SetBehaviorId(int32_t id);
[[nodiscard]] int32_t GetBehaviorId() const noexcept { return m_BehaviorId; }
void SetBehaviorId(int32_t id) noexcept { m_BehaviorId = id; }
private:
// The states this behavior has.

View File

@@ -3,7 +3,7 @@
#include "Amf3.h"
#include "ControlBehaviorMsgs.h"
template<>
template <>
void State::HandleMsg(AddStripMessage& msg) {
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
m_Strips.resize(msg.GetActionContext().GetStripId() + 1);
@@ -11,7 +11,7 @@ void State::HandleMsg(AddStripMessage& msg) {
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
};
template<>
template <>
void State::HandleMsg(AddActionMessage& msg) {
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
return;
@@ -20,7 +20,7 @@ void State::HandleMsg(AddActionMessage& msg) {
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
};
template<>
template <>
void State::HandleMsg(UpdateStripUiMessage& msg) {
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
return;
@@ -29,7 +29,7 @@ void State::HandleMsg(UpdateStripUiMessage& msg) {
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
};
template<>
template <>
void State::HandleMsg(RemoveActionsMessage& msg) {
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
return;
@@ -38,7 +38,7 @@ void State::HandleMsg(RemoveActionsMessage& msg) {
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
};
template<>
template <>
void State::HandleMsg(RearrangeStripMessage& msg) {
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
return;
@@ -47,7 +47,7 @@ void State::HandleMsg(RearrangeStripMessage& msg) {
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
};
template<>
template <>
void State::HandleMsg(UpdateActionMessage& msg) {
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
return;
@@ -56,7 +56,7 @@ void State::HandleMsg(UpdateActionMessage& msg) {
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
};
template<>
template <>
void State::HandleMsg(RemoveStripMessage& msg) {
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
return;
@@ -65,7 +65,7 @@ void State::HandleMsg(RemoveStripMessage& msg) {
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
};
template<>
template <>
void State::HandleMsg(SplitStripMessage& msg) {
if (msg.GetTransferredActions().empty()) {
if (m_Strips.size() <= msg.GetSourceActionContext().GetStripId()) {
@@ -82,7 +82,7 @@ void State::HandleMsg(SplitStripMessage& msg) {
}
};
template<>
template <>
void State::HandleMsg(MergeStripsMessage& msg) {
if (msg.GetMigratedActions().empty()) {
if (m_Strips.size() <= msg.GetSourceActionContext().GetStripId()) {
@@ -99,7 +99,7 @@ void State::HandleMsg(MergeStripsMessage& msg) {
}
};
template<>
template <>
void State::HandleMsg(MigrateActionsMessage& msg) {
if (msg.GetMigratedActions().empty()) {
if (m_Strips.size() <= msg.GetSourceActionContext().GetStripId()) {
@@ -117,19 +117,19 @@ void State::HandleMsg(MigrateActionsMessage& msg) {
};
bool State::IsEmpty() const {
for (auto& strip : m_Strips) {
for (const auto& strip : m_Strips) {
if (!strip.IsEmpty()) return false;
}
return true;
}
void State::SendBehaviorBlocksToClient(AMFArrayValue& args) const {
auto* strips = args.InsertArray("strips");
for (int32_t stripId = 0; stripId < m_Strips.size(); stripId++) {
auto& strip = m_Strips.at(stripId);
auto* const strips = args.InsertArray("strips");
for (size_t stripId = 0; stripId < m_Strips.size(); ++stripId) {
const auto& strip = m_Strips.at(stripId);
if (strip.IsEmpty()) continue;
auto* stripArgs = strips->PushArray();
auto* const stripArgs = strips->PushArray();
stripArgs->Insert("id", static_cast<double>(stripId));
strip.SendBehaviorBlocksToClient(*stripArgs);

View File

@@ -7,11 +7,12 @@ class AMFArrayValue;
class State {
public:
template<typename Msg>
template <typename Msg>
void HandleMsg(Msg& msg);
void SendBehaviorBlocksToClient(AMFArrayValue& args) const;
bool IsEmpty() const;
private:
std::vector<Strip> m_Strips;
};

View File

@@ -3,48 +3,47 @@
#include "Amf3.h"
#include "ControlBehaviorMsgs.h"
template<>
template <>
void Strip::HandleMsg(AddStripMessage& msg) {
m_Actions = msg.GetActionsToAdd();
m_Position = msg.GetPosition();
};
template<>
template <>
void Strip::HandleMsg(AddActionMessage& msg) {
if (msg.GetActionIndex() == -1) return;
m_Actions.insert(m_Actions.begin() + msg.GetActionIndex(), msg.GetAction());
};
template<>
template <>
void Strip::HandleMsg(UpdateStripUiMessage& msg) {
m_Position = msg.GetPosition();
};
template<>
template <>
void Strip::HandleMsg(RemoveStripMessage& msg) {
m_Actions.clear();
};
template<>
template <>
void Strip::HandleMsg(RemoveActionsMessage& msg) {
if (msg.GetActionIndex() >= m_Actions.size()) return;
m_Actions.erase(m_Actions.begin() + msg.GetActionIndex(), m_Actions.end());
};
template<>
template <>
void Strip::HandleMsg(UpdateActionMessage& msg) {
if (msg.GetActionIndex() >= m_Actions.size()) return;
m_Actions.at(msg.GetActionIndex()) = msg.GetAction();
};
template<>
template <>
void Strip::HandleMsg(RearrangeStripMessage& msg) {
if (msg.GetDstActionIndex() >= m_Actions.size() || msg.GetSrcActionIndex() >= m_Actions.size() || msg.GetSrcActionIndex() <= msg.GetDstActionIndex()) return;
std::rotate(m_Actions.begin() + msg.GetDstActionIndex(), m_Actions.begin() + msg.GetSrcActionIndex(), m_Actions.end());
};
template<>
template <>
void Strip::HandleMsg(SplitStripMessage& msg) {
if (msg.GetTransferredActions().empty() && !m_Actions.empty()) {
auto startToMove = m_Actions.begin() + msg.GetSrcActionIndex();
@@ -56,7 +55,7 @@ void Strip::HandleMsg(SplitStripMessage& msg) {
}
};
template<>
template <>
void Strip::HandleMsg(MergeStripsMessage& msg) {
if (msg.GetMigratedActions().empty() && !m_Actions.empty()) {
msg.SetMigratedActions(m_Actions.begin(), m_Actions.end());
@@ -66,7 +65,7 @@ void Strip::HandleMsg(MergeStripsMessage& msg) {
}
};
template<>
template <>
void Strip::HandleMsg(MigrateActionsMessage& msg) {
if (msg.GetMigratedActions().empty() && !m_Actions.empty()) {
auto startToMove = m_Actions.begin() + msg.GetSrcActionIndex();
@@ -80,8 +79,8 @@ void Strip::HandleMsg(MigrateActionsMessage& msg) {
void Strip::SendBehaviorBlocksToClient(AMFArrayValue& args) const {
m_Position.SendBehaviorBlocksToClient(args);
auto* actions = args.InsertArray("actions");
for (auto& action : m_Actions) {
auto* const actions = args.InsertArray("actions");
for (const auto& action : m_Actions) {
action.SendBehaviorBlocksToClient(*actions);
}
};

View File

@@ -10,11 +10,12 @@ class AMFArrayValue;
class Strip {
public:
template<typename Msg>
template <typename Msg>
void HandleMsg(Msg& msg);
void SendBehaviorBlocksToClient(AMFArrayValue& args) const;
bool IsEmpty() const { return m_Actions.empty(); }
bool IsEmpty() const noexcept { return m_Actions.empty(); }
private:
std::vector<Action> m_Actions;
StripUiPosition m_Position;

View File

@@ -4,16 +4,24 @@
#include "MovingPlatformComponent.h"
void PropertyPlatform::OnQuickBuildComplete(Entity* self, Entity* target) {
GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS
, static_cast<eMovementPlatformState>(eMovementPlatformState::Waiting | eMovementPlatformState::ReachedDesiredWaypoint | eMovementPlatformState::ReachedFinalWaypoint),
true, 0, 0, 0);
// auto* movingPlatform = self->GetComponent<MovingPlatformComponent>();
// if (movingPlatform != nullptr) {
// movingPlatform->StopPathing();
// movingPlatform->SetNoAutoStart(true);
// }
GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0,
0, 0, eMovementPlatformState::Stationary);
}
void PropertyPlatform::OnUse(Entity* self, Entity* user) {
auto* rebuildComponent = self->GetComponent<QuickBuildComponent>();
if (rebuildComponent != nullptr && rebuildComponent->GetState() == eQuickBuildState::COMPLETED) {
GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, eMovementPlatformState::Travelling, true, 0,
1, 1);
auto* quickBuildComponent = self->GetComponent<QuickBuildComponent>();
if (quickBuildComponent != nullptr && quickBuildComponent->GetState() == eQuickBuildState::COMPLETED) {
// auto* movingPlatform = self->GetComponent<MovingPlatformComponent>();
// if (movingPlatform != nullptr) {
// movingPlatform->GotoWaypoint(1);
// }
GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0,
1, 1, eMovementPlatformState::Moving);
self->AddCallbackTimer(movementDelay + effectDelay, [self, this]() {
self->SetNetworkVar<float_t>(u"startEffect", dieDelay);

View File

@@ -5,7 +5,6 @@
#include "Character.h"
#include "dZoneManager.h"
#include "RenderComponent.h"
#include "MovingPlatformComponent.h"
void CavePrisonCage::OnStartup(Entity* self) {
const auto& myNum = self->GetVar<std::u16string>(u"myNumber");
@@ -84,8 +83,8 @@ void CavePrisonCage::SpawnCounterweight(Entity* self, Spawner* spawner) {
return;
}
auto* mpc = counterweight->GetComponent<MovingPlatformComponent>();
if (mpc) mpc->StartPathing();
// Move the counterweight down 2 units
counterweight->SetPosition(counterweight->GetPosition() + NiPoint3(0, -2, 0));
// Serialize the counterweight
Game::entityManager->SerializeEntity(counterweight);

View File

@@ -2,7 +2,6 @@
#include "Entity.h"
#include "GameMessages.h"
#include "ProximityMonitorComponent.h"
#include "MovingPlatformComponent.h"
void AgBusDoor::OnStartup(Entity* self) {
m_Counter = 0;
@@ -49,9 +48,9 @@ void AgBusDoor::OnProximityUpdate(Entity* self, Entity* entering, std::string na
void AgBusDoor::MoveDoor(Entity* self, bool bOpen) {
if (bOpen) {
GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, eMovementPlatformState::Travelling, true, 1, 0);
GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 1, 0);
} else {
GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, eMovementPlatformState::Travelling, true, 0, 1);
GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, 1);
self->AddTimer("dustTimer", 2.0f);
}

View File

@@ -1,7 +1,6 @@
#include "AgQbElevator.h"
#include "EntityManager.h"
#include "GameMessages.h"
#include "MovingPlatformComponent.h"
void AgQbElevator::OnStartup(Entity* self) {
@@ -15,9 +14,8 @@ void AgQbElevator::OnQuickBuildComplete(Entity* self, Entity* target) {
float delayTime = killTime - endTime;
if (delayTime < 1) delayTime = 1;
GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS,
static_cast<eMovementPlatformState>(eMovementPlatformState::Waiting | eMovementPlatformState::ReachedDesiredWaypoint | eMovementPlatformState::ReachedFinalWaypoint)
, true, 0, 0, 0);
GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0,
0, 0, eMovementPlatformState::Stationary);
//add a timer that will kill the QB if no players get on in the killTime
self->AddTimer("startKillTimer", killTime);
@@ -34,8 +32,8 @@ void AgQbElevator::OnProximityUpdate(Entity* self, Entity* entering, std::string
self->SetBoolean(u"qbPlayerRdy", true);
self->CancelTimer("StartElevator");
GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, eMovementPlatformState::Travelling, true, 0,
1, 1);
GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0,
1, 1, eMovementPlatformState::Moving);
} else if (!self->GetBoolean(u"StartTimer")) {
self->SetBoolean(u"StartTimer", true);
self->AddTimer("StartElevator", startTime);
@@ -46,8 +44,8 @@ void AgQbElevator::OnProximityUpdate(Entity* self, Entity* entering, std::string
void AgQbElevator::OnTimerDone(Entity* self, std::string timerName) {
if (timerName == "StartElevator") {
GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, eMovementPlatformState::Travelling, true, 0,
1, 1);
GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0,
1, 1, eMovementPlatformState::Moving);
} else if (timerName == "startKillTimer") {
killTimerStartup(self);
} else if (timerName == "KillTimer") {

View File

@@ -16,7 +16,6 @@
#include "eReplicaComponentType.h"
#include "RenderComponent.h"
#include "eGameActivity.h"
#include "MovingPlatformComponent.h"
void SGCannon::OnStartup(Entity* self) {
LOG("OnStartup");
@@ -327,13 +326,11 @@ void SGCannon::DoSpawnTimerFunc(Entity* self, const std::string& name) {
// Save the enemy and tell it to start pathing
if (enemy != nullptr) {
const_cast<std::vector<LWOOBJID>&>(self->GetVar<std::vector<LWOOBJID>>(SpawnedObjects)).push_back(enemy->GetObjectID());
GameMessages::SendPlatformResync(enemy, UNASSIGNED_SYSTEM_ADDRESS, eMovementPlatformState::Travelling);
GameMessages::SendPlatformResync(enemy, UNASSIGNED_SYSTEM_ADDRESS);
}
}
}
#pragma warning("TODO: FIX THE ABOVE GM CALL")
void SGCannon::EndGameBufferTimerFunc(Entity* self) {
RecordPlayerScore(self);
StopGame(self, false);
@@ -349,68 +346,7 @@ void SGCannon::OnActivityTimerDone(Entity* self, const std::string& name) {
} else if (name == GameOverTimer) {
GameOverTimerFunc(self);
} else if (name.rfind(DoSpawnTimer, 0) == 0) {
if (self->GetVar<bool>(GameStartedVariable)) {
const auto spawnNumber = (uint32_t)std::stoi(name.substr(7));
const auto& activeSpawns = self->GetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable);
if (activeSpawns.size() < spawnNumber) {
LOG("Trying to spawn %i when spawns size is only %i", spawnNumber, activeSpawns.size());
return;
}
const auto& toSpawn = activeSpawns.at(spawnNumber);
const auto pathIndex = GeneralUtils::GenerateRandomNumber<float_t>(0, toSpawn.spawnPaths.size() - 1);
const auto* path = Game::zoneManager->GetZone()->GetPath(toSpawn.spawnPaths.at(pathIndex));
if (!path) {
LOG("Path %s at index %i is null", toSpawn.spawnPaths.at(pathIndex).c_str(), pathIndex);
return;
}
auto info = EntityInfo{};
info.lot = toSpawn.lot;
info.spawnerID = self->GetObjectID();
info.pos = path->pathWaypoints.at(0).position;
info.settings = {
new LDFData<SGEnemy>(u"SpawnData", toSpawn),
new LDFData<std::string>(u"custom_script_server", "scripts/ai/ACT/SG_TARGET.lua"),
new LDFData<std::string>(u"custom_script_client", "scripts/client/ai/SG_TARGET_CLIENT.lua"),
new LDFData<std::string>(u"attached_path", path->pathName),
new LDFData<uint32_t>(u"attached_path_start", 0),
new LDFData<std::u16string>(u"groupID", u"SGEnemy")
};
LOG("Spawning enemy %i on path %s", toSpawn.lot, path->pathName.c_str());
auto* enemy = Game::entityManager->CreateEntity(info, nullptr, self);
Game::entityManager->ConstructEntity(enemy);
auto* movementAI = enemy->AddComponent<MovementAIComponent, MovementAIInfo>({});
movementAI->SetMaxSpeed(toSpawn.initialSpeed);
movementAI->SetCurrentSpeed(toSpawn.initialSpeed);
movementAI->SetHaltDistance(0.0f);
std::vector<NiPoint3> pathWaypoints;
for (const auto& waypoint : path->pathWaypoints) {
pathWaypoints.push_back(waypoint.position);
}
if (GeneralUtils::GenerateRandomNumber<float_t>(0, 1) < 0.5f) {
std::reverse(pathWaypoints.begin(), pathWaypoints.end());
}
movementAI->SetPath(pathWaypoints);
enemy->AddDieCallback([this, self, enemy, name]() {
RegisterHit(self, enemy, name);
});
// Save the enemy and tell it to start pathing
if (enemy != nullptr) {
const_cast<std::vector<LWOOBJID>&>(self->GetVar<std::vector<LWOOBJID>>(SpawnedObjects)).push_back(enemy->GetObjectID());
GameMessages::SendPlatformResync(enemy, UNASSIGNED_SYSTEM_ADDRESS, eMovementPlatformState::Travelling);
}
}
DoSpawnTimerFunc(self, name);
} else if (name == EndGameBufferTimer) {
EndGameBufferTimerFunc(self);
}

View File

@@ -348,7 +348,7 @@ void Zone::LoadPath(std::istream& file) {
BinaryIO::BinaryRead(file, path.pathVersion);
BinaryIO::ReadString<uint8_t>(file, path.pathName, BinaryIO::ReadType::WideString);
LOG("pathname: %s", path.pathName.c_str());
BinaryIO::BinaryRead(file, path.pathType);
BinaryIO::BinaryRead(file, path.flags);
BinaryIO::BinaryRead(file, path.pathBehavior);
@@ -420,7 +420,6 @@ void Zone::LoadPath(std::istream& file) {
if (path.pathType == PathType::MovingPlatform) {
BinaryIO::BinaryRead(file, waypoint.movingPlatform.lockPlayer);
BinaryIO::BinaryRead(file, waypoint.movingPlatform.speed);
LOG("speed: %f", waypoint.movingPlatform.speed);
BinaryIO::BinaryRead(file, waypoint.movingPlatform.wait);
if (path.pathVersion >= 13) {
BinaryIO::ReadString<uint8_t>(file, waypoint.movingPlatform.departSound, BinaryIO::ReadType::WideString);

View File

@@ -212,7 +212,6 @@ public:
const uint32_t GetChecksum() const { return m_CheckSum; }
LUTriggers::Trigger* GetTrigger(uint32_t sceneID, uint32_t triggerID);
const Path* GetPath(std::string name) const;
void AddPath(const Path& path) { m_Paths.push_back(path); };
uint32_t GetWorldID() const { return m_WorldID; }
[[nodiscard]] std::string GetZoneName() const { return m_ZoneName; }

View File

@@ -13,28 +13,3 @@ namespace Game {
EntityManager* entityManager = nullptr;
std::string projectVersion;
}
void GameDependenciesTest::SetUpDependencies() {
info.pos = NiPoint3Constant::ZERO;
info.rot = NiQuaternionConstant::IDENTITY;
info.scale = 1.0f;
info.spawner = nullptr;
info.lot = 999;
Game::logger = new Logger("./testing.log", true, true);
Game::server = new dServerMock();
Game::config = new dConfig("worldconfig.ini");
Game::entityManager = new EntityManager();
Game::zoneManager = new dZoneManager();
Game::zoneManager->LoadZone(LWOZONEID(0, 0, 0));
}
void GameDependenciesTest::TearDownDependencies() {
if (Game::server) delete Game::server;
if (Game::entityManager) delete Game::entityManager;
if (Game::config) delete Game::config;
if (Game::zoneManager) delete Game::zoneManager;
if (Game::logger) {
Game::logger->Flush();
delete Game::logger;
}
}

View File

@@ -7,7 +7,6 @@
#include "CDClientManager.h"
#include "EntityInfo.h"
#include "EntityManager.h"
#include "dZoneManager.h"
#include "dConfig.h"
#include <gtest/gtest.h>
@@ -25,11 +24,32 @@ public:
class GameDependenciesTest : public ::testing::Test {
protected:
void SetUpDependencies();
void SetUpDependencies() {
info.pos = NiPoint3Constant::ZERO;
info.rot = NiQuaternionConstant::IDENTITY;
info.scale = 1.0f;
info.spawner = nullptr;
info.lot = 999;
Game::logger = new Logger("./testing.log", true, true);
Game::server = new dServerMock();
Game::config = new dConfig("worldconfig.ini");
Game::entityManager = new EntityManager();
void TearDownDependencies();
// Create a CDClientManager instance and load from defaults
CDClientManager::LoadValuesFromDefaults();
}
EntityInfo info;
void TearDownDependencies() {
if (Game::server) delete Game::server;
if (Game::entityManager) delete Game::entityManager;
if (Game::logger) {
Game::logger->Flush();
delete Game::logger;
}
if (Game::config) delete Game::config;
}
EntityInfo info{};
};
#endif //!__GAMEDEPENDENCIES__H__

View File

@@ -1,6 +1,5 @@
set(DCOMPONENTS_TESTS
"DestroyableComponentTests.cpp"
"MovingPlatformComponentTests.cpp"
"PetComponentTests.cpp"
"SimplePhysicsComponentTests.cpp"
)

View File

@@ -1,451 +0,0 @@
#include "GameDependencies.h"
#include <gtest/gtest.h>
#include "BitStream.h"
#include "Entity.h"
#define _MOVING_PLATFORM_TEST
#include "MovingPlatformComponent.h"
#undef _MOVING_PLATFORM_TEST
#include "Zone.h"
#include "SimplePhysicsComponent.h"
#include "eReplicaComponentType.h"
class MovingPlatformComponentTests : public GameDependenciesTest {
protected:
std::unique_ptr<Entity> baseEntity;
CBITSTREAM;
uint32_t flags = 0;
Path pathOnce;
Path pathBounce;
Path pathLoop;
void SetUp() override {
SetUpDependencies();
PathWaypoint waypointStart;
waypointStart.position = NiPoint3(1, 2, 3);
waypointStart.rotation = NiQuaternion(4, 5, 6, 7);
waypointStart.movingPlatform.speed = 16.0f;
PathWaypoint waypointMiddle;
waypointMiddle.position = NiPoint3(4, 5, 6);
waypointMiddle.rotation = NiQuaternion(7, 8, 9, 10);
waypointStart.movingPlatform.speed = 16.0f;
PathWaypoint waypointEnd;
waypointEnd.position = NiPoint3(4, 5, 7);
waypointEnd.rotation = NiQuaternion(7, 8, 9, 10);
waypointStart.movingPlatform.speed = 16.0f;
{
pathOnce.movingPlatform.timeBasedMovement = false;
pathOnce.pathBehavior = PathBehavior::Once;
pathOnce.pathName = "ExampleOncePath";
pathOnce.pathWaypoints.push_back(waypointStart);
pathOnce.pathWaypoints.push_back(waypointMiddle);
pathOnce.pathWaypoints.push_back(waypointEnd);
Game::zoneManager->GetZone()->AddPath(pathOnce);
}
{
pathBounce.movingPlatform.timeBasedMovement = false;
pathBounce.pathBehavior = PathBehavior::Bounce;
pathBounce.pathName = "ExampleBouncePath";
pathBounce.pathWaypoints.push_back(waypointStart);
pathBounce.pathWaypoints.push_back(waypointMiddle);
pathBounce.pathWaypoints.push_back(waypointEnd);
Game::zoneManager->GetZone()->AddPath(pathBounce);
}
{
pathLoop.movingPlatform.timeBasedMovement = false;
pathLoop.pathBehavior = PathBehavior::Loop;
pathLoop.pathName = "ExampleLoopPath";
pathLoop.pathWaypoints.push_back(waypointStart);
pathLoop.pathWaypoints.push_back(waypointMiddle);
pathLoop.pathWaypoints.push_back(waypointEnd);
Game::zoneManager->GetZone()->AddPath(pathLoop);
}
// Set our starting position
info.pos = NiPoint3(25, 26, 27);
info.rot = NiQuaternion(28, 29, 30, 31);
// Simple mover data
info.settings.push_back(new LDFData<float>(u"platformMoveX", 23));
info.settings.push_back(new LDFData<float>(u"platformMoveY", 453));
info.settings.push_back(new LDFData<float>(u"platformMoveZ", 523));
info.settings.push_back(new LDFData<float>(u"platformMoveTime", 5724));
info.settings.push_back(new LDFData<bool>(u"platformStartAtEnd", true));
info.settings.push_back(new LDFData<bool>(u"dbonly", false));
info.settings.push_back(new LDFData<bool>(u"platformIsMover", true));
info.settings.push_back(new LDFData<bool>(u"platformIsSimpleMover", true));
info.settings.push_back(new LDFData<bool>(u"platformIsRotater", true));
baseEntity = std::make_unique<Entity>(15, GameDependenciesTest::info);
auto* simplePhysicsComponent = baseEntity->AddComponent<SimplePhysicsComponent>(1);
auto* movingPlatformComponent = baseEntity->AddComponent<MovingPlatformComponent>("ExampleOncePath");
movingPlatformComponent->LoadConfigData();
movingPlatformComponent->LoadDataFromTemplate();
}
void TearDown() override {
TearDownDependencies();
}
void DeserializeSimpleMoverPlatformSubComponent() {
bool dirtyStartingPoint = false;
bitStream.Read(dirtyStartingPoint);
ASSERT_TRUE(dirtyStartingPoint);
bool hasStartingPoint = false;
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 isDirty;
bitStream.Read(isDirty);
ASSERT_TRUE(isDirty);
eMovementPlatformState state;
bitStream.Read(state);
ASSERT_EQ(state, eMovementPlatformState::Stopped | eMovementPlatformState::ReachedDesiredWaypoint);
int32_t currentWaypointIndex;
bitStream.Read(currentWaypointIndex);
ASSERT_EQ(currentWaypointIndex, 0);
bool isInReverse;
bitStream.Read(isInReverse);
ASSERT_FALSE(isInReverse);
}
void DeserializeMovingPlatformSubComponent() {
bool isDirty;
ASSERT_TRUE(bitStream.Read(isDirty));
ASSERT_TRUE(isDirty);
eMovementPlatformState state;
ASSERT_TRUE(bitStream.Read(state));
ASSERT_EQ(state, eMovementPlatformState::Stopped | eMovementPlatformState::ReachedDesiredWaypoint);
int32_t desiredWaypointIndex;
ASSERT_TRUE(bitStream.Read(desiredWaypointIndex));
ASSERT_EQ(desiredWaypointIndex, -1);
bool shouldStopAtDesiredWaypoint;
ASSERT_TRUE(bitStream.Read(shouldStopAtDesiredWaypoint));
ASSERT_FALSE(shouldStopAtDesiredWaypoint);
bool isInReverse2;
ASSERT_TRUE(bitStream.Read(isInReverse2));
ASSERT_FALSE(isInReverse2);
float percentBetweenPoints;
ASSERT_TRUE(bitStream.Read(percentBetweenPoints));
ASSERT_EQ(percentBetweenPoints, 0);
NiPoint3 position;
ASSERT_TRUE(bitStream.Read(position.x));
ASSERT_TRUE(bitStream.Read(position.y));
ASSERT_TRUE(bitStream.Read(position.z));
ASSERT_EQ(position, NiPoint3(25, 26, 27));
uint32_t currentWaypointIndex;
ASSERT_TRUE(bitStream.Read(currentWaypointIndex));
ASSERT_EQ(currentWaypointIndex, 0);
uint32_t nextWaypointIndex;
ASSERT_TRUE(bitStream.Read(nextWaypointIndex));
ASSERT_EQ(nextWaypointIndex, -1);
float idleTimeElapsed;
ASSERT_TRUE(bitStream.Read(idleTimeElapsed));
ASSERT_FLOAT_EQ(idleTimeElapsed, 0.0f);
float moveTimeElapsed;
ASSERT_TRUE(bitStream.Read(moveTimeElapsed));
ASSERT_FLOAT_EQ(moveTimeElapsed, 0.0f);
}
void DeserializeMovingPlatformComponent() {
// read in the full BitStream and check the values match what they were set to above
bool hasPlatformSubComponents = false;
ASSERT_TRUE(bitStream.Read(hasPlatformSubComponents));
ASSERT_TRUE(hasPlatformSubComponents);
bool dirtyPathInfo;
ASSERT_TRUE(bitStream.Read(dirtyPathInfo));
ASSERT_TRUE(dirtyPathInfo);
bool hasPath;
ASSERT_TRUE(bitStream.Read(hasPath));
ASSERT_TRUE(hasPath);
std::u16string pathName;
uint16_t pathNameLength;
ASSERT_TRUE(bitStream.Read(pathNameLength));
pathName.resize(pathNameLength);
ASSERT_TRUE(bitStream.ReadBits(reinterpret_cast<unsigned char*>(pathName.data()), BYTES_TO_BITS(pathNameLength) * 2));
ASSERT_EQ(pathName, u"ExampleOncePath");
uint32_t pathStartIndex;
ASSERT_TRUE(bitStream.Read(pathStartIndex));
ASSERT_EQ(pathStartIndex, 0);
bool isInReverse;
ASSERT_TRUE(bitStream.Read(isInReverse));
ASSERT_FALSE(isInReverse);
bool hasPlatformData;
ASSERT_TRUE(bitStream.Read(hasPlatformData));
ASSERT_TRUE(hasPlatformData);
eMoverSubComponentType platformType;
ASSERT_TRUE(bitStream.Read(platformType));
ASSERT_EQ(platformType, eMoverSubComponentType::Mover);
DeserializeMovingPlatformSubComponent();
ASSERT_TRUE(bitStream.Read(hasPlatformData));
ASSERT_TRUE(hasPlatformData);
ASSERT_TRUE(bitStream.Read(platformType));
ASSERT_EQ(platformType, eMoverSubComponentType::SimpleMover);
DeserializeSimpleMoverPlatformSubComponent();
ASSERT_TRUE(bitStream.Read(hasPlatformData));
ASSERT_TRUE(hasPlatformData);
ASSERT_TRUE(bitStream.Read(platformType));
ASSERT_EQ(platformType, eMoverSubComponentType::Rotator);
DeserializeMovingPlatformSubComponent();
ASSERT_TRUE(bitStream.Read(hasPlatformData));
ASSERT_FALSE(hasPlatformData);
}
void TestSerialization() {
auto* movingPlatformComponent = baseEntity->GetComponent<MovingPlatformComponent>();
ASSERT_NE(movingPlatformComponent, nullptr);
movingPlatformComponent->Serialize(&bitStream, true);
DeserializeMovingPlatformComponent();
}
};
TEST_F(MovingPlatformComponentTests, MovingPlatformConstructionTest) {
TestSerialization();
}
TEST_F(MovingPlatformComponentTests, MovingPlatformSerializationTest) {
TestSerialization();
}
TEST_F(MovingPlatformComponentTests, MovingPlatformSubComponentPathOnceAdvanceTest) {
MoverPlatformSubComponent moverPlatformSubComponent(baseEntity->GetComponent<MovingPlatformComponent>());
moverPlatformSubComponent.SetupPath("ExampleOncePath", 0, false);
ASSERT_EQ(moverPlatformSubComponent.GetCurrentWaypointIndex(), 0);
ASSERT_EQ(moverPlatformSubComponent.GetNextWaypointIndex(), 1);
moverPlatformSubComponent.AdvanceToNextWaypoint();
ASSERT_EQ(moverPlatformSubComponent.GetCurrentWaypointIndex(), 1);
ASSERT_EQ(moverPlatformSubComponent.GetNextWaypointIndex(), 2);
moverPlatformSubComponent.AdvanceToNextWaypoint();
ASSERT_EQ(moverPlatformSubComponent.GetCurrentWaypointIndex(), 2);
ASSERT_EQ(moverPlatformSubComponent.GetNextWaypointIndex(), 2);
ASSERT_FALSE(moverPlatformSubComponent.GetInReverse());
moverPlatformSubComponent.AdvanceToNextWaypoint();
ASSERT_EQ(moverPlatformSubComponent.GetCurrentWaypointIndex(), 2);
ASSERT_EQ(moverPlatformSubComponent.GetNextWaypointIndex(), 2);
ASSERT_FALSE(moverPlatformSubComponent.GetInReverse());
}
TEST_F(MovingPlatformComponentTests, MovingPlatformSubComponentPathBounceAdvanceTest) {
MoverPlatformSubComponent moverPlatformSubComponent(baseEntity->GetComponent<MovingPlatformComponent>());
moverPlatformSubComponent.SetupPath("ExampleBouncePath", 0, false);
ASSERT_EQ(moverPlatformSubComponent.GetCurrentWaypointIndex(), 0);
ASSERT_EQ(moverPlatformSubComponent.GetNextWaypointIndex(), 1);
moverPlatformSubComponent.AdvanceToNextWaypoint();
ASSERT_EQ(moverPlatformSubComponent.GetCurrentWaypointIndex(), 1);
ASSERT_EQ(moverPlatformSubComponent.GetNextWaypointIndex(), 2);
ASSERT_FALSE(moverPlatformSubComponent.GetInReverse());
moverPlatformSubComponent.AdvanceToNextWaypoint();
ASSERT_EQ(moverPlatformSubComponent.GetCurrentWaypointIndex(), 2);
ASSERT_EQ(moverPlatformSubComponent.GetNextWaypointIndex(), 1);
ASSERT_TRUE(moverPlatformSubComponent.GetInReverse());
moverPlatformSubComponent.AdvanceToNextReverseWaypoint();
ASSERT_EQ(moverPlatformSubComponent.GetCurrentWaypointIndex(), 1);
ASSERT_EQ(moverPlatformSubComponent.GetNextWaypointIndex(), 0);
ASSERT_TRUE(moverPlatformSubComponent.GetInReverse());
moverPlatformSubComponent.AdvanceToNextReverseWaypoint();
ASSERT_EQ(moverPlatformSubComponent.GetCurrentWaypointIndex(), 0);
ASSERT_EQ(moverPlatformSubComponent.GetNextWaypointIndex(), 1);
ASSERT_FALSE(moverPlatformSubComponent.GetInReverse());
}
TEST_F(MovingPlatformComponentTests, MovingPlatformSubComponentLoopAdvanceTest) {
MoverPlatformSubComponent moverPlatformSubComponent(baseEntity->GetComponent<MovingPlatformComponent>());
moverPlatformSubComponent.SetupPath("ExampleLoopPath", 0, false);
ASSERT_EQ(moverPlatformSubComponent.GetCurrentWaypointIndex(), 0);
ASSERT_EQ(moverPlatformSubComponent.GetNextWaypointIndex(), 1);
moverPlatformSubComponent.AdvanceToNextWaypoint();
ASSERT_EQ(moverPlatformSubComponent.GetCurrentWaypointIndex(), 1);
ASSERT_EQ(moverPlatformSubComponent.GetNextWaypointIndex(), 2);
moverPlatformSubComponent.AdvanceToNextWaypoint();
ASSERT_EQ(moverPlatformSubComponent.GetCurrentWaypointIndex(), 2);
ASSERT_EQ(moverPlatformSubComponent.GetNextWaypointIndex(), 0);
ASSERT_FALSE(moverPlatformSubComponent.GetInReverse());
moverPlatformSubComponent.AdvanceToNextWaypoint();
ASSERT_EQ(moverPlatformSubComponent.GetCurrentWaypointIndex(), 0);
ASSERT_EQ(moverPlatformSubComponent.GetNextWaypointIndex(), 1);
ASSERT_FALSE(moverPlatformSubComponent.GetInReverse());
}
TEST_F(MovingPlatformComponentTests, MovingPlatformSubComponentLoopAdvanceReverseTest) {
MoverPlatformSubComponent moverPlatformSubComponent(baseEntity->GetComponent<MovingPlatformComponent>());
moverPlatformSubComponent.SetupPath("ExampleLoopPath", 0, true);
ASSERT_EQ(moverPlatformSubComponent.GetCurrentWaypointIndex(), 0);
ASSERT_EQ(moverPlatformSubComponent.GetNextWaypointIndex(), 2);
ASSERT_TRUE(moverPlatformSubComponent.GetInReverse());
moverPlatformSubComponent.AdvanceToNextReverseWaypoint();
ASSERT_EQ(moverPlatformSubComponent.GetCurrentWaypointIndex(), 2);
ASSERT_EQ(moverPlatformSubComponent.GetNextWaypointIndex(), 1);
ASSERT_TRUE(moverPlatformSubComponent.GetInReverse());
moverPlatformSubComponent.AdvanceToNextReverseWaypoint();
ASSERT_EQ(moverPlatformSubComponent.GetCurrentWaypointIndex(), 1);
ASSERT_EQ(moverPlatformSubComponent.GetNextWaypointIndex(), 0);
ASSERT_TRUE(moverPlatformSubComponent.GetInReverse());
moverPlatformSubComponent.AdvanceToNextReverseWaypoint();
ASSERT_EQ(moverPlatformSubComponent.GetCurrentWaypointIndex(), 0);
ASSERT_EQ(moverPlatformSubComponent.GetNextWaypointIndex(), 2);
ASSERT_TRUE(moverPlatformSubComponent.GetInReverse());
}
TEST_F(MovingPlatformComponentTests, MovingPlatformMoverSpeedCalculationTest) {
MoverPlatformSubComponent moverPlatformSubComponent(baseEntity->GetComponent<MovingPlatformComponent>());
moverPlatformSubComponent.SetupPath("ExampleOncePath", 0, false);
ASSERT_EQ(moverPlatformSubComponent.CalculateSpeed(), 16.0f);
NiPoint3 r = moverPlatformSubComponent.CalculateLinearVelocity();
ASSERT_FLOAT_EQ(r.x, 9.2376051);
ASSERT_FLOAT_EQ(r.y, 9.2376051);
ASSERT_FLOAT_EQ(r.z, 9.2376051);
moverPlatformSubComponent.AdvanceToNextWaypoint();
}
TEST_F(MovingPlatformComponentTests, MovingPlatformNextAndCurrentWaypointAccess) {
MoverPlatformSubComponent moverPlatformSubComponent(baseEntity->GetComponent<MovingPlatformComponent>());
moverPlatformSubComponent.SetupPath("ExampleOncePath", 0, false);
ASSERT_EQ(moverPlatformSubComponent.GetCurrentWaypoint().position, NiPoint3(1, 2, 3));
ASSERT_EQ(moverPlatformSubComponent.GetNextWaypoint().position, NiPoint3(4, 5, 6));
moverPlatformSubComponent.AdvanceToNextWaypoint();
ASSERT_EQ(moverPlatformSubComponent.GetCurrentWaypoint().position, NiPoint3(4, 5, 6));
ASSERT_EQ(moverPlatformSubComponent.GetNextWaypoint().position, NiPoint3(4, 5, 7));
}
TEST_F(MovingPlatformComponentTests, MovingPlatformRunTest) {
baseEntity->SetPosition(NiPoint3(99.296440f, 419.293335f, 207.219498f));
Path path;
PathWaypoint waypointStart;
waypointStart.position = NiPoint3(99.296440f, 419.293335f, 207.219498f);
waypointStart.rotation = NiQuaternion(0, 0, 0, 0);
waypointStart.movingPlatform.speed = 16.0f;
PathWaypoint waypointEnd;
waypointEnd.position = NiPoint3(141.680099f, 419.990051f, 208.680450f);
waypointEnd.rotation = NiQuaternion(0, 0, 0, 0);
waypointStart.movingPlatform.speed = 16.0f;
path.movingPlatform.timeBasedMovement = false;
path.pathBehavior = PathBehavior::Once;
path.pathName = "ExamplePath";
path.pathWaypoints.push_back(waypointStart);
path.pathWaypoints.push_back(waypointEnd);
Game::zoneManager->GetZone()->AddPath(path);
MoverPlatformSubComponent moverPlatformSubComponent(baseEntity->GetComponent<MovingPlatformComponent>());
moverPlatformSubComponent.SetupPath("ExamplePath", 0, false);
moverPlatformSubComponent.UpdateLinearVelocity();
moverPlatformSubComponent.StartPathing();
moverPlatformSubComponent.Update(2.65f);
auto [x,y,z] = moverPlatformSubComponent.GetPosition();
// just check that its close enough
EXPECT_LT(141.680099f - x, 0.1f);
EXPECT_LT(419.990051f - y, 0.1f);
EXPECT_LT(208.680450f - z, 0.1f);
}
TEST_F(MovingPlatformComponentTests, MovingPlatformPercentBetweenPointsTest) {
Path path;
PathWaypoint waypointStart;
waypointStart.position = NiPoint3(0, 0, 0);
waypointStart.rotation = NiQuaternion(0, 0, 0, 0);
waypointStart.movingPlatform.speed = 16.0f;
PathWaypoint waypointEnd;
waypointEnd.position = NiPoint3(2, 0, 0);
waypointEnd.rotation = NiQuaternion(0, 0, 0, 0);
waypointStart.movingPlatform.speed = 16.0f;
path.movingPlatform.timeBasedMovement = false;
path.pathBehavior = PathBehavior::Once;
path.pathName = "ExamplePath";
path.pathWaypoints.push_back(waypointStart);
path.pathWaypoints.push_back(waypointEnd);
Game::zoneManager->GetZone()->AddPath(path);
{
baseEntity->SetPosition(NiPoint3(0, 0, 0));
MoverPlatformSubComponent moverPlatformSubComponent(baseEntity->GetComponent<MovingPlatformComponent>());
moverPlatformSubComponent.SetupPath("ExamplePath", 0, false);
EXPECT_FLOAT_EQ(moverPlatformSubComponent.CalculatePercentToNextWaypoint(), 0.0f);
}
{
baseEntity->SetPosition(NiPoint3(1, 0, 0));
MoverPlatformSubComponent moverPlatformSubComponent(baseEntity->GetComponent<MovingPlatformComponent>());
moverPlatformSubComponent.SetupPath("ExamplePath", 0, false);
EXPECT_FLOAT_EQ(moverPlatformSubComponent.CalculatePercentToNextWaypoint(), 0.5f);
}
{
baseEntity->SetPosition(NiPoint3(2, 0, 0));
MoverPlatformSubComponent moverPlatformSubComponent(baseEntity->GetComponent<MovingPlatformComponent>());
moverPlatformSubComponent.SetupPath("ExamplePath", 0, false);
EXPECT_FLOAT_EQ(moverPlatformSubComponent.CalculatePercentToNextWaypoint(), 1.0f);
}
{
path.movingPlatform.timeBasedMovement = true;
path.pathName = "ExamplePath2";
Game::zoneManager->GetZone()->AddPath(path);
baseEntity->SetPosition(NiPoint3(1, 0, 0));
MoverPlatformSubComponent moverPlatformSubComponent(baseEntity->GetComponent<MovingPlatformComponent>());
moverPlatformSubComponent.SetupPath("ExamplePath2", 0, false);
ASSERT_FLOAT_EQ(moverPlatformSubComponent.CalculatePercentToNextWaypoint(), 0.0f);
}
}