From da801c61ab4bd0d8247f391f5566d0ce58e62f05 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 31 Aug 2025 22:13:57 +0000 Subject: [PATCH] Update CDBaseCombatAIComponentTable with complete column structure and add BuffComponent tests Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com> --- .../CDBaseCombatAIComponentTable.cpp | 26 +- .../CDBaseCombatAIComponentTable.h | 13 +- .../dComponentsTests/BuffComponentTests.cpp | 232 ++++++++++++++++++ 3 files changed, 268 insertions(+), 3 deletions(-) create mode 100644 tests/dGameTests/dComponentsTests/BuffComponentTests.cpp diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDBaseCombatAIComponentTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDBaseCombatAIComponentTable.cpp index 90baaaac..5ebb8d86 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDBaseCombatAIComponentTable.cpp +++ b/dDatabase/CDClientDatabase/CDClientTables/CDBaseCombatAIComponentTable.cpp @@ -4,11 +4,22 @@ namespace { // Default entries for fallback CDBaseCombatAIComponent defaultEntry{ .id = 1, - .aggroRadius = 25.0f, + .behaviorType = 0, + .combatRoundLength = 5.0f, + .combatRole = 0, + .minRoundLength = 3.0f, + .maxRoundLength = 8.0f, .tetherSpeed = 4.0f, .pursuitSpeed = 2.0f, + .combatStartDelay = 0.5f, .softTetherRadius = 25.0f, .hardTetherRadius = 100.0f, + .spawnTimer = 0.0f, + .tetherEffectID = 0, + .ignoreMediator = false, + .aggroRadius = 25.0f, + .ignoreStatReset = false, + .ignoreParent = false, }; } @@ -35,11 +46,22 @@ void CDBaseCombatAIComponentTable::LoadValuesFromDatabase() { CDBaseCombatAIComponent entry; entry.id = tableDataResult.getIntField("id", -1); - entry.aggroRadius = tableDataResult.getFloatField("aggroRadius", 25.0f); + entry.behaviorType = tableDataResult.getIntField("behaviorType", 0); + entry.combatRoundLength = tableDataResult.getFloatField("combatRoundLength", 5.0f); + entry.combatRole = tableDataResult.getIntField("combatRole", 0); + entry.minRoundLength = tableDataResult.getFloatField("minRoundLength", 3.0f); + entry.maxRoundLength = tableDataResult.getFloatField("maxRoundLength", 8.0f); entry.tetherSpeed = tableDataResult.getFloatField("tetherSpeed", 4.0f); entry.pursuitSpeed = tableDataResult.getFloatField("pursuitSpeed", 2.0f); + entry.combatStartDelay = tableDataResult.getFloatField("combatStartDelay", 0.5f); entry.softTetherRadius = tableDataResult.getFloatField("softTetherRadius", 25.0f); entry.hardTetherRadius = tableDataResult.getFloatField("hardTetherRadius", 100.0f); + entry.spawnTimer = tableDataResult.getFloatField("spawnTimer", 0.0f); + entry.tetherEffectID = tableDataResult.getIntField("tetherEffectID", 0); + entry.ignoreMediator = tableDataResult.getIntField("ignoreMediator", 0) != 0; + entry.aggroRadius = tableDataResult.getFloatField("aggroRadius", 25.0f); + entry.ignoreStatReset = tableDataResult.getIntField("ignoreStatReset", 0) != 0; + entry.ignoreParent = tableDataResult.getIntField("ignoreParent", 0) != 0; entries.push_back(entry); tableDataResult.nextRow(); diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDBaseCombatAIComponentTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDBaseCombatAIComponentTable.h index ca4af585..1b7fd695 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDBaseCombatAIComponentTable.h +++ b/dDatabase/CDClientDatabase/CDClientTables/CDBaseCombatAIComponentTable.h @@ -5,11 +5,22 @@ struct CDBaseCombatAIComponent { int32_t id; - float aggroRadius; + int32_t behaviorType; + float combatRoundLength; + int32_t combatRole; + float minRoundLength; + float maxRoundLength; float tetherSpeed; float pursuitSpeed; + float combatStartDelay; float softTetherRadius; float hardTetherRadius; + float spawnTimer; + int32_t tetherEffectID; + bool ignoreMediator; + float aggroRadius; + bool ignoreStatReset; + bool ignoreParent; }; class CDBaseCombatAIComponentTable : public CDTable> { diff --git a/tests/dGameTests/dComponentsTests/BuffComponentTests.cpp b/tests/dGameTests/dComponentsTests/BuffComponentTests.cpp new file mode 100644 index 00000000..ac78d44d --- /dev/null +++ b/tests/dGameTests/dComponentsTests/BuffComponentTests.cpp @@ -0,0 +1,232 @@ +#include "GameDependencies.h" +#include + +#include "BitStream.h" +#include "BuffComponent.h" +#include "Entity.h" +#include "eReplicaComponentType.h" + +class BuffComponentTest : public GameDependenciesTest { +protected: + Entity* baseEntity; + BuffComponent* buffComponent; + CBITSTREAM + uint32_t flags = 0; + + void SetUp() override { + SetUpDependencies(); + baseEntity = new Entity(15, GameDependenciesTest::info); + buffComponent = baseEntity->AddComponent(); + } + + void TearDown() override { + delete baseEntity; + TearDownDependencies(); + } +}; + +/** + * Test BuffComponent serialization with no buffs applied + */ +TEST_F(BuffComponentTest, BuffComponentSerializeNoBuffsTest) { + bitStream.Reset(); + + // With no buffs, should serialize empty state + buffComponent->Serialize(bitStream, true); + + // Read back the serialized data + bool hasBuffs; + bitStream.Read(hasBuffs); + EXPECT_EQ(hasBuffs, false); // No buffs applied + + bool immunityData; + bitStream.Read(immunityData); + EXPECT_EQ(immunityData, false); // Immunity data bit should be false +} + +/** + * Test BuffComponent serialization with single buff applied + */ +TEST_F(BuffComponentTest, BuffComponentSerializeSingleBuffTest) { + bitStream.Reset(); + + // Apply a buff with specific properties + int32_t buffId = 123; + float duration = 5.0f; + LWOOBJID source = 9876; + + buffComponent->ApplyBuff(buffId, duration, source, false, true, false, true, false, true, false, true, false); + buffComponent->Serialize(bitStream, true); + + // Read back the serialized data + bool hasBuffs; + bitStream.Read(hasBuffs); + EXPECT_EQ(hasBuffs, true); // Has buffs + + uint32_t buffCount; + bitStream.Read(buffCount); + EXPECT_EQ(buffCount, 1); // Should have 1 buff + + // Read buff data + uint32_t serializedBuffId; + bitStream.Read(serializedBuffId); + EXPECT_EQ(serializedBuffId, buffId); + + bool hasTime; + bitStream.Read(hasTime); + EXPECT_EQ(hasTime, true); // Buff has time + + uint32_t timeMs; + bitStream.Read(timeMs); + EXPECT_GT(timeMs, 0); // Should have positive time (approx 5000ms but could be slightly less due to timing) + EXPECT_LE(timeMs, 5000); // Should not exceed initial duration + + // Read cancel flags in order they're written + bool cancelOnDeath; + bitStream.Read(cancelOnDeath); + EXPECT_EQ(cancelOnDeath, false); // Set to false in ApplyBuff call + + bool cancelOnZone; + bitStream.Read(cancelOnZone); + EXPECT_EQ(cancelOnZone, true); // Set to true in ApplyBuff call + + bool cancelOnDamaged; + bitStream.Read(cancelOnDamaged); + EXPECT_EQ(cancelOnDamaged, true); // Set to true in ApplyBuff call + + bool cancelOnRemoveBuff; + bitStream.Read(cancelOnRemoveBuff); + EXPECT_EQ(cancelOnRemoveBuff, false); // Set to false in ApplyBuff call + + bool cancelOnUi; + bitStream.Read(cancelOnUi); + EXPECT_EQ(cancelOnUi, true); // Set to true in ApplyBuff call + + bool cancelOnLogout; + bitStream.Read(cancelOnLogout); + EXPECT_EQ(cancelOnLogout, false); // Set to false in ApplyBuff call + + bool cancelOnUnequip; + bitStream.Read(cancelOnUnequip); + EXPECT_EQ(cancelOnUnequip, true); // Set to true in ApplyBuff call + + bool cancelOnDamageAbsorbRanOut; + bitStream.Read(cancelOnDamageAbsorbRanOut); + EXPECT_EQ(cancelOnDamageAbsorbRanOut, false); // Always false + + bool addedByTeammate; + bitStream.Read(addedByTeammate); + EXPECT_EQ(addedByTeammate, false); // No team setup in test + + bool applyOnTeammates; + bitStream.Read(applyOnTeammates); + EXPECT_EQ(applyOnTeammates, false); // Set to false in ApplyBuff call + + uint32_t refCount; + bitStream.Read(refCount); + EXPECT_EQ(refCount, 1); // Should have ref count of 1 + + bool immunityData; + bitStream.Read(immunityData); + EXPECT_EQ(immunityData, false); // Immunity data bit should be false +} + +/** + * Test BuffComponent serialization with multiple buffs + */ +TEST_F(BuffComponentTest, BuffComponentSerializeMultipleBuffsTest) { + bitStream.Reset(); + + // Apply multiple buffs + buffComponent->ApplyBuff(100, 3.0f, 1000); + buffComponent->ApplyBuff(200, 0.0f, 2000); // Permanent buff (time = 0) + buffComponent->ApplyBuff(300, 10.0f, 3000); + + buffComponent->Serialize(bitStream, true); + + // Read back the serialized data + bool hasBuffs; + bitStream.Read(hasBuffs); + EXPECT_EQ(hasBuffs, true); + + uint32_t buffCount; + bitStream.Read(buffCount); + EXPECT_EQ(buffCount, 3); // Should have 3 buffs + + // Read first buff (ID 100) + uint32_t buffId1; + bitStream.Read(buffId1); + EXPECT_EQ(buffId1, 100); + + bool hasTime1; + bitStream.Read(hasTime1); + EXPECT_EQ(hasTime1, true); + + uint32_t timeMs1; + bitStream.Read(timeMs1); + EXPECT_GT(timeMs1, 0); + EXPECT_LE(timeMs1, 3000); + + // Skip the rest of first buff's flags (8 bools + team stuff + refcount) + bool dummy; + for (int i = 0; i < 8; i++) bitStream.Read(dummy); // cancel flags + bitStream.Read(dummy); // addedByTeammate + bitStream.Read(dummy); // applyOnTeammates + uint32_t dummyInt; + bitStream.Read(dummyInt); // refCount + + // Read second buff (ID 200) - permanent buff + uint32_t buffId2; + bitStream.Read(buffId2); + EXPECT_EQ(buffId2, 200); + + bool hasTime2; + bitStream.Read(hasTime2); + EXPECT_EQ(hasTime2, false); // Permanent buff has no time + + // Skip the rest of second buff's flags + for (int i = 0; i < 8; i++) bitStream.Read(dummy); + bitStream.Read(dummy); + bitStream.Read(dummy); + bitStream.Read(dummyInt); + + // Read third buff (ID 300) + uint32_t buffId3; + bitStream.Read(buffId3); + EXPECT_EQ(buffId3, 300); + + bool hasTime3; + bitStream.Read(hasTime3); + EXPECT_EQ(hasTime3, true); + + uint32_t timeMs3; + bitStream.Read(timeMs3); + EXPECT_GT(timeMs3, 0); + EXPECT_LE(timeMs3, 10000); + + // Skip the rest of third buff's flags + for (int i = 0; i < 8; i++) bitStream.Read(dummy); + bitStream.Read(dummy); + bitStream.Read(dummy); + bitStream.Read(dummyInt); + + bool immunityData; + bitStream.Read(immunityData); + EXPECT_EQ(immunityData, false); +} + +/** + * Test BuffComponent regular update serialization (should not serialize) + */ +TEST_F(BuffComponentTest, BuffComponentSerializeRegularUpdateTest) { + bitStream.Reset(); + + // Apply a buff first + buffComponent->ApplyBuff(123, 5.0f, 9876); + + // Regular update should not serialize anything + buffComponent->Serialize(bitStream, false); + + // BitStream should be empty for regular updates + EXPECT_EQ(bitStream.GetNumberOfBitsUsed(), 0); +} \ No newline at end of file