mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 02:43:44 +00:00
feat(moving platform): simple movers and rotaters, chosen as the client chooses
The subcomponent comes from the platformIsMover, platformIsSimpleMover and platformIsRotater settings; with none set, a platform without a registry component is a mover and one with a registry component a simple mover (also when it has an attached path, so the registry ID is passed then too). All flags set false means no subcomponent. A simple mover reads its MovingPlatforms row and the platformMove* settings, is always constructed with its starting point and state as live did, and travels between its start and start + platformMove in platformMoveTime. A rotater is written as type 6 with a mover's data. On arrival platforms fire OnWaypointReached, then OnArrivedAtDesiredWaypoint at the waypoint they were sent to and OnPlatformAtLastWaypoint at an end. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -787,7 +787,8 @@ void Entity::Initialize() {
|
||||
if (path) {
|
||||
// if we have a moving platform path, then we need a moving platform component
|
||||
if (path->pathType == PathType::MovingPlatform) {
|
||||
AddComponent<MovingPlatformComponent>(-1, pathName);
|
||||
// The registry component ID picks the subcomponent (a simple mover when it has one), path or not
|
||||
AddComponent<MovingPlatformComponent>(compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MOVING_PLATFORM, -1), pathName);
|
||||
} else if (path->pathType == PathType::Movement) {
|
||||
auto* const movementAIcomponent = GetComponent<MovementAIComponent>();
|
||||
if (movementAIcomponent && combatAiID == 0) {
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
#include "CppScripts.h"
|
||||
#include "SimplePhysicsComponent.h"
|
||||
#include "Zone.h"
|
||||
#include "CDClientDatabase.h"
|
||||
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
MoverSubComponent::MoverSubComponent(const NiPoint3& startPos) {
|
||||
mPosition = {};
|
||||
@@ -53,11 +56,93 @@ void MoverSubComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsIniti
|
||||
outBitStream.Write<float_t>(0.0f); // Move time elapsed
|
||||
}
|
||||
|
||||
//------------- SimpleMoverSubComponent below --------------
|
||||
|
||||
// LWOPlatformSimpleMover::Deserialize: a dirty bit, then whether there is a starting point with its position and
|
||||
// rotation (w, x, y, z); a dirty bit, then the state, the current waypoint and whether it is reversing
|
||||
void SimpleMoverSubComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) {
|
||||
outBitStream.Write(bIsInitialUpdate || mDirtyStartingPoint);
|
||||
if (bIsInitialUpdate || mDirtyStartingPoint) {
|
||||
outBitStream.Write1();
|
||||
outBitStream.Write(mStartPosition.x);
|
||||
outBitStream.Write(mStartPosition.y);
|
||||
outBitStream.Write(mStartPosition.z);
|
||||
outBitStream.Write(mStartRotation.w);
|
||||
outBitStream.Write(mStartRotation.x);
|
||||
outBitStream.Write(mStartRotation.y);
|
||||
outBitStream.Write(mStartRotation.z);
|
||||
if (!bIsInitialUpdate) mDirtyStartingPoint = false;
|
||||
}
|
||||
|
||||
outBitStream.Write(bIsInitialUpdate || mDirtyState);
|
||||
if (bIsInitialUpdate || mDirtyState) {
|
||||
outBitStream.Write<uint32_t>(mState);
|
||||
outBitStream.Write<int32_t>(mCurrentWaypointIndex);
|
||||
outBitStream.Write(mInReverse);
|
||||
if (!bIsInitialUpdate) mDirtyState = false;
|
||||
}
|
||||
}
|
||||
|
||||
NiPoint3 SimpleMoverSubComponent::GetWaypointPosition(const int32_t index) const {
|
||||
if (index <= 0) return mStartPosition;
|
||||
const glm::vec3 moved = mStartRotation * glm::vec3(mMove.x, mMove.y, mMove.z);
|
||||
return mStartPosition + NiPoint3(moved.x, moved.y, moved.z);
|
||||
}
|
||||
|
||||
eMoverSubComponentType ChooseMoverSubComponentType(const int32_t componentID, const Entity& entity) {
|
||||
const bool setRotater = entity.HasVar(u"platformIsRotater");
|
||||
const bool setMover = entity.HasVar(u"platformIsMover");
|
||||
const bool setSimpleMover = entity.HasVar(u"platformIsSimpleMover");
|
||||
|
||||
if (!setRotater && !setMover && !setSimpleMover) {
|
||||
return componentID < 1 ? eMoverSubComponentType::mover : eMoverSubComponentType::simpleMover;
|
||||
}
|
||||
|
||||
if (setMover && entity.GetVar<bool>(u"platformIsMover")) return eMoverSubComponentType::mover;
|
||||
if (setSimpleMover && entity.GetVar<bool>(u"platformIsSimpleMover")) return eMoverSubComponentType::simpleMover;
|
||||
if (setRotater && entity.GetVar<bool>(u"platformIsRotater")) return eMoverSubComponentType::rotater;
|
||||
return eMoverSubComponentType::none;
|
||||
}
|
||||
|
||||
//------------- MovingPlatformComponent below --------------
|
||||
|
||||
MovingPlatformComponent::MovingPlatformComponent(Entity* parent, const int32_t componentID, const std::string& pathName) : Component(parent, componentID) {
|
||||
m_MoverSubComponentType = eMoverSubComponentType::mover;
|
||||
m_MoverSubComponentType = ChooseMoverSubComponentType(componentID, *m_Parent);
|
||||
if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) {
|
||||
auto* const simpleMover = new SimpleMoverSubComponent();
|
||||
m_MoverSubComponent = simpleMover;
|
||||
simpleMover->mStartPosition = m_Parent->GetDefaultPosition();
|
||||
simpleMover->mStartRotation = m_Parent->GetDefaultRotation();
|
||||
|
||||
// LWOPlatformSimpleMover::LoadTemplateData: the MovingPlatforms row, unless the object sets dbonly false
|
||||
const bool dbOnly = m_Parent->GetVar<bool>(u"dbonly");
|
||||
if (componentID > 0 && (!m_Parent->HasVar(u"dbonly") || dbOnly)) {
|
||||
auto query = CDClientDatabase::CreatePreppedStmt(
|
||||
"SELECT platformMoveX, platformMoveY, platformMoveZ, platformMoveTime, platformStartAtEnd FROM MovingPlatforms WHERE id = ?;");
|
||||
query.bind(1, componentID);
|
||||
auto result = query.execQuery();
|
||||
if (!result.eof()) {
|
||||
simpleMover->mMove = NiPoint3(result.getFloatField(0), result.getFloatField(1), result.getFloatField(2));
|
||||
simpleMover->mMoveTime = result.getFloatField(3);
|
||||
simpleMover->mStartAtEnd = result.getIntField(4) != 0;
|
||||
} else {
|
||||
LOG("LOT %i couldn't find simple mover %i in MovingPlatforms", m_Parent->GetLOT(), componentID);
|
||||
}
|
||||
}
|
||||
|
||||
// LWOPlatformSimpleMover::LoadConfigData: the object's settings over the table's, unless it is db only
|
||||
if (m_Parent->HasVar(u"attached_path_start")) simpleMover->mStartAtEnd = m_Parent->GetVar<int32_t>(u"attached_path_start") != 0;
|
||||
if (m_Parent->HasVar(u"platformStartAtEnd")) simpleMover->mStartAtEnd = m_Parent->GetVar<bool>(u"platformStartAtEnd");
|
||||
if (!dbOnly) {
|
||||
if (m_Parent->HasVar(u"platformMoveX")) simpleMover->mMove.x = m_Parent->GetVar<float>(u"platformMoveX");
|
||||
if (m_Parent->HasVar(u"platformMoveY")) simpleMover->mMove.y = m_Parent->GetVar<float>(u"platformMoveY");
|
||||
if (m_Parent->HasVar(u"platformMoveZ")) simpleMover->mMove.z = m_Parent->GetVar<float>(u"platformMoveZ");
|
||||
if (m_Parent->HasVar(u"platformMoveTime")) simpleMover->mMoveTime = m_Parent->GetVar<float>(u"platformMoveTime");
|
||||
}
|
||||
simpleMover->mCurrentWaypointIndex = simpleMover->mStartAtEnd ? 1 : 0;
|
||||
} else {
|
||||
m_MoverSubComponent = new MoverSubComponent(m_Parent->GetDefaultPosition());
|
||||
}
|
||||
m_PathName = GeneralUtils::ASCIIToUTF16(pathName);
|
||||
m_Path = Game::zoneManager->GetZone()->GetPath(pathName);
|
||||
m_NoAutoStart = false;
|
||||
@@ -72,10 +157,28 @@ MovingPlatformComponent::MovingPlatformComponent(Entity* parent, const int32_t c
|
||||
}
|
||||
|
||||
MovingPlatformComponent::~MovingPlatformComponent() {
|
||||
delete static_cast<MoverSubComponent*>(m_MoverSubComponent);
|
||||
if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) delete static_cast<SimpleMoverSubComponent*>(m_MoverSubComponent);
|
||||
else delete static_cast<MoverSubComponent*>(m_MoverSubComponent);
|
||||
}
|
||||
|
||||
void MovingPlatformComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) {
|
||||
// Live always constructed a simple mover with its starting point (the client builds its path from it), and
|
||||
// serialized it only when its state changed: no path, then the one subcomponent and the 0 bit ending the list
|
||||
if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) {
|
||||
auto* const simpleMover = GetSimpleMoverSubComponent();
|
||||
const bool dirty = bIsInitialUpdate || simpleMover->mDirtyStartingPoint || simpleMover->mDirtyState;
|
||||
outBitStream.Write(dirty);
|
||||
outBitStream.Write(bIsInitialUpdate);
|
||||
if (bIsInitialUpdate) outBitStream.Write0();
|
||||
if (dirty) {
|
||||
outBitStream.Write1();
|
||||
outBitStream.Write(m_MoverSubComponentType);
|
||||
simpleMover->Serialize(outBitStream, bIsInitialUpdate);
|
||||
outBitStream.Write0();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Here we don't serialize the moving platform to let the client simulate the movement
|
||||
|
||||
if (!m_Serialize) {
|
||||
@@ -106,18 +209,15 @@ void MovingPlatformComponent::Serialize(RakNet::BitStream& outBitStream, bool bI
|
||||
outBitStream.Write<bool>(false);
|
||||
}
|
||||
|
||||
const auto hasPlatform = m_MoverSubComponent != nullptr;
|
||||
// A platform the client made no subcomponent for must not get one: it could not read it
|
||||
const auto hasPlatform = m_MoverSubComponentType != eMoverSubComponentType::none;
|
||||
outBitStream.Write<bool>(hasPlatform);
|
||||
|
||||
if (hasPlatform) {
|
||||
// A rotater's data is a mover's (both read by LWOPlatform::Deserialize)
|
||||
auto* mover = static_cast<MoverSubComponent*>(m_MoverSubComponent);
|
||||
outBitStream.Write(m_MoverSubComponentType);
|
||||
|
||||
if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) {
|
||||
// TODO
|
||||
} else {
|
||||
mover->Serialize(outBitStream, bIsInitialUpdate);
|
||||
}
|
||||
|
||||
// The client reads subcomponents while a 1 bit comes before one: a 0 bit ends the list
|
||||
outBitStream.Write0();
|
||||
@@ -125,10 +225,21 @@ void MovingPlatformComponent::Serialize(RakNet::BitStream& outBitStream, bool bI
|
||||
}
|
||||
|
||||
void MovingPlatformComponent::OnQuickBuildInitilized() {
|
||||
// Live left a quick built simple mover (the NJ counterweights) where it was, only resending its state: scripts
|
||||
// send it on
|
||||
if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) {
|
||||
GetSimpleMoverSubComponent()->mDirtyState = true;
|
||||
return;
|
||||
}
|
||||
StopPathing();
|
||||
}
|
||||
|
||||
void MovingPlatformComponent::OnCompleteQuickBuild() {
|
||||
if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) {
|
||||
GetSimpleMoverSubComponent()->mDirtyState = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_NoAutoStart)
|
||||
return;
|
||||
|
||||
@@ -136,6 +247,14 @@ void MovingPlatformComponent::OnCompleteQuickBuild() {
|
||||
}
|
||||
|
||||
void MovingPlatformComponent::SetMovementState(eMovementPlatformState value) {
|
||||
if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) {
|
||||
auto* const simpleMover = GetSimpleMoverSubComponent();
|
||||
simpleMover->mState = static_cast<uint32_t>(value);
|
||||
simpleMover->mDirtyState = true;
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
return;
|
||||
}
|
||||
|
||||
auto* subComponent = static_cast<MoverSubComponent*>(m_MoverSubComponent);
|
||||
|
||||
subComponent->mState = value;
|
||||
@@ -144,6 +263,11 @@ void MovingPlatformComponent::SetMovementState(eMovementPlatformState value) {
|
||||
}
|
||||
|
||||
void MovingPlatformComponent::GotoWaypoint(uint32_t index, bool stopAtWaypoint) {
|
||||
if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) {
|
||||
SimpleMoverGotoWaypoint(static_cast<int32_t>(index));
|
||||
return;
|
||||
}
|
||||
|
||||
auto* subComponent = static_cast<MoverSubComponent*>(m_MoverSubComponent);
|
||||
|
||||
subComponent->mDesiredWaypointIndex = index;
|
||||
@@ -154,6 +278,11 @@ void MovingPlatformComponent::GotoWaypoint(uint32_t index, bool stopAtWaypoint)
|
||||
}
|
||||
|
||||
void MovingPlatformComponent::StartPathing() {
|
||||
if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) {
|
||||
// A simple mover's path is start to end: starting sends it to the other end
|
||||
SimpleMoverGotoWaypoint(GetSimpleMoverSubComponent()->mCurrentWaypointIndex == 0 ? 1 : 0);
|
||||
return;
|
||||
}
|
||||
//GameMessages::SendStartPathing(m_Parent);
|
||||
m_PathingStopped = false;
|
||||
|
||||
@@ -190,7 +319,7 @@ void MovingPlatformComponent::StartPathing() {
|
||||
const auto travelNext = subComponent->mWaitTime + travelTime;
|
||||
|
||||
m_Parent->AddCallbackTimer(travelTime, [subComponent, this] {
|
||||
this->m_Parent->GetScript()->OnWaypointReached(m_Parent, subComponent->mNextWaypointIndex);
|
||||
FireArrivalHooks(subComponent->mNextWaypointIndex, subComponent->mNextWaypointIndex == static_cast<uint32_t>(subComponent->mDesiredWaypointIndex));
|
||||
});
|
||||
|
||||
m_Parent->AddCallbackTimer(travelNext, [this] {
|
||||
@@ -203,6 +332,7 @@ void MovingPlatformComponent::StartPathing() {
|
||||
}
|
||||
|
||||
void MovingPlatformComponent::ContinuePathing() {
|
||||
if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) return;
|
||||
auto* subComponent = static_cast<MoverSubComponent*>(m_MoverSubComponent);
|
||||
|
||||
subComponent->mState = eMovementPlatformState::Stationary;
|
||||
@@ -300,7 +430,7 @@ void MovingPlatformComponent::ContinuePathing() {
|
||||
const auto travelNext = subComponent->mWaitTime + travelTime;
|
||||
|
||||
m_Parent->AddCallbackTimer(travelTime, [subComponent, this] {
|
||||
this->m_Parent->GetScript()->OnWaypointReached(m_Parent, subComponent->mNextWaypointIndex);
|
||||
FireArrivalHooks(subComponent->mNextWaypointIndex, subComponent->mNextWaypointIndex == static_cast<uint32_t>(subComponent->mDesiredWaypointIndex));
|
||||
});
|
||||
|
||||
m_Parent->AddCallbackTimer(travelNext, [this] {
|
||||
@@ -311,6 +441,15 @@ void MovingPlatformComponent::ContinuePathing() {
|
||||
}
|
||||
|
||||
void MovingPlatformComponent::StopPathing() {
|
||||
if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) {
|
||||
// LWOPlatformSimpleMover::StopPlatform: it stops where it is, no longer travelling
|
||||
auto* const simpleMover = GetSimpleMoverSubComponent();
|
||||
m_MoveGeneration++;
|
||||
simpleMover->mState = ePlatformStateFlag::Stopped;
|
||||
simpleMover->mDirtyState = true;
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
return;
|
||||
}
|
||||
//m_Parent->CancelCallbackTimers();
|
||||
|
||||
auto* subComponent = static_cast<MoverSubComponent*>(m_MoverSubComponent);
|
||||
@@ -339,6 +478,17 @@ void MovingPlatformComponent::SetNoAutoStart(const bool value) {
|
||||
}
|
||||
|
||||
void MovingPlatformComponent::WarpToWaypoint(size_t index) {
|
||||
if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) {
|
||||
auto* const simpleMover = GetSimpleMoverSubComponent();
|
||||
m_MoveGeneration++;
|
||||
simpleMover->mCurrentWaypointIndex = index == 0 ? 0 : 1;
|
||||
simpleMover->mInReverse = simpleMover->mCurrentWaypointIndex == 1;
|
||||
simpleMover->mState = ePlatformStateFlag::Stopped | ePlatformStateFlag::ReachedDesiredWaypoint | ePlatformStateFlag::ReachedFinalDestination;
|
||||
simpleMover->mDirtyState = true;
|
||||
m_Parent->SetPosition(simpleMover->GetWaypointPosition(simpleMover->mCurrentWaypointIndex));
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
return;
|
||||
}
|
||||
const auto& waypoint = m_Path->pathWaypoints[index];
|
||||
|
||||
m_Parent->SetPosition(waypoint.position);
|
||||
@@ -348,9 +498,61 @@ void MovingPlatformComponent::WarpToWaypoint(size_t index) {
|
||||
}
|
||||
|
||||
size_t MovingPlatformComponent::GetLastWaypointIndex() const {
|
||||
if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) return 1;
|
||||
return m_Path->pathWaypoints.size() - 1;
|
||||
}
|
||||
|
||||
MoverSubComponent* MovingPlatformComponent::GetMoverSubComponent() const {
|
||||
if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) return nullptr;
|
||||
return static_cast<MoverSubComponent*>(m_MoverSubComponent);
|
||||
}
|
||||
|
||||
SimpleMoverSubComponent* MovingPlatformComponent::GetSimpleMoverSubComponent() const {
|
||||
if (m_MoverSubComponentType != eMoverSubComponentType::simpleMover) return nullptr;
|
||||
return static_cast<SimpleMoverSubComponent*>(m_MoverSubComponent);
|
||||
}
|
||||
|
||||
// The client runs the two point path at |platformMove| / platformMoveTime, so it takes platformMoveTime seconds from
|
||||
// either end. Sending it travelling from its current waypoint towards the other one is all the client needs.
|
||||
void MovingPlatformComponent::SimpleMoverGotoWaypoint(int32_t index) {
|
||||
auto* const simpleMover = GetSimpleMoverSubComponent();
|
||||
index = index <= 0 ? 0 : 1;
|
||||
const bool travelling = (simpleMover->mState & ePlatformStateFlag::Travelling) != 0;
|
||||
if (!travelling && index == simpleMover->mCurrentWaypointIndex) return;
|
||||
|
||||
simpleMover->mCurrentWaypointIndex = index == 1 ? 0 : 1;
|
||||
simpleMover->mInReverse = index == 0;
|
||||
simpleMover->mState = ePlatformStateFlag::Travelling;
|
||||
simpleMover->mDirtyState = true;
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
|
||||
const auto generation = ++m_MoveGeneration;
|
||||
m_Parent->AddCallbackTimer(simpleMover->mMoveTime, [this, generation, index] {
|
||||
if (generation == m_MoveGeneration) OnSimpleMoverArrived(index);
|
||||
});
|
||||
}
|
||||
|
||||
void MovingPlatformComponent::OnSimpleMoverArrived(const int32_t index) {
|
||||
auto* const simpleMover = GetSimpleMoverSubComponent();
|
||||
if (!simpleMover) return;
|
||||
|
||||
// LWOPlatform::ArrivedAtWaypoint: both ends are the path's ends, and a path run once stops there
|
||||
simpleMover->mCurrentWaypointIndex = index;
|
||||
simpleMover->mState = ePlatformStateFlag::Stopped | ePlatformStateFlag::ReachedDesiredWaypoint | ePlatformStateFlag::ReachedFinalDestination;
|
||||
simpleMover->mInReverse = index == 1;
|
||||
simpleMover->mDirtyState = true;
|
||||
m_Parent->SetPosition(simpleMover->GetWaypointPosition(index));
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
|
||||
FireArrivalHooks(index, true);
|
||||
}
|
||||
|
||||
// LWOPlatform::HandleWaypointArrived: Arrived, then ArrivedAtDesiredWaypoint at the waypoint it was sent to, then
|
||||
// PlatformAtLastWaypoint at either end of the path
|
||||
void MovingPlatformComponent::FireArrivalHooks(const uint32_t index, const bool atDesiredWaypoint) {
|
||||
auto* const script = m_Parent->GetScript();
|
||||
script->OnWaypointReached(m_Parent, index);
|
||||
if (atDesiredWaypoint) script->OnArrivedAtDesiredWaypoint(m_Parent, index);
|
||||
const size_t last = m_MoverSubComponentType == eMoverSubComponentType::simpleMover ? 1 : (m_Path ? m_Path->pathWaypoints.size() - 1 : 0);
|
||||
if (index == 0 || index == last) script->OnPlatformAtLastWaypoint(m_Parent);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "RakNetTypes.h"
|
||||
#include "NiPoint3.h"
|
||||
#include "NiQuaternion.h"
|
||||
#include <string>
|
||||
|
||||
#include "dCommonVars.h"
|
||||
@@ -25,9 +26,69 @@ enum class eMoverSubComponentType : uint32_t {
|
||||
mover = 4,
|
||||
|
||||
/**
|
||||
* Used in NJ
|
||||
* A two point mover set up from the MovingPlatforms table or the platformMove* settings (used in NJ)
|
||||
*/
|
||||
simpleMover = 5,
|
||||
|
||||
/**
|
||||
* A mover that turns between rotations along its path (same data as a mover)
|
||||
*/
|
||||
rotater = 6,
|
||||
|
||||
/**
|
||||
* The level config set the platform flags all false: the client makes no subcomponent
|
||||
*/
|
||||
none = 0,
|
||||
};
|
||||
|
||||
/**
|
||||
* The client's platform state flags (LWOPlatform)
|
||||
*/
|
||||
namespace ePlatformStateFlag {
|
||||
constexpr uint32_t Stopped = 1;
|
||||
constexpr uint32_t Travelling = 2;
|
||||
constexpr uint32_t Waiting = 4;
|
||||
constexpr uint32_t ReachedDesiredWaypoint = 8;
|
||||
constexpr uint32_t ReachedFinalDestination = 16;
|
||||
};
|
||||
|
||||
/**
|
||||
* How the client picks the subcomponent (LWOMovingPlatformComponent::LoadConfigData): the platformIsRotater,
|
||||
* platformIsMover and platformIsSimpleMover settings, and when none is set a mover for a platform with no registry
|
||||
* component (set up from its attached path) or a simple mover for one with a registry component.
|
||||
* The client makes one subcomponent per flag set (mover, simple mover, rotater, LWOMovingPlatformComponent::SetupPlatform);
|
||||
* DLU keeps one, the first in that order.
|
||||
*/
|
||||
eMoverSubComponentType ChooseMoverSubComponentType(int32_t componentID, const Entity& entity);
|
||||
|
||||
/**
|
||||
* A mover between a start point and that point moved by platformMove (in the start rotation), taking
|
||||
* platformMoveTime seconds, as LWOPlatformSimpleMover::GenerateSimpleMoverPath builds its two waypoint path.
|
||||
*/
|
||||
class SimpleMoverSubComponent {
|
||||
public:
|
||||
void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate);
|
||||
|
||||
NiPoint3 mStartPosition{};
|
||||
NiQuaternion mStartRotation{};
|
||||
NiPoint3 mMove{};
|
||||
float mMoveTime = 0.0f;
|
||||
bool mStartAtEnd = false;
|
||||
|
||||
/**
|
||||
* ePlatformStateFlag bits. Live constructed simple movers stopped at their desired waypoint.
|
||||
*/
|
||||
uint32_t mState = ePlatformStateFlag::Stopped | ePlatformStateFlag::ReachedDesiredWaypoint;
|
||||
int32_t mCurrentWaypointIndex = 0;
|
||||
bool mInReverse = false;
|
||||
|
||||
bool mDirtyStartingPoint = false;
|
||||
bool mDirtyState = false;
|
||||
|
||||
/**
|
||||
* The world position of a waypoint (0 the start, 1 the end)
|
||||
*/
|
||||
NiPoint3 GetWaypointPosition(int32_t index) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -187,6 +248,19 @@ public:
|
||||
*/
|
||||
MoverSubComponent* GetMoverSubComponent() const;
|
||||
|
||||
/**
|
||||
* Returns the simple mover sub component, if this platform is a simple mover
|
||||
*/
|
||||
SimpleMoverSubComponent* GetSimpleMoverSubComponent() const;
|
||||
|
||||
eMoverSubComponentType GetMoverSubComponentType() const { return m_MoverSubComponentType; }
|
||||
|
||||
/**
|
||||
* Called when a simple mover gets to the waypoint it was sent to: the client's LWOPlatform::ArrivedAtWaypoint
|
||||
* and HandleWaypointArrived (Arrived, then ArrivedAtDesiredWaypoint and PlatformAtLastWaypoint)
|
||||
*/
|
||||
void OnSimpleMoverArrived(int32_t index);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
@@ -214,6 +288,15 @@ private:
|
||||
*/
|
||||
void* m_MoverSubComponent;
|
||||
|
||||
/**
|
||||
* Counts sends so an arrival timer from an older send does nothing
|
||||
*/
|
||||
uint32_t m_MoveGeneration = 0;
|
||||
|
||||
void SimpleMoverGotoWaypoint(int32_t index);
|
||||
|
||||
void FireArrivalHooks(uint32_t index, bool atDesiredWaypoint);
|
||||
|
||||
/**
|
||||
* Whether the platform shouldn't auto start
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user