Add waypoint command handling

This commit is contained in:
Aaron Kimbre 2023-08-14 09:31:10 -05:00
parent 1b54387677
commit a63d7df0d2
5 changed files with 191 additions and 113 deletions

View File

@ -15,6 +15,7 @@ set(DGAME_DCOMPONENTS_SOURCES "BaseCombatAIComponent.cpp"
"ModelComponent.cpp" "ModelComponent.cpp"
"ModuleAssemblyComponent.cpp" "ModuleAssemblyComponent.cpp"
"MovementAIComponent.cpp" "MovementAIComponent.cpp"
"MovementAIComponentAronwk.cpp"
"MovingPlatformComponent.cpp" "MovingPlatformComponent.cpp"
"PetComponent.cpp" "PetComponent.cpp"
"PhantomPhysicsComponent.cpp" "PhantomPhysicsComponent.cpp"

View File

@ -310,6 +310,7 @@ public:
*/ */
const std::vector<int32_t>& GetFactionIDs() const { return m_FactionIDs; } const std::vector<int32_t>& GetFactionIDs() const { return m_FactionIDs; }
const bool BelongsToFaction(int32_t factionID) const {return std::find(m_FactionIDs.begin(), m_FactionIDs.end(), factionID) != m_FactionIDs.end(); }
/** /**
* Returns all the faction IDs that this entity considers an enemy * Returns all the faction IDs that this entity considers an enemy
* @return all the faction IDs that this entity considers an enemy * @return all the faction IDs that this entity considers an enemy

View File

@ -155,7 +155,7 @@ void MovementAIComponent::Update(const float deltaTime) {
} else { } else {
// 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(); HandleWaypointArrived(0);
if (!AdvancePathWaypointIndex()) { if (!AdvancePathWaypointIndex()) {
if (m_Path) { if (m_Path) {
if (m_Path->pathBehavior == PathBehavior::Bounce) { if (m_Path->pathBehavior == PathBehavior::Bounce) {

View File

@ -194,7 +194,7 @@ public:
void ReversePath(); void ReversePath();
void HandleWaypointArrived(); void HandleWaypointArrived(uint32_t commandIndex);
void SetupPath(const std::string& pathname); void SetupPath(const std::string& pathname);
@ -228,18 +228,17 @@ private:
// TODO: Advance properly // TODO: Advance properly
void SetCurrentPathWaypointIndex(uint32_t value) { }; void SetCurrentPathWaypointIndex(uint32_t value) { };
void SetNextPathWaypointIndex(uint32_t value) { }; void SetNextPathWaypointIndex(uint32_t value) { };
void HandleWaypointCommandGroupEmote(std::string data); float HandleWaypointCommandGroupEmote(const std::string& data);
void HandleWaypointCommandSetVariable(std::string data); void HandleWaypointCommandSetVariable(const std::string& data);
void HandleWaypointCommandCastSkill(std::string data); void HandleWaypointCommandCastSkill(const std::string& data);
void HandleWaypointCommandEquipInventory(std::string data); void HandleWaypointCommandEquipInventory(const std::string& data);
void HandleWaypointCommandUnequipInventory(std::string data); void HandleWaypointCommandUnequipInventory(const std::string& data);
void HandleWaypointCommandDelay(std::string data); float HandleWaypointCommandDelay(const std::string& data);
void HandleWaypointCommandEmote(std::string data); void HandleWaypointCommandTeleport(const std::string& data);
void HandleWaypointCommandTeleport(std::string data); void HandleWaypointCommandPathSpeed(const std::string& data);
void HandleWaypointCommandPathSpeed(std::string data); void HandleWaypointCommandRemoveNPC(const std::string& data);
void HandleWaypointCommandRemoveNPC(std::string data); void HandleWaypointCommandChangeWaypoint(const std::string& data);
void HandleWaypointCommandChangeWaypoint(std::string data); void HandleWaypointCommandSpawnObject(const std::string& data);
void HandleWaypointCommandSpawnObject(std::string data);
/** /**
* Sets the current position of the entity * Sets the current position of the entity

View File

@ -4,17 +4,32 @@
#include "eWaypointCommandType.h" #include "eWaypointCommandType.h"
#include "RenderComponent.h" #include "RenderComponent.h"
#include "SkillComponent.h" #include "SkillComponent.h"
#include "InventoryComponent.h"
#include "Zone.h"
#include "EntityInfo.h"
#include "ProximityMonitorComponent.h"
#include "DestroyableComponent.h"
void MovementAIComponent::HandleWaypointArrived() { void MovementAIComponent::HandleWaypointArrived(uint32_t commandIndex) {
if (!m_Path) return; Pause();
if (m_Path->pathWaypoints.at(m_CurrentPathWaypointIndex).commands.empty()) return; if (!m_Path){
for(auto [command, data] : m_Path->pathWaypoints.at(m_CurrentPathWaypointIndex).commands){ Resume();
return;
}
if (commandIndex >= m_Path->pathWaypoints.at(m_CurrentPathWaypointIndex).commands.size()){
Resume();
return;
}
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){ switch(command){
case eWaypointCommandType::STOP: case eWaypointCommandType::STOP:
Stop(); Stop();
break; break;
case eWaypointCommandType::GROUP_EMOTE: case eWaypointCommandType::GROUP_EMOTE:
HandleWaypointCommandGroupEmote(data); delay = HandleWaypointCommandGroupEmote(data);
break; break;
case eWaypointCommandType::SET_VARIABLE: case eWaypointCommandType::SET_VARIABLE:
HandleWaypointCommandSetVariable(data); HandleWaypointCommandSetVariable(data);
@ -29,10 +44,10 @@ void MovementAIComponent::HandleWaypointArrived() {
HandleWaypointCommandUnequipInventory(data); HandleWaypointCommandUnequipInventory(data);
break; break;
case eWaypointCommandType::DELAY: case eWaypointCommandType::DELAY:
HandleWaypointCommandDelay(data); delay = HandleWaypointCommandDelay(data);
break; break;
case eWaypointCommandType::EMOTE: case eWaypointCommandType::EMOTE:
HandleWaypointCommandEmote(data); delay = RenderComponent::PlayAnimation(m_Parent, data);
break; break;
case eWaypointCommandType::TELEPORT: case eWaypointCommandType::TELEPORT:
HandleWaypointCommandTeleport(data); HandleWaypointCommandTeleport(data);
@ -59,90 +74,152 @@ void MovementAIComponent::HandleWaypointArrived() {
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", "Unusable Command %i", command); 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](){
auto newCommandIndex = commandIndex + 1;
this->HandleWaypointArrived(newCommandIndex);
} }
);
} }
void MovementAIComponent::HandleWaypointCommandGroupEmote(std::string data) { float MovementAIComponent::HandleWaypointCommandGroupEmote(const std::string& data) {
const auto& split = GeneralUtils::SplitString(data, ';'); const auto& split = GeneralUtils::SplitString(data, ';');
if (split.size() != 2) return; if (split.size() != 2) return 0.0f;
const auto& entities = Game::entityManager->GetEntitiesInGroup(split[0]); const auto& entities = Game::entityManager->GetEntitiesInGroup(split.at(0));
float delay = 0.0f;
for (auto& entity: entities){ for (auto& entity: entities){
RenderComponent::PlayAnimation(entity, split[1]); delay = RenderComponent::PlayAnimation(entity, split.at(1));
} }
// delay for animation time return delay;
} }
void MovementAIComponent::HandleWaypointCommandSetVariable(std::string data) {
const auto& split = GeneralUtils::SplitString(data, '='); void MovementAIComponent::HandleWaypointCommandSetVariable(const std::string& data) {
m_Parent->SetNetworkVar(GeneralUtils::ASCIIToUTF16(split[0]), split[1]); const auto& split = GeneralUtils::SplitString(data, ',');
m_Parent->SetNetworkVar(GeneralUtils::ASCIIToUTF16(split.at(0)), split.at(1));
} }
void MovementAIComponent::HandleWaypointCommandCastSkill(std::string data) {
void MovementAIComponent::HandleWaypointCommandCastSkill(const std::string& data) {
if (data.empty()) return; if (data.empty()) return;
auto* skillComponent = m_Parent->GetComponent<SkillComponent>(); auto* skillComponent = m_Parent->GetComponent<SkillComponent>();
if (!skillComponent) { if (!skillComponent) {
Game::logger->LogDebug("MovementAIComponent::HandleWaypointArrived", "Skill component not found!"); Game::logger->LogDebug("MovementAIComponent::HandleWaypointCommandCastSkill", "Skill component not found!");
return; return;
} }
uint32_t skillId = 0; uint32_t skillId = 0;
GeneralUtils::TryParse<uint32_t>(data, skillId); GeneralUtils::TryParse<uint32_t>(data, skillId);
if (skillId != 0) skillComponent->CastSkill(skillId); if (skillId != 0) skillComponent->CastSkill(skillId);
// add some delay?? return;
} }
void MovementAIComponent::HandleWaypointCommandEquipInventory(std::string data) {
// equip item via ID (not lot???) void MovementAIComponent::HandleWaypointCommandEquipInventory(const std::string& data) {
if (data.empty()) return;
auto* inventoryComponent = m_Parent->GetComponent<InventoryComponent>();
if (!inventoryComponent) {
Game::logger->LogDebug("MovementAIComponent::HandleWaypointCommandEquipInventory", "Inventory component not found!");
return;
} }
void MovementAIComponent::HandleWaypointCommandUnequipInventory(std::string data) { // the client says use slot 0 of items
// unequip item via ID (not lot??) const auto inventory = inventoryComponent->GetInventory(eInventoryType::ITEMS);
if (!inventory) return;
const auto slots = inventory->GetSlots();
const auto item = slots.find(0);
if (item != slots.end()) inventoryComponent->EquipItem(item->second);
} }
void MovementAIComponent::HandleWaypointCommandDelay(std::string data) {
Pause(); void MovementAIComponent::HandleWaypointCommandUnequipInventory(const std::string& data) {
std::remove_if(data.begin(), data.end(), ::isspace); if (data.empty()) return;
// delay for time auto* inventoryComponent = m_Parent->GetComponent<InventoryComponent>();
if (!inventoryComponent) {
Game::logger->LogDebug("MovementAIComponent::HandleWaypointCommandEquipInventory", "Inventory component not found!");
return;
} }
void MovementAIComponent::HandleWaypointCommandEmote(std::string data) { // the client says use slot 0 of items
// pause for animation time const auto inventory = inventoryComponent->GetInventory(eInventoryType::ITEMS);
auto delay = RenderComponent::PlayAnimation(m_Parent, data); if (!inventory) return;
const auto slots = inventory->GetSlots();
const auto item = slots.find(0);
if (item != slots.end()) inventoryComponent->UnEquipItem(item->second);
} }
void MovementAIComponent::HandleWaypointCommandTeleport(std::string data) {
float MovementAIComponent::HandleWaypointCommandDelay(const std::string& data) {
float delay = 0.0f;
std::string delayString = data;
std::remove_if(delayString.begin(), delayString.end(), ::isspace);
GeneralUtils::TryParse<float>(delayString, delay);
return delay;
}
void MovementAIComponent::HandleWaypointCommandTeleport(const std::string& data) {
auto posString = GeneralUtils::SplitString(data, ','); auto posString = GeneralUtils::SplitString(data, ',');
if (posString.size() == 0) return; if (posString.size() == 0) return;
auto newPos = NiPoint3(); auto newPos = NiPoint3();
if (posString.size() == 1) GeneralUtils::TryParse<float>(posString.at(0), newPos.x); if (posString.size() == 1 && !GeneralUtils::TryParse<float>(posString.at(0), newPos.x)) return;
if (posString.size() == 2) GeneralUtils::TryParse<float>(posString.at(1), newPos.y); if (posString.size() == 2 && !GeneralUtils::TryParse<float>(posString.at(1), newPos.y)) return;
if (posString.size() == 3) GeneralUtils::TryParse<float>(posString.at(2), newPos.z); if (posString.size() == 3 && !GeneralUtils::TryParse<float>(posString.at(2), newPos.z)) return;
GameMessages::SendTeleport(m_Parent->GetObjectID(), newPos, NiQuaternion::IDENTITY, UNASSIGNED_SYSTEM_ADDRESS); GameMessages::SendTeleport(m_Parent->GetObjectID(), newPos, NiQuaternion::IDENTITY, UNASSIGNED_SYSTEM_ADDRESS);
} }
void MovementAIComponent::HandleWaypointCommandPathSpeed(std::string data) {
void MovementAIComponent::HandleWaypointCommandPathSpeed(const std::string& data) {
float speed = 0.0; float speed = 0.0;
GeneralUtils::TryParse<float>(data, speed); GeneralUtils::TryParse<float>(data, speed);
SetMaxSpeed(speed); SetCurrentSpeed(speed);
} }
void MovementAIComponent::HandleWaypointCommandRemoveNPC(std::string data) {
// get objects in proximity void MovementAIComponent::HandleWaypointCommandRemoveNPC(const std::string& data) {
// KillOBJS ??? if (data.empty()) return;
auto* proximityMonitorComponent = m_Parent->GetComponent<ProximityMonitorComponent>();
if (!proximityMonitorComponent) {
Game::logger->LogDebug("MovementAIComponent::HandleWaypointCommandRemoveNPC", "Proximity monitor component not found!");
return;
} }
void MovementAIComponent::HandleWaypointCommandChangeWaypoint(std::string data) { const auto foundObjs = proximityMonitorComponent->GetProximityObjects("KillOBJS");
for (auto& [objid, phyEntity] : foundObjs){
auto entity = Game::entityManager->GetEntity(objid);
if (!entity) return;
auto* destroyableComponent = m_Parent->GetComponent<DestroyableComponent>();
if (!destroyableComponent) {
Game::logger->LogDebug("MovementAIComponent::HandleWaypointCommandRemoveNPC", "Destroyable component not found!");
return;
}
uint32_t factionID = -1;
GeneralUtils::TryParse<uint32_t>(data, factionID);
if (destroyableComponent->BelongsToFaction(factionID)) m_Parent->Kill();
}
}
void MovementAIComponent::HandleWaypointCommandChangeWaypoint(const std::string& data) {
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[0]; path_string = datas.at(0);
index = stoi(datas[1]); GeneralUtils::TryParse(datas.at(1), index);
} else path_string = data; } else path_string = data;
if (path_string != "") { if (path_string != "") {
SetupPath(path_string); SetupPath(path_string);
// TODO: do better? talk to emo
SetCurrentPathWaypointIndex(index); SetCurrentPathWaypointIndex(index);
SetNextPathWaypointIndex(index); SetNextPathWaypointIndex(index);
} }
} }
void MovementAIComponent::HandleWaypointCommandSpawnObject(std::string data) {
// just do it void MovementAIComponent::HandleWaypointCommandSpawnObject(const std::string& data) {
LOT newObjectLOT = 0;
GeneralUtils::TryParse(data, newObjectLOT);
EntityInfo info{};
info.lot = newObjectLOT;
info.pos = m_Parent->GetPosition();
info.rot = m_Parent->GetRotation();
auto* spawnedEntity = Game::entityManager->CreateEntity(info, nullptr, m_Parent);
Game::entityManager->ConstructEntity(spawnedEntity);
m_Parent->Smash(LWOOBJID_EMPTY, eKillType::SILENT);
} }