diff --git a/dDatabase/CDClientDatabase/CDClientManager.cpp b/dDatabase/CDClientDatabase/CDClientManager.cpp index 7c2f3953..bf5634b2 100644 --- a/dDatabase/CDClientDatabase/CDClientManager.cpp +++ b/dDatabase/CDClientDatabase/CDClientManager.cpp @@ -77,6 +77,7 @@ CDClientManager::CDClientManager() { CDCLIENT_DONT_CACHE_TABLE(CDObjectsTable::Instance().LoadValuesFromDatabase()); CDPhysicsComponentTable::Instance().LoadValuesFromDatabase(); CDPackageComponentTable::Instance().LoadValuesFromDatabase(); + CDPetComponentTable::Instance().LoadValuesFromDatabase(); CDProximityMonitorComponentTable::Instance().LoadValuesFromDatabase(); CDPropertyEntranceComponentTable::Instance().LoadValuesFromDatabase(); CDPropertyTemplateTable::Instance().LoadValuesFromDatabase(); diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDPetComponentTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDPetComponentTable.cpp new file mode 100644 index 00000000..03bf479d --- /dev/null +++ b/dDatabase/CDClientDatabase/CDClientTables/CDPetComponentTable.cpp @@ -0,0 +1,34 @@ +#include "CDPetComponentTable.h" + +void CDPetComponentTable::LoadValuesFromDatabase() { + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PetComponent"); + while (!tableData.eof()) { + CDPetComponent entry; + entry.id = tableData.getIntField("id", -1); + UNUSED_COLUMN(entry.minTameUpdateTime = tableData.getFloatField("minTameUpdateTime", 60.0f);) + UNUSED_COLUMN(entry.maxTameUpdateTime = tableData.getFloatField("maxTameUpdateTime", 300.0f);) + UNUSED_COLUMN(entry.percentTameChance = tableData.getFloatField("percentTameChance", 101.0f);) + UNUSED_COLUMN(entry.tameability = tableData.getFloatField("tamability", 100.0f);) // Mispelled as "tamability" in CDClient + UNUSED_COLUMN(entry.elementType = tableData.getIntField("elementType", 1);) + entry.walkSpeed = tableData.getFloatField("walkSpeed", 2.5f); + entry.runSpeed = tableData.getFloatField("runSpeed", 5.0f); + entry.sprintSpeed = tableData.getFloatField("sprintSpeed", 10.0f); + UNUSED_COLUMN(entry.idleTimeMin = tableData.getFloatField("idleTimeMin", 60.0f);) + UNUSED_COLUMN(entry.idleTimeMax = tableData.getFloatField("idleTimeMax", 300.0f);) + UNUSED_COLUMN(entry.petForm = tableData.getIntField("petForm", 0);) + entry.imaginationDrainRate = tableData.getFloatField("imaginationDrainRate", 60.0f); + UNUSED_COLUMN(entry.AudioMetaEventSet = tableData.getStringField("AudioMetaEventSet", "");) + UNUSED_COLUMN(entry.buffIDs = tableData.getStringField("buffIDs", "");) + + m_entries.insert(std::make_pair(entry.id, entry)); + tableData.nextRow(); + } + + tableData.finalize(); + +} + +CDPetComponent* CDPetComponentTable::GetByID(unsigned int componentID) { + auto itr = m_entries.find(componentID); + return itr != m_entries.end() ? &itr->second : nullptr; +} diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDPetComponentTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDPetComponentTable.h new file mode 100644 index 00000000..5e0d6477 --- /dev/null +++ b/dDatabase/CDClientDatabase/CDClientTables/CDPetComponentTable.h @@ -0,0 +1,32 @@ +#pragma once +#include "CDTable.h" +#include + +struct CDPetComponent { + unsigned int id; + UNUSED_COLUMN(float minTameUpdateTime;) + UNUSED_COLUMN(float maxTameUpdateTime;) + UNUSED_COLUMN(float percentTameChance;) + UNUSED_COLUMN(float tameability;) // Mispelled as "tamability" in CDClient + UNUSED_COLUMN(unsigned int elementType;) + float walkSpeed; + float runSpeed; + float sprintSpeed; + UNUSED_COLUMN(float idleTimeMin;) + UNUSED_COLUMN(float idleTimeMax;) + UNUSED_COLUMN(unsigned int petForm;) + float imaginationDrainRate; + UNUSED_COLUMN(std::string AudioMetaEventSet;) + UNUSED_COLUMN(std::string buffIDs;) +}; + +class CDPetComponentTable : public CDTable { +public: + void LoadValuesFromDatabase(); + + static const std::string GetTableName() { return "PetComponent"; }; + CDPetComponent* GetByID(unsigned int componentID); + +private: + std::map m_entries; +}; diff --git a/dDatabase/CDClientDatabase/CDClientTables/CMakeLists.txt b/dDatabase/CDClientDatabase/CDClientTables/CMakeLists.txt index b2551efa..af401db2 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CMakeLists.txt +++ b/dDatabase/CDClientDatabase/CDClientTables/CMakeLists.txt @@ -23,6 +23,7 @@ set(DDATABASE_CDCLIENTDATABASE_CDCLIENTTABLES_SOURCES "CDActivitiesTable.cpp" "CDMovementAIComponentTable.cpp" "CDObjectSkillsTable.cpp" "CDObjectsTable.cpp" + "CDPetComponentTable.cpp" "CDPackageComponentTable.cpp" "CDPhysicsComponentTable.cpp" "CDPropertyEntranceComponentTable.cpp" diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index 05461ba8..14b2198e 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -2,6 +2,7 @@ #include "GameMessages.h" #include "BrickDatabase.h" #include "CDClientDatabase.h" +#include "CDPetComponentTable.h" #include "ChatPackets.h" #include "EntityManager.h" #include "Character.h" @@ -37,7 +38,6 @@ std::unordered_map PetComponent::buildCache{}; std::unordered_map PetComponent::currentActivities{}; std::unordered_map PetComponent::activePets{}; -float PetComponent::m_FollowRadius{}; /** * Maps all the pet lots to a flag indicating that the player has caught it. All basic pets have been guessed by ObjID @@ -94,7 +94,6 @@ PetComponent::PetComponent(Entity* parent, uint32_t componentId): Component(pare m_ReadyToInteract = false; SetPetAiState(PetAiState::spawn); - m_FollowRadius = Game::zoneManager->GetPetFollowRadius(); SetIsHandlingInteraction(false); std::string checkPreconditions = GeneralUtils::UTF16ToWTF8(parent->GetVar(u"CheckPrecondition")); @@ -103,22 +102,28 @@ PetComponent::PetComponent(Entity* parent, uint32_t componentId): Component(pare SetPreconditions(checkPreconditions); } + // Load database values + m_FollowRadius = Game::zoneManager->GetPetFollowRadius(); + if (!GetPetInfo(m_ComponentId, m_PetInfo)) LOG("Failed to load PetComponent information from CDClient!"); + + /*m_PetInfo.id; + m_PetInfo.runSpeed; + m_PetInfo.sprintSpeed; + m_PetInfo.walkSpeed;*/ + + //CDClientManager::GetTable() //LoadDataFromTemplate(); // TODO: Figure out how to load this with the tests (DarkflameServer/dDatabase/CDClientDatabase/CDClientTables/) } -void PetComponent::LoadDataFromTemplate() { - auto query = CDClientDatabase::CreatePreppedStmt( - "SELECT walkSpeed, runSpeed, sprintSpeed, imaginationDrainRate FROM PetComponent WHERE id = ?;"); - query.bind(1, static_cast(m_ComponentId)); +bool PetComponent::GetPetInfo(uint32_t petId, CDPetComponent& result) { + auto* petTable = CDClientManager::Instance().GetTable(); - auto result = query.execQuery(); + const auto pet = petTable->GetByID(petId); + if (!pet) return false; - if (!result.eof()) { - m_WalkSpeed = result.getFloatField(0, 2.5f); - m_RunSpeed = result.getFloatField(1, 5.0f); - m_SprintSpeed = result.getFloatField(2, 10.0f); - imaginationDrainRate = result.getFloatField(3, 60.0f); - } + result = pet[0]; + + return true; } void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { @@ -216,6 +221,7 @@ void PetComponent::OnUse(Entity* originator) { std::string buildFile; + // TODO: MOVE THIS OUT OF THE COMPONENT if (cached == buildCache.end()) { auto query = CDClientDatabase::CreatePreppedStmt( "SELECT ValidPiecesLXF, PuzzleModelLot, Timelimit, NumValidPieces, imagCostPerBuild FROM TamingBuildPuzzles WHERE NPCLot = ?;"); @@ -338,7 +344,7 @@ void PetComponent::OnUse(Entity* originator) { GameMessages::SendNotifyPetTamingPuzzleSelected(originator->GetObjectID(), bricks, originator->GetSystemAddress()); m_Tamer = originator->GetObjectID(); - SetStatus(5); + SetFlag(UNKNOWN1, UNKNOWN4); //SetStatus(5); currentActivities.insert_or_assign(m_Tamer, m_Parent->GetObjectID()); @@ -607,7 +613,7 @@ void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) { missionComponent->Progress(eMissionTaskType::PET_TAMING, m_Parent->GetLOT()); } - SetStatus(1); + SetFlag(UNKNOWN1); // SetStatus(1); auto* characterComponent = tamer->GetComponent(); if (characterComponent != nullptr) { @@ -815,11 +821,11 @@ void PetComponent::Wander() { return; } - m_MovementAI->SetMaxSpeed(m_SprintSpeed); //info.wanderSpeed); + m_MovementAI->SetMaxSpeed(m_PetInfo.sprintSpeed); //info.wanderSpeed); m_MovementAI->SetDestination(destination); - m_Timer += (m_MovementAI->GetParent()->GetPosition().x - destination.x) / m_SprintSpeed; //info.wanderSpeed; + m_Timer += (m_MovementAI->GetParent()->GetPosition().x - destination.x) / m_PetInfo.sprintSpeed; } void PetComponent::OnSpawn() { @@ -834,7 +840,7 @@ void PetComponent::OnSpawn() { if (m_Owner != LWOOBJID_EMPTY) { m_Parent->SetOwnerOverride(m_Owner); - m_MovementAI->SetMaxSpeed(m_SprintSpeed); + m_MovementAI->SetMaxSpeed(m_PetInfo.sprintSpeed); m_MovementAI->SetHaltDistance(m_FollowRadius); SetStatus(PetFlag::NONE); SetPetAiState(PetAiState::follow); @@ -931,7 +937,7 @@ void PetComponent::StartInteract(const NiPoint3 position, const PetInteractType SetInteractType(interactType); SetAbility(ePetAbilityType::GoToObject); SetPetAiState(PetAiState::goToObj); - m_MovementAI->SetMaxSpeed(m_RunSpeed); + m_MovementAI->SetMaxSpeed(m_PetInfo.runSpeed); m_MovementAI->SetHaltDistance(0.0f); m_MovementAI->SetDestination(position); LOG_DEBUG("Starting interaction!"); @@ -947,10 +953,10 @@ void PetComponent::StopInteract() { SetInteractType(PetInteractType::none); SetAbility(petAbility); SetPetAiState(PetAiState::follow); - SetStatus(PetFlag::NONE); + SetOnlyFlag(NONE); //SetStatus(PetFlag::NONE); SetIsReadyToInteract(false); SetIsHandlingInteraction(false); // Needed? - m_MovementAI->SetMaxSpeed(m_SprintSpeed); + m_MovementAI->SetMaxSpeed(m_PetInfo.sprintSpeed); m_MovementAI->SetHaltDistance(m_FollowRadius); LOG_DEBUG("Stopping interaction!"); @@ -977,7 +983,7 @@ void PetComponent::SetupInteractTreasureDig() { auto petAbility = ePetAbilityType::DigAtPosition; SetAbility(petAbility); - SetStatus(PetFlag::NOT_WAITING); // TODO: Double-check this is the right flag being set + SetFlag(NOT_WAITING); //SetStatus(PetFlag::NOT_WAITING); // TODO: Double-check this is the right flag being set Game::entityManager->SerializeEntity(m_Parent); // TODO: Double-check pet packet captures const auto sysAddr = owner->GetSystemAddress(); @@ -1007,8 +1013,7 @@ void PetComponent::StartInteractTreasureDig() { Game::entityManager->SerializeEntity(user); SetIsHandlingInteraction(true); - auto newStatus = GeneralUtils::ClearBit(GetStatus(), 6); - SetStatus(newStatus); // TODO: FIND THE CORRECT STATUS TO USE HERE + UnsetFlag(NOT_WAITING); // TODO: FIND THE CORRECT STATUS TO USE HERE Game::entityManager->SerializeEntity(m_Parent); Command(NiPoint3::ZERO, LWOOBJID_EMPTY, 1, PetEmote::DigTreasure, true); // Plays 'dig' animation @@ -1119,7 +1124,7 @@ void PetComponent::AddDrainImaginationTimer(Item* item, bool fromTaming) { if (!fromTaming) playerDestroyableComponent->Imagine(-1); // Set this to a variable so when this is called back from the player the timer doesn't fire off. - m_Parent->AddCallbackTimer(imaginationDrainRate, [playerDestroyableComponent, this, item]() { + m_Parent->AddCallbackTimer(m_PetInfo.imaginationDrainRate, [playerDestroyableComponent, this, item]() { if (!playerDestroyableComponent) { LOG("No petComponent and/or no playerDestroyableComponent"); return; diff --git a/dGame/dComponents/PetComponent.h b/dGame/dComponents/PetComponent.h index 32e6034f..2c7d6504 100644 --- a/dGame/dComponents/PetComponent.h +++ b/dGame/dComponents/PetComponent.h @@ -7,6 +7,7 @@ #include "Preconditions.h" #include "eReplicaComponentType.h" #include "ePetAbilityType.h" +#include "CDPetComponentTable.h" /* * The current state of the pet AI @@ -34,6 +35,8 @@ enum PetInteractType : uint8_t { */ enum PetFlag : uint32_t { NONE, + UNKNOWN1 = 1 << 0, //0x01, + UNKNOWN4 = 1 << 2, //0x04, BEING_TAMED = 1 << 4, //0x10, NOT_WAITING = 1 << 5, //0x20, SPAWNING = 1 << 7, //0x80 @@ -61,10 +64,10 @@ public: ~PetComponent() override; /** - * Loads pet data from CDClient + * Loads pet info from CDClient */ - void LoadDataFromTemplate(); //TODO: Move - + bool GetPetInfo(uint32_t petId, CDPetComponent& result); + /** * Serializes the pet * @param outBitStream The output bitstream @@ -88,35 +91,35 @@ public: * @param flag PetFlag(s) to set */ template - void SetFlag(varArg... flag) { m_Flags |= (static_cast(flag) | ...); } + void SetFlag(varArg... flag) { m_Flags |= (static_cast(flag) | ...); }; /** * Sets the pet to ONLY have the specified flag(s), clearing all others * @param flag PetFlag(s) to set exclusively */ template - void SetOnlyFlag(varArg... flag) { m_Flags = (static_cast(flag) | ...); } + void SetOnlyFlag(varArg... flag) { m_Flags = (static_cast(flag) | ...); }; /** * Unsets one or more pet flags * @param flag PetFlag(s) to unset */ template - void UnsetFlag(varArg... flag) { m_Flags &= ~(static_cast(flag) | ...); } + void UnsetFlag(varArg... flag) { m_Flags &= ~(static_cast(flag) | ...); }; /** * Returns true if the pet has all the specified flag(s) * @param flag PetFlag(s) to check */ template - const bool HasFlag(varArg... flag) { return (m_Flags & (static_cast(flag) | ...)) == (static_cast(flag) | ...); } + const bool HasFlag(varArg... flag) { return (m_Flags & (static_cast(flag) | ...)) == (static_cast(flag) | ...); }; /** * Returns true if the pet has ONLY the specified flag(s) * @param flag PetFlag(s) to check if the pet has exclusively */ template - const bool HasOnlyFlag(varArg... flag) { return m_Flags == (static_cast(flag) | ...); } + const bool HasOnlyFlag(varArg... flag) { return m_Flags == (static_cast(flag) | ...); }; /** * Governs the pet update loop @@ -423,6 +426,11 @@ private: int32_t numValidPieces; }; + /** + * Information that describes the different variables used to make a pet entity move around + */ + CDPetComponent m_PetInfo; + /** * Cache of all the pets that are currently spawned, indexed by tamer */ @@ -444,9 +452,9 @@ private: static std::map petFlags; /** - * The halting radius of the pet while following a player + * The halting radius of the pet while following a player TODO: Move into struct? */ - static float m_FollowRadius; + float m_FollowRadius; /** * The ID of the component in the pet component table @@ -557,26 +565,6 @@ private: * Preconditions that need to be met before an entity can tame this pet */ PreconditionExpression* m_Preconditions; - - /** - * The rate at which imagination is drained from the user for having the pet out. - */ - 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; }; #endif // PETCOMPONENT_H