mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-01-20 02:24:45 +00:00
SquadAction and SquadResponse were worked into SquadServiceMessage and SquadServiceResponse, respectively, so that traits could be sealed; the continuous join request prompt has been exorcised from squad operations; switching to auto-approve for squads will now resolve all pending join requests; enumerated shared cases in SDAM
This commit is contained in:
parent
93f2264f61
commit
5916fa68be
|
|
@ -1,8 +1,7 @@
|
|||
// Copyright (c) 2019 PSForever
|
||||
package net.psforever.objects.teamwork
|
||||
|
||||
import akka.actor.{Actor, ActorContext, ActorRef, Cancellable, Props}
|
||||
import net.psforever.objects.DefaultCancellable
|
||||
import akka.actor.{Actor, ActorContext, ActorRef, Props}
|
||||
import net.psforever.types.SquadWaypoints
|
||||
import services.teamwork.SquadService.WaypointData
|
||||
import services.teamwork.SquadSwitchboard
|
||||
|
|
@ -11,8 +10,8 @@ class SquadFeatures(val Squad : Squad) {
|
|||
/**
|
||||
* `initialAssociation` per squad is similar to "Does this squad want to recruit members?"
|
||||
* The squad does not have to be flagged.
|
||||
* Dispatches an `AssociateWithSquad` `SDAM` to the squad leader and ???
|
||||
* and then a `SDDUM` that includes at least the squad owner name and char id.
|
||||
* Dispatches an `AssociateWithSquad` `SquadDefinitionActionMessage` packet to the squad leader and ???
|
||||
* and then a `SquadDetailDefinitionUpdateMessage` that includes at least the squad owner name and char id.
|
||||
* Dispatched only once when a squad is first listed
|
||||
* or when the squad leader searches for recruits by proximity or for certain roles or by invite
|
||||
* or when a spontaneous squad forms,
|
||||
|
|
@ -52,8 +51,6 @@ class SquadFeatures(val Squad : Squad) {
|
|||
* Handle persistent data related to `ProximityInvite` and `LookingForSquadRoleInvite` messages
|
||||
*/
|
||||
private var proxyInvites : List[Long] = Nil
|
||||
|
||||
private var requestInvitePrompt : Cancellable = DefaultCancellable.obj
|
||||
/**
|
||||
* These useres rejected invitation to this squad.
|
||||
* For the purposes of wide-searches for membership
|
||||
|
|
@ -79,7 +76,6 @@ class SquadFeatures(val Squad : Squad) {
|
|||
switchboard ! akka.actor.PoisonPill
|
||||
switchboard = Actor.noSender
|
||||
waypoints = Array.empty
|
||||
requestInvitePrompt.cancel
|
||||
this
|
||||
}
|
||||
|
||||
|
|
@ -143,13 +139,4 @@ class SquadFeatures(val Squad : Squad) {
|
|||
}
|
||||
|
||||
def ToChannel : String = channel
|
||||
|
||||
def Prompt : Cancellable = requestInvitePrompt
|
||||
|
||||
def Prompt_=(callback: Cancellable) : Cancellable = {
|
||||
if(requestInvitePrompt.isCancelled) {
|
||||
requestInvitePrompt = callback
|
||||
}
|
||||
Prompt
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -426,16 +426,23 @@ object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMe
|
|||
((code : @switch) match {
|
||||
case 0 => displaySquadCodec
|
||||
case 1 => squadMemberInitializationIssueCodec
|
||||
case 2 => unknownCodec(action = 2)
|
||||
case 3 => saveSquadFavoriteCodec
|
||||
case 4 => loadSquadFavoriteCodec
|
||||
case 5 => deleteSquadFavoriteCodec
|
||||
case 6 => unknownCodec(action = 6)
|
||||
case 7 => listSquadFavoriteCodec
|
||||
case 8 => requestListSquadCodec
|
||||
case 9 => stopListSquadCodec
|
||||
case 10 => selectRoleForYourselfCodec
|
||||
case 11 => unknownCodec(action = 11)
|
||||
case 12 => unknownCodec(action = 12)
|
||||
case 13 => unknownCodec(action = 13)
|
||||
case 14 => unknownCodec(action = 14)
|
||||
case 15 => cancelSelectRoleForYourselfCodec
|
||||
case 16 => associateWithSquadCodec
|
||||
case 17 => setListSquadCodec
|
||||
case 18 => unknownCodec(action = 18)
|
||||
case 19 => changeSquadPurposeCodec
|
||||
case 20 => changeSquadZoneCodec
|
||||
case 21 => closeSquadMemberPositionCodec
|
||||
|
|
@ -444,17 +451,23 @@ object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMe
|
|||
case 24 => changeSquadMemberRequirementsDetailedOrdersCodec
|
||||
case 25 => changeSquadMemberRequirementsCertificationsCodec
|
||||
case 26 => resetAllCodec
|
||||
//case 27 => ?
|
||||
case 28 => autoApproveInvitationRequestsCodec
|
||||
case 29 => unknownCodec(action = 29)
|
||||
case 30 => unknownCodec(action = 30)
|
||||
case 31 => locationFollowsSquadLeadCodec
|
||||
case 32 => unknownCodec(action = 32)
|
||||
case 33 => unknownCodec(action = 33)
|
||||
case 34 => searchForSquadsWithParticularRoleCodec
|
||||
case 35 => cancelSquadSearchCodec
|
||||
case 36 => unknownCodec(action = 36)
|
||||
case 37 => unknownCodec(action = 37)
|
||||
case 38 => assignSquadMemberToRoleCodec
|
||||
case 39 => noSquadSearchResultsCodec
|
||||
case 40 => findLfsSoldiersForRoleCodec
|
||||
case 41 => cancelFindCodec
|
||||
case 2 | 6 | 11 | 12 | 13 |
|
||||
14 | 18 | 29 | 30 | 32 |
|
||||
33 | 36 | 37 | 42 | 43 => unknownCodec(code)
|
||||
case 42 => unknownCodec(action = 42)
|
||||
case 43 => unknownCodec(action = 43)
|
||||
case _ => failureCodec(code)
|
||||
}).asInstanceOf[Codec[SquadAction]]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -657,44 +657,6 @@ object SquadDetailDefinitionUpdateMessage extends Marshallable[SquadDetailDefini
|
|||
}
|
||||
)
|
||||
}
|
||||
//TODO while this pattern looks elegant, bitsOverByte does not accumulate properly with the either(bool, L, R); why?
|
||||
// private def membersCodec(bitsOverByte : StreamLengthToken) : Codec[SquadDetail] = {
|
||||
// import shapeless.::
|
||||
// either(bool,
|
||||
// { //false
|
||||
// bitsOverByte.Add(3)
|
||||
// uint2 :: FullyPopulatedPositions.codec(bitsOverByte)
|
||||
// },
|
||||
// { //true
|
||||
// bitsOverByte.Add(4)
|
||||
// uint(3) :: vector(ItemizedPositions.codec(bitsOverByte))
|
||||
// }
|
||||
// ).exmap[SquadDetail] (
|
||||
// {
|
||||
// case Left(_ :: member_list :: HNil) =>
|
||||
// Attempt.successful(SquadDetail(None, None, None, None, None, None, None, None, Some(ignoreTerminatingEntry(member_list.toList))))
|
||||
// case Right(_ :: member_list :: HNil) =>
|
||||
// Attempt.successful(SquadDetail(None, None, None, None, None, None, None, None, Some(ignoreTerminatingEntry(member_list.toList))))
|
||||
// },
|
||||
// {
|
||||
// case SquadDetail(_, _, _, _, _, _, _, _, Some(member_list)) =>
|
||||
// if(member_list
|
||||
// .collect { case position if position.info.nonEmpty =>
|
||||
// val info = position.info.get
|
||||
// List(info.is_closed, info.role, info.detailed_orders, info.requirements, info.char_id, info.name)
|
||||
// }
|
||||
// .flatten
|
||||
// .count(_.isEmpty) == 0) {
|
||||
// Attempt.successful(Left(2 :: ensureTerminatingEntry(member_list).toVector :: HNil))
|
||||
// }
|
||||
// else {
|
||||
// Attempt.successful(Right(4 :: ensureTerminatingEntry(member_list).toVector :: HNil))
|
||||
// }
|
||||
// case _ =>
|
||||
// Attempt.failure(Err("failed to encode squad data for members"))
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
/**
|
||||
* A failing pattern for when the coded value is not tied to a known field pattern.
|
||||
* This pattern does not read or write any bit data.
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
// Copyright (c) 2019 PSForever
|
||||
package services.teamwork
|
||||
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game._
|
||||
import net.psforever.types.{PlanetSideEmpire, SquadRequestType, SquadWaypoints, Vector3}
|
||||
|
||||
object SquadAction {
|
||||
trait Action
|
||||
|
||||
final case class InitSquadList() extends Action
|
||||
final case class InitCharId() extends Action
|
||||
|
||||
final case class Definition(guid : PlanetSideGUID, line : Int, action : SquadAction) extends Action
|
||||
final case class Membership(request_type : SquadRequestType.Value, unk2 : Long, unk3 : Option[Long], player_name : String, unk5 : Option[Option[String]]) extends Action
|
||||
final case class Waypoint(event_type : WaypointEventAction.Value, waypoint_type : SquadWaypoints.Value, unk : Option[Long], waypoint_info : Option[WaypointInfo]) extends Action
|
||||
final case class Update(char_id : Long, health : Int, max_health : Int, armor : Int, max_armor : Int, pos : Vector3, zone_number : Int) extends Action
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
// Copyright (c) 2019 PSForever
|
||||
package services.teamwork
|
||||
|
||||
import net.psforever.objects.teamwork.Squad
|
||||
import net.psforever.packet.game._
|
||||
import net.psforever.types.{SquadResponseType, SquadWaypoints}
|
||||
|
||||
object SquadResponse {
|
||||
trait Response
|
||||
|
||||
final case class ListSquadFavorite(line : Int, task : String) extends Response
|
||||
|
||||
final case class InitList(info : Vector[SquadInfo]) extends Response
|
||||
final case class UpdateList(infos : Iterable[(Int, SquadInfo)]) extends Response
|
||||
final case class RemoveFromList(infos : Iterable[Int]) extends Response
|
||||
|
||||
final case class AssociateWithSquad(squad_guid : PlanetSideGUID) extends Response
|
||||
final case class SetListSquad(squad_guid : PlanetSideGUID) extends Response
|
||||
|
||||
final case class Membership(request_type : SquadResponseType.Value, unk1 : Int, unk2 : Int, unk3 : Long, unk4 : Option[Long], player_name : String, unk5 : Boolean, unk6 : Option[Option[String]]) extends Response //see SquadMembershipResponse
|
||||
final case class WantsSquadPosition(leader_char_id : Long, bid_name : String) extends Response
|
||||
final case class Join(squad : Squad, positionsToUpdate : List[Int], channel : String) extends Response
|
||||
final case class Leave(squad : Squad, positionsToUpdate : List[(Long, Int)]) extends Response
|
||||
final case class UpdateMembers(squad : Squad, update_info : List[SquadAction.Update]) extends Response
|
||||
final case class AssignMember(squad : Squad, from_index : Int, to_index : Int) extends Response
|
||||
final case class PromoteMember(squad : Squad, char_id : Long, from_index : Int, to_index : Int) extends Response
|
||||
|
||||
final case class Detail(guid : PlanetSideGUID, squad_detail : SquadDetail) extends Response
|
||||
|
||||
final case class InitWaypoints(char_id : Long, waypoints : Iterable[(SquadWaypoints.Value, WaypointInfo, Int)]) extends Response
|
||||
final case class WaypointEvent(event_type : WaypointEventAction.Value, char_id : Long, waypoint_type : SquadWaypoints.Value, unk5 : Option[Long], waypoint_info : Option[WaypointInfo], unk : Int) extends Response
|
||||
|
||||
final case class SquadSearchResults() extends Response
|
||||
}
|
||||
|
|
@ -612,7 +612,6 @@ class SquadService extends Actor {
|
|||
//player requested to join a squad's specific position
|
||||
//invitedPlayer is actually the squad leader; petitioner is the actual "invitedPlayer"
|
||||
val features = squadFeatures(guid)
|
||||
features.Prompt.cancel
|
||||
JoinSquad(petitioner, features.Squad, position)
|
||||
RemoveInvitesForSquadAndPosition(guid, position)
|
||||
|
||||
|
|
@ -832,7 +831,6 @@ class SquadService extends Actor {
|
|||
//rejectingPlayer is the squad leader; candidate is the would-be squad member who was rejected
|
||||
val features = squadFeatures(guid)
|
||||
features.Refuse = rejectingPlayer
|
||||
features.Prompt.cancel
|
||||
(Some(rejectingPlayer), None)
|
||||
|
||||
case _ => ;
|
||||
|
|
@ -902,8 +900,6 @@ class SquadService extends Actor {
|
|||
val (member, index) = membership.zipWithIndex.find { case (_member, _) => _member.CharId == promotedPlayer }.get
|
||||
val features = squadFeatures(squad.GUID)
|
||||
SwapMemberPosition(leader, member)
|
||||
//cancel previous leader invite prompt, if any
|
||||
features.Prompt.cancel
|
||||
//move around invites so that the proper squad leader deals with them
|
||||
val leaderInvite = invites.remove(promotingPlayer)
|
||||
val leaderQueuedInvites = queuedInvites.remove(promotingPlayer).toList.flatten
|
||||
|
|
@ -1108,6 +1104,28 @@ class SquadService extends Actor {
|
|||
case AutoApproveInvitationRequests(state) =>
|
||||
val features = squadFeatures(lSquadOpt.getOrElse(StartSquad(tplayer)).GUID)
|
||||
features.AutoApproveInvitationRequests = state
|
||||
if(state) {
|
||||
//allowed auto-approval - resolve the requests (only)
|
||||
val charId = tplayer.CharId
|
||||
val (requests, others) = (invites.get(charId).toList ++ queuedInvites.get(charId).toList)
|
||||
.partition({ case _ : RequestRole => true})
|
||||
invites.remove(charId)
|
||||
queuedInvites.remove(charId)
|
||||
previousInvites.remove(charId)
|
||||
requests.foreach {
|
||||
case request : RequestRole =>
|
||||
JoinSquad(request.player, features.Squad, request.position)
|
||||
case _ => ;
|
||||
}
|
||||
others.collect { case invite : Invitation => invite } match {
|
||||
case Nil => ;
|
||||
case x :: Nil =>
|
||||
AddInviteAndRespond(charId, x, x.InviterCharId, x.InviterName)
|
||||
case x :: xs =>
|
||||
AddInviteAndRespond(charId, x, x.InviterCharId, x.InviterName)
|
||||
queuedInvites += charId -> xs
|
||||
}
|
||||
}
|
||||
|
||||
case FindLfsSoldiersForRole(position) =>
|
||||
lSquadOpt match {
|
||||
|
|
@ -1439,9 +1457,6 @@ class SquadService extends Actor {
|
|||
debug(s"Unhandled message $msg from $sender")
|
||||
}
|
||||
|
||||
case data @ SquadResponse.WantsSquadPosition(leader_char_id, _) =>
|
||||
Publish(leader_char_id, data)
|
||||
|
||||
case msg =>
|
||||
debug(s"Unhandled message $msg from $sender")
|
||||
}
|
||||
|
|
@ -2145,9 +2160,7 @@ class SquadService extends Actor {
|
|||
self ! SquadServiceMessage(player, Zone.Nowhere, SquadAction.Membership(SquadRequestType.Accept, leaderCharId, None, "", None))
|
||||
}
|
||||
else {
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
features.Prompt = context.system.scheduler.schedule(1 milliseconds, 45000 milliseconds, self, SquadResponse.WantsSquadPosition(leaderCharId, player.Name))
|
||||
Publish(leaderCharId, SquadResponse.WantsSquadPosition(leaderCharId, player.Name))
|
||||
}
|
||||
true
|
||||
case _ =>
|
||||
|
|
|
|||
|
|
@ -3,9 +3,23 @@ package services.teamwork
|
|||
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game.{PlanetSideGUID, SquadAction => PacketSquadAction, WaypointEventAction, WaypointInfo}
|
||||
import net.psforever.types.{SquadRequestType, SquadWaypoints, Vector3}
|
||||
|
||||
final case class SquadServiceMessage(tplayer : Player, zone : Zone, actionMessage : Any)
|
||||
|
||||
object SquadServiceMessage {
|
||||
final case class RecoverSquadMembership()
|
||||
}
|
||||
|
||||
object SquadAction {
|
||||
sealed trait Action
|
||||
|
||||
final case class InitSquadList() extends Action
|
||||
final case class InitCharId() extends Action
|
||||
|
||||
final case class Definition(guid : PlanetSideGUID, line : Int, action : PacketSquadAction) extends Action
|
||||
final case class Membership(request_type : SquadRequestType.Value, unk2 : Long, unk3 : Option[Long], player_name : String, unk5 : Option[Option[String]]) extends Action
|
||||
final case class Waypoint(event_type : WaypointEventAction.Value, waypoint_type : SquadWaypoints.Value, unk : Option[Long], waypoint_info : Option[WaypointInfo]) extends Action
|
||||
final case class Update(char_id : Long, health : Int, max_health : Int, armor : Int, max_armor : Int, pos : Vector3, zone_number : Int) extends Action
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
// Copyright (c) 2019 PSForever
|
||||
package services.teamwork
|
||||
|
||||
import net.psforever.objects.teamwork.Squad
|
||||
import net.psforever.packet.game._
|
||||
import net.psforever.types.{SquadResponseType, SquadWaypoints}
|
||||
import services.GenericEventBusMsg
|
||||
|
||||
final case class SquadServiceResponse(toChannel : String, exclude : Iterable[Long], response : SquadResponse.Response) extends GenericEventBusMsg
|
||||
|
|
@ -12,3 +15,31 @@ object SquadServiceResponse {
|
|||
def apply(toChannel : String, exclude : Long, response : SquadResponse.Response) : SquadServiceResponse =
|
||||
SquadServiceResponse(toChannel, Seq(exclude), response)
|
||||
}
|
||||
|
||||
object SquadResponse {
|
||||
sealed trait Response
|
||||
|
||||
final case class ListSquadFavorite(line : Int, task : String) extends Response
|
||||
|
||||
final case class InitList(info : Vector[SquadInfo]) extends Response
|
||||
final case class UpdateList(infos : Iterable[(Int, SquadInfo)]) extends Response
|
||||
final case class RemoveFromList(infos : Iterable[Int]) extends Response
|
||||
|
||||
final case class AssociateWithSquad(squad_guid : PlanetSideGUID) extends Response
|
||||
final case class SetListSquad(squad_guid : PlanetSideGUID) extends Response
|
||||
|
||||
final case class Membership(request_type : SquadResponseType.Value, unk1 : Int, unk2 : Int, unk3 : Long, unk4 : Option[Long], player_name : String, unk5 : Boolean, unk6 : Option[Option[String]]) extends Response //see SquadMembershipResponse
|
||||
final case class WantsSquadPosition(leader_char_id : Long, bid_name : String) extends Response
|
||||
final case class Join(squad : Squad, positionsToUpdate : List[Int], channel : String) extends Response
|
||||
final case class Leave(squad : Squad, positionsToUpdate : List[(Long, Int)]) extends Response
|
||||
final case class UpdateMembers(squad : Squad, update_info : List[SquadAction.Update]) extends Response
|
||||
final case class AssignMember(squad : Squad, from_index : Int, to_index : Int) extends Response
|
||||
final case class PromoteMember(squad : Squad, char_id : Long, from_index : Int, to_index : Int) extends Response
|
||||
|
||||
final case class Detail(guid : PlanetSideGUID, squad_detail : SquadDetail) extends Response
|
||||
|
||||
final case class InitWaypoints(char_id : Long, waypoints : Iterable[(SquadWaypoints.Value, WaypointInfo, Int)]) extends Response
|
||||
final case class WaypointEvent(event_type : WaypointEventAction.Value, char_id : Long, waypoint_type : SquadWaypoints.Value, unk5 : Option[Long], waypoint_info : Option[WaypointInfo], unk : Int) extends Response
|
||||
|
||||
final case class SquadSearchResults() extends Response
|
||||
}
|
||||
|
|
|
|||
|
|
@ -539,7 +539,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
SwapSquadUIElements(squad, from_index, to_index)
|
||||
|
||||
case SquadResponse.UpdateMembers(squad, positions) =>
|
||||
import services.teamwork.SquadAction.{Update => SAUpdate}
|
||||
val pairedEntries = positions.collect {
|
||||
case entry if squadUI.contains(entry.char_id) =>
|
||||
(entry, squadUI(entry.char_id))
|
||||
|
|
@ -3220,6 +3219,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
val clientVersion = s"Client Version: $majorVersion.$minorVersion.$revision, $buildDate"
|
||||
log.info(s"New world login to $server with Token:$token. $clientVersion")
|
||||
//TODO begin temp player character auto-loading; remove later
|
||||
//this is all just temporary character creation used in the dev branch, making explicit values that allow for testing
|
||||
//the unique character identifier number for this testing character is based on the original test character,
|
||||
//whose identifier number was 41605314
|
||||
//all head features, faction, and sex also match that test character
|
||||
import net.psforever.objects.GlobalDefinitions._
|
||||
import net.psforever.types.CertificationType._
|
||||
val faction = PlanetSideEmpire.VS
|
||||
|
|
|
|||
Loading…
Reference in a new issue