mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-19 18:44:45 +00:00
experimental invitation management commands for squad leaders, mostly untested atm; messages for being denied squad admission
This commit is contained in:
parent
d15e916f46
commit
2372a95040
|
|
@ -138,6 +138,7 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
|
||||||
case "grenade" => ops.customCommandGrenade(session, log)
|
case "grenade" => ops.customCommandGrenade(session, log)
|
||||||
case "macro" => ops.customCommandMacro(session, params)
|
case "macro" => ops.customCommandMacro(session, params)
|
||||||
case "progress" => ops.customCommandProgress(session, params)
|
case "progress" => ops.customCommandProgress(session, params)
|
||||||
|
case "squad" => ops.customCommandSquad(params)
|
||||||
case _ =>
|
case _ =>
|
||||||
// command was not handled
|
// command was not handled
|
||||||
sendResponse(
|
sendResponse(
|
||||||
|
|
|
||||||
|
|
@ -349,6 +349,9 @@ class SquadHandlerLogic(val ops: SessionSquadHandlers, implicit val context: Act
|
||||||
case SquadResponse.WaypointEvent(WaypointEventAction.Remove, char_id, waypoint_type, _, _, _) =>
|
case SquadResponse.WaypointEvent(WaypointEventAction.Remove, char_id, waypoint_type, _, _, _) =>
|
||||||
sendResponse(SquadWaypointEvent.Remove(ops.squad_supplement_id, char_id, waypoint_type))
|
sendResponse(SquadWaypointEvent.Remove(ops.squad_supplement_id, char_id, waypoint_type))
|
||||||
|
|
||||||
|
case SquadResponse.SquadRelatedComment(comment) =>
|
||||||
|
sendResponse(ChatMsg(ChatMessageType.UNK_227, comment))
|
||||||
|
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
package net.psforever.actors.session.support
|
package net.psforever.actors.session.support
|
||||||
|
|
||||||
import akka.actor.Cancellable
|
import akka.actor.Cancellable
|
||||||
|
import net.psforever.objects.LivePlayerList
|
||||||
|
import akka.actor.{ActorRef => ClassicActorRef}
|
||||||
import akka.actor.typed.ActorRef
|
import akka.actor.typed.ActorRef
|
||||||
import akka.actor.{ActorContext, typed}
|
import akka.actor.{ActorContext, typed}
|
||||||
import net.psforever.actors.session.spectator.SpectatorMode
|
import net.psforever.actors.session.spectator.SpectatorMode
|
||||||
|
|
@ -12,6 +14,7 @@ import net.psforever.objects.zones.ZoneInfo
|
||||||
import net.psforever.packet.game.SetChatFilterMessage
|
import net.psforever.packet.game.SetChatFilterMessage
|
||||||
import net.psforever.services.chat.{DefaultChannel, SquadChannel}
|
import net.psforever.services.chat.{DefaultChannel, SquadChannel}
|
||||||
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||||
|
import net.psforever.services.teamwork.SquadService
|
||||||
import net.psforever.types.ChatMessageType.CMT_QUIT
|
import net.psforever.types.ChatMessageType.CMT_QUIT
|
||||||
import org.log4s.Logger
|
import org.log4s.Logger
|
||||||
|
|
||||||
|
|
@ -54,6 +57,7 @@ class ChatOperations(
|
||||||
val sessionLogic: SessionData,
|
val sessionLogic: SessionData,
|
||||||
val avatarActor: typed.ActorRef[AvatarActor.Command],
|
val avatarActor: typed.ActorRef[AvatarActor.Command],
|
||||||
val chatService: typed.ActorRef[ChatService.Command],
|
val chatService: typed.ActorRef[ChatService.Command],
|
||||||
|
val squadService: ClassicActorRef,
|
||||||
val cluster: typed.ActorRef[InterstellarClusterService.Command],
|
val cluster: typed.ActorRef[InterstellarClusterService.Command],
|
||||||
implicit val context: ActorContext
|
implicit val context: ActorContext
|
||||||
) extends CommonSessionInterfacingFunctionality {
|
) extends CommonSessionInterfacingFunctionality {
|
||||||
|
|
@ -1284,6 +1288,32 @@ class ChatOperations(
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def customCommandSquad(params: Seq[String]): Boolean = {
|
||||||
|
params match {
|
||||||
|
case "invites" :: _ =>
|
||||||
|
squadService ! SquadService.ListAllCurrentInvites
|
||||||
|
|
||||||
|
case "accept" :: names if names.contains("all") =>
|
||||||
|
squadService ! SquadService.ChainAcceptance(player, player.CharId, Nil)
|
||||||
|
case "accept" :: names if names.nonEmpty =>
|
||||||
|
val results = names.flatMap { name =>
|
||||||
|
LivePlayerList.WorldPopulation { case (_, p) => p.name.equals(name) }.map(_.id.toLong)
|
||||||
|
}
|
||||||
|
squadService ! SquadService.ChainAcceptance(player, player.CharId, results)
|
||||||
|
|
||||||
|
case "reject" :: names if names.contains("all") =>
|
||||||
|
squadService ! SquadService.ChainRejection(player, player.CharId, Nil)
|
||||||
|
case "reject" :: names if names.nonEmpty =>
|
||||||
|
val results = names.flatMap { name =>
|
||||||
|
LivePlayerList.WorldPopulation { case (_, p) => p.name.equals(name) }.map(_.id.toLong)
|
||||||
|
}
|
||||||
|
squadService ! SquadService.ChainRejection(player, player.CharId, results)
|
||||||
|
|
||||||
|
case _ => ()
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
def firstParam[T](
|
def firstParam[T](
|
||||||
session: Session,
|
session: Session,
|
||||||
buffer: Iterable[String],
|
buffer: Iterable[String],
|
||||||
|
|
|
||||||
|
|
@ -165,15 +165,15 @@ class SessionData(
|
||||||
case LookupResult("squad", endpoint) =>
|
case LookupResult("squad", endpoint) =>
|
||||||
squadService = endpoint
|
squadService = endpoint
|
||||||
buildDependentOperationsForSquad(endpoint)
|
buildDependentOperationsForSquad(endpoint)
|
||||||
|
buildDependentOperationsForChat(chatService, endpoint, cluster)
|
||||||
true
|
true
|
||||||
case ICS.InterstellarClusterServiceKey.Listing(listings) =>
|
case ICS.InterstellarClusterServiceKey.Listing(listings) =>
|
||||||
cluster = listings.head
|
cluster = listings.head
|
||||||
buildDependentOperationsForZoning(galaxyService, cluster)
|
buildDependentOperationsForZoning(galaxyService, cluster)
|
||||||
buildDependentOperationsForChat(chatService, cluster)
|
|
||||||
true
|
true
|
||||||
case ChatService.ChatServiceKey.Listing(listings) =>
|
case ChatService.ChatServiceKey.Listing(listings) =>
|
||||||
chatService = listings.head
|
chatService = listings.head
|
||||||
buildDependentOperationsForChat(chatService, cluster)
|
buildDependentOperationsForChat(chatService, squadService, cluster)
|
||||||
true
|
true
|
||||||
|
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
@ -200,9 +200,16 @@ class SessionData(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def buildDependentOperationsForChat(chatService: typed.ActorRef[ChatService.Command], clusterActor: typed.ActorRef[ICS.Command]): Unit = {
|
def buildDependentOperationsForChat(
|
||||||
if (chatOpt.isEmpty && chatService != Default.typed.Actor && clusterActor != Default.typed.Actor) {
|
chatService: typed.ActorRef[ChatService.Command],
|
||||||
chatOpt = Some(new ChatOperations(sessionLogic=this, avatarActor, chatService, clusterActor, context))
|
squadService: ActorRef,
|
||||||
|
clusterActor: typed.ActorRef[ICS.Command]
|
||||||
|
): Unit = {
|
||||||
|
if (chatOpt.isEmpty &&
|
||||||
|
chatService != Default.typed.Actor &&
|
||||||
|
squadService !=Default.Actor &&
|
||||||
|
clusterActor != Default.typed.Actor) {
|
||||||
|
chatOpt = Some(new ChatOperations(sessionLogic=this, avatarActor, chatService, squadService, clusterActor, context))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ package net.psforever.services.teamwork
|
||||||
import akka.actor.ActorRef
|
import akka.actor.ActorRef
|
||||||
import akka.pattern.ask
|
import akka.pattern.ask
|
||||||
import akka.util.Timeout
|
import akka.util.Timeout
|
||||||
|
|
||||||
|
import scala.annotation.unused
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
|
|
@ -119,14 +121,15 @@ class SquadInvitationManager(subs: SquadSubscriptionEntity, parent: ActorRef) {
|
||||||
val leader = squad2.Leader.CharId
|
val leader = squad2.Leader.CharId
|
||||||
Allowed(invitedPlayer, invitingPlayer)
|
Allowed(invitedPlayer, invitingPlayer)
|
||||||
Allowed(leader, invitingPlayer)
|
Allowed(leader, invitingPlayer)
|
||||||
|
lazy val preface = s"$invitingPlayer's invitation got reversed to $invitedPlayer's squad, but"
|
||||||
if (squad2.Size == squad2.Capacity) {
|
if (squad2.Size == squad2.Capacity) {
|
||||||
log.debug(s"$invitingPlayer's invitation got reversed to $invitedPlayer's squad, but the squad has no available positions")
|
log.debug(s"$preface the squad has no available positions")
|
||||||
} else if (Refused(invitingPlayer).contains(invitedPlayer)) {
|
} else if (Refused(invitingPlayer).contains(invitedPlayer)) {
|
||||||
log.debug(s"$invitingPlayer's invitation got reversed to $invitedPlayer's squad, but $invitedPlayer repeated a previous refusal to $invitingPlayer's invitation offer")
|
log.debug(s"$preface $invitedPlayer repeated a previous refusal to $invitingPlayer's invitation offer")
|
||||||
} else if (Refused(invitingPlayer).contains(leader)) {
|
} else if (Refused(invitingPlayer).contains(leader)) {
|
||||||
log.debug(s"$invitingPlayer's invitation got reversed to $invitedPlayer's squad, but $leader repeated a previous refusal to $invitingPlayer's invitation offer")
|
log.debug(s"$preface $leader repeated a previous refusal to $invitingPlayer's invitation offer")
|
||||||
} else if (features.DeniedPlayers().contains(invitingPlayer)) {
|
} else if (features.DeniedPlayers().contains(invitingPlayer)) {
|
||||||
log.debug(s"$invitingPlayer's invitation got reversed to $invitedPlayer's squad, but $invitingPlayer is denied the invitation")
|
log.debug(s"$preface $invitingPlayer is denied the invitation")
|
||||||
} else {
|
} else {
|
||||||
features.AllowedPlayers(invitedPlayer)
|
features.AllowedPlayers(invitedPlayer)
|
||||||
AddInviteAndRespond(
|
AddInviteAndRespond(
|
||||||
|
|
@ -165,7 +168,7 @@ class SquadInvitationManager(subs: SquadSubscriptionEntity, parent: ActorRef) {
|
||||||
val availableForJoiningSquad = notLimitedByEnrollmentInSquad(invitedPlayerSquadOpt, invitedPlayer)
|
val availableForJoiningSquad = notLimitedByEnrollmentInSquad(invitedPlayerSquadOpt, invitedPlayer)
|
||||||
acceptedInvite match {
|
acceptedInvite match {
|
||||||
case Some(RequestRole(petitioner, features, position))
|
case Some(RequestRole(petitioner, features, position))
|
||||||
if canEnrollInSquad(features, petitioner.CharId) =>
|
if SquadInvitationManager.canEnrollInSquad(features, petitioner.CharId) =>
|
||||||
//player requested to join a squad's specific position
|
//player requested to join a squad's specific position
|
||||||
//invitedPlayer is actually the squad leader; petitioner is the actual "invitedPlayer"
|
//invitedPlayer is actually the squad leader; petitioner is the actual "invitedPlayer"
|
||||||
if (JoinSquad(petitioner, features, position)) {
|
if (JoinSquad(petitioner, features, position)) {
|
||||||
|
|
@ -174,7 +177,7 @@ class SquadInvitationManager(subs: SquadSubscriptionEntity, parent: ActorRef) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case Some(IndirectInvite(recruit, features))
|
case Some(IndirectInvite(recruit, features))
|
||||||
if canEnrollInSquad(features, recruit.CharId) =>
|
if SquadInvitationManager.canEnrollInSquad(features, recruit.CharId) =>
|
||||||
//tplayer / invitedPlayer is actually the squad leader
|
//tplayer / invitedPlayer is actually the squad leader
|
||||||
val recruitCharId = recruit.CharId
|
val recruitCharId = recruit.CharId
|
||||||
HandleVacancyInvite(features, recruitCharId, invitedPlayer, recruit) match {
|
HandleVacancyInvite(features, recruitCharId, invitedPlayer, recruit) match {
|
||||||
|
|
@ -188,7 +191,7 @@ class SquadInvitationManager(subs: SquadSubscriptionEntity, parent: ActorRef) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case Some(VacancyInvite(invitingPlayer, _, features))
|
case Some(VacancyInvite(invitingPlayer, _, features))
|
||||||
if availableForJoiningSquad && canEnrollInSquad(features, invitedPlayer) =>
|
if availableForJoiningSquad && SquadInvitationManager.canEnrollInSquad(features, invitedPlayer) =>
|
||||||
//accepted an invitation to join an existing squad
|
//accepted an invitation to join an existing squad
|
||||||
HandleVacancyInvite(features, invitedPlayer, invitingPlayer, tplayer) match {
|
HandleVacancyInvite(features, invitedPlayer, invitingPlayer, tplayer) match {
|
||||||
case Some((_, line)) =>
|
case Some((_, line)) =>
|
||||||
|
|
@ -204,7 +207,7 @@ class SquadInvitationManager(subs: SquadSubscriptionEntity, parent: ActorRef) {
|
||||||
SquadMembershipAcceptInviteAction(invitingPlayer, tplayer, invitedPlayer)
|
SquadMembershipAcceptInviteAction(invitingPlayer, tplayer, invitedPlayer)
|
||||||
|
|
||||||
case Some(LookingForSquadRoleInvite(member, features, position))
|
case Some(LookingForSquadRoleInvite(member, features, position))
|
||||||
if availableForJoiningSquad && canEnrollInSquad(features, invitedPlayer) =>
|
if availableForJoiningSquad && SquadInvitationManager.canEnrollInSquad(features, invitedPlayer) =>
|
||||||
val invitingPlayer = member.CharId
|
val invitingPlayer = member.CharId
|
||||||
features.ProxyInvites = features.ProxyInvites.filterNot { _ == invitedPlayer }
|
features.ProxyInvites = features.ProxyInvites.filterNot { _ == invitedPlayer }
|
||||||
if (JoinSquad(tplayer, features, position)) {
|
if (JoinSquad(tplayer, features, position)) {
|
||||||
|
|
@ -215,7 +218,7 @@ class SquadInvitationManager(subs: SquadSubscriptionEntity, parent: ActorRef) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case Some(ProximityInvite(member, features, position))
|
case Some(ProximityInvite(member, features, position))
|
||||||
if availableForJoiningSquad && canEnrollInSquad(features, invitedPlayer) =>
|
if availableForJoiningSquad && SquadInvitationManager.canEnrollInSquad(features, invitedPlayer) =>
|
||||||
val invitingPlayer = member.CharId
|
val invitingPlayer = member.CharId
|
||||||
features.ProxyInvites = features.ProxyInvites.filterNot { _ == invitedPlayer }
|
features.ProxyInvites = features.ProxyInvites.filterNot { _ == invitedPlayer }
|
||||||
if (JoinSquad(tplayer, features, position)) {
|
if (JoinSquad(tplayer, features, position)) {
|
||||||
|
|
@ -280,10 +283,6 @@ class SquadInvitationManager(subs: SquadSubscriptionEntity, parent: ActorRef) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def canEnrollInSquad(features: SquadFeatures, charId: Long): Boolean = {
|
|
||||||
!features.Squad.Membership.exists { _.CharId == charId }
|
|
||||||
}
|
|
||||||
|
|
||||||
def SquadMembershipAcceptInviteAction(invitingPlayer: Player, player: Player, invitedPlayer: Long): Unit = {
|
def SquadMembershipAcceptInviteAction(invitingPlayer: Player, player: Player, invitedPlayer: Long): Unit = {
|
||||||
//originally, we were invited by someone into a new squad they would form
|
//originally, we were invited by someone into a new squad they would form
|
||||||
val invitingPlayerCharId = invitingPlayer.CharId
|
val invitingPlayerCharId = invitingPlayer.CharId
|
||||||
|
|
@ -416,24 +415,75 @@ class SquadInvitationManager(subs: SquadSubscriptionEntity, parent: ActorRef) {
|
||||||
def handleRejection(
|
def handleRejection(
|
||||||
tplayer: Player,
|
tplayer: Player,
|
||||||
rejectingPlayer: Long,
|
rejectingPlayer: Long,
|
||||||
squadsToLeaders: List[(PlanetSideGUID, Long)]
|
squadsToLeaders: List[(PlanetSideGUID, SquadFeatures)]
|
||||||
): Unit = {
|
): Unit = {
|
||||||
val rejectedBid = RemoveInvite(rejectingPlayer)
|
val rejectedBid = RemoveInvite(rejectingPlayer)
|
||||||
(rejectedBid match {
|
FormatRejection(
|
||||||
|
DoRejection(rejectedBid, tplayer, rejectingPlayer, squadsToLeaders),
|
||||||
|
tplayer
|
||||||
|
)
|
||||||
|
NextInviteAndRespond(rejectingPlayer)
|
||||||
|
}
|
||||||
|
|
||||||
|
def ParseRejection(
|
||||||
|
rejectedBid: Option[Invitation],
|
||||||
|
@unused tplayer: Player,
|
||||||
|
rejectingPlayer: Long,
|
||||||
|
squadsToLeaders: List[(PlanetSideGUID, SquadFeatures)]
|
||||||
|
): (Option[Long], Option[Long]) = {
|
||||||
|
rejectedBid match {
|
||||||
|
case Some(SpontaneousInvite(leader)) =>
|
||||||
|
//rejectingPlayer is the would-be squad member; the would-be squad leader sent the request and was rejected
|
||||||
|
val invitingPlayerCharId = leader.CharId
|
||||||
|
(Some(rejectingPlayer), Some(invitingPlayerCharId))
|
||||||
|
|
||||||
|
case Some(VacancyInvite(leader, _, _))
|
||||||
|
/*if SquadInvitationManager.notLeaderOfThisSquad(squadsToLeaders, features.Squad.GUID, rejectingPlayer)*/ =>
|
||||||
|
//rejectingPlayer is the would-be squad member; the squad leader sent the request and was rejected
|
||||||
|
(Some(rejectingPlayer), Some(leader))
|
||||||
|
|
||||||
|
case Some(ProximityInvite(_, _, _))
|
||||||
|
/*if SquadInvitationManager.notLeaderOfThisSquad(squadsToLeaders, features.Squad.GUID, rejectingPlayer)*/ =>
|
||||||
|
//rejectingPlayer is the would-be squad member; the squad leader sent the request and was rejected
|
||||||
|
(Some(rejectingPlayer), None)
|
||||||
|
|
||||||
|
case Some(LookingForSquadRoleInvite(member, _, _))
|
||||||
|
if member.CharId != rejectingPlayer =>
|
||||||
|
val leaderCharId = member.CharId
|
||||||
|
//rejectingPlayer is the would-be squad member; the squad leader sent the request and was rejected
|
||||||
|
(Some(rejectingPlayer), Some(leaderCharId))
|
||||||
|
|
||||||
|
case Some(RequestRole(rejected, features, _))
|
||||||
|
if SquadInvitationManager.notLeaderOfThisSquad(squadsToLeaders, features.Squad.GUID, rejected.CharId) =>
|
||||||
|
//rejected is the would-be squad member; rejectingPlayer is the squad leader who rejected the request
|
||||||
|
(Some(rejectingPlayer), None)
|
||||||
|
|
||||||
|
case _ => //TODO IndirectInvite, etc., but how to handle them?
|
||||||
|
(None, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def DoRejection(
|
||||||
|
rejectedBid: Option[Invitation],
|
||||||
|
tplayer: Player,
|
||||||
|
rejectingPlayer: Long,
|
||||||
|
squadsToLeaders: List[(PlanetSideGUID, SquadFeatures)]
|
||||||
|
): (Option[Long], Option[Long], String) = {
|
||||||
|
rejectedBid match {
|
||||||
case Some(SpontaneousInvite(leader)) =>
|
case Some(SpontaneousInvite(leader)) =>
|
||||||
//rejectingPlayer is the would-be squad member; the would-be squad leader sent the request and was rejected
|
//rejectingPlayer is the would-be squad member; the would-be squad leader sent the request and was rejected
|
||||||
val invitingPlayerCharId = leader.CharId
|
val invitingPlayerCharId = leader.CharId
|
||||||
Refused(rejectingPlayer, invitingPlayerCharId)
|
Refused(rejectingPlayer, invitingPlayerCharId)
|
||||||
(Some(rejectingPlayer), Some(invitingPlayerCharId))
|
(Some(rejectingPlayer), Some(invitingPlayerCharId), "anonymous")
|
||||||
|
|
||||||
case Some(VacancyInvite(leader, _, _))
|
case Some(VacancyInvite(leader, _, features))
|
||||||
/*if notLeaderOfThisSquad(squadsToLeaders, features.Squad.GUID, rejectingPlayer)*/ =>
|
/*if SquadInvitationManager.notLeaderOfThisSquad(squadsToLeaders, features.Squad.GUID, rejectingPlayer)*/ =>
|
||||||
//rejectingPlayer is the would-be squad member; the squad leader sent the request and was rejected
|
//rejectingPlayer is the would-be squad member; the squad leader sent the request and was rejected
|
||||||
Refused(rejectingPlayer, leader)
|
Refused(rejectingPlayer, leader)
|
||||||
(Some(rejectingPlayer), Some(leader))
|
(Some(rejectingPlayer), Some(leader), features.Squad.Task)
|
||||||
|
|
||||||
case Some(ProximityInvite(_, features, position))
|
case Some(ProximityInvite(_, features, position))
|
||||||
/*if notLeaderOfThisSquad(squadsToLeaders, features.Squad.GUID, rejectingPlayer)*/ =>
|
/*if SquadInvitationManager.notLeaderOfThisSquad(squadsToLeaders, features.Squad.GUID, rejectingPlayer)*/ =>
|
||||||
//rejectingPlayer is the would-be squad member; the squad leader sent the request and was rejected
|
//rejectingPlayer is the would-be squad member; the squad leader sent the request and was rejected
|
||||||
ReloadProximityInvite(
|
ReloadProximityInvite(
|
||||||
tplayer.Zone.Players,
|
tplayer.Zone.Players,
|
||||||
|
|
@ -441,52 +491,53 @@ class SquadInvitationManager(subs: SquadSubscriptionEntity, parent: ActorRef) {
|
||||||
features,
|
features,
|
||||||
position
|
position
|
||||||
)
|
)
|
||||||
(Some(rejectingPlayer), None)
|
(Some(rejectingPlayer), None, features.Squad.Task)
|
||||||
|
|
||||||
case Some(LookingForSquadRoleInvite(member, guid, position))
|
case Some(LookingForSquadRoleInvite(member, features, position))
|
||||||
if member.CharId != rejectingPlayer =>
|
if member.CharId != rejectingPlayer =>
|
||||||
val leaderCharId = member.CharId
|
val leaderCharId = member.CharId
|
||||||
//rejectingPlayer is the would-be squad member; the squad leader sent the request and was rejected
|
//rejectingPlayer is the would-be squad member; the squad leader sent the request and was rejected
|
||||||
ReloadSearchForRoleInvite(
|
ReloadSearchForRoleInvite(
|
||||||
LivePlayerList.WorldPopulation { _ => true },
|
LivePlayerList.WorldPopulation { _ => true },
|
||||||
rejectingPlayer,
|
rejectingPlayer,
|
||||||
guid,
|
features,
|
||||||
position
|
position
|
||||||
)
|
)
|
||||||
(Some(rejectingPlayer), Some(leaderCharId))
|
(Some(rejectingPlayer), Some(leaderCharId), features.Squad.Task)
|
||||||
|
|
||||||
case Some(RequestRole(rejected, features, _))
|
case Some(RequestRole(rejected, features, _))
|
||||||
if notLeaderOfThisSquad(squadsToLeaders, features.Squad.GUID, rejected.CharId) =>
|
if SquadInvitationManager.notLeaderOfThisSquad(squadsToLeaders, features.Squad.GUID, rejected.CharId) =>
|
||||||
//rejected is the would-be squad member; rejectingPlayer is the squad leader who rejected the request
|
//rejected is the would-be squad member; rejectingPlayer is the squad leader who rejected the request
|
||||||
features.DeniedPlayers(rejected.CharId)
|
features.DeniedPlayers(rejected.CharId)
|
||||||
(Some(rejectingPlayer), None)
|
(Some(rejectingPlayer), None, features.Squad.Task)
|
||||||
|
|
||||||
case _ => ; //TODO IndirectInvite, etc., but how to handle them?
|
case _ => //TODO IndirectInvite, etc., but how to handle them?
|
||||||
(None, None)
|
(None, None, "n|a")
|
||||||
}) match {
|
}
|
||||||
case (Some(rejected), Some(invited)) =>
|
}
|
||||||
|
|
||||||
|
def FormatRejection(
|
||||||
|
rejectedPair: (Option[Long], Option[Long], String),
|
||||||
|
tplayer: Player
|
||||||
|
): Unit = {
|
||||||
|
rejectedPair match {
|
||||||
|
case (Some(rejected), Some(inviter), squadName) =>
|
||||||
subs.Publish(
|
subs.Publish(
|
||||||
rejected,
|
rejected,
|
||||||
SquadResponse.Membership(SquadResponseType.Reject, 0, 0, rejected, Some(invited), "", unk5=true, Some(None))
|
SquadResponse.Membership(SquadResponseType.Reject, 0, 0, rejected, Some(inviter), "", unk5=true, Some(None))
|
||||||
)
|
)
|
||||||
subs.Publish(
|
subs.Publish(
|
||||||
invited,
|
inviter,
|
||||||
SquadResponse.Membership(SquadResponseType.Reject, 0, 0, invited, Some(rejected), tplayer.Name, unk5=false, Some(None))
|
SquadResponse.Membership(SquadResponseType.Reject, 0, 0, inviter, Some(rejected), tplayer.Name, unk5=false, Some(None))
|
||||||
)
|
)
|
||||||
case (Some(rejected), None) =>
|
subs.Publish(rejected, SquadResponse.SquadRelatedComment(s"Your request to join squad '$squadName' has been refused."))
|
||||||
|
case (Some(rejected), None, squadName) =>
|
||||||
subs.Publish(
|
subs.Publish(
|
||||||
rejected,
|
rejected,
|
||||||
SquadResponse.Membership(SquadResponseType.Reject, 0, 0, rejected, Some(rejected), "", unk5=true, Some(None))
|
SquadResponse.Membership(SquadResponseType.Reject, 0, 0, rejected, Some(rejected), "", unk5=true, Some(None))
|
||||||
)
|
)
|
||||||
case _ => ;
|
subs.Publish(rejected, SquadResponse.SquadRelatedComment(s"Your request to join squad '$squadName' has been refused."))
|
||||||
}
|
case _ => ()
|
||||||
NextInviteAndRespond(rejectingPlayer)
|
|
||||||
}
|
|
||||||
|
|
||||||
def notLeaderOfThisSquad(squadsToLeaders: List[(PlanetSideGUID, Long)], guid: PlanetSideGUID, charId: Long): Boolean = {
|
|
||||||
squadsToLeaders.find { case (squadGuid, _) => squadGuid == guid } match {
|
|
||||||
case Some((_, leaderId)) => leaderId != charId
|
|
||||||
case None => false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -611,8 +662,14 @@ class SquadInvitationManager(subs: SquadSubscriptionEntity, parent: ActorRef) {
|
||||||
tplayer: Player,
|
tplayer: Player,
|
||||||
features: SquadFeatures
|
features: SquadFeatures
|
||||||
): Unit = {
|
): Unit = {
|
||||||
|
SquadActionDefinitionAutoApproveInvitationRequests(tplayer.CharId, features)
|
||||||
|
}
|
||||||
|
|
||||||
|
def SquadActionDefinitionAutoApproveInvitationRequests(
|
||||||
|
charId: Long,
|
||||||
|
features: SquadFeatures
|
||||||
|
): Unit = {
|
||||||
//allowed auto-approval - resolve the requests (only)
|
//allowed auto-approval - resolve the requests (only)
|
||||||
val charId = tplayer.CharId
|
|
||||||
val (requests, others) =
|
val (requests, others) =
|
||||||
(invites.get(charId) match {
|
(invites.get(charId) match {
|
||||||
case Some(invite) => invite +: queuedInvites.getOrElse(charId, Nil)
|
case Some(invite) => invite +: queuedInvites.getOrElse(charId, Nil)
|
||||||
|
|
@ -911,6 +968,155 @@ class SquadInvitationManager(subs: SquadSubscriptionEntity, parent: ActorRef) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def listCurrentInvitations(charId: Long): List[String] = {
|
||||||
|
((invites.get(charId), queuedInvites.get(charId)) match {
|
||||||
|
case (Some(invite), Some(invites)) =>
|
||||||
|
invite +: invites
|
||||||
|
case (Some(invite), None) =>
|
||||||
|
List(invite)
|
||||||
|
case (None, Some(invites)) =>
|
||||||
|
invites
|
||||||
|
case _ =>
|
||||||
|
List()
|
||||||
|
}).collect {
|
||||||
|
case RequestRole(player, _, _) => player.Name
|
||||||
|
case IndirectInvite(player, features) if !features.Squad.Leader.Name.equals(player.Name) => player.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def tryChainAcceptance(
|
||||||
|
inviter: Player,
|
||||||
|
charId: Long,
|
||||||
|
list: List[Long],
|
||||||
|
features: SquadFeatures
|
||||||
|
): Unit = {
|
||||||
|
//filter queued invites
|
||||||
|
lazy val squadToLeader = List((features.Squad.GUID, features))
|
||||||
|
lazy val squadName = features.Squad.Task
|
||||||
|
var foundPairs: List[(Player, Invitation)] = List()
|
||||||
|
val unmatchedInvites = queuedInvites
|
||||||
|
.getOrElse(charId, Nil)
|
||||||
|
.filter {
|
||||||
|
case invite @ RequestRole(invitee, _, _)
|
||||||
|
if list.contains(invitee.CharId) && !features.Squad.Leader.Name.equals(invitee.Name) =>
|
||||||
|
foundPairs = foundPairs :+ (invitee, invite)
|
||||||
|
false
|
||||||
|
case invite @ IndirectInvite(invitee, _)
|
||||||
|
if list.contains(invitee.CharId) && !features.Squad.Leader.Name.equals(invitee.Name) =>
|
||||||
|
foundPairs = foundPairs :+ (invitee, invite)
|
||||||
|
false
|
||||||
|
case _ =>
|
||||||
|
true
|
||||||
|
}
|
||||||
|
//handle active invite
|
||||||
|
val clearedActiveInvite = invites
|
||||||
|
.get(charId)
|
||||||
|
.collect {
|
||||||
|
case invite @ RequestRole(invitee, _, _)
|
||||||
|
if list.contains(invitee.CharId) && !features.Squad.Leader.Name.equals(invitee.Name) =>
|
||||||
|
SquadActionMembershipAcceptInvite(inviter, invitee.CharId, Some(invite), Some(features))
|
||||||
|
invites.remove(charId)
|
||||||
|
true
|
||||||
|
case invite @ IndirectInvite(invitee, _)
|
||||||
|
if list.contains(invitee.CharId) && !features.Squad.Leader.Name.equals(invitee.Name) =>
|
||||||
|
SquadActionMembershipAcceptInvite(inviter, invitee.CharId, Some(invite), Some(features))
|
||||||
|
invites.remove(charId)
|
||||||
|
true
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
}
|
||||||
|
//handle selected queued invites
|
||||||
|
val pairIterator = foundPairs.iterator
|
||||||
|
while (pairIterator.hasNext && features.Squad.Capacity < features.Squad.Size) {
|
||||||
|
val (player, invite) = pairIterator.next()
|
||||||
|
SquadActionMembershipAcceptInvite(inviter, player.CharId, Some(invite), Some(features))
|
||||||
|
}
|
||||||
|
//evaluate final squad composition
|
||||||
|
if (features.Squad.Capacity < features.Squad.Size) {
|
||||||
|
//replace unfiltered invites
|
||||||
|
if (unmatchedInvites.isEmpty) {
|
||||||
|
queuedInvites.remove(charId)
|
||||||
|
} else {
|
||||||
|
queuedInvites.put(charId, unmatchedInvites)
|
||||||
|
}
|
||||||
|
//manage next invitation
|
||||||
|
clearedActiveInvite.collect {
|
||||||
|
case true => NextInviteAndRespond(charId)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//squad is full
|
||||||
|
previousInvites.remove(charId)
|
||||||
|
queuedInvites.remove(charId)
|
||||||
|
clearedActiveInvite.collect {
|
||||||
|
case true => invites.remove(charId)
|
||||||
|
}
|
||||||
|
unmatchedInvites.foreach { invite =>
|
||||||
|
val (refusedId, _) = ParseRejection(Some(invite), inviter, inviter.CharId, squadToLeader)
|
||||||
|
subs.Publish(refusedId, SquadResponse.SquadRelatedComment(s"Your request to join squad '$squadName' has been refused."))
|
||||||
|
}
|
||||||
|
NextInviteAndRespond(charId)
|
||||||
|
}
|
||||||
|
//clean up any incomplete selected invites
|
||||||
|
pairIterator.foreach { case (_, invite) =>
|
||||||
|
val (refusedId, _) = ParseRejection(Some(invite), inviter, inviter.CharId, squadToLeader)
|
||||||
|
subs.Publish(refusedId, SquadResponse.SquadRelatedComment(s"Your request to join squad '$squadName' has been refused."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def tryChainRejection(
|
||||||
|
inviter: Player,
|
||||||
|
charId: Long,
|
||||||
|
list: List[Long],
|
||||||
|
features: SquadFeatures): Unit = {
|
||||||
|
//handle queued invites
|
||||||
|
lazy val squadToLeader = List((features.Squad.GUID, features))
|
||||||
|
lazy val squadName = features.Squad.Task
|
||||||
|
val unmatchedInvites = queuedInvites
|
||||||
|
.getOrElse(charId, Nil)
|
||||||
|
.filter {
|
||||||
|
case invite @ RequestRole(invitee, _, _)
|
||||||
|
if list.contains(invitee.CharId) && !features.Squad.Leader.Name.equals(invitee.Name) =>
|
||||||
|
val (refusedId, _, _) = DoRejection(Some(invite), inviter, charId, squadToLeader)
|
||||||
|
subs.Publish(refusedId, SquadResponse.SquadRelatedComment(s"Your request to join squad '$squadName' has been refused."))
|
||||||
|
false
|
||||||
|
case invite @ IndirectInvite(invitee, _)
|
||||||
|
if list.contains(invitee.CharId) && !features.Squad.Leader.Name.equals(invitee.Name) =>
|
||||||
|
val (refusedId, _, _) = DoRejection(Some(invite), inviter, charId, squadToLeader)
|
||||||
|
subs.Publish(refusedId, SquadResponse.SquadRelatedComment(s"Your request to join squad '$squadName' has been refused."))
|
||||||
|
false
|
||||||
|
case _ =>
|
||||||
|
true
|
||||||
|
}
|
||||||
|
queuedInvites.put(charId, unmatchedInvites)
|
||||||
|
//handle active invite
|
||||||
|
invites
|
||||||
|
.get(charId)
|
||||||
|
.collect {
|
||||||
|
case invite @ RequestRole(player, features, _)
|
||||||
|
if list.contains(player.CharId) && !features.Squad.Leader.Name.equals(player.Name) =>
|
||||||
|
val (refusedId, _, _) = DoRejection(Some(invite), inviter, charId, squadToLeader)
|
||||||
|
subs.Publish(refusedId, SquadResponse.SquadRelatedComment(s"Your request to join squad '$squadName' has been refused."))
|
||||||
|
invites.remove(charId)
|
||||||
|
NextInviteAndRespond(charId)
|
||||||
|
case invite @ IndirectInvite(player, features)
|
||||||
|
if list.contains(player.CharId) && !features.Squad.Leader.Name.equals(player.Name) =>
|
||||||
|
val (refusedId, _, _) = DoRejection(Some(invite), inviter, charId, squadToLeader)
|
||||||
|
subs.Publish(refusedId, SquadResponse.SquadRelatedComment(s"Your request to join squad '$squadName' has been refused."))
|
||||||
|
invites.remove(charId)
|
||||||
|
NextInviteAndRespond(charId)
|
||||||
|
case _ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def tryChainRejectionAll(charId: Long, features: SquadFeatures): Unit = {
|
||||||
|
val squadName = features.Squad.Task
|
||||||
|
CleanUpAllInvitesToSquad(features)
|
||||||
|
.filterNot(_ == charId)
|
||||||
|
.foreach { refusedId =>
|
||||||
|
subs.Publish(refusedId, SquadResponse.SquadRelatedComment(s"Your request to join squad '$squadName' has been refused."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def ShiftInvitesToPromotedSquadLeader(
|
def ShiftInvitesToPromotedSquadLeader(
|
||||||
sponsoringPlayer: Long,
|
sponsoringPlayer: Long,
|
||||||
promotedPlayer: Long
|
promotedPlayer: Long
|
||||||
|
|
@ -1695,18 +1901,18 @@ class SquadInvitationManager(subs: SquadSubscriptionEntity, parent: ActorRef) {
|
||||||
* @see `VacancyInvite`
|
* @see `VacancyInvite`
|
||||||
* @param features the squad identifier
|
* @param features the squad identifier
|
||||||
*/
|
*/
|
||||||
def CleanUpAllInvitesToSquad(features: SquadFeatures): Unit = {
|
def CleanUpAllInvitesToSquad(features: SquadFeatures): List[Long] = {
|
||||||
val guid = features.Squad.GUID
|
val guid = features.Squad.GUID
|
||||||
//clean up invites
|
//clean up invites
|
||||||
val activeInviteIds = {
|
val activeInviteIds = {
|
||||||
val keys = invites.keys.toSeq
|
val keys = invites.keys.toSeq
|
||||||
invites.values.zipWithIndex
|
invites.values.zipWithIndex
|
||||||
.collect {
|
.collect {
|
||||||
case (VacancyInvite(_, _, _squad), index) if _squad.Squad.GUID == guid => index
|
case (VacancyInvite(_, _, f), index) if f.Squad.GUID == guid => index
|
||||||
case (IndirectInvite(_, _squad), index) if _squad.Squad.GUID == guid => index
|
case (IndirectInvite(_, f), index) if f.Squad.GUID == guid => index
|
||||||
case (LookingForSquadRoleInvite(_, _squad, _), index) if _squad.Squad.GUID == guid => index
|
case (LookingForSquadRoleInvite(_, f, _), index) if f.Squad.GUID == guid => index
|
||||||
case (ProximityInvite(_, _squad, _), index) if _squad.Squad.GUID == guid => index
|
case (ProximityInvite(_, f, _), index) if f.Squad.GUID == guid => index
|
||||||
case (RequestRole(_, _squad, _), index) if _squad.Squad.GUID == guid => index
|
case (RequestRole(_, f, _), index) if f.Squad.GUID == guid => index
|
||||||
}
|
}
|
||||||
.map { index =>
|
.map { index =>
|
||||||
val key = keys(index)
|
val key = keys(index)
|
||||||
|
|
@ -1723,11 +1929,11 @@ class SquadInvitationManager(subs: SquadSubscriptionEntity, parent: ActorRef) {
|
||||||
case (queue, index) =>
|
case (queue, index) =>
|
||||||
val key = keys(index)
|
val key = keys(index)
|
||||||
val (targets, retained) = queue.partition {
|
val (targets, retained) = queue.partition {
|
||||||
case VacancyInvite(_, _, _squad) => _squad.Squad.GUID == guid
|
case VacancyInvite(_, _, f) => f.Squad.GUID == guid
|
||||||
case IndirectInvite(_, _squad) => _squad.Squad.GUID == guid
|
case IndirectInvite(_, f) => f.Squad.GUID == guid
|
||||||
case LookingForSquadRoleInvite(_, _squad, _) => _squad.Squad.GUID == guid
|
case LookingForSquadRoleInvite(_, f, _) => f.Squad.GUID == guid
|
||||||
case ProximityInvite(_, _squad, _) => _squad.Squad.GUID == guid
|
case ProximityInvite(_, f, _) => f.Squad.GUID == guid
|
||||||
case RequestRole(_, _squad, _) => _squad.Squad.GUID == guid
|
case RequestRole(_, f, _) => f.Squad.GUID == guid
|
||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
if (retained.isEmpty) {
|
if (retained.isEmpty) {
|
||||||
|
|
@ -1744,7 +1950,9 @@ class SquadInvitationManager(subs: SquadSubscriptionEntity, parent: ActorRef) {
|
||||||
.flatten
|
.flatten
|
||||||
.toList
|
.toList
|
||||||
}
|
}
|
||||||
CleanUpSquadFeatures(activeInviteIds ++ queuedInviteIds, features, position = -1)
|
val allInviteIds = (activeInviteIds ++ queuedInviteIds).distinct
|
||||||
|
CleanUpSquadFeatures(allInviteIds, features, position = -1)
|
||||||
|
allInviteIds
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -2151,4 +2359,15 @@ object SquadInvitationManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
final case class FinishStartSquad(features: SquadFeatures)
|
final case class FinishStartSquad(features: SquadFeatures)
|
||||||
|
|
||||||
|
def canEnrollInSquad(features: SquadFeatures, charId: Long): Boolean = {
|
||||||
|
!features.Squad.Membership.exists { _.CharId == charId }
|
||||||
|
}
|
||||||
|
|
||||||
|
def notLeaderOfThisSquad(squadsToLeaders: List[(PlanetSideGUID, SquadFeatures)], guid: PlanetSideGUID, charId: Long): Boolean = {
|
||||||
|
squadsToLeaders.find { case (squadGuid, _) => squadGuid == guid } match {
|
||||||
|
case Some((_, features)) => features.Squad.Leader.CharId != charId
|
||||||
|
case None => false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
package net.psforever.services.teamwork
|
package net.psforever.services.teamwork
|
||||||
|
|
||||||
import akka.actor.{Actor, ActorRef, Terminated}
|
import akka.actor.{Actor, ActorRef, Terminated}
|
||||||
|
import net.psforever.actors.session.SessionActor
|
||||||
|
import net.psforever.packet.game.ChatMsg
|
||||||
|
import net.psforever.types.ChatMessageType
|
||||||
|
|
||||||
import java.io.{PrintWriter, StringWriter}
|
import java.io.{PrintWriter, StringWriter}
|
||||||
import scala.annotation.unused
|
import scala.annotation.unused
|
||||||
|
|
@ -111,7 +114,7 @@ class SquadService extends Actor {
|
||||||
* @return `true`, if the identifier is reset; `false`, otherwise
|
* @return `true`, if the identifier is reset; `false`, otherwise
|
||||||
*/
|
*/
|
||||||
def TryResetSquadId(): Boolean = {
|
def TryResetSquadId(): Boolean = {
|
||||||
if (squadFeatures.isEmpty) {
|
if (squadFeatures.isEmpty && LivePlayerList.WorldPopulation(_ => true).isEmpty) {
|
||||||
sid = 1
|
sid = 1
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -199,7 +202,7 @@ class SquadService extends Actor {
|
||||||
LeaveInGeneral(sender())
|
LeaveInGeneral(sender())
|
||||||
|
|
||||||
case Terminated(actorRef) =>
|
case Terminated(actorRef) =>
|
||||||
TerminatedBy(actorRef)
|
LeaveInGeneral(actorRef)
|
||||||
|
|
||||||
case message @ SquadServiceMessage(tplayer, zone, squad_action) =>
|
case message @ SquadServiceMessage(tplayer, zone, squad_action) =>
|
||||||
squad_action match {
|
squad_action match {
|
||||||
|
|
@ -243,16 +246,39 @@ class SquadService extends Actor {
|
||||||
case SquadService.ResendActiveInvite(charId) =>
|
case SquadService.ResendActiveInvite(charId) =>
|
||||||
invitations.resendActiveInvite(charId)
|
invitations.resendActiveInvite(charId)
|
||||||
|
|
||||||
|
case SquadService.ListAllCurrentInvites(charId) =>
|
||||||
|
ListCurrentInvitations(charId)
|
||||||
|
|
||||||
|
case SquadService.ChainAcceptance(player, charId, list) =>
|
||||||
|
ChainAcceptanceIntoSquad(player, charId, list)
|
||||||
|
|
||||||
|
case SquadService.ChainRejection(player, charId, list) =>
|
||||||
|
ChainRejectionFromSquad(player, charId, list)
|
||||||
|
|
||||||
case msg =>
|
case msg =>
|
||||||
log.warn(s"Unhandled message $msg from ${sender()}")
|
log.warn(s"Unhandled message $msg from ${sender()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribe to a faction-wide channel.
|
||||||
|
* @param faction sub-channel name
|
||||||
|
* @param sender subscriber
|
||||||
|
*/
|
||||||
def JoinByFaction(faction: String, sender: ActorRef): Unit = {
|
def JoinByFaction(faction: String, sender: ActorRef): Unit = {
|
||||||
val path = s"/$faction/Squad"
|
val path = s"/$faction/Squad"
|
||||||
log.trace(s"$sender has joined $path")
|
log.trace(s"$sender has joined $path")
|
||||||
subs.SquadEvents.subscribe(sender, path)
|
subs.SquadEvents.subscribe(sender, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribe to a client-specific channel.
|
||||||
|
* The channel name is expected to be a `Long` number but is passed as a `String`.
|
||||||
|
* As is the case, the actual channel name may not parse into a proper long integer after being passed and
|
||||||
|
* there are failure cases.
|
||||||
|
* @param charId sub-channel name
|
||||||
|
* @param sender subscriber
|
||||||
|
* @see `SquadInvitationManager.handleJoin`
|
||||||
|
*/
|
||||||
def JoinByCharacterId(charId: String, sender: ActorRef): Unit = {
|
def JoinByCharacterId(charId: String, sender: ActorRef): Unit = {
|
||||||
try {
|
try {
|
||||||
val longCharId = charId.toLong
|
val longCharId = charId.toLong
|
||||||
|
|
@ -272,12 +298,23 @@ class SquadService extends Actor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsubscribe from a faction-wide channel.
|
||||||
|
* @param faction sub-channel name
|
||||||
|
* @param sender subscriber
|
||||||
|
*/
|
||||||
def LeaveByFaction(faction: String, sender: ActorRef): Unit = {
|
def LeaveByFaction(faction: String, sender: ActorRef): Unit = {
|
||||||
val path = s"/$faction/Squad"
|
val path = s"/$faction/Squad"
|
||||||
log.trace(s"$sender has left $path")
|
log.trace(s"$sender has left $path")
|
||||||
subs.SquadEvents.unsubscribe(sender, path)
|
subs.SquadEvents.unsubscribe(sender, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsubscribe from a client-specific channel.
|
||||||
|
* @param charId sub-channel name
|
||||||
|
* @param sender subscriber
|
||||||
|
* @see `LeaveService`
|
||||||
|
*/
|
||||||
def LeaveByCharacterId(charId: String, sender: ActorRef): Unit = {
|
def LeaveByCharacterId(charId: String, sender: ActorRef): Unit = {
|
||||||
try {
|
try {
|
||||||
LeaveService(charId.toLong, sender)
|
LeaveService(charId.toLong, sender)
|
||||||
|
|
@ -292,23 +329,23 @@ class SquadService extends Actor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assuming a subscriber that matches previously subscribed data,
|
||||||
|
* completely unsubscribe and forget this entry.
|
||||||
|
* @param sender subscriber
|
||||||
|
* @see `LeaveService`
|
||||||
|
*/
|
||||||
def LeaveInGeneral(sender: ActorRef): Unit = {
|
def LeaveInGeneral(sender: ActorRef): Unit = {
|
||||||
subs.UserEvents find { case (_, subscription) => subscription.path.equals(sender.path) } match {
|
context.unwatch(sender)
|
||||||
|
subs.UserEvents.find {
|
||||||
|
case (_, subscription) => (subscription eq sender) || subscription.path.equals(sender.path)
|
||||||
|
} match {
|
||||||
case Some((to, _)) =>
|
case Some((to, _)) =>
|
||||||
LeaveService(to, sender)
|
LeaveService(to, sender)
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def TerminatedBy(requestee: ActorRef): Unit = {
|
|
||||||
context.unwatch(requestee)
|
|
||||||
subs.UserEvents find { case (_, subscription) => subscription eq requestee } match {
|
|
||||||
case Some((to, _)) =>
|
|
||||||
LeaveService(to, requestee)
|
|
||||||
case _ => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def performStartSquad(sender: ActorRef, player: Player): Unit = {
|
def performStartSquad(sender: ActorRef, player: Player): Unit = {
|
||||||
val invitingPlayerCharId = player.CharId
|
val invitingPlayerCharId = player.CharId
|
||||||
if (EnsureEmptySquad(invitingPlayerCharId)) {
|
if (EnsureEmptySquad(invitingPlayerCharId)) {
|
||||||
|
|
@ -544,7 +581,7 @@ class SquadService extends Actor {
|
||||||
invitations.handleRejection(
|
invitations.handleRejection(
|
||||||
tplayer,
|
tplayer,
|
||||||
rejectingPlayer,
|
rejectingPlayer,
|
||||||
squadFeatures.map { case (guid, features) => (guid, features.Squad.Leader.CharId) }.toList
|
squadFeatures.map { case (guid, features) => (guid, features) }.toList
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1084,9 +1121,14 @@ class SquadService extends Actor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* na
|
* Completely remove information about a former subscriber from the squad management service.
|
||||||
* @param charId the player's unique character identifier number
|
* @param charId the player's unique character identifier number
|
||||||
* @param sender the `ActorRef` associated with this character
|
* @param sender the `ActorRef` associated with this character
|
||||||
|
* @see `DisbandSquad`
|
||||||
|
* @see `LeaveSquad`
|
||||||
|
* @see `SquadInvitationManager.handleLeave`
|
||||||
|
* @see `SquadSwitchboard.PanicLeaveSquad`
|
||||||
|
* @see `TryResetSquadId`
|
||||||
*/
|
*/
|
||||||
def LeaveService(charId: Long, sender: ActorRef): Unit = {
|
def LeaveService(charId: Long, sender: ActorRef): Unit = {
|
||||||
subs.MonitorSquadDetails.subtractOne(charId)
|
subs.MonitorSquadDetails.subtractOne(charId)
|
||||||
|
|
@ -1129,8 +1171,7 @@ class SquadService extends Actor {
|
||||||
}
|
}
|
||||||
subs.SquadEvents.unsubscribe(sender) //just to make certain
|
subs.SquadEvents.unsubscribe(sender) //just to make certain
|
||||||
searchData.remove(charId)
|
searchData.remove(charId)
|
||||||
//todo turn this back on. See PR 1157 for why it was commented out.
|
TryResetSquadId()
|
||||||
//TryResetSquadId()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1285,6 +1326,50 @@ class SquadService extends Actor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def ListCurrentInvitations(charId: Long) : Unit = {
|
||||||
|
GetLeadingSquad(charId, None)
|
||||||
|
.map { _ =>
|
||||||
|
invitations.listCurrentInvitations(charId)
|
||||||
|
}
|
||||||
|
.collect {
|
||||||
|
case listOfInvites if listOfInvites.nonEmpty =>
|
||||||
|
listOfInvites match {
|
||||||
|
case active :: queued if queued.nonEmpty =>
|
||||||
|
subs.Publish(charId, SquadResponse.WantsSquadPosition(charId, s"$active, ${queued.mkString(", ")}"))
|
||||||
|
listOfInvites
|
||||||
|
case active :: _ =>
|
||||||
|
subs.Publish(charId, SquadResponse.WantsSquadPosition(charId, active))
|
||||||
|
listOfInvites
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.orElse {
|
||||||
|
context.self ! SessionActor.SendResponse(ChatMsg(ChatMessageType.UNK_227, "You do not have any current invites to manage."))
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def ChainAcceptanceIntoSquad(player: Player, charId: Long, listOfCharIds: List[Long]): Unit = {
|
||||||
|
GetLeadingSquad(charId, None)
|
||||||
|
.foreach { features =>
|
||||||
|
if (listOfCharIds.nonEmpty) {
|
||||||
|
invitations.tryChainAcceptance(player, charId, listOfCharIds, features)
|
||||||
|
} else {
|
||||||
|
invitations.SquadActionDefinitionAutoApproveInvitationRequests(charId, features)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def ChainRejectionFromSquad(player: Player, charId: Long, listOfCharIds: List[Long]): Unit = {
|
||||||
|
GetLeadingSquad(charId, None)
|
||||||
|
.foreach { features =>
|
||||||
|
if (listOfCharIds.nonEmpty) {
|
||||||
|
invitations.tryChainRejection(player, charId, listOfCharIds, features)
|
||||||
|
} else {
|
||||||
|
invitations.tryChainRejectionAll(charId, features)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object SquadService {
|
object SquadService {
|
||||||
|
|
@ -1294,6 +1379,12 @@ object SquadService {
|
||||||
|
|
||||||
final case class ResendActiveInvite(charId: Long)
|
final case class ResendActiveInvite(charId: Long)
|
||||||
|
|
||||||
|
final case class ListAllCurrentInvites(charId: Long)
|
||||||
|
|
||||||
|
final case class ChainAcceptance(player: Player, charId: Long, listOfCharIds: List[Long])
|
||||||
|
|
||||||
|
final case class ChainRejection(player: Player, charId: Long, listOfCharIds: List[Long])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message to indicate that the squad list needs to update for the clients.
|
* A message to indicate that the squad list needs to update for the clients.
|
||||||
* @param features the squad
|
* @param features the squad
|
||||||
|
|
|
||||||
|
|
@ -73,4 +73,6 @@ object SquadResponse {
|
||||||
unk2: Int,
|
unk2: Int,
|
||||||
zoneNumber: Int
|
zoneNumber: Int
|
||||||
) extends Response
|
) extends Response
|
||||||
|
|
||||||
|
final case class SquadRelatedComment(str: String) extends Response
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ class SquadSubscriptionEntity {
|
||||||
case str if str.matches("\\d+") =>
|
case str if str.matches("\\d+") =>
|
||||||
Publish(to.toLong, msg, excluded)
|
Publish(to.toLong, msg, excluded)
|
||||||
case _ =>
|
case _ =>
|
||||||
log.warn(s"Publish(String): subscriber information is an unhandled format - $to")
|
log.warn(s"Publish(String): subscriber information is an unhandled format - $to; message $msg dropped")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -148,7 +148,7 @@ class SquadSubscriptionEntity {
|
||||||
case Some(user) =>
|
case Some(user) =>
|
||||||
user ! SquadServiceResponse("", msg)
|
user ! SquadServiceResponse("", msg)
|
||||||
case None =>
|
case None =>
|
||||||
log.warn(s"Publish(Long): subscriber information can not be found - $to")
|
log.warn(s"Publish(Long): subscriber information can not be found - $to; message $msg dropped")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -174,7 +174,7 @@ class SquadSubscriptionEntity {
|
||||||
* @param msg a message that can be stored in a `SquadServiceResponse` object
|
* @param msg a message that can be stored in a `SquadServiceResponse` object
|
||||||
*/
|
*/
|
||||||
def Publish[ANY >: Any](to: ANY, msg: SquadResponse.Response): Unit = {
|
def Publish[ANY >: Any](to: ANY, msg: SquadResponse.Response): Unit = {
|
||||||
log.warn(s"Publish(Any): subscriber information is an unhandled format - $to")
|
log.warn(s"Publish(Any): subscriber information is an unhandled format - $to; message $msg dropped")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -187,7 +187,7 @@ class SquadSubscriptionEntity {
|
||||||
* @param excluded a group of character identifier numbers who should not receive the message
|
* @param excluded a group of character identifier numbers who should not receive the message
|
||||||
*/
|
*/
|
||||||
def Publish[ANY >: Any](to: ANY, msg: SquadResponse.Response, excluded: Iterable[Long]): Unit = {
|
def Publish[ANY >: Any](to: ANY, msg: SquadResponse.Response, excluded: Iterable[Long]): Unit = {
|
||||||
log.warn(s"Publish(Any): subscriber information is an unhandled format - $to")
|
log.warn(s"Publish(Any): subscriber information is an unhandled format - $to; message $msg dropped")
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The following functions are related to common communications of squad information, mainly detail. */
|
/* The following functions are related to common communications of squad information, mainly detail. */
|
||||||
|
|
@ -211,7 +211,7 @@ class SquadSubscriptionEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatch an intial message entailing the strategic information and the composition of this squad.
|
* Dispatch an initial message entailing the strategic information and the composition of this squad.
|
||||||
* The details of the squad will be updated in full and be sent to all indicated observers.
|
* The details of the squad will be updated in full and be sent to all indicated observers.
|
||||||
* @see `SquadService.PublishFullDetails`
|
* @see `SquadService.PublishFullDetails`
|
||||||
* @param guid the unique squad identifier to be used when composing the details for this message
|
* @param guid the unique squad identifier to be used when composing the details for this message
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue