bool UPartyBeaconState::SwapTeams(const FUniqueNetIdRepl& PartyLeader, const FUniqueNetIdRepl& OtherPartyLeader) { bool bSuccess = false; int32 ResIdx = GetExistingReservation(PartyLeader); int32 OtherResIdx = GetExistingReservation(OtherPartyLeader); if (ResIdx != INDEX_NONE && OtherResIdx != INDEX_NONE) { FPartyReservation& PartyRes = Reservations[ResIdx]; FPartyReservation& OtherPartyRes = Reservations[OtherResIdx]; if (PartyRes.TeamNum != OtherPartyRes.TeamNum) { int32 TeamSize = GetNumPlayersOnTeam(PartyRes.TeamNum); int32 OtherTeamSize = GetNumPlayersOnTeam(OtherPartyRes.TeamNum); // Will the new teams fit bool bValidTeamSizeA = (PartyRes.PartyMembers.Num() + (OtherTeamSize - OtherPartyRes.PartyMembers.Num())) <= NumPlayersPerTeam; bool bValidTeamSizeB = (OtherPartyRes.PartyMembers.Num() + (TeamSize - PartyRes.PartyMembers.Num())) <= NumPlayersPerTeam; if (bValidTeamSizeA && bValidTeamSizeB) { Swap(PartyRes.TeamNum, OtherPartyRes.TeamNum); bSuccess = true; } } } return bSuccess; }
bool UPartyBeaconState::ReconfigureTeamAndPlayerCount(int32 InNumTeams, int32 InNumPlayersPerTeam, int32 InNumReservations) { bool bSuccess = false; //Check total existing reservations against new total maximum if (NumConsumedReservations < InNumReservations) { bool bTeamError = false; // Check teams with reservations against new team count if (NumTeams > InNumTeams) { // Any team about to be removed can't have players already there for (int32 TeamIdx = InNumTeams; TeamIdx < NumTeams; TeamIdx++) { if (GetNumPlayersOnTeam(TeamIdx) > 0) { bTeamError = true; UE_LOG(LogBeacon, Warning, TEXT("Beacon has players on a team about to be removed.")); } } } bool bTeamSizeError = false; // Check num players per team against new team size if (NumPlayersPerTeam > InNumPlayersPerTeam) { for (int32 TeamIdx = 0; TeamIdx<NumTeams; TeamIdx++) { if (GetNumPlayersOnTeam(TeamIdx) > InNumPlayersPerTeam) { bTeamSizeError = true; UE_LOG(LogBeacon, Warning, TEXT("Beacon has too many players on a team about to be resized.")); } } } if (!bTeamError && !bTeamSizeError) { NumTeams = InNumTeams; NumPlayersPerTeam = InNumPlayersPerTeam; MaxReservations = InNumReservations; InitTeamArray(); bSuccess = true; UE_LOG(LogBeacon, Display, TEXT("Reconfiguring to team count (%d), team size (%d)"), NumTeams, NumPlayersPerTeam); } } else { UE_LOG(LogBeacon, Warning, TEXT("Beacon has too many consumed reservations for this reconfiguration, ignoring request.")); } return bSuccess; }
bool UPartyBeaconState::ChangeTeam(const FUniqueNetIdRepl& PartyLeader, int32 NewTeamNum) { bool bSuccess = false; if (NewTeamNum >= 0 && NewTeamNum < NumTeams) { int32 ResIdx = GetExistingReservation(PartyLeader); if (ResIdx != INDEX_NONE) { FPartyReservation& PartyRes = Reservations[ResIdx]; if (PartyRes.TeamNum != NewTeamNum) { int32 OtherTeamSize = GetNumPlayersOnTeam(NewTeamNum); bool bValidTeamSize = (PartyRes.PartyMembers.Num() + OtherTeamSize) <= NumPlayersPerTeam; if (bValidTeamSize) { PartyRes.TeamNum = NewTeamNum; bSuccess = true; } } } } return bSuccess; }
int32 UPartyBeaconState::GetMaxAvailableTeamSize() const { int32 MaxFreeSlots = 0; // find the largest available free slots within all the teams for (int32 TeamIdx = 0; TeamIdx < NumTeams; TeamIdx++) { MaxFreeSlots = FMath::Max<int32>(MaxFreeSlots, NumPlayersPerTeam - GetNumPlayersOnTeam(TeamIdx)); } return MaxFreeSlots; }
bool UPartyBeaconState::AreTeamsAvailable(const FPartyReservation& ReservationRequest) const { int32 IncomingPartySize = ReservationRequest.PartyMembers.Num(); for (int32 TeamIdx = 0; TeamIdx < NumTeams; TeamIdx++) { const int32 CurrentPlayersOnTeam = GetNumPlayersOnTeam(TeamIdx); if ((CurrentPlayersOnTeam + IncomingPartySize) <= NumPlayersPerTeam) { return true; } } return false; }
int32 UPartyBeaconState::GetTeamAssignment(const FPartyReservation& Party) { if (NumTeams > 1) { TArray<FTeamBalanceInfo> PotentialTeamChoices; for (int32 TeamIdx = 0; TeamIdx < NumTeams; TeamIdx++) { const int32 CurrentPlayersOnTeam = GetNumPlayersOnTeam(TeamIdx); if ((CurrentPlayersOnTeam + Party.PartyMembers.Num()) <= NumPlayersPerTeam) { new (PotentialTeamChoices)FTeamBalanceInfo(TeamIdx, CurrentPlayersOnTeam); } } // Grab one from our list of choices if (PotentialTeamChoices.Num() > 0) { if (TeamAssignmentMethod == ETeamAssignmentMethod::Smallest) { PotentialTeamChoices.Sort(FSortTeamSizeSmallestToLargest()); return PotentialTeamChoices[0].TeamIdx; } else if (TeamAssignmentMethod == ETeamAssignmentMethod::BestFit) { PotentialTeamChoices.Sort(FSortTeamSizeSmallestToLargest()); return PotentialTeamChoices[PotentialTeamChoices.Num() - 1].TeamIdx; } else if (TeamAssignmentMethod == ETeamAssignmentMethod::Random) { int32 TeamIndex = FMath::Rand() % PotentialTeamChoices.Num(); return PotentialTeamChoices[TeamIndex].TeamIdx; } } else { UE_LOG(LogBeacon, Warning, TEXT("UPartyBeaconHost::GetTeamAssignment: couldn't find an open team for party members.")); return INDEX_NONE; } } return ForceTeamNum; }
EPartyReservationResult::Type APartyBeaconHost::UpdatePartyReservation(const FPartyReservation& ReservationUpdateRequest) { EPartyReservationResult::Type Result = EPartyReservationResult::GeneralError; if (!State || GetBeaconState() == EBeaconState::DenyRequests) { return EPartyReservationResult::ReservationDenied; } if (ReservationUpdateRequest.IsValid()) { if (!State->IsBeaconFull()) { const int32 ExistingReservationIdx = State->GetExistingReservation(ReservationUpdateRequest.PartyLeader); if (ExistingReservationIdx != INDEX_NONE) { // Count the number of available slots for the existing reservation's team TArray<FPartyReservation>& Reservations = State->GetReservations(); FPartyReservation& ExistingReservation = Reservations[ExistingReservationIdx]; const int32 NumTeamMembers = GetNumPlayersOnTeam(ExistingReservation.TeamNum); const int32 NumAvailableSlotsOnTeam = FMath::Max<int32>(0, GetMaxPlayersPerTeam() - NumTeamMembers); // Read the list of new players and remove the ones that have existing reservation entries TArray<FPlayerReservation> NewPlayers; for (int32 PlayerIdx = 0; PlayerIdx < ReservationUpdateRequest.PartyMembers.Num(); PlayerIdx++) { const FPlayerReservation& NewPlayerRes = ReservationUpdateRequest.PartyMembers[PlayerIdx]; FPlayerReservation* PlayerRes = ExistingReservation.PartyMembers.FindByPredicate( [NewPlayerRes](const FPlayerReservation& ExistingPlayerRes) { return NewPlayerRes.UniqueId == ExistingPlayerRes.UniqueId; }); if (!PlayerRes) { // player reservation doesn't exist so add it as a new player NewPlayers.Add(NewPlayerRes); } else { // duplicate entry for this player UE_LOG(LogBeacon, Log, TEXT("Skipping player %s"), *NewPlayerRes.UniqueId.ToString()); } } // Validate that adding the new party members to this reservation entry still fits within the team size if (NewPlayers.Num() <= NumAvailableSlotsOnTeam) { if (NewPlayers.Num() > 0) { // Copy new player entries into existing reservation for (int32 PlayerIdx = 0; PlayerIdx < NewPlayers.Num(); PlayerIdx++) { const FPlayerReservation& PlayerRes = NewPlayers[PlayerIdx]; ExistingReservation.PartyMembers.Add(PlayerRes); // Keep track of newly added players NewPlayerAdded(PlayerRes); } // Update the reservation count before sending the response State->NumConsumedReservations += NewPlayers.Num(); // Tell any UI and/or clients that there has been a change in the reservation state SendReservationUpdates(); // Tell the owner that we've received a reservation so the UI can be updated NotifyReservationEventNextFrame(ReservationChanged); if (State->IsBeaconFull()) { // If we've hit our limit, fire the delegate so the host can do the // next step in getting parties together NotifyReservationEventNextFrame(ReservationsFull); } Result = EPartyReservationResult::ReservationAccepted; } else { // Duplicate entries (or zero) so existing reservation not updated Result = EPartyReservationResult::ReservationDuplicate; } } else { // Send an invalid party size response Result = EPartyReservationResult::IncorrectPlayerCount; } } else { // Send a not found reservation response Result = EPartyReservationResult::ReservationNotFound; } } else { // Send a session full response Result = EPartyReservationResult::PartyLimitReached; } } else { // Invalid reservation Result = EPartyReservationResult::ReservationInvalid; } return Result; }