Fix CDClient database dependency issues for component tests by implementing LoadValuesFromDefaults and database connectivity checks

Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2025-09-01 15:22:58 +00:00
parent 9274494023
commit d3b5941458
17 changed files with 247 additions and 13 deletions

View File

@@ -161,4 +161,11 @@ void CDClientManager::LoadValuesFromDefaults() {
CDActivitiesTable::Instance().LoadValuesFromDefaults();
CDActivityRewardsTable::Instance().LoadValuesFromDefaults();
CDCurrencyTableTable::Instance().LoadValuesFromDefaults();
CDMissionsTable::Instance().LoadValuesFromDefaults();
CDComponentsRegistryTable::Instance().LoadValuesFromDefaults();
CDItemComponentTable::Instance().LoadValuesFromDefaults();
CDSkillBehaviorTable::Instance().LoadValuesFromDefaults();
CDVendorComponentTable::Instance().LoadValuesFromDefaults();
CDLootMatrixTable::Instance().LoadValuesFromDefaults();
CDLootTableTable::Instance().LoadValuesFromDefaults();
}

View File

@@ -20,6 +20,20 @@ void CDComponentsRegistryTable::LoadValuesFromDatabase() {
tableData.finalize();
}
void CDComponentsRegistryTable::LoadValuesFromDefaults() {
auto& entries = GetEntriesMutable();
entries.clear();
// Add some default component registrations for common LOTs
// Component type ITEM (LOT 1000)
entries.insert_or_assign(static_cast<uint64_t>(eReplicaComponentType::ITEM) << 32 | static_cast<uint64_t>(1000), 1);
entries.insert_or_assign(1000, 0);
// Component type VENDOR (LOT 2000)
entries.insert_or_assign(static_cast<uint64_t>(eReplicaComponentType::VENDOR) << 32 | static_cast<uint64_t>(2000), 1);
entries.insert_or_assign(2000, 0);
}
int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue) {
auto& entries = GetEntriesMutable();
auto exists = entries.find(id);
@@ -28,6 +42,12 @@ int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponent
return iter == entries.end() ? defaultValue : iter->second;
}
// If database is not connected (e.g., in tests), return default value
if (!CDClientDatabase::isConnected) {
entries.insert_or_assign(id, 0);
return defaultValue;
}
// Now get the data. Get all components of this entity so we dont do a query for each component
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM ComponentsRegistry WHERE id = ?;");
query.bind(1, static_cast<int32_t>(id));

View File

@@ -16,5 +16,6 @@ struct CDComponentsRegistry {
class CDComponentsRegistryTable : public CDTable<CDComponentsRegistryTable, std::unordered_map<uint64_t, uint32_t>> {
public:
void LoadValuesFromDatabase();
void LoadValuesFromDefaults();
int32_t GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue = 0);
};

View File

@@ -70,6 +70,56 @@ void CDItemComponentTable::LoadValuesFromDatabase() {
tableData.finalize();
}
void CDItemComponentTable::LoadValuesFromDefaults() {
auto& entries = GetEntriesMutable();
entries.clear();
// Add default item component entry
CDItemComponent defaultEntry{
.id = 1,
.equipLocation = "",
.baseValue = 0,
.isKitPiece = false,
.rarity = 0,
.itemType = 0,
.itemInfo = 0,
.inLootTable = false,
.inVendor = false,
.isUnique = false,
.isBOP = false,
.isBOE = false,
.reqFlagID = 0,
.reqSpecialtyID = 0,
.reqSpecRank = 0,
.reqAchievementID = 0,
.stackSize = 1,
.color1 = 0,
.decal = 0,
.offsetGroupID = 0,
.buildTypes = 0,
.reqPrecondition = "",
.animationFlag = 0,
.equipEffects = 0,
.readyForQA = false,
.itemRating = 0,
.isTwoHanded = false,
.minNumRequired = 0,
.delResIndex = 0,
.currencyLOT = 0,
.altCurrencyCost = 0,
.subItems = "",
.noEquipAnimation = false,
.commendationLOT = 0,
.commendationCost = 0,
.currencyCosts = "",
.locStatus = 0,
.forgeType = 0,
.SellMultiplier = 1.0f,
};
entries.insert(std::make_pair(defaultEntry.id, defaultEntry));
}
const CDItemComponent& CDItemComponentTable::GetItemComponentByID(uint32_t skillID) {
auto& entries = GetEntriesMutable();
const auto& it = entries.find(skillID);
@@ -77,6 +127,12 @@ const CDItemComponent& CDItemComponentTable::GetItemComponentByID(uint32_t skill
return it->second;
}
// If database is not connected (e.g., in tests), return the default entry
if (!CDClientDatabase::isConnected) {
entries.insert(std::make_pair(skillID, Default));
return Default;
}
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM ItemComponent WHERE id = ?;");
query.bind(1, static_cast<int32_t>(skillID));

View File

@@ -52,6 +52,7 @@ struct CDItemComponent {
class CDItemComponentTable : public CDTable<CDItemComponentTable, std::map<uint32_t, CDItemComponent>> {
public:
void LoadValuesFromDatabase();
void LoadValuesFromDefaults();
static std::map<LOT, uint32_t> ParseCraftingCurrencies(const CDItemComponent& itemComponent);
// Gets an entry by ID

View File

@@ -39,6 +39,23 @@ void CDLootMatrixTable::LoadValuesFromDatabase() {
}
}
void CDLootMatrixTable::LoadValuesFromDefaults() {
auto& entries = GetEntriesMutable();
entries.clear();
// Add default loot matrix entry
CDLootMatrix defaultEntry{
.LootTableIndex = 1,
.RarityTableIndex = 1,
.percent = 1.0f,
.minToDrop = 1,
.maxToDrop = 1,
.flagID = 0,
};
entries[0].push_back(defaultEntry);
}
const LootMatrixEntries& CDLootMatrixTable::GetMatrix(uint32_t matrixId) {
auto& entries = GetEntriesMutable();
auto itr = entries.find(matrixId);
@@ -46,6 +63,11 @@ const LootMatrixEntries& CDLootMatrixTable::GetMatrix(uint32_t matrixId) {
return itr->second;
}
// If database is not connected (e.g., in tests), return empty vector
if (!CDClientDatabase::isConnected) {
return entries[matrixId]; // Creates empty vector
}
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM LootMatrix where LootMatrixIndex = ?;");
query.bind(1, static_cast<int32_t>(matrixId));

View File

@@ -19,6 +19,7 @@ typedef std::vector<CDLootMatrix> LootMatrixEntries;
class CDLootMatrixTable : public CDTable<CDLootMatrixTable, std::unordered_map<LootMatrixIndex, LootMatrixEntries>> {
public:
void LoadValuesFromDatabase();
void LoadValuesFromDefaults();
// Gets a matrix by ID or inserts a blank one if none existed.
const LootMatrixEntries& GetMatrix(uint32_t matrixId);

View File

@@ -66,6 +66,21 @@ void CDLootTableTable::LoadValuesFromDatabase() {
}
}
void CDLootTableTable::LoadValuesFromDefaults() {
auto& entries = GetEntriesMutable();
entries.clear();
// Add default loot table entry
CDLootTable defaultEntry{
.itemid = 1000,
.LootTableIndex = 1,
.MissionDrop = false,
.sortPriority = 1,
};
entries[1].push_back(defaultEntry);
}
const LootTableEntries& CDLootTableTable::GetTable(const uint32_t tableId) {
auto& entries = GetEntriesMutable();
auto itr = entries.find(tableId);
@@ -73,6 +88,11 @@ const LootTableEntries& CDLootTableTable::GetTable(const uint32_t tableId) {
return itr->second;
}
// If database is not connected (e.g., in tests), return empty vector
if (!CDClientDatabase::isConnected) {
return entries[tableId]; // Creates empty vector
}
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM LootTable WHERE LootTableIndex = ?;");
query.bind(1, static_cast<int32_t>(tableId));
auto tableData = query.execQuery();

View File

@@ -21,6 +21,7 @@ private:
public:
void LoadValuesFromDatabase();
void LoadValuesFromDefaults();
// Queries the table with a custom "where" clause
const LootTableEntries& GetTable(const uint32_t tableId);
};

View File

@@ -83,6 +83,67 @@ void CDMissionsTable::LoadValuesFromDatabase() {
Default.id = -1;
}
void CDMissionsTable::LoadValuesFromDefaults() {
auto& entries = GetEntriesMutable();
entries.clear();
// Add default mission entry
CDMissions defaultEntry{
.id = 1,
.defined_type = "Mission",
.defined_subtype = "",
.UISortOrder = 0,
.offer_objectID = -1,
.target_objectID = -1,
.reward_currency = 0,
.LegoScore = 0,
.reward_reputation = 0,
.isChoiceReward = false,
.reward_item1 = 0,
.reward_item1_count = 0,
.reward_item2 = 0,
.reward_item2_count = 0,
.reward_item3 = 0,
.reward_item3_count = 0,
.reward_item4 = 0,
.reward_item4_count = 0,
.reward_emote = -1,
.reward_emote2 = -1,
.reward_emote3 = -1,
.reward_emote4 = -1,
.reward_maximagination = -1,
.reward_maxhealth = -1,
.reward_maxinventory = -1,
.reward_maxmodel = -1,
.reward_maxwidget = -1,
.reward_maxwallet = -1,
.repeatable = false,
.reward_currency_repeatable = 0,
.reward_item1_repeatable = 0,
.reward_item1_repeat_count = 0,
.reward_item2_repeatable = 0,
.reward_item2_repeat_count = 0,
.reward_item3_repeatable = 0,
.reward_item3_repeat_count = 0,
.reward_item4_repeatable = 0,
.reward_item4_repeat_count = 0,
.time_limit = -1,
.isMission = true,
.missionIconID = -1,
.prereqMissionID = "",
.localize = false,
.inMOTD = false,
.cooldownTime = -1,
.isRandom = false,
.randomPool = "",
.UIPrereqID = -1,
.reward_bankinventory = -1,
};
entries.push_back(defaultEntry);
Default.id = -1;
}
std::vector<CDMissions> CDMissionsTable::Query(std::function<bool(CDMissions)> predicate) {
std::vector<CDMissions> data = cpplinq::from(GetEntries())

View File

@@ -63,6 +63,7 @@ struct CDMissions {
class CDMissionsTable : public CDTable<CDMissionsTable, std::vector<CDMissions>> {
public:
void LoadValuesFromDatabase();
void LoadValuesFromDefaults();
// Queries the table with a custom "where" clause
std::vector<CDMissions> Query(std::function<bool(CDMissions)> predicate);

View File

@@ -50,6 +50,22 @@ void CDSkillBehaviorTable::LoadValuesFromDatabase() {
tableData.finalize();
}
void CDSkillBehaviorTable::LoadValuesFromDefaults() {
auto& entries = GetEntriesMutable();
entries.clear();
// Add default skill behavior entry
CDSkillBehavior defaultEntry{
.skillID = 1,
.behaviorID = 1,
.imaginationcost = 0,
.cooldowngroup = 0,
.cooldown = 0.0f,
};
entries.insert(std::make_pair(defaultEntry.skillID, defaultEntry));
}
const CDSkillBehavior& CDSkillBehaviorTable::GetSkillByID(uint32_t skillID) {
auto& entries = GetEntries();
auto it = entries.find(skillID);

View File

@@ -28,6 +28,7 @@ struct CDSkillBehavior {
class CDSkillBehaviorTable : public CDTable<CDSkillBehaviorTable, std::map<uint32_t, CDSkillBehavior>> {
public:
void LoadValuesFromDatabase();
void LoadValuesFromDefaults();
// Gets an entry by skillID
const CDSkillBehavior& GetSkillByID(uint32_t skillID);

View File

@@ -34,6 +34,22 @@ void CDVendorComponentTable::LoadValuesFromDatabase() {
tableData.finalize();
}
void CDVendorComponentTable::LoadValuesFromDefaults() {
auto& entries = GetEntriesMutable();
entries.clear();
// Add default vendor component entry
CDVendorComponent defaultEntry{
.id = 1,
.buyScalar = 1.0f,
.sellScalar = 1.0f,
.refreshTimeSeconds = 0.0f,
.LootMatrixIndex = 0,
};
entries.push_back(defaultEntry);
}
//! Queries the table with a custom "where" clause
std::vector<CDVendorComponent> CDVendorComponentTable::Query(std::function<bool(CDVendorComponent)> predicate) {

View File

@@ -14,6 +14,7 @@ struct CDVendorComponent {
class CDVendorComponentTable : public CDTable<CDVendorComponentTable, std::vector<CDVendorComponent>> {
public:
void LoadValuesFromDatabase();
void LoadValuesFromDefaults();
// Queries the table with a custom "where" clause
std::vector<CDVendorComponent> Query(std::function<bool(CDVendorComponent)> predicate);
};

View File

@@ -68,6 +68,8 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id)
/*
* Find skills
*/
// Only execute skill query if database is connected
if (CDClientDatabase::isConnected) {
auto skillQuery = CDClientDatabase::CreatePreppedStmt(
"SELECT skillID, cooldown, behaviorID FROM SkillBehavior WHERE skillID IN (SELECT skillID FROM ObjectSkills WHERE objectTemplate = ?);");
skillQuery.bind(1, static_cast<int>(parent->GetLOT()));
@@ -91,6 +93,7 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id)
result.nextRow();
}
}
Stun(1.0f);

View File

@@ -435,6 +435,12 @@ const std::vector<BuffParameter>& BuffComponent::GetBuffParameters(int32_t buffI
return pair->second;
}
// If database is not connected (e.g., in tests), return empty parameters
if (!CDClientDatabase::isConnected) {
m_Cache.insert_or_assign(buffId, std::vector<BuffParameter>{});
return m_Cache.find(buffId)->second;
}
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM BuffParameters WHERE BuffID = ?;");
query.bind(1, static_cast<int>(buffId));