/* * Darkflame Universe * Copyright 2019 */ #ifndef MOVINGPLATFORMCOMPONENT_H #define MOVINGPLATFORMCOMPONENT_H #include "NiPoint3.h" #include #include #include #include "dCommonVars.h" #include "Component.h" #include "eMovementPlatformState.h" #include "eReplicaComponentType.h" class Path; /** * Different types of available platforms */ enum class eMoverSubComponentType : uint32_t { None = 0, Mover = 4, SimpleMover = 5, Rotator = 6 }; class PlatformSubComponent { public: PlatformSubComponent(); virtual ~PlatformSubComponent() = default; virtual void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate); virtual eMoverSubComponentType GetPlatformType() { return eMoverSubComponentType::None; }; bool GetIsDirty() const { return m_IsDirty; } protected: #ifdef _MOVING_PLATFORM_TEST public: #endif /** * The state the platform is currently in */ eMovementPlatformState m_State = eMovementPlatformState::Stopped | eMovementPlatformState::ReachedDesiredWaypoint; int32_t m_DesiredWaypointIndex = 0; float m_PercentBetweenPoints = 0; NiPoint3 m_Position; uint32_t m_CurrentWaypointIndex; uint32_t m_NextWaypointIndex; float m_IdleTimeElapsed = 0; float m_Speed = 0; float m_WaitTime = 0; float m_MoveTimeElapsed = 0; bool m_IsDirty = false; bool m_InReverse = false; bool m_ShouldStopAtDesiredWaypoint = false; }; class MoverPlatformSubComponent : public PlatformSubComponent { public: MoverPlatformSubComponent() : PlatformSubComponent() {}; ~MoverPlatformSubComponent() override = default; eMoverSubComponentType GetPlatformType() override { return eMoverSubComponentType::Mover; } void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override { PlatformSubComponent::Serialize(outBitStream, bIsInitialUpdate); }; }; class RotatorPlatformSubComponent : public PlatformSubComponent { public: RotatorPlatformSubComponent() : PlatformSubComponent() {}; ~RotatorPlatformSubComponent() override = default; eMoverSubComponentType GetPlatformType() override { return eMoverSubComponentType::Rotator; } void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override { PlatformSubComponent::Serialize(outBitStream, bIsInitialUpdate); }; }; // Only moves. Has NO path. class SimpleMoverPlatformSubComponent : public PlatformSubComponent { public: SimpleMoverPlatformSubComponent() : PlatformSubComponent() {}; ~SimpleMoverPlatformSubComponent() override = default; eMoverSubComponentType GetPlatformType() override { return eMoverSubComponentType::SimpleMover; } void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override { PlatformSubComponent::Serialize(outBitStream, bIsInitialUpdate); }; }; /** * Represents entities that may be moving platforms, indicating how they should move through the world. * NOTE: the logic in this component hardly does anything, apparently the client can figure most of this stuff out * if you just serialize it correctly, resulting in smoother results anyway. Don't be surprised if the exposed APIs * don't at all do what you expect them to as we don't instruct the client of changes made here. * ^^^ Trivia: This made the red blocks platform and property platforms a pain to implement. */ class MovingPlatformComponent : public Component { public: static const eReplicaComponentType ComponentType = eReplicaComponentType::MOVING_PLATFORM; MovingPlatformComponent(Entity* parent, const std::string& pathName); void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); /** * Stops all pathing, called when an entity starts a quick build associated with this platform */ void OnRebuildInitilized(); /** * Starts the pathing, called when an entity completed a quick build associated with this platform */ void OnCompleteRebuild(); /** * Updates the movement state for the moving platform * @param value the movement state to set */ void SetMovementState(eMovementPlatformState value); /** * Instructs the moving platform to go to some waypoint * @param index the index of the waypoint * @param stopAtWaypoint determines if the platform should stop at the waypoint */ void GotoWaypoint(uint32_t index, bool stopAtWaypoint = true); /** * Starts the pathing of this platform, setting appropriate waypoints and speeds */ void StartPathing(); /** * Continues the path of the platform, after it's been stopped */ void ContinuePathing(); /** * Stops the platform from moving, waiting for it to be activated again. */ void StopPathing(); /** * Determines if the entity should be serialized on the next update * @param value whether to serialize the entity or not */ void SetSerialized(bool value); /** * Returns if this platform will start automatically after spawn * @return if this platform will start automatically after spawn */ bool GetNoAutoStart() const; /** * Sets the auto start value for this platform * @param value the auto start value to set */ void SetNoAutoStart(bool value); /** * Warps the platform to a waypoint index, skipping its current path * @param index the index to go to */ void WarpToWaypoint(size_t index); /** * Returns the waypoint this platform was previously at * @return the waypoint this platform was previously at */ size_t GetLastWaypointIndex() const; #ifdef _MOVING_PLATFORM_TEST /** * Only used for testing. Do not call in production code. Let the constructor take care of this. * * @param platformSubComponent */ void _AddPlatformSubComponent(std::unique_ptr platformSubComponent) { m_Platforms.push_back(std::move(platformSubComponent)); } void _SetPath(const std::u16string& path) { m_PathName = path; m_DirtyPathInfo = true; } #endif private: /** * The name of the path this platform is currently on */ std::u16string m_PathName; /** * Whether the platform has stopped pathing */ bool m_PathingStopped = false; /** * The mover sub component that belongs to this platform */ std::vector> m_Platforms; /** * Whether the platform shouldn't auto start */ bool m_NoAutoStart; /** * Whether to serialize the entity on the next update */ bool m_Serialize = false; bool m_DirtyPathInfo = false; }; #endif // MOVINGPLATFORMCOMPONENT_H