Fixed speed stuff

Should be tested more.
This commit is contained in:
David Markowitz 2023-08-21 12:33:13 -07:00
parent e3ae0b6304
commit 294efe0fe0
7 changed files with 121 additions and 108 deletions

View File

@ -55,6 +55,13 @@ MovementAIComponent::MovementAIComponent(Entity* parent, MovementAIInfo info) :
m_NextPathWaypointIndex = 0; 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) { void MovementAIComponent::SetupPath(const std::string& pathname) {
std::string path = pathname; std::string path = pathname;
if (path.empty()) path = m_Parent->GetVarAsString(u"attached_path"); 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); waypoints.push_back(waypoint.position);
} }
SetPath(waypoints); SetPath(waypoints);
SetMaxSpeed(3.0f);
} else { } else {
Game::logger->Log("MovementAIComponent", "No path found for %i:%llu", m_Parent->GetLOT(), m_Parent->GetObjectID()); 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) { if (m_NextWaypoint == source) {
m_TimeToTravel = 0.0f; m_TimeToTravel = 0.0f;
goto nextAction; return;
} }
// if (m_CurrentSpeed < m_MaxSpeed) {
// m_CurrentSpeed += m_Acceleration;
// }
if (m_CurrentSpeed < m_MaxSpeed) { if (m_CurrentSpeed < m_MaxSpeed) {
m_CurrentSpeed += m_Acceleration;
}
if (m_CurrentSpeed > m_MaxSpeed) {
m_CurrentSpeed = m_MaxSpeed; m_CurrentSpeed = m_MaxSpeed;
} }
@ -152,7 +158,7 @@ void MovementAIComponent::Update(const float deltaTime) {
// Normalize the vector // Normalize the vector
const auto length = delta.Length(); const auto length = delta.Length();
if (length > 0) { 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 // 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 // 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. // All checks for how to progress when you arrive at a waypoint will be handled in this else block.
HandleWaypointArrived(0); HandleWaypointArrived(0);
if (!AdvancePathWaypointIndex()) { return;
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());
} }
nextAction: nextAction:
@ -231,15 +220,11 @@ NiPoint3 MovementAIComponent::GetCurrentWaypoint() const {
NiPoint3 MovementAIComponent::ApproximateLocation() const { NiPoint3 MovementAIComponent::ApproximateLocation() const {
auto source = m_Parent->GetPosition(); auto source = m_Parent->GetPosition();
if (AtFinalWaypoint()) return source; if (AtFinalWaypoint()) return source;
auto destination = m_NextWaypoint; auto destination = GetNextWaypoint();
auto percentageToWaypoint = m_TimeToTravel > 0 ? m_TimeTravelled / m_TimeToTravel : 0; auto percentageToWaypoint = m_TimeToTravel > 0 ? m_TimeTravelled / m_TimeToTravel : 0;
auto approximation = source + ((destination - source) * percentageToWaypoint); auto approximation = source + ((destination - source) * percentageToWaypoint);
if (dpWorld::Instance().IsLoaded()) { if (dpWorld::Instance().IsLoaded()) {
approximation.y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(approximation); approximation.y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(approximation);
} }
@ -284,6 +269,7 @@ void MovementAIComponent::Resume() {
if (AtFinalWaypoint() || !IsPaused()) return; if (AtFinalWaypoint() || !IsPaused()) return;
m_IsPaused = false; m_IsPaused = false;
SetDestination(GetCurrentPathWaypoint()); SetDestination(GetCurrentPathWaypoint());
SetMaxSpeed(GetCurrentPathWaypointSpeed());
} }
void MovementAIComponent::Stop() { void MovementAIComponent::Stop() {
@ -341,6 +327,7 @@ void MovementAIComponent::SetPath(std::vector<NiPoint3> path, bool startInRevers
AdvancePathWaypointIndex(); AdvancePathWaypointIndex();
SetDestination(GetCurrentPathWaypoint()); SetDestination(GetCurrentPathWaypoint());
SetMaxSpeed(GetCurrentPathWaypointSpeed());
} }
float MovementAIComponent::GetBaseSpeed(LOT lot) { float MovementAIComponent::GetBaseSpeed(LOT lot) {

View File

@ -154,6 +154,19 @@ public:
*/ */
NiPoint3 GetNextWaypoint() const { return m_NextWaypoint; } 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 * Returns the approximate current location of the entity, including y coordinates
* @return the approximate current location of the entity * @return the approximate current location of the entity
@ -198,6 +211,8 @@ public:
void SetupPath(const std::string& pathname); 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, * 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. * after which its AI is enabled again.

View File

@ -11,77 +11,92 @@
#include "DestroyableComponent.h" #include "DestroyableComponent.h"
void MovementAIComponent::HandleWaypointArrived(uint32_t commandIndex) { void MovementAIComponent::HandleWaypointArrived(uint32_t commandIndex) {
if (!m_Path){ if (!m_Path || commandIndex >= m_Path->pathWaypoints.at(m_CurrentPathWaypointIndex).commands.size()) {
if(IsPaused()) Resume(); 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; return;
} }
if (commandIndex >= m_Path->pathWaypoints.at(m_CurrentPathWaypointIndex).commands.size()){ if (!IsPaused()) Pause();
if(IsPaused()) Resume();
return;
}
if(!IsPaused()) Pause();
const auto& data = m_Path->pathWaypoints.at(m_CurrentPathWaypointIndex).commands.at(commandIndex).data; 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; const auto& command = m_Path->pathWaypoints.at(m_CurrentPathWaypointIndex).commands.at(commandIndex).command;
float delay = 0.0f; float delay = 0.0f;
switch(command){ switch (command) {
case eWaypointCommandType::STOP: case eWaypointCommandType::STOP:
Stop(); Stop();
break; break;
case eWaypointCommandType::GROUP_EMOTE: case eWaypointCommandType::GROUP_EMOTE:
delay = HandleWaypointCommandGroupEmote(data); delay = HandleWaypointCommandGroupEmote(data);
break; break;
case eWaypointCommandType::SET_VARIABLE: case eWaypointCommandType::SET_VARIABLE:
HandleWaypointCommandSetVariable(data); HandleWaypointCommandSetVariable(data);
break; break;
case eWaypointCommandType::CAST_SKILL: case eWaypointCommandType::CAST_SKILL:
HandleWaypointCommandCastSkill(data); HandleWaypointCommandCastSkill(data);
break; break;
case eWaypointCommandType::EQUIP_INVENTORY: case eWaypointCommandType::EQUIP_INVENTORY:
HandleWaypointCommandEquipInventory(data); HandleWaypointCommandEquipInventory(data);
break; break;
case eWaypointCommandType::UNEQUIP_INVENTORY: case eWaypointCommandType::UNEQUIP_INVENTORY:
HandleWaypointCommandUnequipInventory(data); HandleWaypointCommandUnequipInventory(data);
break; break;
case eWaypointCommandType::DELAY: case eWaypointCommandType::DELAY:
delay = HandleWaypointCommandDelay(data); delay = HandleWaypointCommandDelay(data);
break; break;
case eWaypointCommandType::EMOTE: case eWaypointCommandType::EMOTE:
delay = RenderComponent::PlayAnimation(m_Parent, data); delay = RenderComponent::PlayAnimation(m_Parent, data);
break; break;
case eWaypointCommandType::TELEPORT: case eWaypointCommandType::TELEPORT:
HandleWaypointCommandTeleport(data); HandleWaypointCommandTeleport(data);
break; break;
case eWaypointCommandType::PATH_SPEED: case eWaypointCommandType::PATH_SPEED:
HandleWaypointCommandPathSpeed(data); HandleWaypointCommandPathSpeed(data);
break; break;
case eWaypointCommandType::REMOVE_NPC: case eWaypointCommandType::REMOVE_NPC:
HandleWaypointCommandRemoveNPC(data); HandleWaypointCommandRemoveNPC(data);
break; break;
case eWaypointCommandType::CHANGE_WAYPOINT: case eWaypointCommandType::CHANGE_WAYPOINT:
HandleWaypointCommandChangeWaypoint(data); HandleWaypointCommandChangeWaypoint(data);
break; break;
case eWaypointCommandType::KILL_SELF: case eWaypointCommandType::KILL_SELF:
m_Parent->Smash(LWOOBJID_EMPTY, eKillType::SILENT); m_Parent->Smash(LWOOBJID_EMPTY, eKillType::SILENT);
break; break;
case eWaypointCommandType::DELETE_SELF: case eWaypointCommandType::DELETE_SELF:
m_Parent->Kill(); m_Parent->Kill();
break; break;
case eWaypointCommandType::SPAWN_OBJECT: case eWaypointCommandType::SPAWN_OBJECT:
HandleWaypointCommandSpawnObject(data); HandleWaypointCommandSpawnObject(data);
break; break;
case eWaypointCommandType::PLAY_SOUND: case eWaypointCommandType::PLAY_SOUND:
GameMessages::SendPlayNDAudioEmitter(m_Parent, UNASSIGNED_SYSTEM_ADDRESS, data); GameMessages::SendPlayNDAudioEmitter(m_Parent, UNASSIGNED_SYSTEM_ADDRESS, data);
break; break;
case eWaypointCommandType::BOUNCE: case eWaypointCommandType::BOUNCE:
Game::logger->LogDebug("MovementAIComponent", "Unable to process bounce waypoint command server side!"); Game::logger->LogDebug("MovementAIComponent", "Unable to process bounce waypoint command server side!");
break; break;
case eWaypointCommandType::INVALID: case eWaypointCommandType::INVALID:
default: default:
Game::logger->LogDebug("MovementAIComponent", "Got invalid waypoint command %i", command); Game::logger->LogDebug("MovementAIComponent", "Got invalid waypoint command %i", command);
break; break;
} }
m_Parent->AddCallbackTimer(delay, [this, commandIndex](){ m_Parent->AddCallbackTimer(delay, [this, commandIndex]() {
this->HandleWaypointArrived(commandIndex + 1); this->HandleWaypointArrived(commandIndex + 1);
} }
); );
@ -92,7 +107,7 @@ float MovementAIComponent::HandleWaypointCommandGroupEmote(const std::string& da
if (split.size() != 2) return 0.0f; if (split.size() != 2) return 0.0f;
const auto& entities = Game::entityManager->GetEntitiesInGroup(split.at(0)); const auto& entities = Game::entityManager->GetEntitiesInGroup(split.at(0));
float delay = 0.0f; float delay = 0.0f;
for (auto& entity: entities){ for (auto& entity : entities) {
delay = RenderComponent::PlayAnimation(entity, split.at(1)); delay = RenderComponent::PlayAnimation(entity, split.at(1));
} }
return delay; return delay;
@ -149,7 +164,7 @@ void MovementAIComponent::HandleWaypointCommandUnequipInventory(const std::strin
float MovementAIComponent::HandleWaypointCommandDelay(const std::string& data) { float MovementAIComponent::HandleWaypointCommandDelay(const std::string& data) {
float delay = 0.0f; float delay = 0.0f;
std::string delayString = data; std::string delayString = data;
if (!GeneralUtils::TryParse<float>(delayString, delay)){ if (!GeneralUtils::TryParse<float>(delayString, delay)) {
Game::logger->LogDebug("MovementAIComponentAronwk", "Failed to parse delay %s", data.c_str()); Game::logger->LogDebug("MovementAIComponentAronwk", "Failed to parse delay %s", data.c_str());
} }
return delay; return delay;
@ -179,7 +194,7 @@ void MovementAIComponent::HandleWaypointCommandRemoveNPC(const std::string& data
return; return;
} }
const auto foundObjs = proximityMonitorComponent->GetProximityObjects("KillOBJS"); const auto foundObjs = proximityMonitorComponent->GetProximityObjects("KillOBJS");
for (auto& [objid, phyEntity] : foundObjs){ for (auto& [objid, phyEntity] : foundObjs) {
auto entity = Game::entityManager->GetEntity(objid); auto entity = Game::entityManager->GetEntity(objid);
if (!entity) return; if (!entity) return;
auto* destroyableComponent = m_Parent->GetComponent<DestroyableComponent>(); auto* destroyableComponent = m_Parent->GetComponent<DestroyableComponent>();
@ -197,7 +212,7 @@ void MovementAIComponent::HandleWaypointCommandChangeWaypoint(const std::string&
std::string path_string = ""; std::string path_string = "";
int32_t index = 0; int32_t index = 0;
// sometimes there's a path and what waypoint to start, which are comma separated // 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, ','); auto datas = GeneralUtils::SplitString(data, ',');
path_string = datas.at(0); path_string = datas.at(0);
if (!GeneralUtils::TryParse(datas.at(1), index)) return; if (!GeneralUtils::TryParse(datas.at(1), index)) return;

View File

@ -162,7 +162,7 @@ void MovingPlatformComponent::StartPathing() {
const auto& nextWaypoint = m_Path->pathWaypoints[subComponent->mNextWaypointIndex]; const auto& nextWaypoint = m_Path->pathWaypoints[subComponent->mNextWaypointIndex];
subComponent->mPosition = currentWaypoint.position; subComponent->mPosition = currentWaypoint.position;
subComponent->mSpeed = currentWaypoint.movingPlatform.speed; subComponent->mSpeed = currentWaypoint.speed;
subComponent->mWaitTime = currentWaypoint.movingPlatform.wait; subComponent->mWaitTime = currentWaypoint.movingPlatform.wait;
targetPosition = nextWaypoint.position; targetPosition = nextWaypoint.position;
@ -213,7 +213,7 @@ void MovingPlatformComponent::ContinuePathing() {
const auto& nextWaypoint = m_Path->pathWaypoints[subComponent->mNextWaypointIndex]; const auto& nextWaypoint = m_Path->pathWaypoints[subComponent->mNextWaypointIndex];
subComponent->mPosition = currentWaypoint.position; subComponent->mPosition = currentWaypoint.position;
subComponent->mSpeed = currentWaypoint.movingPlatform.speed; subComponent->mSpeed = currentWaypoint.speed;
subComponent->mWaitTime = currentWaypoint.movingPlatform.wait; // + 2; subComponent->mWaitTime = currentWaypoint.movingPlatform.wait; // + 2;
pathSize = m_Path->pathWaypoints.size() - 1; pathSize = m_Path->pathWaypoints.size() - 1;

View File

@ -348,6 +348,7 @@ int main(int argc, char** argv) {
Game::im->GetInstance(0, false, 0); Game::im->GetInstance(0, false, 0);
Game::im->GetInstance(1200, false, 0); Game::im->GetInstance(1200, false, 0);
Game::im->GetInstance(1800, false, 0);
StartAuthServer(); StartAuthServer();
} }

View File

@ -491,7 +491,7 @@ void Zone::LoadPath(std::istream& file) {
if (path.pathType == PathType::MovingPlatform) { if (path.pathType == PathType::MovingPlatform) {
BinaryIO::BinaryRead(file, waypoint.movingPlatform.lockPlayer); BinaryIO::BinaryRead(file, waypoint.movingPlatform.lockPlayer);
BinaryIO::BinaryRead(file, waypoint.movingPlatform.speed); BinaryIO::BinaryRead(file, waypoint.speed);
BinaryIO::BinaryRead(file, waypoint.movingPlatform.wait); BinaryIO::BinaryRead(file, waypoint.movingPlatform.wait);
if (path.pathVersion >= 13) { if (path.pathVersion >= 13) {
uint8_t count1; uint8_t count1;
@ -522,7 +522,7 @@ void Zone::LoadPath(std::istream& file) {
BinaryIO::BinaryRead(file, waypoint.racing.planeHeight); BinaryIO::BinaryRead(file, waypoint.racing.planeHeight);
BinaryIO::BinaryRead(file, waypoint.racing.shortestDistanceToEnd); BinaryIO::BinaryRead(file, waypoint.racing.shortestDistanceToEnd);
} else if (path.pathType == PathType::Rail) { } 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 // object LDF configs

View File

@ -50,7 +50,6 @@ struct SceneTransition {
struct MovingPlatformPathWaypoint { struct MovingPlatformPathWaypoint {
uint8_t lockPlayer; uint8_t lockPlayer;
float speed;
float wait; float wait;
std::string departSound; std::string departSound;
std::string arriveSound; std::string arriveSound;
@ -72,17 +71,13 @@ struct RacingPathWaypoint {
float shortestDistanceToEnd; float shortestDistanceToEnd;
}; };
struct RailPathWaypoint {
float speed;
};
struct PathWaypoint { struct PathWaypoint {
NiPoint3 position; NiPoint3 position;
NiQuaternion rotation; // not included in all, but it's more convenient here NiQuaternion rotation; // not included in all, but it's more convenient here
MovingPlatformPathWaypoint movingPlatform; MovingPlatformPathWaypoint movingPlatform;
CameraPathWaypoint camera; CameraPathWaypoint camera;
RacingPathWaypoint racing; RacingPathWaypoint racing;
RailPathWaypoint rail; float speed = 1.0f;
std::vector<LDFBaseData*> config; std::vector<LDFBaseData*> config;
std::vector<WaypointCommand> commands; std::vector<WaypointCommand> commands;
}; };