diff --git a/src/main/scala/net/psforever/actors/session/support/SessionSquadHandlers.scala b/src/main/scala/net/psforever/actors/session/support/SessionSquadHandlers.scala index 9daeac6f..e3ff2bb0 100644 --- a/src/main/scala/net/psforever/actors/session/support/SessionSquadHandlers.scala +++ b/src/main/scala/net/psforever/actors/session/support/SessionSquadHandlers.scala @@ -55,17 +55,17 @@ class SessionSquadHandlers( /* packet */ def handleSquadDefinitionAction(pkt: SquadDefinitionActionMessage): Unit = { -// val SquadDefinitionActionMessage(u1, u2, action) = pkt -// squadService ! SquadServiceMessage(player, continent, SquadServiceAction.Definition(u1, u2, action)) + val SquadDefinitionActionMessage(u1, u2, action) = pkt + squadService ! SquadServiceMessage(player, continent, SquadServiceAction.Definition(u1, u2, action)) } def handleSquadMemberRequest(pkt: SquadMembershipRequest): Unit = { -// val SquadMembershipRequest(request_type, char_id, unk3, player_name, unk5) = pkt -// squadService ! SquadServiceMessage( -// player, -// continent, -// SquadServiceAction.Membership(request_type, char_id, unk3, player_name, unk5) -// ) + val SquadMembershipRequest(request_type, char_id, unk3, player_name, unk5) = pkt + squadService ! SquadServiceMessage( + player, + continent, + SquadServiceAction.Membership(request_type, char_id, unk3, player_name, unk5) + ) } def handleSquadWaypointRequest(pkt: SquadWaypointRequest): Unit = { @@ -336,19 +336,19 @@ class SessionSquadHandlers( sendResponse(CharacterKnowledgeMessage(charId, Some(CharacterKnowledgeInfo(name, certs, u1, u2, zone)))) case SquadResponse.SquadSearchResults(results) => - //TODO positive squad search results message? - if(results.nonEmpty) { - results.foreach { guid => - sendResponse(SquadDefinitionActionMessage( - guid, - 0, - SquadAction.SquadListDecorator(SquadListDecoration.SearchResult)) - ) - } - } else { - sendResponse(SquadDefinitionActionMessage(player.GUID, 0, SquadAction.NoSquadSearchResults())) - } - sendResponse(SquadDefinitionActionMessage(player.GUID, 0, SquadAction.CancelSquadSearch())) + //TODO positive squad search results message? +// if(results.nonEmpty) { +// results.foreach { guid => +// sendResponse(SquadDefinitionActionMessage( +// guid, +// 0, +// SquadAction.SquadListDecorator(SquadListDecoration.SearchResult)) +// ) +// } +// } else { +// sendResponse(SquadDefinitionActionMessage(player.GUID, 0, SquadAction.NoSquadSearchResults())) +// } +// sendResponse(SquadDefinitionActionMessage(player.GUID, 0, SquadAction.CancelSquadSearch())) case SquadResponse.InitWaypoints(char_id, waypoints) => waypoints.foreach { diff --git a/src/main/scala/net/psforever/services/teamwork/SquadInvitationManager.scala b/src/main/scala/net/psforever/services/teamwork/SquadInvitationManager.scala index 9b7f3eb8..9e58d2fa 100644 --- a/src/main/scala/net/psforever/services/teamwork/SquadInvitationManager.scala +++ b/src/main/scala/net/psforever/services/teamwork/SquadInvitationManager.scala @@ -165,7 +165,7 @@ class SquadInvitationManager(subs: SquadSubscriptionEntity, parent: ActorRef) { val availableForJoiningSquad = notLimitedByEnrollmentInSquad(invitedPlayerSquadOpt, invitedPlayer) acceptedInvite match { case Some(RequestRole(petitioner, features, position)) - if availableForJoiningSquad && canEnrollInSquad(features, petitioner.CharId) => + if canEnrollInSquad(features, petitioner.CharId) => //player requested to join a squad's specific position //invitedPlayer is actually the squad leader; petitioner is the actual "invitedPlayer" if (JoinSquad(petitioner, features, position)) { @@ -174,7 +174,7 @@ class SquadInvitationManager(subs: SquadSubscriptionEntity, parent: ActorRef) { } case Some(IndirectInvite(recruit, features)) - if availableForJoiningSquad && canEnrollInSquad(features, recruit.CharId) => + if canEnrollInSquad(features, recruit.CharId) => //tplayer / invitedPlayer is actually the squad leader val recruitCharId = recruit.CharId HandleVacancyInvite(features, recruitCharId, invitedPlayer, recruit) match { @@ -426,14 +426,14 @@ class SquadInvitationManager(subs: SquadSubscriptionEntity, parent: ActorRef) { Refused(rejectingPlayer, invitingPlayerCharId) (Some(rejectingPlayer), Some(invitingPlayerCharId)) - case Some(VacancyInvite(leader, _, features)) - if notLeaderOfThisSquad(squadsToLeaders, features.Squad.GUID, rejectingPlayer) => + case Some(VacancyInvite(leader, _, _)) + /*if notLeaderOfThisSquad(squadsToLeaders, features.Squad.GUID, rejectingPlayer)*/ => //rejectingPlayer is the would-be squad member; the squad leader sent the request and was rejected Refused(rejectingPlayer, leader) (Some(rejectingPlayer), Some(leader)) case Some(ProximityInvite(_, features, position)) - if notLeaderOfThisSquad(squadsToLeaders, features.Squad.GUID, rejectingPlayer) => + /*if notLeaderOfThisSquad(squadsToLeaders, features.Squad.GUID, rejectingPlayer)*/ => //rejectingPlayer is the would-be squad member; the squad leader sent the request and was rejected ReloadProximityInvite( tplayer.Zone.Players, @@ -456,7 +456,7 @@ class SquadInvitationManager(subs: SquadSubscriptionEntity, parent: ActorRef) { (Some(rejectingPlayer), Some(leaderCharId)) case Some(RequestRole(rejected, features, _)) - if notLeaderOfThisSquad(squadsToLeaders, features.Squad.GUID, rejectingPlayer) => + if notLeaderOfThisSquad(squadsToLeaders, features.Squad.GUID, rejected.CharId) => //rejected is the would-be squad member; rejectingPlayer is the squad leader who rejected the request features.DeniedPlayers(rejected.CharId) (Some(rejectingPlayer), None) @@ -2028,7 +2028,8 @@ class SquadInvitationManager(subs: SquadSubscriptionEntity, parent: ActorRef) { avatar.lookingForSquad && !deniedAndExcluded.contains(charId) && !refused(charId).contains(squadLeader) && - requirementsToMeet.intersect(avatar.certifications) == requirementsToMeet + requirementsToMeet.intersect(avatar.certifications) == requirementsToMeet && + charId != invitingPlayerCharId //don't send invite to yourself. can cause issues if rejected } match { case None => None diff --git a/src/main/scala/net/psforever/services/teamwork/SquadService.scala b/src/main/scala/net/psforever/services/teamwork/SquadService.scala index b2149fa8..5a1edb56 100644 --- a/src/main/scala/net/psforever/services/teamwork/SquadService.scala +++ b/src/main/scala/net/psforever/services/teamwork/SquadService.scala @@ -6,7 +6,7 @@ import java.io.{PrintWriter, StringWriter} import scala.collection.concurrent.TrieMap import scala.collection.mutable // -import net.psforever.objects.{Default, LivePlayerList, Player} +import net.psforever.objects.{LivePlayerList, Player} import net.psforever.objects.teamwork.{Member, Squad, SquadFeatures} import net.psforever.objects.avatar.{Avatar, Certification} import net.psforever.objects.definition.converter.StatConverter @@ -76,7 +76,7 @@ class SquadService extends Actor { //squads and members (users) squadFeatures.foreach { case (_, features) => - CloseSquad(features.Squad) + DisbandSquad(features) } memberToSquad.clear() publishedLists.clear() @@ -377,7 +377,7 @@ class SquadService extends Actor { SquadActionMembershipCancel(cancellingPlayer) case SquadAction.Membership(SquadRequestType.Promote, promotingPlayer, Some(_promotedPlayer), promotedName, _) => - SquadActionMembershipPromote(promotingPlayer, _promotedPlayer, promotedName, SquadServiceMessage(tplayer, zone, action), sender()) + //SquadActionMembershipPromote(promotingPlayer, _promotedPlayer, promotedName, SquadServiceMessage(tplayer, zone, action), sender()) case SquadAction.Membership(event, _, _, _, _) => debug(s"SquadAction.Membership: $event is not yet supported") @@ -686,10 +686,10 @@ class SquadService extends Actor { } None case search: SearchForSquadsWithParticularRole => - SquadActionDefinitionSearchForSquadsWithParticularRole(tplayer, search) +// SquadActionDefinitionSearchForSquadsWithParticularRole(tplayer, search) None case _: CancelSquadSearch => - SquadActionDefinitionCancelSquadSearch(tplayer.CharId) +// SquadActionDefinitionCancelSquadSearch(tplayer.CharId) None case _: DisplaySquad => GetSquad(guid) match { @@ -863,6 +863,11 @@ class SquadService extends Actor { val sguid = GetNextSquadId() val squad = new Squad(sguid, faction) val leadPosition = squad.Membership(0) + //keep publishedLists clear of old squads. PR 1157 for details + val factionListings = publishedLists(faction) + val guidsToRemove = factionListings.filterNot(squadFeatures.contains).toList + guidsToRemove.foreach(factionListings -= _) + leadPosition.Name = name leadPosition.CharId = player.CharId leadPosition.Health = StatConverter.Health(player.Health, player.MaxHealth, min = 1, max = 64) @@ -902,9 +907,8 @@ class SquadService extends Actor { val squad = features.Squad subs.UserEvents.get(charId) match { case Some(events) - if !memberToSquad.contains(charId) && - squad.Leader.CharId != charId && - squad.isAvailable(position, player.avatar.certifications) => + if squad.isAvailable(position, player.avatar.certifications) && + EnsureEmptySquad(charId) => memberToSquad(charId) = squad.GUID subs.MonitorSquadDetails.subtractOne(charId) invitations.handleCleanup(charId) @@ -951,6 +955,7 @@ class SquadService extends Actor { membership.find { case (_member, _) => _member.CharId == charId } match { case Some(_) if squad.Leader.CharId != charId => memberToSquad.remove(charId) + subs.MonitorSquadDetails.subtractOne(charId) features.Switchboard ! SquadSwitchboard.Leave(charId) true case _ => @@ -1010,6 +1015,10 @@ class SquadService extends Actor { subs.Publish(charId, SquadResponse.Detail(PlanetSideGUID(0), completelyBlankSquadDetail)) } UpdateSquadListWhenListed(features.Stop, None) + //remove from list of squads + squadFeatures -= guid + //really make sure it is removed from listed squads + publishedLists(squad.Faction) -= guid } /** @@ -1083,6 +1092,7 @@ class SquadService extends Actor { pSquadOpt match { //member of the squad; leave the squad case Some(features) => + LeaveSquad(charId, features) //adding this fixed issue of rejoining the squad on login. val squad = features.Squad val size = squad.Size subs.UserEvents.remove(charId) match { @@ -1093,25 +1103,8 @@ class SquadService extends Actor { if (size > 2) { GetLeadingSquad(charId, pSquadOpt) match { case Some(_) => - //leader of a squad; search for a suitable substitute leader - squad.Membership.drop(1).find { _.CharId > 0 } match { - case Some(member) => - //leader was shifted into a subordinate position and will retire from duty - SquadActionMembershipPromote( - charId, - member.CharId, - features, - SquadServiceMessage(null, null, SquadAction.Membership(SquadRequestType.Promote, charId, Some(member.CharId), "", None)), - Default.Actor - ) - LeaveSquad(charId, features) - case _ => - //the squad will be disbanded - PanicDisbandSquad( - features, - squad.Membership.collect { case member if member.CharId > 0 && member.CharId != charId => member.CharId } - ) - } + //leader of a squad; the squad will be disbanded. Same logic as when a SL uses /leave and the squad is disbanded. + DisbandSquad(features) case None => //not the leader of a full squad; tell other members that we are leaving SquadSwitchboard.PanicLeaveSquad( @@ -1125,10 +1118,7 @@ class SquadService extends Actor { } } else { //with only two members before our leave, the squad will be disbanded - PanicDisbandSquad( - features, - squad.Membership.collect { case member if member.CharId > 0 && member.CharId != charId => member.CharId } - ) + DisbandSquad(features) } case None => //not a member of any squad; nothing really to do here @@ -1136,7 +1126,8 @@ class SquadService extends Actor { } subs.SquadEvents.unsubscribe(sender) //just to make certain searchData.remove(charId) - TryResetSquadId() + //todo turn this back on. See PR 1157 for why it was commented out. + //TryResetSquadId() } /** diff --git a/src/main/scala/net/psforever/services/teamwork/SquadSwitchboard.scala b/src/main/scala/net/psforever/services/teamwork/SquadSwitchboard.scala index 40d35a3c..ea8a5571 100644 --- a/src/main/scala/net/psforever/services/teamwork/SquadSwitchboard.scala +++ b/src/main/scala/net/psforever/services/teamwork/SquadSwitchboard.scala @@ -171,13 +171,12 @@ class SquadSwitchboard( //update for leader features.InitialAssociation = false subscriptions.Publish(leaderId, SquadResponse.IdentifyAsSquadLeader(squad.GUID)) - subscriptions.Publish(leaderId, SquadResponse.CharacterKnowledge(charId, role.Name, role.Certifications, 40, 5, role.ZoneId)) + subscriptions.Publish(leaderId, SquadResponse.CharacterKnowledge(charId, role.Name, role.Certifications, player.avatar.br.value, player.avatar.cr.value, role.ZoneId)) //everyone subscriptions.InitSquadDetail(features) } else { //joining an active squad; different people update differently //new member gets full squad UI updates - subscriptions.InitSquadDetail(squad.GUID, Seq(charId), squad) subscriptions.Publish( charId, SquadResponse.Join( @@ -201,8 +200,9 @@ class SquadSwitchboard( ) subscriptions.Publish(toChannel, SquadResponse.Join(squad, List(position), "", self), Seq(charId)) //update for leader - subscriptions.Publish(leaderId, SquadResponse.CharacterKnowledge(charId, role.Name, role.Certifications, 40, 5, role.ZoneId)) + subscriptions.Publish(leaderId, SquadResponse.CharacterKnowledge(charId, role.Name, role.Certifications, player.avatar.br.value, player.avatar.cr.value, role.ZoneId)) subscriptions.SquadEvents.subscribe(sendTo, s"/$toChannel/Squad") + subscriptions.InitSquadDetail(squad.GUID, Seq(charId), squad) } context.parent ! SquadService.UpdateSquadListWhenListed( features, @@ -653,7 +653,7 @@ class SquadSwitchboard( if (squad.Leader.CharId == char_id) { membership.lift(position) match { case Some(toMember) => - SquadActionMembershipPromote(char_id, toMember.CharId) + //SquadActionMembershipPromote(char_id, toMember.CharId) case _ => ; } } else { @@ -684,7 +684,7 @@ class SquadSwitchboard( def SquadActionMembership(action: Any): Unit = { action match { case SquadAction.Membership(SquadRequestType.Promote, promotingPlayer, Some(promotedPlayer), _, _) => - SquadActionMembershipPromote(promotingPlayer, promotedPlayer) + //SquadActionMembershipPromote(promotingPlayer, promotedPlayer) case SquadAction.Membership(event, _, _, _, _) => log.debug(s"SquadAction.Membership: $event is not supported here") @@ -729,6 +729,7 @@ class SquadSwitchboard( _.CharId == promotedPlayer } .foreach { member => + //todo: get member br & cr to replace 40, 5 subscriptions.Publish(promotedPlayer, SquadResponse.CharacterKnowledge(member.CharId, member.Name, member.Certifications, 40, 5, member.ZoneId)) } //to old and to new squad leader @@ -904,18 +905,18 @@ class SquadSwitchboard( if (leaderCharId != charId) { subscriptions.Publish( leaderCharId, - SquadResponse.CharacterKnowledge(charId, member.Name, certifications, 40, 5, zoneNumber) + SquadResponse.CharacterKnowledge(charId, member.Name, certifications, player.avatar.br.value, player.avatar.cr.value, zoneNumber) ) } context.parent ! SquadServiceMessage(player, player.Zone, SquadAction.ReloadDecoration()) } else if (zoneBefore != zoneNumber && leaderCharId != charId) { subscriptions.Publish( leaderCharId, - SquadResponse.CharacterKnowledge(charId, member.Name, certifications, 40, 5, 0) + SquadResponse.CharacterKnowledge(charId, member.Name, certifications, player.avatar.br.value, player.avatar.cr.value, 0) ) subscriptions.Publish( leaderCharId, - SquadResponse.CharacterKnowledge(charId, member.Name, certifications, 40, 5, zoneNumber) + SquadResponse.CharacterKnowledge(charId, member.Name, certifications, player.avatar.br.value, player.avatar.cr.value, zoneNumber) ) } if (features.LocationFollowsSquadLead) {