fix(Core/Battlefield): collapse BfCapturePoint::ActivePlayers to single set (#26034)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Andrew
2026-05-30 21:20:20 -03:00
committed by GitHub
parent 919eefef7e
commit f8ceac0468
2 changed files with 45 additions and 40 deletions
+41 -38
View File
@@ -857,7 +857,7 @@ bool BfCapturePoint::HandlePlayerEnter(Player* player)
player->SendUpdateWorldState(go->GetGOInfo()->capturePoint.worldstate2, uint32(std::ceil((Value + MaxValue) / (2 * MaxValue) * 100.0f))); player->SendUpdateWorldState(go->GetGOInfo()->capturePoint.worldstate2, uint32(std::ceil((Value + MaxValue) / (2 * MaxValue) * 100.0f)));
player->SendUpdateWorldState(go->GetGOInfo()->capturePoint.worldstate3, NeutralValuePct); player->SendUpdateWorldState(go->GetGOInfo()->capturePoint.worldstate3, NeutralValuePct);
} }
return ActivePlayers[player->GetTeamId()].insert(player->GetGUID()).second; return ActivePlayers.insert(player->GetGUID()).second;
} }
GuidUnorderedSet::iterator BfCapturePoint::HandlePlayerLeave(Player* player) GuidUnorderedSet::iterator BfCapturePoint::HandlePlayerLeave(Player* player)
@@ -865,13 +865,12 @@ GuidUnorderedSet::iterator BfCapturePoint::HandlePlayerLeave(Player* player)
if (GameObject* go = GetCapturePointGo(player)) if (GameObject* go = GetCapturePointGo(player))
player->SendUpdateWorldState(go->GetGOInfo()->capturePoint.worldState1, 0); player->SendUpdateWorldState(go->GetGOInfo()->capturePoint.worldState1, 0);
GuidUnorderedSet::iterator current = ActivePlayers[player->GetTeamId()].find(player->GetGUID()); GuidUnorderedSet::iterator current = ActivePlayers.find(player->GetGUID());
if (current == ActivePlayers[player->GetTeamId()].end()) if (current == ActivePlayers.end())
return current; // return end() return current; // return end()
current = ActivePlayers[player->GetTeamId()].erase(current); return ActivePlayers.erase(current);
return current;
} }
void BfCapturePoint::SendChangePhase() void BfCapturePoint::SendChangePhase()
@@ -880,17 +879,16 @@ void BfCapturePoint::SendChangePhase()
if (!capturePoint) if (!capturePoint)
return; return;
for (uint8 team = 0; team < 2; ++team) for (ObjectGuid const& guid : ActivePlayers) // send to all players present in the area
for (ObjectGuid const& guid : ActivePlayers[team]) // send to all players present in the area if (Player* player = ObjectAccessor::FindPlayer(guid))
if (Player* player = ObjectAccessor::FindPlayer(guid)) {
{ // send this too, sometimes the slider disappears, dunno why :(
// send this too, sometimes the slider disappears, dunno why :( player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldState1, 1);
player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldState1, 1); // send these updates to only the ones in this objective
// send these updates to only the ones in this objective player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate2, (uint32) std::ceil((Value + MaxValue) / (2 * MaxValue) * 100.0f));
player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate2, (uint32) std::ceil((Value + MaxValue) / (2 * MaxValue) * 100.0f)); // send this too, sometimes it resets :S
// send this too, sometimes it resets :S player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate3, NeutralValuePct);
player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate3, NeutralValuePct); }
}
} }
bool BfCapturePoint::SetCapturePointData(GameObject* capturePoint, TeamId team) bool BfCapturePoint::SetCapturePointData(GameObject* capturePoint, TeamId team)
@@ -962,19 +960,19 @@ bool BfCapturePoint::Update(uint32 diff)
float radius = capturePoint->GetGOInfo()->capturePoint.radius; float radius = capturePoint->GetGOInfo()->capturePoint.radius;
for (uint8 team = 0; team < 2; ++team) // Single pass over the existing set: drop leavers, count survivors per team.
uint32 counts[PVP_TEAMS_COUNT] = { 0, 0 };
for (auto itr = ActivePlayers.begin(); itr != ActivePlayers.end();)
{ {
for (auto itr = ActivePlayers[team].begin(); itr != ActivePlayers[team].end();) Player* player = ObjectAccessor::FindPlayer(*itr);
if (player && capturePoint->IsWithinDistInMap(player, radius) && player->IsOutdoorPvPActive())
{ {
if (Player* player = ObjectAccessor::FindPlayer(*itr)) ++counts[player->GetTeamId()];
if (!capturePoint->IsWithinDistInMap(player, radius) || !player->IsOutdoorPvPActive())
{
itr = HandlePlayerLeave(player);
continue;
}
++itr; ++itr;
continue;
} }
itr = (player ? HandlePlayerLeave(player) : ActivePlayers.erase(itr));
} }
std::list<Player*> players; std::list<Player*> players;
@@ -984,11 +982,14 @@ bool BfCapturePoint::Update(uint32 diff)
for (Player* player : players) for (Player* player : players)
if (player->IsOutdoorPvPActive()) if (player->IsOutdoorPvPActive())
if (ActivePlayers[player->GetTeamId()].insert(player->GetGUID()).second) if (ActivePlayers.insert(player->GetGUID()).second)
{
HandlePlayerEnter(player); HandlePlayerEnter(player);
++counts[player->GetTeamId()];
}
// get the difference of numbers // get the difference of numbers
float factDiff = ((float) ActivePlayers[0].size() - (float) ActivePlayers[1].size()) * diff / BATTLEFIELD_OBJECTIVE_UPDATE_INTERVAL; float factDiff = ((float)counts[TEAM_ALLIANCE] - (float)counts[TEAM_HORDE]) * diff / BATTLEFIELD_OBJECTIVE_UPDATE_INTERVAL;
if (G3D::fuzzyEq(factDiff, 0.0f)) if (G3D::fuzzyEq(factDiff, 0.0f))
return false; return false;
@@ -1074,34 +1075,36 @@ bool BfCapturePoint::Update(uint32 diff)
void BfCapturePoint::SendUpdateWorldState(uint32 field, uint32 value) void BfCapturePoint::SendUpdateWorldState(uint32 field, uint32 value)
{ {
for (uint8 team = 0; team < 2; ++team) for (ObjectGuid const& guid : ActivePlayers) // send to all players present in the area
for (ObjectGuid const& guid : ActivePlayers[team]) // send to all players present in the area if (Player* player = ObjectAccessor::FindPlayer(guid))
if (Player* player = ObjectAccessor::FindPlayer(guid)) player->SendUpdateWorldState(field, value);
player->SendUpdateWorldState(field, value);
} }
void BfCapturePoint::SendObjectiveComplete(uint32 id, ObjectGuid guid) void BfCapturePoint::SendObjectiveComplete(uint32 id, ObjectGuid guid)
{ {
uint8 team; TeamId winner;
switch (State) switch (State)
{ {
case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE: case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE:
team = 0; winner = TEAM_ALLIANCE;
break; break;
case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE: case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE:
team = 1; winner = TEAM_HORDE;
break; break;
default: default:
return; return;
} }
// send to all players present in the area // Credit only players on the controlling team. Team is read from the
for (ObjectGuid const& playerGuid : ActivePlayers[team]) // player at iteration time, not at insert time, so players whose
// GetTeamId() changed mid-stay get credit on their current side.
for (ObjectGuid const& playerGuid : ActivePlayers)
if (Player* player = ObjectAccessor::FindPlayer(playerGuid)) if (Player* player = ObjectAccessor::FindPlayer(playerGuid))
player->KilledMonsterCredit(id, guid); if (player->GetTeamId() == winner)
player->KilledMonsterCredit(id, guid);
} }
bool BfCapturePoint::IsInsideObjective(Player* player) const bool BfCapturePoint::IsInsideObjective(Player* player) const
{ {
return ActivePlayers[player->GetTeamId()].find(player->GetGUID()) != ActivePlayers[player->GetTeamId()].end(); return ActivePlayers.find(player->GetGUID()) != ActivePlayers.end();
} }
+4 -2
View File
@@ -119,8 +119,10 @@ public:
protected: protected:
bool DelCapturePoint(); bool DelCapturePoint();
// Active players in the area of the objective, 0 - alliance, 1 - horde // Active players in the area of the objective. Single set keyed by GUID:
GuidUnorderedSet ActivePlayers[2]; // team is computed from Player::GetTeamId() at the point it is needed.
// Splitting by team here would desync if GetTeamId() changes mid-stay.
GuidUnorderedSet ActivePlayers;
// Total shift needed to capture the objective // Total shift needed to capture the objective
float MaxValue; float MaxValue;