mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-12-25 06:53:35 +00:00
redone pet update loop
This commit is contained in:
parent
1c01219ae9
commit
200d679dd8
@ -82,32 +82,41 @@ PetComponent::PetComponent(Entity* parent, uint32_t componentId): Component(pare
|
|||||||
m_DatabaseId = LWOOBJID_EMPTY;
|
m_DatabaseId = LWOOBJID_EMPTY;
|
||||||
m_Status = PetStatus::TAMEABLE; // Tameable
|
m_Status = PetStatus::TAMEABLE; // Tameable
|
||||||
m_Ability = PetAbilityType::Invalid;
|
m_Ability = PetAbilityType::Invalid;
|
||||||
m_StartPosition = NiPoint3::ZERO;
|
m_StartPosition = m_Parent->GetPosition(); //NiPoint3::ZERO;
|
||||||
m_MovementAI = nullptr;
|
m_MovementAI = nullptr;
|
||||||
m_TresureTime = 0;
|
m_TresureTime = 0;
|
||||||
m_Preconditions = nullptr;
|
m_Preconditions = nullptr;
|
||||||
|
|
||||||
m_ReadyToDig = false;
|
m_ReadyToDig = false;
|
||||||
m_InInteract = false;
|
SetPetAiState(PetAiState::spawn);
|
||||||
|
|
||||||
std::string checkPreconditions = GeneralUtils::UTF16ToWTF8(parent->GetVar<std::u16string>(u"CheckPrecondition"));
|
std::string checkPreconditions = GeneralUtils::UTF16ToWTF8(parent->GetVar<std::u16string>(u"CheckPrecondition"));
|
||||||
|
|
||||||
if (!checkPreconditions.empty()) {
|
if (!checkPreconditions.empty()) {
|
||||||
SetPreconditions(checkPreconditions);
|
SetPreconditions(checkPreconditions);
|
||||||
}
|
}
|
||||||
// Get the imagination drain rate from the CDClient
|
|
||||||
auto query = CDClientDatabase::CreatePreppedStmt("SELECT imaginationDrainRate FROM PetComponent WHERE id = ?;");
|
|
||||||
|
|
||||||
|
// Get pet information from the CDClient
|
||||||
|
auto query = CDClientDatabase::CreatePreppedStmt(
|
||||||
|
"SELECT walkSpeed, runSpeed, sprintSpeed, imaginationDrainRate FROM PetComponent WHERE id = ?;");
|
||||||
query.bind(1, static_cast<int>(componentId));
|
query.bind(1, static_cast<int>(componentId));
|
||||||
|
|
||||||
auto result = query.execQuery();
|
auto result = query.execQuery();
|
||||||
|
|
||||||
// Should a result not exist for this pet default to 60 seconds.
|
if (!result.eof()) {
|
||||||
if (!result.eof() && !result.fieldIsNull(0)) {
|
if (!result.fieldIsNull(0))
|
||||||
imaginationDrainRate = result.getFloatField(0, 60.0f);
|
m_walkSpeed = result.getFloatField(0);
|
||||||
} else {
|
|
||||||
imaginationDrainRate = 60.0f;
|
if (!result.fieldIsNull(1))
|
||||||
|
m_RunSpeed = result.getFloatField(1);
|
||||||
|
|
||||||
|
if (!result.fieldIsNull(2))
|
||||||
|
m_SprintSpeed = result.getFloatField(2);
|
||||||
|
|
||||||
|
if (!result.fieldIsNull(3))
|
||||||
|
imaginationDrainRate = result.getFloatField(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
result.finalize();
|
result.finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,19 +161,17 @@ void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpd
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PetComponent::SetPetAiState(PetAiState newState) {
|
||||||
|
if (newState == GetPetAiState()) return;
|
||||||
|
this->m_State = newState;
|
||||||
|
LOG_DEBUG("Set pet AI state!");
|
||||||
|
//Game::entityManager->SerializeEntity(m_Parent); // Do we need to serialize entity?
|
||||||
|
}
|
||||||
|
|
||||||
void PetComponent::OnUse(Entity* originator) {
|
void PetComponent::OnUse(Entity* originator) {
|
||||||
LOG("PET USE!");
|
LOG("PET USE!");
|
||||||
|
|
||||||
/*if(m_ReadyToDig) {
|
if (m_Owner != LWOOBJID_EMPTY) return;
|
||||||
LOG("Dig initiated!");
|
|
||||||
m_TresureTime = 2.0f;
|
|
||||||
//m_ReadyToDig = false;
|
|
||||||
SetAbility(PetAbilityType::DigAtPosition);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if (m_Owner != LWOOBJID_EMPTY) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_Tamer != LWOOBJID_EMPTY) {
|
if (m_Tamer != LWOOBJID_EMPTY) {
|
||||||
auto* tamer = Game::entityManager->GetEntity(m_Tamer);
|
auto* tamer = Game::entityManager->GetEntity(m_Tamer);
|
||||||
@ -336,29 +343,159 @@ void PetComponent::OnUse(Entity* originator) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PetComponent::Update(float deltaTime) {
|
void PetComponent::Update(float deltaTime) {
|
||||||
if (m_StartPosition == NiPoint3::ZERO) {
|
// If pet does not have an owner, use the UpdateUnowned() loop
|
||||||
m_StartPosition = m_Parent->GetPosition();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_Owner == LWOOBJID_EMPTY) {
|
if (m_Owner == LWOOBJID_EMPTY) {
|
||||||
UpdateUnowned(deltaTime);
|
UpdateUnowned(deltaTime);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine pet owner
|
||||||
auto* owner = GetOwner();
|
auto* owner = GetOwner();
|
||||||
if (!owner) {
|
if (!owner) {
|
||||||
m_Parent->Kill();
|
m_Parent->Kill(); // Kill pet if no owner
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_MovementAI = m_Parent->GetComponent<MovementAIComponent>();
|
// Update timer
|
||||||
if (!m_MovementAI) return;
|
if (m_Timer > 0) {
|
||||||
|
m_Timer -= deltaTime;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle treasure timer
|
||||||
if (m_TresureTime > 0.0f) { //TODO: Find better trigger?
|
if (m_TresureTime > 0.0f) { //TODO: Find better trigger?
|
||||||
InteractDig(deltaTime);
|
InteractDig(deltaTime);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle pet AI states
|
||||||
|
switch (m_State) {
|
||||||
|
// Handle idle state
|
||||||
|
case PetAiState::idle: {
|
||||||
|
LOG_DEBUG("Pet in idle state!");
|
||||||
|
m_Timer = 1.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Handle follow state
|
||||||
|
case PetAiState::follow: {
|
||||||
|
// Get movement AI component
|
||||||
|
m_MovementAI = m_Parent->GetComponent<MovementAIComponent>();
|
||||||
|
if (!m_MovementAI) return;
|
||||||
|
|
||||||
|
// Get and set destination
|
||||||
|
//auto position = m_MovementAI->GetParent()->GetPosition();
|
||||||
|
auto ownerPos = owner->GetPosition();
|
||||||
|
NiPoint3 destination = ownerPos;
|
||||||
|
NiPoint3 interactPos = NiPoint3::ZERO;
|
||||||
|
|
||||||
|
// Determine if the "Lost Tags" mission has been completed and digging has been unlocked
|
||||||
|
auto* missionComponent = owner->GetComponent<MissionComponent>();
|
||||||
|
if (!missionComponent) return;
|
||||||
|
const bool digUnlocked = missionComponent->GetMissionState(842) == eMissionState::COMPLETE;
|
||||||
|
|
||||||
|
// Interactions checks
|
||||||
|
SwitchComponent* closestSwitch = SwitchComponent::GetClosestSwitch(ownerPos);
|
||||||
|
Entity* closestTreasure = PetDigServer::GetClosestTresure(ownerPos);
|
||||||
|
if (closestSwitch != nullptr && !closestSwitch->GetActive()) {
|
||||||
|
m_Interaction = closestSwitch->GetParentEntity()->GetObjectID();
|
||||||
|
interactPos = closestSwitch->GetParentEntity()->GetPosition();
|
||||||
|
m_Ability = PetAbilityType::GoToObject;
|
||||||
|
}
|
||||||
|
if (closestTreasure != nullptr && digUnlocked) {
|
||||||
|
m_Interaction = closestTreasure->GetObjectID();
|
||||||
|
interactPos = closestTreasure->GetPosition();
|
||||||
|
m_Ability = PetAbilityType::GoToObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger interaction if checks are valid
|
||||||
|
if (m_Ability != PetAbilityType::Invalid) {
|
||||||
|
float distance = Vector3::DistanceSquared(ownerPos, interactPos);
|
||||||
|
if (distance < 20 * 20) {
|
||||||
|
destination = interactPos;
|
||||||
|
m_MovementAI->SetHaltDistance(0.0f);
|
||||||
|
SetPetAiState(PetAiState::interact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_MovementAI->SetDestination(destination);
|
||||||
|
//LOG_DEBUG("Pet destination: %f %f %f", destination.x, destination.y, destination.z);
|
||||||
|
m_Timer = 1.0f;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Handle interact state
|
||||||
|
case PetAiState::interact: {
|
||||||
|
LOG_DEBUG("Interacting with object!");
|
||||||
|
|
||||||
|
// Get movement AI component
|
||||||
|
m_MovementAI = m_Parent->GetComponent<MovementAIComponent>();
|
||||||
|
if (!m_MovementAI) return;
|
||||||
|
|
||||||
|
// Get distance from owner
|
||||||
|
auto ownerPos = owner->GetPosition();
|
||||||
|
auto position = m_MovementAI->GetParent()->GetPosition();
|
||||||
|
float distanceFromOwner = Vector3::DistanceSquared(position, ownerPos);
|
||||||
|
|
||||||
|
// Switch back to follow AI state if player moves too far away from pet
|
||||||
|
if (distanceFromOwner > 15 * 15) {
|
||||||
|
m_MovementAI->SetHaltDistance(5.0f); // TODO: Remove this magic number
|
||||||
|
m_Interaction = LWOOBJID_EMPTY;
|
||||||
|
m_Ability = PetAbilityType::Invalid;
|
||||||
|
SetIsReadyToDig(false);
|
||||||
|
SetPetAiState(PetAiState::follow);
|
||||||
|
LOG_DEBUG("Pet interaction aborted due to player distance!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get distance from interactable
|
||||||
|
auto destination = m_MovementAI->GetDestination();
|
||||||
|
float distanceFromInteract = Vector3::DistanceSquared(position, destination);
|
||||||
|
|
||||||
|
// Handle the interaction
|
||||||
|
if (m_MovementAI->AtFinalWaypoint()) {
|
||||||
|
Entity* interactEntity = Game::entityManager->GetEntity(m_Interaction);
|
||||||
|
|
||||||
|
/*auto* switchComponent = interactEntity->GetComponent<SwitchComponent>();
|
||||||
|
if (switchComponent != nullptr) {
|
||||||
|
switchComponent->EntityEnter(m_Parent);
|
||||||
|
}
|
||||||
|
else {*/
|
||||||
|
Command(NiPoint3::ZERO, LWOOBJID_EMPTY, 1, PetEmote::Bounce, true); // Plays 'bounce' animation
|
||||||
|
SetIsReadyToDig(true);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Timer = 1.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Handle spawn state
|
||||||
|
case PetAiState::spawn: {
|
||||||
|
LOG_DEBUG("Pet spawned!");
|
||||||
|
|
||||||
|
// Get movement AI component
|
||||||
|
m_MovementAI = m_Parent->GetComponent<MovementAIComponent>();
|
||||||
|
if (!m_MovementAI) return;
|
||||||
|
|
||||||
|
// Determine the pet start position
|
||||||
|
if (m_StartPosition == NiPoint3::ZERO) m_StartPosition = m_Parent->GetPosition();
|
||||||
|
|
||||||
|
// Determine next state;
|
||||||
|
if (m_Owner == LWOOBJID_EMPTY) {
|
||||||
|
SetPetAiState(PetAiState::idle);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SetPetAiState(PetAiState::follow);
|
||||||
|
m_MovementAI->SetMaxSpeed(m_SprintSpeed);
|
||||||
|
m_MovementAI->SetHaltDistance(5.0f); // TODO: Remove magic number
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
auto destination = owner->GetPosition();
|
auto destination = owner->GetPosition();
|
||||||
NiPoint3 position = m_MovementAI->GetParent()->GetPosition();
|
NiPoint3 position = m_MovementAI->GetParent()->GetPosition();
|
||||||
|
|
||||||
@ -387,8 +524,7 @@ void PetComponent::Update(float deltaTime) {
|
|||||||
|
|
||||||
float haltDistance = 5;
|
float haltDistance = 5;
|
||||||
|
|
||||||
if (closestSwitch != nullptr) {
|
if (closestSwitch != nullptr && !closestSwitch->GetActive()) {
|
||||||
if (!closestSwitch->GetActive()) {
|
|
||||||
NiPoint3 switchPosition = closestSwitch->GetParentEntity()->GetPosition();
|
NiPoint3 switchPosition = closestSwitch->GetParentEntity()->GetPosition();
|
||||||
float distance = Vector3::DistanceSquared(position, switchPosition);
|
float distance = Vector3::DistanceSquared(position, switchPosition);
|
||||||
if (distance < 3 * 3) {
|
if (distance < 3 * 3) {
|
||||||
@ -396,11 +532,9 @@ void PetComponent::Update(float deltaTime) {
|
|||||||
closestSwitch->EntityEnter(m_Parent);
|
closestSwitch->EntityEnter(m_Parent);
|
||||||
} else if (distance < 20 * 20) {
|
} else if (distance < 20 * 20) {
|
||||||
haltDistance = 1;
|
haltDistance = 1;
|
||||||
|
|
||||||
destination = switchPosition;
|
destination = switchPosition;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Determine if the "Lost Tags" mission has been completed and digging has been unlocked
|
// Determine if the "Lost Tags" mission has been completed and digging has been unlocked
|
||||||
auto* missionComponent = owner->GetComponent<MissionComponent>();
|
auto* missionComponent = owner->GetComponent<MissionComponent>();
|
||||||
@ -434,13 +568,13 @@ void PetComponent::Update(float deltaTime) {
|
|||||||
|
|
||||||
skipTresure:
|
skipTresure:
|
||||||
|
|
||||||
//m_MovementAI->SetHaltDistance(haltDistance);
|
m_MovementAI->SetHaltDistance(haltDistance);
|
||||||
|
|
||||||
//m_MovementAI->SetMaxSpeed(2.5f);
|
//m_MovementAI->SetMaxSpeed(2.5f);
|
||||||
|
|
||||||
m_MovementAI->SetDestination(destination);
|
m_MovementAI->SetDestination(destination);
|
||||||
|
|
||||||
m_Timer = 1;
|
m_Timer = 1;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void PetComponent::UpdateUnowned(float deltaTime) {
|
void PetComponent::UpdateUnowned(float deltaTime) {
|
||||||
@ -473,6 +607,7 @@ void PetComponent::SetIsReadyToDig(bool isReady) {
|
|||||||
//SetAbility(PetAbilityType::JumpOnObject);
|
//SetAbility(PetAbilityType::JumpOnObject);
|
||||||
SetStatus(PetStatus::IS_NOT_WAITING); // Treasure dig status
|
SetStatus(PetStatus::IS_NOT_WAITING); // Treasure dig status
|
||||||
m_ReadyToDig = true;
|
m_ReadyToDig = true;
|
||||||
|
Game::entityManager->SerializeEntity(m_Parent);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG("Dig state ended!");
|
LOG("Dig state ended!");
|
||||||
@ -480,6 +615,7 @@ void PetComponent::SetIsReadyToDig(bool isReady) {
|
|||||||
//SetAbility(PetAbilityType::Invalid);
|
//SetAbility(PetAbilityType::Invalid);
|
||||||
SetStatus(0); // TODO: Check status
|
SetStatus(0); // TODO: Check status
|
||||||
m_ReadyToDig = false;
|
m_ReadyToDig = false;
|
||||||
|
Game::entityManager->SerializeEntity(m_Parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1022,7 +1158,7 @@ void PetComponent::Command(NiPoint3 position, LWOOBJID source, int32_t commandTy
|
|||||||
// Emotes
|
// Emotes
|
||||||
GameMessages::SendPlayEmote(m_Parent->GetObjectID(), typeId, owner->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS);
|
GameMessages::SendPlayEmote(m_Parent->GetObjectID(), typeId, owner->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS);
|
||||||
} else if (commandType == 3) {
|
} else if (commandType == 3) {
|
||||||
// Follow me, ???
|
SetPetAiState(PetAiState::follow);
|
||||||
} else if (commandType == 6) {
|
} else if (commandType == 6) {
|
||||||
// TODO: Go to player
|
// TODO: Go to player
|
||||||
}
|
}
|
||||||
@ -1034,7 +1170,7 @@ void PetComponent::Command(NiPoint3 position, LWOOBJID source, int32_t commandTy
|
|||||||
// Add movement functionality
|
// Add movement functionality
|
||||||
if (position != NiPoint3::ZERO) {
|
if (position != NiPoint3::ZERO) {
|
||||||
m_MovementAI->SetDestination(position);
|
m_MovementAI->SetDestination(position);
|
||||||
m_Timer = 9; //Is this setting how long until the next update tick?
|
//m_Timer = 9; //Is this setting how long until the next update tick?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,21 @@
|
|||||||
#include "Preconditions.h"
|
#include "Preconditions.h"
|
||||||
#include "eReplicaComponentType.h"
|
#include "eReplicaComponentType.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The current state of the pet AI
|
||||||
|
*/
|
||||||
|
enum class PetAiState : uint {
|
||||||
|
idle = 0, // Doing nothing
|
||||||
|
spawn, // Spawning into the world
|
||||||
|
follow, // Following player
|
||||||
|
interact, // Beginning interaction
|
||||||
|
goToObj, // Go to object
|
||||||
|
despawn // Despawning from world
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The status of the pet: Governs the icon above their head and the interactions available
|
||||||
|
*/
|
||||||
enum PetStatus : uint32_t {
|
enum PetStatus : uint32_t {
|
||||||
NONE,
|
NONE,
|
||||||
BEING_TAMED = 0x10,
|
BEING_TAMED = 0x10,
|
||||||
@ -41,6 +56,18 @@ public:
|
|||||||
~PetComponent() override;
|
~PetComponent() override;
|
||||||
|
|
||||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the AI state of the pet
|
||||||
|
* @param newState New pet AI state
|
||||||
|
*/
|
||||||
|
void SetPetAiState(PetAiState newState);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the AI state of the pet
|
||||||
|
*/
|
||||||
|
PetAiState GetPetAiState() { return m_State; };
|
||||||
|
|
||||||
void Update(float deltaTime) override;
|
void Update(float deltaTime) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -373,6 +400,11 @@ private:
|
|||||||
*/
|
*/
|
||||||
uint32_t m_Status;
|
uint32_t m_Status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current state of the pet AI
|
||||||
|
*/
|
||||||
|
PetAiState m_State;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A currently active ability, mostly unused
|
* A currently active ability, mostly unused
|
||||||
*/
|
*/
|
||||||
@ -399,11 +431,6 @@ private:
|
|||||||
*/
|
*/
|
||||||
bool m_ReadyToDig;
|
bool m_ReadyToDig;
|
||||||
|
|
||||||
/**
|
|
||||||
* Boolean that sets if a pet is in an interaction
|
|
||||||
*/
|
|
||||||
bool m_InInteract;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The position that this pet was spawned at
|
* The position that this pet was spawned at
|
||||||
*/
|
*/
|
||||||
@ -423,4 +450,19 @@ private:
|
|||||||
* The rate at which imagination is drained from the user for having the pet out.
|
* The rate at which imagination is drained from the user for having the pet out.
|
||||||
*/
|
*/
|
||||||
float imaginationDrainRate;
|
float imaginationDrainRate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The walk speed of the pet
|
||||||
|
*/
|
||||||
|
float m_walkSpeed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The run speed of the pet
|
||||||
|
*/
|
||||||
|
float m_RunSpeed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sprint speed of the pet
|
||||||
|
*/
|
||||||
|
float m_SprintSpeed;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user