diff --git a/conf/CFBG.conf.dist b/conf/CFBG.conf.dist index e9c91b1..5b1fabc 100644 --- a/conf/CFBG.conf.dist +++ b/conf/CFBG.conf.dist @@ -110,10 +110,11 @@ # # CFBG.BalanceTeamsOnEntry.Enabled # Description: When a solo player enters a battleground while the teams are -# uneven, move them to the smaller team according to the live -# in-BG head counts at that moment. If the teams are already -# even they keep the team chosen at invite time, and grouped -# players are never moved. +# uneven, move them to the smaller team according to the +# invited counts at that moment (players inside plus accepted +# or pending invitees still on their way). If the teams are +# already even they keep the team chosen at invite time, and +# grouped players are never moved. # Default: 1 - (Enabled) # 0 - (Disabled) diff --git a/src/CFBG.cpp b/src/CFBG.cpp index b2d9b97..d47c889 100644 --- a/src/CFBG.cpp +++ b/src/CFBG.cpp @@ -376,10 +376,19 @@ void CFBG::BalanceTeamsOnEntry(Battleground* bg, Player* player) TeamId provisional = player->GetBgTeamId(); - // Live head counts correctly EXCLUDE the entering player (counted later in - // Battleground::AddPlayer). - int32 countA = bg->GetPlayersCountByTeam(TEAM_ALLIANCE); - int32 countH = bg->GetPlayersCountByTeam(TEAM_HORDE); + // The invited ledger (entered + accepted-in-flight + pending-invited) sees + // reservations that live head counts miss while invitees are still porting + // (issue #172: a solo flipped onto a porting premade's side -> 1v3). + int32 countA = bg->GetInvitedCount(TEAM_ALLIANCE); + int32 countH = bg->GetInvitedCount(TEAM_HORDE); + + // Accept does not release the reservation (RemovePlayer with + // decreaseInvitedCount=false), so the entrant is still ledgered on the + // provisional side: exclude them from the comparison. + if (provisional == TEAM_ALLIANCE) + --countA; + else + --countH; // Sides already balanced: keep the provisional team, no morph / count churn. if (countA == countH) @@ -735,6 +744,13 @@ std::array CFBG::GetProjectedBaseCounts(Battleground* bg, Battlegroun if (gInfo->IsInvitedToBGInstanceGUID == bg->GetInstanceID()) counts[gInfo->teamId] += gInfo->Players.size(); + // A player between accept and worldport ack is in neither term above (the + // accept deleted their ginfo; AddPlayer has not run yet). The BG's invited + // ledger still holds every reservation, so clamp up to it; max() degrades + // gracefully if either register is skewed. + counts[TEAM_ALLIANCE] = std::max(counts[TEAM_ALLIANCE], bg->GetInvitedCount(TEAM_ALLIANCE)); + counts[TEAM_HORDE] = std::max(counts[TEAM_HORDE], bg->GetInvitedCount(TEAM_HORDE)); + return counts; }