diff --git a/dGame/dComponents/MovementAIComponent.cpp b/dGame/dComponents/MovementAIComponent.cpp index 12927506..05063862 100644 --- a/dGame/dComponents/MovementAIComponent.cpp +++ b/dGame/dComponents/MovementAIComponent.cpp @@ -55,6 +55,13 @@ MovementAIComponent::MovementAIComponent(Entity* parent, MovementAIInfo info) : m_NextPathWaypointIndex = 0; } +float MovementAIComponent::GetCurrentPathWaypointSpeed() const { + if (!m_Path || m_CurrentPathWaypointIndex >= m_CurrentPath.size() || m_CurrentPathWaypointIndex < 0) { + return 1.0f; + } + return m_Path->pathWaypoints.at(m_CurrentPathWaypointIndex).speed; +} + void MovementAIComponent::SetupPath(const std::string& pathname) { std::string path = pathname; if (path.empty()) path = m_Parent->GetVarAsString(u"attached_path"); @@ -79,7 +86,6 @@ void MovementAIComponent::SetupPath(const std::string& pathname) { waypoints.push_back(waypoint.position); } SetPath(waypoints); - SetMaxSpeed(3.0f); } else { Game::logger->Log("MovementAIComponent", "No path found for %i:%llu", m_Parent->GetLOT(), m_Parent->GetObjectID()); } @@ -134,14 +140,14 @@ void MovementAIComponent::Update(const float deltaTime) { if (m_NextWaypoint == source) { m_TimeToTravel = 0.0f; - goto nextAction; + return; } + // if (m_CurrentSpeed < m_MaxSpeed) { + // m_CurrentSpeed += m_Acceleration; + // } + if (m_CurrentSpeed < m_MaxSpeed) { - m_CurrentSpeed += m_Acceleration; - } - - if (m_CurrentSpeed > m_MaxSpeed) { m_CurrentSpeed = m_MaxSpeed; } @@ -152,7 +158,7 @@ void MovementAIComponent::Update(const float deltaTime) { // Normalize the vector const auto length = delta.Length(); if (length > 0) { - velocity = (delta / length) * speed; + velocity = (delta / length).Unitize() * speed; } // Calclute the time it will take to reach the next waypoint with the current speed @@ -164,24 +170,7 @@ void MovementAIComponent::Update(const float deltaTime) { // Check if there are more waypoints in the queue, if so set our next destination to the next waypoint // All checks for how to progress when you arrive at a waypoint will be handled in this else block. HandleWaypointArrived(0); - if (!AdvancePathWaypointIndex()) { - if (m_Path) { - if (m_Path->pathBehavior == PathBehavior::Bounce) { - ReversePath(); - } else if (m_Path->pathBehavior == PathBehavior::Loop) { - m_CurrentPathWaypointIndex = 0; - m_NextPathWaypointIndex = 0; - AdvancePathWaypointIndex(); - SetDestination(GetCurrentPathWaypoint()); - } else { - Stop(); - } - } else { - Stop(); - } - return; - } - SetDestination(GetCurrentPathWaypoint()); + return; } nextAction: @@ -231,15 +220,11 @@ NiPoint3 MovementAIComponent::GetCurrentWaypoint() const { NiPoint3 MovementAIComponent::ApproximateLocation() const { auto source = m_Parent->GetPosition(); - if (AtFinalWaypoint()) return source; - auto destination = m_NextWaypoint; - + auto destination = GetNextWaypoint(); auto percentageToWaypoint = m_TimeToTravel > 0 ? m_TimeTravelled / m_TimeToTravel : 0; - auto approximation = source + ((destination - source) * percentageToWaypoint); - if (dpWorld::Instance().IsLoaded()) { approximation.y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(approximation); } @@ -284,6 +269,7 @@ void MovementAIComponent::Resume() { if (AtFinalWaypoint() || !IsPaused()) return; m_IsPaused = false; SetDestination(GetCurrentPathWaypoint()); + SetMaxSpeed(GetCurrentPathWaypointSpeed()); } void MovementAIComponent::Stop() { @@ -341,6 +327,7 @@ void MovementAIComponent::SetPath(std::vector path, bool startInRevers AdvancePathWaypointIndex(); SetDestination(GetCurrentPathWaypoint()); + SetMaxSpeed(GetCurrentPathWaypointSpeed()); } float MovementAIComponent::GetBaseSpeed(LOT lot) { diff --git a/dGame/dComponents/MovementAIComponent.h b/dGame/dComponents/MovementAIComponent.h index d6c25844..76508d8c 100644 --- a/dGame/dComponents/MovementAIComponent.h +++ b/dGame/dComponents/MovementAIComponent.h @@ -154,6 +154,19 @@ public: */ NiPoint3 GetNextWaypoint() const { return m_NextWaypoint; } + NiPoint3 GetNextPathWaypoint() const { + if (m_CurrentPath.empty()) return GetNextWaypoint(); + if (m_IsInReverse) { + return m_CurrentPathWaypointIndex - 1 < 0 ? + m_CurrentPath.front() : + m_CurrentPath.at(m_CurrentPathWaypointIndex - 1); + } else { + return m_CurrentPathWaypointIndex + 1 >= m_CurrentPath.size() ? + m_CurrentPath.back() : + m_CurrentPath.at(m_CurrentPathWaypointIndex + 1); + } + } + /** * Returns the approximate current location of the entity, including y coordinates * @return the approximate current location of the entity @@ -198,6 +211,8 @@ public: void SetupPath(const std::string& pathname); + float GetCurrentPathWaypointSpeed() const; + /** * Stops the current movement and moves the entity to a certain point. Will continue until it's close enough, * after which its AI is enabled again. diff --git a/dGame/dComponents/MovementAIComponentAronwk.cpp b/dGame/dComponents/MovementAIComponentAronwk.cpp index 367c01aa..a6c4cc58 100644 --- a/dGame/dComponents/MovementAIComponentAronwk.cpp +++ b/dGame/dComponents/MovementAIComponentAronwk.cpp @@ -11,77 +11,92 @@ #include "DestroyableComponent.h" void MovementAIComponent::HandleWaypointArrived(uint32_t commandIndex) { - if (!m_Path){ - if(IsPaused()) Resume(); + if (!m_Path || commandIndex >= m_Path->pathWaypoints.at(m_CurrentPathWaypointIndex).commands.size()) { + if (!AdvancePathWaypointIndex()) { + if (m_Path) { + if (m_Path->pathBehavior == PathBehavior::Bounce) { + ReversePath(); + } else if (m_Path->pathBehavior == PathBehavior::Loop) { + m_CurrentPathWaypointIndex = 0; + m_NextPathWaypointIndex = 0; + AdvancePathWaypointIndex(); + SetDestination(GetCurrentPathWaypoint()); + SetMaxSpeed(GetCurrentPathWaypointSpeed()); + } else { + Stop(); + } + } else { + Stop(); + } + return; + } + SetDestination(GetCurrentPathWaypoint()); + SetMaxSpeed(GetCurrentPathWaypointSpeed()); return; } - if (commandIndex >= m_Path->pathWaypoints.at(m_CurrentPathWaypointIndex).commands.size()){ - if(IsPaused()) Resume(); - return; - } - if(!IsPaused()) Pause(); + if (!IsPaused()) Pause(); const auto& data = m_Path->pathWaypoints.at(m_CurrentPathWaypointIndex).commands.at(commandIndex).data; const auto& command = m_Path->pathWaypoints.at(m_CurrentPathWaypointIndex).commands.at(commandIndex).command; float delay = 0.0f; - switch(command){ - case eWaypointCommandType::STOP: - Stop(); - break; - case eWaypointCommandType::GROUP_EMOTE: - delay = HandleWaypointCommandGroupEmote(data); - break; - case eWaypointCommandType::SET_VARIABLE: - HandleWaypointCommandSetVariable(data); - break; - case eWaypointCommandType::CAST_SKILL: - HandleWaypointCommandCastSkill(data); - break; - case eWaypointCommandType::EQUIP_INVENTORY: - HandleWaypointCommandEquipInventory(data); - break; - case eWaypointCommandType::UNEQUIP_INVENTORY: - HandleWaypointCommandUnequipInventory(data); - break; - case eWaypointCommandType::DELAY: - delay = HandleWaypointCommandDelay(data); - break; - case eWaypointCommandType::EMOTE: - delay = RenderComponent::PlayAnimation(m_Parent, data); - break; - case eWaypointCommandType::TELEPORT: - HandleWaypointCommandTeleport(data); - break; - case eWaypointCommandType::PATH_SPEED: - HandleWaypointCommandPathSpeed(data); - break; - case eWaypointCommandType::REMOVE_NPC: - HandleWaypointCommandRemoveNPC(data); - break; - case eWaypointCommandType::CHANGE_WAYPOINT: - HandleWaypointCommandChangeWaypoint(data); - break; - case eWaypointCommandType::KILL_SELF: - m_Parent->Smash(LWOOBJID_EMPTY, eKillType::SILENT); - break; - case eWaypointCommandType::DELETE_SELF: - m_Parent->Kill(); - break; - case eWaypointCommandType::SPAWN_OBJECT: - HandleWaypointCommandSpawnObject(data); - break; - case eWaypointCommandType::PLAY_SOUND: - GameMessages::SendPlayNDAudioEmitter(m_Parent, UNASSIGNED_SYSTEM_ADDRESS, data); - break; - case eWaypointCommandType::BOUNCE: - Game::logger->LogDebug("MovementAIComponent", "Unable to process bounce waypoint command server side!"); - break; - case eWaypointCommandType::INVALID: - default: - Game::logger->LogDebug("MovementAIComponent", "Got invalid waypoint command %i", command); - break; + switch (command) { + case eWaypointCommandType::STOP: + Stop(); + break; + case eWaypointCommandType::GROUP_EMOTE: + delay = HandleWaypointCommandGroupEmote(data); + break; + case eWaypointCommandType::SET_VARIABLE: + HandleWaypointCommandSetVariable(data); + break; + case eWaypointCommandType::CAST_SKILL: + HandleWaypointCommandCastSkill(data); + break; + case eWaypointCommandType::EQUIP_INVENTORY: + HandleWaypointCommandEquipInventory(data); + break; + case eWaypointCommandType::UNEQUIP_INVENTORY: + HandleWaypointCommandUnequipInventory(data); + break; + case eWaypointCommandType::DELAY: + delay = HandleWaypointCommandDelay(data); + break; + case eWaypointCommandType::EMOTE: + delay = RenderComponent::PlayAnimation(m_Parent, data); + break; + case eWaypointCommandType::TELEPORT: + HandleWaypointCommandTeleport(data); + break; + case eWaypointCommandType::PATH_SPEED: + HandleWaypointCommandPathSpeed(data); + break; + case eWaypointCommandType::REMOVE_NPC: + HandleWaypointCommandRemoveNPC(data); + break; + case eWaypointCommandType::CHANGE_WAYPOINT: + HandleWaypointCommandChangeWaypoint(data); + break; + case eWaypointCommandType::KILL_SELF: + m_Parent->Smash(LWOOBJID_EMPTY, eKillType::SILENT); + break; + case eWaypointCommandType::DELETE_SELF: + m_Parent->Kill(); + break; + case eWaypointCommandType::SPAWN_OBJECT: + HandleWaypointCommandSpawnObject(data); + break; + case eWaypointCommandType::PLAY_SOUND: + GameMessages::SendPlayNDAudioEmitter(m_Parent, UNASSIGNED_SYSTEM_ADDRESS, data); + break; + case eWaypointCommandType::BOUNCE: + Game::logger->LogDebug("MovementAIComponent", "Unable to process bounce waypoint command server side!"); + break; + case eWaypointCommandType::INVALID: + default: + Game::logger->LogDebug("MovementAIComponent", "Got invalid waypoint command %i", command); + break; } - m_Parent->AddCallbackTimer(delay, [this, commandIndex](){ + m_Parent->AddCallbackTimer(delay, [this, commandIndex]() { this->HandleWaypointArrived(commandIndex + 1); } ); @@ -92,7 +107,7 @@ float MovementAIComponent::HandleWaypointCommandGroupEmote(const std::string& da if (split.size() != 2) return 0.0f; const auto& entities = Game::entityManager->GetEntitiesInGroup(split.at(0)); float delay = 0.0f; - for (auto& entity: entities){ + for (auto& entity : entities) { delay = RenderComponent::PlayAnimation(entity, split.at(1)); } return delay; @@ -149,7 +164,7 @@ void MovementAIComponent::HandleWaypointCommandUnequipInventory(const std::strin float MovementAIComponent::HandleWaypointCommandDelay(const std::string& data) { float delay = 0.0f; std::string delayString = data; - if (!GeneralUtils::TryParse(delayString, delay)){ + if (!GeneralUtils::TryParse(delayString, delay)) { Game::logger->LogDebug("MovementAIComponentAronwk", "Failed to parse delay %s", data.c_str()); } return delay; @@ -179,7 +194,7 @@ void MovementAIComponent::HandleWaypointCommandRemoveNPC(const std::string& data return; } const auto foundObjs = proximityMonitorComponent->GetProximityObjects("KillOBJS"); - for (auto& [objid, phyEntity] : foundObjs){ + for (auto& [objid, phyEntity] : foundObjs) { auto entity = Game::entityManager->GetEntity(objid); if (!entity) return; auto* destroyableComponent = m_Parent->GetComponent(); @@ -197,7 +212,7 @@ void MovementAIComponent::HandleWaypointCommandChangeWaypoint(const std::string& std::string path_string = ""; int32_t index = 0; // sometimes there's a path and what waypoint to start, which are comma separated - if (data.find(",") != std::string::npos){ + if (data.find(",") != std::string::npos) { auto datas = GeneralUtils::SplitString(data, ','); path_string = datas.at(0); if (!GeneralUtils::TryParse(datas.at(1), index)) return; diff --git a/dGame/dComponents/MovingPlatformComponent.cpp b/dGame/dComponents/MovingPlatformComponent.cpp index 60d320f4..ef702fd6 100644 --- a/dGame/dComponents/MovingPlatformComponent.cpp +++ b/dGame/dComponents/MovingPlatformComponent.cpp @@ -162,7 +162,7 @@ void MovingPlatformComponent::StartPathing() { const auto& nextWaypoint = m_Path->pathWaypoints[subComponent->mNextWaypointIndex]; subComponent->mPosition = currentWaypoint.position; - subComponent->mSpeed = currentWaypoint.movingPlatform.speed; + subComponent->mSpeed = currentWaypoint.speed; subComponent->mWaitTime = currentWaypoint.movingPlatform.wait; targetPosition = nextWaypoint.position; @@ -213,7 +213,7 @@ void MovingPlatformComponent::ContinuePathing() { const auto& nextWaypoint = m_Path->pathWaypoints[subComponent->mNextWaypointIndex]; subComponent->mPosition = currentWaypoint.position; - subComponent->mSpeed = currentWaypoint.movingPlatform.speed; + subComponent->mSpeed = currentWaypoint.speed; subComponent->mWaitTime = currentWaypoint.movingPlatform.wait; // + 2; pathSize = m_Path->pathWaypoints.size() - 1; diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index 1b87abc3..5e760b85 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -348,6 +348,7 @@ int main(int argc, char** argv) { Game::im->GetInstance(0, false, 0); Game::im->GetInstance(1200, false, 0); + Game::im->GetInstance(1800, false, 0); StartAuthServer(); } diff --git a/dZoneManager/Zone.cpp b/dZoneManager/Zone.cpp index 5c02b29f..7e406614 100644 --- a/dZoneManager/Zone.cpp +++ b/dZoneManager/Zone.cpp @@ -491,7 +491,7 @@ void Zone::LoadPath(std::istream& file) { if (path.pathType == PathType::MovingPlatform) { BinaryIO::BinaryRead(file, waypoint.movingPlatform.lockPlayer); - BinaryIO::BinaryRead(file, waypoint.movingPlatform.speed); + BinaryIO::BinaryRead(file, waypoint.speed); BinaryIO::BinaryRead(file, waypoint.movingPlatform.wait); if (path.pathVersion >= 13) { uint8_t count1; @@ -522,7 +522,7 @@ void Zone::LoadPath(std::istream& file) { BinaryIO::BinaryRead(file, waypoint.racing.planeHeight); BinaryIO::BinaryRead(file, waypoint.racing.shortestDistanceToEnd); } else if (path.pathType == PathType::Rail) { - if (path.pathVersion > 16) BinaryIO::BinaryRead(file, waypoint.rail.speed); + if (path.pathVersion > 16) BinaryIO::BinaryRead(file, waypoint.speed); } // object LDF configs diff --git a/dZoneManager/Zone.h b/dZoneManager/Zone.h index 309ca132..307e6d51 100644 --- a/dZoneManager/Zone.h +++ b/dZoneManager/Zone.h @@ -50,7 +50,6 @@ struct SceneTransition { struct MovingPlatformPathWaypoint { uint8_t lockPlayer; - float speed; float wait; std::string departSound; std::string arriveSound; @@ -72,17 +71,13 @@ struct RacingPathWaypoint { float shortestDistanceToEnd; }; -struct RailPathWaypoint { - float speed; -}; - struct PathWaypoint { NiPoint3 position; NiQuaternion rotation; // not included in all, but it's more convenient here MovingPlatformPathWaypoint movingPlatform; CameraPathWaypoint camera; RacingPathWaypoint racing; - RailPathWaypoint rail; + float speed = 1.0f; std::vector config; std::vector commands; };