chore: Assorted pet improvements (#1402)

* Assorted pet improvements

* remove unecessary include

* updates to address some feedback

* fixed database code for testing

* Removed reference member (for now)

* Removed cmake flag
This commit is contained in:
jadebenn 2024-01-08 17:32:09 -06:00 committed by GitHub
parent fbdcc17bb5
commit 4a50c60559
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 245 additions and 63 deletions

View File

@ -51,7 +51,7 @@ set(RECASTNAVIGATION_EXAMPLES OFF CACHE BOOL "" FORCE)
# Disabled no-register # Disabled no-register
# Disabled unknown pragmas because Linux doesn't understand Windows pragmas. # Disabled unknown pragmas because Linux doesn't understand Windows pragmas.
if(UNIX) if(UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -fPIC") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wuninitialized -fPIC")
add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0 _GLIBCXX_USE_CXX17_ABI=0) add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0 _GLIBCXX_USE_CXX17_ABI=0)
if(NOT APPLE) if(NOT APPLE)

View File

@ -0,0 +1,13 @@
#ifndef __EPETABILITYTYPE__H__
#define __EPETABILITYTYPE__H__
#include <cstdint>
enum class ePetAbilityType : uint32_t {
Invalid,
GoToObject,
JumpOnObject,
DigAtPosition
};
#endif //!__EPETABILITYTYPE__H__

View File

@ -4,9 +4,13 @@
// Static Variables // Static Variables
static CppSQLite3DB* conn = new CppSQLite3DB(); static CppSQLite3DB* conn = new CppSQLite3DB();
// Status Variables
bool CDClientDatabase::isConnected = false;
//! Opens a connection with the CDClient //! Opens a connection with the CDClient
void CDClientDatabase::Connect(const std::string& filename) { void CDClientDatabase::Connect(const std::string& filename) {
conn->open(filename.c_str()); conn->open(filename.c_str());
isConnected = true;
} }
//! Queries the CDClient //! Queries the CDClient

View File

@ -15,6 +15,10 @@
//! The CDClient Database namespace //! The CDClient Database namespace
namespace CDClientDatabase { namespace CDClientDatabase {
/**
* Boolean defining the connection status of CDClient
*/
extern bool isConnected;
//! Opens a connection with the CDClient //! Opens a connection with the CDClient
/*! /*!

View File

@ -3,6 +3,7 @@
#include "CDAnimationsTable.h" #include "CDAnimationsTable.h"
#include "CDBehaviorParameterTable.h" #include "CDBehaviorParameterTable.h"
#include "CDBehaviorTemplateTable.h" #include "CDBehaviorTemplateTable.h"
#include "CDClientDatabase.h"
#include "CDComponentsRegistryTable.h" #include "CDComponentsRegistryTable.h"
#include "CDCurrencyTableTable.h" #include "CDCurrencyTableTable.h"
#include "CDDestructibleComponentTable.h" #include "CDDestructibleComponentTable.h"
@ -39,6 +40,8 @@
#include "CDRailActivatorComponent.h" #include "CDRailActivatorComponent.h"
#include "CDRewardCodesTable.h" #include "CDRewardCodesTable.h"
#include <exception>
#ifndef CDCLIENT_CACHE_ALL #ifndef CDCLIENT_CACHE_ALL
// Uncomment this to cache the full cdclient database into memory. This will make the server load faster, but will use more memory. // Uncomment this to cache the full cdclient database into memory. This will make the server load faster, but will use more memory.
// A vanilla CDClient takes about 46MB of memory + the regular world data. // A vanilla CDClient takes about 46MB of memory + the regular world data.
@ -51,7 +54,16 @@
#define CDCLIENT_DONT_CACHE_TABLE(x) #define CDCLIENT_DONT_CACHE_TABLE(x)
#endif #endif
CDClientManager::CDClientManager() { class CDClientConnectionException : public std::exception {
public:
virtual const char* what() const throw() {
return "CDClientDatabase is not connected!";
}
};
void CDClientManager::LoadValuesFromDatabase() {
if (!CDClientDatabase::isConnected) throw CDClientConnectionException();
CDActivityRewardsTable::Instance().LoadValuesFromDatabase(); CDActivityRewardsTable::Instance().LoadValuesFromDatabase();
CDActivitiesTable::Instance().LoadValuesFromDatabase(); CDActivitiesTable::Instance().LoadValuesFromDatabase();
CDCLIENT_DONT_CACHE_TABLE(CDAnimationsTable::Instance().LoadValuesFromDatabase()); CDCLIENT_DONT_CACHE_TABLE(CDAnimationsTable::Instance().LoadValuesFromDatabase());
@ -79,6 +91,7 @@ CDClientManager::CDClientManager() {
CDCLIENT_DONT_CACHE_TABLE(CDObjectsTable::Instance().LoadValuesFromDatabase()); CDCLIENT_DONT_CACHE_TABLE(CDObjectsTable::Instance().LoadValuesFromDatabase());
CDPhysicsComponentTable::Instance().LoadValuesFromDatabase(); CDPhysicsComponentTable::Instance().LoadValuesFromDatabase();
CDPackageComponentTable::Instance().LoadValuesFromDatabase(); CDPackageComponentTable::Instance().LoadValuesFromDatabase();
CDPetComponentTable::Instance().LoadValuesFromDatabase();
CDProximityMonitorComponentTable::Instance().LoadValuesFromDatabase(); CDProximityMonitorComponentTable::Instance().LoadValuesFromDatabase();
CDPropertyEntranceComponentTable::Instance().LoadValuesFromDatabase(); CDPropertyEntranceComponentTable::Instance().LoadValuesFromDatabase();
CDPropertyTemplateTable::Instance().LoadValuesFromDatabase(); CDPropertyTemplateTable::Instance().LoadValuesFromDatabase();
@ -92,3 +105,9 @@ CDClientManager::CDClientManager() {
CDVendorComponentTable::Instance().LoadValuesFromDatabase(); CDVendorComponentTable::Instance().LoadValuesFromDatabase();
CDZoneTableTable::Instance().LoadValuesFromDatabase(); CDZoneTableTable::Instance().LoadValuesFromDatabase();
} }
void CDClientManager::LoadValuesFromDefaults() {
LOG("Loading default CDClient tables!");
CDPetComponentTable::Instance().LoadValuesFromDefaults();
}

View File

@ -11,7 +11,10 @@
*/ */
class CDClientManager : public Singleton<CDClientManager> { class CDClientManager : public Singleton<CDClientManager> {
public: public:
CDClientManager(); CDClientManager() = default;
void LoadValuesFromDatabase();
void LoadValuesFromDefaults();
/** /**
* Fetch a table from CDClient * Fetch a table from CDClient

View File

@ -0,0 +1,61 @@
#include "CDPetComponentTable.h"
namespace {
// Default entries for fallback
CDPetComponent defaultEntry{
.id = 0,
UNUSED_ENTRY(.minTameUpdateTime = 60.0f,)
UNUSED_ENTRY(.maxTameUpdateTime = 300.0f,)
UNUSED_ENTRY(.percentTameChance = 101.0f,)
UNUSED_ENTRY(.tameability = 100.0f,)
UNUSED_ENTRY(.elementType = 1,)
.walkSpeed = 2.5f,
.runSpeed = 5.0f,
.sprintSpeed = 10.0f,
UNUSED_ENTRY(.idleTimeMin = 60.0f,)
UNUSED_ENTRY(.idleTimeMax = 300.0f,)
UNUSED_ENTRY(.petForm = 0,)
.imaginationDrainRate = 60.0f,
UNUSED_ENTRY(.AudioMetaEventSet = "",)
UNUSED_ENTRY(.buffIDs = "",)
};
}
void CDPetComponentTable::LoadValuesFromDatabase() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PetComponent");
while (!tableData.eof()) {
const uint32_t componentID = tableData.getIntField("id", defaultEntry.id);
auto& entry = m_Entries[componentID];
entry.id = componentID;
UNUSED_COLUMN(entry.minTameUpdateTime = tableData.getFloatField("minTameUpdateTime", defaultEntry.minTameUpdateTime));
UNUSED_COLUMN(entry.maxTameUpdateTime = tableData.getFloatField("maxTameUpdateTime", defaultEntry.maxTameUpdateTime));
UNUSED_COLUMN(entry.percentTameChance = tableData.getFloatField("percentTameChance", defaultEntry.percentTameChance));
UNUSED_COLUMN(entry.tameability = tableData.getFloatField("tamability", defaultEntry.tameability)); // Mispelled as "tamability" in CDClient
UNUSED_COLUMN(entry.elementType = tableData.getIntField("elementType", defaultEntry.elementType));
entry.walkSpeed = static_cast<float>(tableData.getFloatField("walkSpeed", defaultEntry.walkSpeed));
entry.runSpeed = static_cast<float>(tableData.getFloatField("runSpeed", defaultEntry.runSpeed));
entry.sprintSpeed = static_cast<float>(tableData.getFloatField("sprintSpeed", defaultEntry.sprintSpeed));
UNUSED_COLUMN(entry.idleTimeMin = tableData.getFloatField("idleTimeMin", defaultEntry.idleTimeMin));
UNUSED_COLUMN(entry.idleTimeMax = tableData.getFloatField("idleTimeMax", defaultEntry.idleTimeMax));
UNUSED_COLUMN(entry.petForm = tableData.getIntField("petForm", defaultEntry.petForm));
entry.imaginationDrainRate = static_cast<float>(tableData.getFloatField("imaginationDrainRate", defaultEntry.imaginationDrainRate));
UNUSED_COLUMN(entry.AudioMetaEventSet = tableData.getStringField("AudioMetaEventSet", defaultEntry.AudioMetaEventSet));
UNUSED_COLUMN(entry.buffIDs = tableData.getStringField("buffIDs", defaultEntry.buffIDs));
tableData.nextRow();
}
}
void CDPetComponentTable::LoadValuesFromDefaults() {
m_Entries.insert(std::make_pair(defaultEntry.id, defaultEntry));
}
CDPetComponent& CDPetComponentTable::GetByID(const uint32_t componentID) {
auto itr = m_Entries.find(componentID);
if (itr == m_Entries.end()) {
LOG("Unable to load pet component (ID %i) values from database! Using default values instead.", componentID);
return defaultEntry;
}
return itr->second;
}

View File

@ -0,0 +1,45 @@
#pragma once
#include "CDTable.h"
#include <cstdint>
#include <string>
struct CDPetComponent {
uint32_t id;
UNUSED_COLUMN(float minTameUpdateTime;)
UNUSED_COLUMN(float maxTameUpdateTime;)
UNUSED_COLUMN(float percentTameChance;)
UNUSED_COLUMN(float tameability;) // Mispelled as "tamability" in CDClient
UNUSED_COLUMN(uint32_t elementType;)
float walkSpeed;
float runSpeed;
float sprintSpeed;
UNUSED_COLUMN(float idleTimeMin;)
UNUSED_COLUMN(float idleTimeMax;)
UNUSED_COLUMN(uint32_t petForm;)
float imaginationDrainRate;
UNUSED_COLUMN(std::string AudioMetaEventSet;)
UNUSED_COLUMN(std::string buffIDs;)
};
class CDPetComponentTable : public CDTable<CDPetComponentTable> {
public:
/**
* Load values from the CD client database
*/
void LoadValuesFromDatabase();
/**
* Load the default values into memory instead of attempting to connect to the CD client database
*/
void LoadValuesFromDefaults();
/**
* Gets the pet component table corresponding to the pet component ID
* @returns A reference to the corresponding table, or the default if one could not be found
*/
CDPetComponent& GetByID(const uint32_t componentID);
private:
std::map<uint32_t, CDPetComponent> m_Entries;
};

View File

@ -23,6 +23,9 @@
// Enable this to skip some unused columns in some tables // Enable this to skip some unused columns in some tables
#define UNUSED_COLUMN(v) #define UNUSED_COLUMN(v)
// Use this to skip unused defaults for unused entries in some tables
#define UNUSED_ENTRY(v, x)
#pragma warning (disable : 4244) //Disable double to float conversion warnings #pragma warning (disable : 4244) //Disable double to float conversion warnings
#pragma warning (disable : 4715) //Disable "not all control paths return a value" #pragma warning (disable : 4715) //Disable "not all control paths return a value"

View File

@ -23,6 +23,7 @@ set(DDATABASE_CDCLIENTDATABASE_CDCLIENTTABLES_SOURCES "CDActivitiesTable.cpp"
"CDMovementAIComponentTable.cpp" "CDMovementAIComponentTable.cpp"
"CDObjectSkillsTable.cpp" "CDObjectSkillsTable.cpp"
"CDObjectsTable.cpp" "CDObjectsTable.cpp"
"CDPetComponentTable.cpp"
"CDPackageComponentTable.cpp" "CDPackageComponentTable.cpp"
"CDPhysicsComponentTable.cpp" "CDPhysicsComponentTable.cpp"
"CDPropertyEntranceComponentTable.cpp" "CDPropertyEntranceComponentTable.cpp"

View File

@ -34,7 +34,6 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id):
m_MovementAI = nullptr; m_MovementAI = nullptr;
m_Disabled = false; m_Disabled = false;
m_SkillEntries = {}; m_SkillEntries = {};
m_MovementAI = nullptr;
m_SoftTimer = 5.0f; m_SoftTimer = 5.0f;
//Grab the aggro information from BaseCombatAI: //Grab the aggro information from BaseCombatAI:

View File

@ -69,7 +69,8 @@ std::map<LOT, int32_t> PetComponent::petFlags = {
{ 13067, 838 }, // Skeleton dragon { 13067, 838 }, // Skeleton dragon
}; };
PetComponent::PetComponent(Entity* parent, uint32_t componentId): Component(parent) { PetComponent::PetComponent(Entity* parentEntity, uint32_t componentId) : Component{ parentEntity } {
m_PetInfo = CDClientManager::Instance().GetTable<CDPetComponentTable>()->GetByID(componentId); // TODO: Make reference when safe
m_ComponentId = componentId; m_ComponentId = componentId;
m_Interaction = LWOOBJID_EMPTY; m_Interaction = LWOOBJID_EMPTY;
@ -81,31 +82,17 @@ PetComponent::PetComponent(Entity* parent, uint32_t componentId): Component(pare
m_TimerAway = 0; m_TimerAway = 0;
m_DatabaseId = LWOOBJID_EMPTY; m_DatabaseId = LWOOBJID_EMPTY;
m_Status = 67108866; // Tamable m_Status = 67108866; // Tamable
m_Ability = PetAbilityType::Invalid; m_Ability = ePetAbilityType::Invalid;
m_StartPosition = NiPoint3::ZERO; m_StartPosition = NiPoint3::ZERO;
m_MovementAI = nullptr; m_MovementAI = nullptr;
m_TresureTime = 0; m_TresureTime = 0;
m_Preconditions = nullptr; m_Preconditions = nullptr;
std::string checkPreconditions = GeneralUtils::UTF16ToWTF8(parent->GetVar<std::u16string>(u"CheckPrecondition")); std::string checkPreconditions = GeneralUtils::UTF16ToWTF8(parentEntity->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 = ?;");
query.bind(1, static_cast<int>(componentId));
auto result = query.execQuery();
// Should a result not exist for this pet default to 60 seconds.
if (!result.eof() && !result.fieldIsNull(0)) {
imaginationDrainRate = result.getFloatField(0, 60.0f);
} else {
imaginationDrainRate = 60.0f;
}
result.finalize();
} }
void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
@ -114,7 +101,7 @@ void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpd
outBitStream->Write1(); // Always serialize as dirty for now outBitStream->Write1(); // Always serialize as dirty for now
outBitStream->Write<uint32_t>(m_Status); outBitStream->Write<uint32_t>(m_Status);
outBitStream->Write(tamed ? m_Ability : PetAbilityType::Invalid); // Something with the overhead icon? outBitStream->Write(tamed ? m_Ability : ePetAbilityType::Invalid); // Something with the overhead icon?
const bool interacting = m_Interaction != LWOOBJID_EMPTY; const bool interacting = m_Interaction != LWOOBJID_EMPTY;
@ -835,11 +822,11 @@ void PetComponent::Wander() {
return; return;
} }
m_MovementAI->SetMaxSpeed(info.wanderSpeed); m_MovementAI->SetMaxSpeed(m_PetInfo.sprintSpeed);
m_MovementAI->SetDestination(destination); m_MovementAI->SetDestination(destination);
m_Timer += (m_MovementAI->GetParent()->GetPosition().x - destination.x) / info.wanderSpeed; m_Timer += (m_MovementAI->GetParent()->GetPosition().x - destination.x) / m_PetInfo.sprintSpeed;
} }
void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) { void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) {
@ -905,8 +892,6 @@ void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) {
GameMessages::SendRegisterPetDBID(m_Owner, m_DatabaseId, owner->GetSystemAddress()); GameMessages::SendRegisterPetDBID(m_Owner, m_DatabaseId, owner->GetSystemAddress());
} }
GameMessages::SendShowPetActionButton(m_Owner, 3, true, owner->GetSystemAddress());
} }
void PetComponent::AddDrainImaginationTimer(Item* item, bool fromTaming) { void PetComponent::AddDrainImaginationTimer(Item* item, bool fromTaming) {
@ -928,7 +913,7 @@ void PetComponent::AddDrainImaginationTimer(Item* item, bool fromTaming) {
if (!fromTaming) playerDestroyableComponent->Imagine(-1); 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. // 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) { if (!playerDestroyableComponent) {
LOG("No petComponent and/or no playerDestroyableComponent"); LOG("No petComponent and/or no playerDestroyableComponent");
return; return;
@ -966,7 +951,7 @@ void PetComponent::Deactivate() {
GameMessages::SendRegisterPetDBID(m_Owner, LWOOBJID_EMPTY, owner->GetSystemAddress()); GameMessages::SendRegisterPetDBID(m_Owner, LWOOBJID_EMPTY, owner->GetSystemAddress());
GameMessages::SendShowPetActionButton(m_Owner, 0, false, owner->GetSystemAddress()); GameMessages::SendShowPetActionButton(m_Owner, ePetAbilityType::Invalid, false, owner->GetSystemAddress());
} }
void PetComponent::Release() { void PetComponent::Release() {
@ -985,12 +970,9 @@ void PetComponent::Release() {
item->SetCount(0, false, false); item->SetCount(0, false, false);
} }
void PetComponent::Command(NiPoint3 position, LWOOBJID source, int32_t commandType, int32_t typeId, bool overrideObey) { void PetComponent::Command(const NiPoint3& position, const LWOOBJID source, const int32_t commandType, const int32_t typeId, const bool overrideObey) {
auto* owner = GetOwner(); auto* owner = GetOwner();
if (!owner) return;
if (owner == nullptr) {
return;
}
if (commandType == 1) { if (commandType == 1) {
// Emotes // Emotes
@ -1030,7 +1012,7 @@ uint32_t PetComponent::GetStatus() const {
return m_Status; return m_Status;
} }
PetAbilityType PetComponent::GetAbility() const { ePetAbilityType PetComponent::GetAbility() const {
return m_Ability; return m_Ability;
} }
@ -1042,7 +1024,7 @@ void PetComponent::SetStatus(uint32_t value) {
m_Status = value; m_Status = value;
} }
void PetComponent::SetAbility(PetAbilityType value) { void PetComponent::SetAbility(ePetAbilityType value) {
m_Ability = value; m_Ability = value;
} }
@ -1098,7 +1080,7 @@ void PetComponent::SetPetNameForModeration(const std::string& petName) {
} }
//Save to db: //Save to db:
Database::Get()->SetPetNameModerationStatus(m_DatabaseId, IPetNames::Info{petName, approved}); Database::Get()->SetPetNameModerationStatus(m_DatabaseId, IPetNames::Info{ petName, approved });
} }
void PetComponent::LoadPetNameFromModeration() { void PetComponent::LoadPetNameFromModeration() {

View File

@ -1,18 +1,13 @@
#pragma once #ifndef PETCOMPONENT_H
#define PETCOMPONENT_H
#include "Entity.h" #include "Entity.h"
#include "MovementAIComponent.h" #include "MovementAIComponent.h"
#include "Component.h" #include "Component.h"
#include "Preconditions.h" #include "Preconditions.h"
#include "ePetAbilityType.h"
#include "eReplicaComponentType.h" #include "eReplicaComponentType.h"
#include "CDPetComponentTable.h"
enum class PetAbilityType : uint32_t
{
Invalid,
GoToObject,
JumpOnObject,
DigAtPosition
};
/** /**
* Represents an entity that is a pet. This pet can be tamed and consequently follows the tamer around, allowing it * Represents an entity that is a pet. This pet can be tamed and consequently follows the tamer around, allowing it
@ -103,7 +98,7 @@ public:
* @param typeId extra information about the command, e.g. the emote to play * @param typeId extra information about the command, e.g. the emote to play
* @param overrideObey unused * @param overrideObey unused
*/ */
void Command(NiPoint3 position, LWOOBJID source, int32_t commandType, int32_t typeId, bool overrideObey); void Command(const NiPoint3& position, const LWOOBJID source, const int32_t commandType, const int32_t typeId, const bool overrideObey);
/** /**
* Returns the ID of the owner of this pet (if any) * Returns the ID of the owner of this pet (if any)
@ -158,13 +153,13 @@ public:
* Returns an ability the pet may perform, currently unused * Returns an ability the pet may perform, currently unused
* @return an ability the pet may perform * @return an ability the pet may perform
*/ */
PetAbilityType GetAbility() const; ePetAbilityType GetAbility() const;
/** /**
* Sets the ability of the pet, currently unused * Sets the ability of the pet, currently unused
* @param value the ability to set * @param value the ability to set
*/ */
void SetAbility(PetAbilityType value); void SetAbility(ePetAbilityType value);
/** /**
* Sets preconditions for the pet that need to be met before it can be tamed * Sets preconditions for the pet that need to be met before it can be tamed
@ -323,7 +318,7 @@ private:
/** /**
* A currently active ability, mostly unused * A currently active ability, mostly unused
*/ */
PetAbilityType m_Ability; ePetAbilityType m_Ability;
/** /**
* The time an entity has left to complete the minigame * The time an entity has left to complete the minigame
@ -357,7 +352,10 @@ private:
PreconditionExpression* m_Preconditions; PreconditionExpression* m_Preconditions;
/** /**
* The rate at which imagination is drained from the user for having the pet out. * Pet information loaded from the CDClientDatabase
* TODO: Switch to a reference when safe to do so
*/ */
float imaginationDrainRate; CDPetComponent m_PetInfo;
}; };
#endif // !PETCOMPONENT_H

View File

@ -94,6 +94,7 @@
#include "eReplicaComponentType.h" #include "eReplicaComponentType.h"
#include "eClientMessageType.h" #include "eClientMessageType.h"
#include "eGameMessageType.h" #include "eGameMessageType.h"
#include "ePetAbilityType.h"
#include "ActivityManager.h" #include "ActivityManager.h"
#include "CDComponentsRegistryTable.h" #include "CDComponentsRegistryTable.h"
@ -3516,14 +3517,14 @@ void GameMessages::SendClientExitTamingMinigame(LWOOBJID objectId, bool bVolunta
SEND_PACKET; SEND_PACKET;
} }
void GameMessages::SendShowPetActionButton(LWOOBJID objectId, int32_t buttonLabel, bool bShow, const SystemAddress& sysAddr) { void GameMessages::SendShowPetActionButton(const LWOOBJID objectId, const ePetAbilityType petAbility, const bool bShow, const SystemAddress& sysAddr) {
CBITSTREAM; CBITSTREAM;
CMSGHEADER; CMSGHEADER;
bitStream.Write(objectId); bitStream.Write(objectId);
bitStream.Write(eGameMessageType::SHOW_PET_ACTION_BUTTON); bitStream.Write(eGameMessageType::SHOW_PET_ACTION_BUTTON);
bitStream.Write(buttonLabel); bitStream.Write(petAbility);
bitStream.Write(bShow); bitStream.Write(bShow);
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;

View File

@ -32,6 +32,7 @@ enum class eObjectWorldState : uint32_t;
enum class eTerminateType : uint32_t; enum class eTerminateType : uint32_t;
enum class eControlScheme : uint32_t; enum class eControlScheme : uint32_t;
enum class eStateChangeType : uint32_t; enum class eStateChangeType : uint32_t;
enum class ePetAbilityType : uint32_t;
enum class ePetTamingNotifyType : uint32_t; enum class ePetTamingNotifyType : uint32_t;
enum class eUseItemResponse : uint32_t; enum class eUseItemResponse : uint32_t;
enum class eQuickBuildFailReason : uint32_t; enum class eQuickBuildFailReason : uint32_t;
@ -386,7 +387,7 @@ namespace GameMessages {
void SendClientExitTamingMinigame(LWOOBJID objectId, bool bVoluntaryExit, const SystemAddress& sysAddr); void SendClientExitTamingMinigame(LWOOBJID objectId, bool bVoluntaryExit, const SystemAddress& sysAddr);
void SendShowPetActionButton(LWOOBJID objectId, int32_t buttonLabel, bool bShow, const SystemAddress& sysAddr); void SendShowPetActionButton(const LWOOBJID objectId, const ePetAbilityType petAbility, const bool bShow, const SystemAddress& sysAddr);
void SendPlayEmote(LWOOBJID objectId, int32_t emoteID, LWOOBJID target, const SystemAddress& sysAddr); void SendPlayEmote(LWOOBJID objectId, int32_t emoteID, LWOOBJID target, const SystemAddress& sysAddr);

View File

@ -180,7 +180,7 @@ int main(int argc, char** argv) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
CDClientManager::Instance(); CDClientManager::Instance().LoadValuesFromDatabase();
Diagnostics::SetProduceMemoryDump(Game::config->GetValue("generate_dump") == "1"); Diagnostics::SetProduceMemoryDump(Game::config->GetValue("generate_dump") == "1");

View File

@ -4,6 +4,7 @@
#include "Game.h" #include "Game.h"
#include "Logger.h" #include "Logger.h"
#include "dServer.h" #include "dServer.h"
#include "CDClientManager.h"
#include "EntityInfo.h" #include "EntityInfo.h"
#include "EntityManager.h" #include "EntityManager.h"
#include "dConfig.h" #include "dConfig.h"
@ -33,6 +34,9 @@ protected:
Game::server = new dServerMock(); Game::server = new dServerMock();
Game::config = new dConfig("worldconfig.ini"); Game::config = new dConfig("worldconfig.ini");
Game::entityManager = new EntityManager(); Game::entityManager = new EntityManager();
// Create a CDClientManager instance and load from defaults
CDClientManager::Instance().LoadValuesFromDefaults();
} }
void TearDownDependencies() { void TearDownDependencies() {

View File

@ -1,5 +1,6 @@
set(DCOMPONENTS_TESTS set(DCOMPONENTS_TESTS
"DestroyableComponentTests.cpp" "DestroyableComponentTests.cpp"
"PetComponentTests.cpp"
"SimplePhysicsComponentTests.cpp" "SimplePhysicsComponentTests.cpp"
) )

View File

@ -0,0 +1,43 @@
#include "GameDependencies.h"
#include <gtest/gtest.h>
#include "BitStream.h"
#include "PetComponent.h"
#include "Entity.h"
#include "eReplicaComponentType.h"
#include "ePetAbilityType.h"
#include "eStateChangeType.h"
class PetTest : public GameDependenciesTest {
protected:
Entity* baseEntity;
PetComponent* petComponent;
CBITSTREAM
void SetUp() override {
SetUpDependencies();
// Set up entity and pet component
baseEntity = new Entity(15, GameDependenciesTest::info);
petComponent = baseEntity->AddComponent<PetComponent>(1);
// Initialize some values to be not default
}
void TearDown() override {
delete baseEntity;
TearDownDependencies();
}
};
TEST_F(PetTest, PlacementNewAddComponentTest) {
// Test adding component
ASSERT_NE(petComponent, nullptr);
baseEntity->AddComponent<PetComponent>(1);
ASSERT_NE(baseEntity->GetComponent<PetComponent>(), nullptr);
// Test getting initial status
ASSERT_EQ(petComponent->GetParent()->GetObjectID(), 15);
ASSERT_EQ(petComponent->GetAbility(), ePetAbilityType::Invalid);
}