mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-29 07:57:14 +00:00
fix(destroyable): take template factions from factionList, keeping -1
The client reads an object's factions only from the DestructibleComponent factionList (LWODestroyableComponent::LoadDataFromTemplate 0x00c9f900: one atol per comma-separated token, -1 kept; the faction column is not read), and live replicated that list: [-1] on 12,829 constructions (vendors, quickbuilds, bouncers). DLU added the faction column and dropped -1, so those objects were sent with no factions, and the four rows with faction 6 but factionList "-1" were sent as [6]. -1 has no Factions row, so it adds no friends or enemies. Test: ReplicaConstructionTest.TemplateFactionMinusOneIsReplicated. Check in game: vendors, quickbuilds, bouncers and NPCs still can't be attacked; enemies still fight players and pets; smashables still smash. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -475,18 +475,7 @@ void Entity::Initialize() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!destCompData.empty()) {
|
if (!destCompData.empty()) comp->AddTemplateFactions(destCompData[0].factionList);
|
||||||
comp->AddFaction(destCompData[0].faction);
|
|
||||||
std::stringstream ss(destCompData[0].factionList);
|
|
||||||
std::string token;
|
|
||||||
|
|
||||||
while (std::getline(ss, token, ',')) {
|
|
||||||
const auto tokenInt = GeneralUtils::TryParse<int32_t>(token);
|
|
||||||
if (tokenInt == destCompData[0].faction) continue;
|
|
||||||
|
|
||||||
if (tokenInt) comp->AddFaction(tokenInt.value());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Level files can replace the factions with set_faction, unless override_faction is 0
|
// Level files can replace the factions with set_faction, unless override_faction is 0
|
||||||
const auto levelFactions = DestroyableComponent::GetLevelFactions(*this);
|
const auto levelFactions = DestroyableComponent::GetLevelFactions(*this);
|
||||||
|
|||||||
@@ -357,6 +357,18 @@ void DestroyableComponent::SetIsShielded(bool value) {
|
|||||||
m_IsShielded = value;
|
m_IsShielded = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DestroyableComponent::AddTemplateFactions(const std::string& factionList) {
|
||||||
|
// The client (LWODestroyableComponent::LoadDataFromTemplate) and live took the factions from the row's factionList,
|
||||||
|
// -1 included (live replicated it as [-1]); the faction column is not used.
|
||||||
|
std::stringstream ss(factionList);
|
||||||
|
std::string token;
|
||||||
|
|
||||||
|
while (std::getline(ss, token, ',')) {
|
||||||
|
const auto faction = GeneralUtils::TryParse<int32_t>(token);
|
||||||
|
if (faction) AddFaction(faction.value(), faction.value() == -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DestroyableComponent::AddFaction(const int32_t factionID, const bool ignoreChecks) {
|
void DestroyableComponent::AddFaction(const int32_t factionID, const bool ignoreChecks) {
|
||||||
// Ignore factionID -1
|
// Ignore factionID -1
|
||||||
if (factionID == -1 && !ignoreChecks) return;
|
if (factionID == -1 && !ignoreChecks) return;
|
||||||
|
|||||||
@@ -213,6 +213,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool GetIsShielded() const { return m_IsShielded; }
|
bool GetIsShielded() const { return m_IsShielded; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the factions in the object's DestructibleComponent factionList (comma separated), -1 included, as the client
|
||||||
|
* reads them
|
||||||
|
*/
|
||||||
|
void AddTemplateFactions(const std::string& factionList);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a faction to the faction list of this entity, potentially making more factions friendly. Fetches the info
|
* Adds a faction to the faction list of this entity, potentially making more factions friendly. Fetches the info
|
||||||
* from the CDClient.
|
* from the CDClient.
|
||||||
|
|||||||
@@ -218,6 +218,30 @@ TEST_F(ReplicaConstructionTest, SimplePhysicsConstructionLikeLive) {
|
|||||||
info.settings.values.clear();
|
info.settings.values.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Live replicated the DestructibleComponent factionList, so a list of -1 as [-1] (12,829 constructions: vendors,
|
||||||
|
// quickbuilds, bouncers; DLU dropped it and sent []), and a row with no faction but factionList 6 as [6].
|
||||||
|
TEST_F(ReplicaConstructionTest, TemplateFactionMinusOneIsReplicated) {
|
||||||
|
CDClientDatabase::Connect(":memory:");
|
||||||
|
CDClientDatabase::ExecuteDML("CREATE TABLE Factions (faction INTEGER, enemyList TEXT);");
|
||||||
|
CDClientDatabase::ExecuteDML("INSERT INTO Factions VALUES (4, '1'), (6, '');");
|
||||||
|
|
||||||
|
Entity vendor(15, info);
|
||||||
|
auto* const destroyable = vendor.AddComponent<DestroyableComponent>(-1);
|
||||||
|
destroyable->AddTemplateFactions("-1");
|
||||||
|
EXPECT_EQ(destroyable->GetFactionIDs(), std::vector<int32_t>{ -1 });
|
||||||
|
|
||||||
|
Entity enemy(16, info);
|
||||||
|
auto* const enemyDestroyable = enemy.AddComponent<DestroyableComponent>(-1);
|
||||||
|
enemyDestroyable->AddTemplateFactions("4");
|
||||||
|
EXPECT_EQ(enemyDestroyable->GetFactionIDs(), std::vector<int32_t>{ 4 });
|
||||||
|
EXPECT_EQ(enemyDestroyable->GetEnemyFactionsIDs(), std::vector<int32_t>{ 1 });
|
||||||
|
|
||||||
|
Entity smashable(17, info);
|
||||||
|
auto* const smashableDestroyable = smashable.AddComponent<DestroyableComponent>(-1);
|
||||||
|
smashableDestroyable->AddTemplateFactions("6");
|
||||||
|
EXPECT_EQ(smashableDestroyable->GetFactionIDs(), std::vector<int32_t>{ 6 });
|
||||||
|
}
|
||||||
|
|
||||||
class InventoryConstructionTest : public GameDependenciesTest {
|
class InventoryConstructionTest : public GameDependenciesTest {
|
||||||
protected:
|
protected:
|
||||||
// The items of the live sample below (CDClient 1.10.64 values)
|
// The items of the live sample below (CDClient 1.10.64 values)
|
||||||
|
|||||||
Reference in New Issue
Block a user