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.worldstate3, NeutralValuePct);
}
return ActivePlayers[player->GetTeamId()].insert(player->GetGUID()).second;
return ActivePlayers.insert(player->GetGUID()).second;
}
GuidUnorderedSet::iterator BfCapturePoint::HandlePlayerLeave(Player* player)
@@ -865,13 +865,12 @@ GuidUnorderedSet::iterator BfCapturePoint::HandlePlayerLeave(Player* player)
if (GameObject* go = GetCapturePointGo(player))
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()
current = ActivePlayers[player->GetTeamId()].erase(current);
return current;
return ActivePlayers.erase(current);
}
void BfCapturePoint::SendChangePhase()
@@ -880,17 +879,16 @@ void BfCapturePoint::SendChangePhase()
if (!capturePoint)
return;
for (uint8 team = 0; team < 2; ++team)
for (ObjectGuid const& guid : ActivePlayers[team]) // send to all players present in the area
if (Player* player = ObjectAccessor::FindPlayer(guid))
{
// send this too, sometimes the slider disappears, dunno why :(
player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldState1, 1);
// 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));
// send this too, sometimes it resets :S
player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate3, NeutralValuePct);
}
for (ObjectGuid const& guid : ActivePlayers) // send to all players present in the area
if (Player* player = ObjectAccessor::FindPlayer(guid))
{
// send this too, sometimes the slider disappears, dunno why :(
player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldState1, 1);
// 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));
// send this too, sometimes it resets :S
player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate3, NeutralValuePct);
}
}
bool BfCapturePoint::SetCapturePointData(GameObject* capturePoint, TeamId team)
@@ -962,19 +960,19 @@ bool BfCapturePoint::Update(uint32 diff)
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))
if (!capturePoint->IsWithinDistInMap(player, radius) || !player->IsOutdoorPvPActive())
{
itr = HandlePlayerLeave(player);
continue;
}
++counts[player->GetTeamId()];
++itr;
continue;
}
itr = (player ? HandlePlayerLeave(player) : ActivePlayers.erase(itr));
}
std::list<Player*> players;
@@ -984,11 +982,14 @@ bool BfCapturePoint::Update(uint32 diff)
for (Player* player : players)
if (player->IsOutdoorPvPActive())
if (ActivePlayers[player->GetTeamId()].insert(player->GetGUID()).second)
if (ActivePlayers.insert(player->GetGUID()).second)
{
HandlePlayerEnter(player);
++counts[player->GetTeamId()];
}
// 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))
return false;
@@ -1074,34 +1075,36 @@ bool BfCapturePoint::Update(uint32 diff)
void BfCapturePoint::SendUpdateWorldState(uint32 field, uint32 value)
{
for (uint8 team = 0; team < 2; ++team)
for (ObjectGuid const& guid : ActivePlayers[team]) // send to all players present in the area
if (Player* player = ObjectAccessor::FindPlayer(guid))
player->SendUpdateWorldState(field, value);
for (ObjectGuid const& guid : ActivePlayers) // send to all players present in the area
if (Player* player = ObjectAccessor::FindPlayer(guid))
player->SendUpdateWorldState(field, value);
}
void BfCapturePoint::SendObjectiveComplete(uint32 id, ObjectGuid guid)
{
uint8 team;
TeamId winner;
switch (State)
{
case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE:
team = 0;
winner = TEAM_ALLIANCE;
break;
case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE:
team = 1;
winner = TEAM_HORDE;
break;
default:
return;
}
// send to all players present in the area
for (ObjectGuid const& playerGuid : ActivePlayers[team])
// Credit only players on the controlling team. Team is read from the
// 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))
player->KilledMonsterCredit(id, guid);
if (player->GetTeamId() == winner)
player->KilledMonsterCredit(id, guid);
}
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:
bool DelCapturePoint();
// Active players in the area of the objective, 0 - alliance, 1 - horde
GuidUnorderedSet ActivePlayers[2];
// Active players in the area of the objective. Single set keyed by GUID:
// 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
float MaxValue;