communication of the details information for a squad and refactored messaging back to WSA; removed an unused description field from the squad and added two fields that were actually represented

This commit is contained in:
FateJH 2019-06-06 14:54:53 -04:00
parent 5c433204cf
commit 9cf1cd92cc
9 changed files with 467 additions and 262 deletions

View file

@ -10,18 +10,21 @@ class Squad(squadId : PlanetSideGUID, alignment : PlanetSideEmpire.Value) extend
private val faction : PlanetSideEmpire.Value = alignment //does not change private val faction : PlanetSideEmpire.Value = alignment //does not change
private var zoneId : Option[Int] = None private var zoneId : Option[Int] = None
private var task : String = "" private var task : String = ""
private var description : String = ""
private val membership : Array[Member] = Array.fill[Member](10)(new Member) private val membership : Array[Member] = Array.fill[Member](10)(new Member)
private val availability : Array[Boolean] = Array.fill[Boolean](10)(true) private val availability : Array[Boolean] = Array.fill[Boolean](10)(true)
private var listed : Boolean = false private var listed : Boolean = false
private var leaderPositionIndex : Int = 0 private var leaderPositionIndex : Int = 0
private var autoApproveInvitationRequests : Boolean = false
private var locationFollowsSquadLead : Boolean = false
override def GUID_=(d : PlanetSideGUID) : PlanetSideGUID = GUID override def GUID_=(d : PlanetSideGUID) : PlanetSideGUID = GUID
def Faction : PlanetSideEmpire.Value = faction def Faction : PlanetSideEmpire.Value = faction
def CustomZoneId : Boolean = zoneId.isDefined
def ZoneId : Int = zoneId.getOrElse({ def ZoneId : Int = zoneId.getOrElse({
membership.headOption match { membership.lift(leaderPositionIndex) match {
case Some(leader) => case Some(leader) =>
leader.ZoneId leader.ZoneId
case _ => case _ =>
@ -45,13 +48,6 @@ class Squad(squadId : PlanetSideGUID, alignment : PlanetSideEmpire.Value) extend
Task Task
} }
def Description : String = description
def Description_=(desc : String) : String = {
description = desc
Description
}
def Listed : Boolean = listed def Listed : Boolean = listed
def Listed_=(announce : Boolean) : Boolean = { def Listed_=(announce : Boolean) : Boolean = {
@ -59,6 +55,20 @@ class Squad(squadId : PlanetSideGUID, alignment : PlanetSideEmpire.Value) extend
Listed Listed
} }
def LocationFollowsSquadLead : Boolean = locationFollowsSquadLead
def LocationFollowsSquadLead_=(follow : Boolean) : Boolean = {
locationFollowsSquadLead = follow
LocationFollowsSquadLead
}
def AutoApproveInvitationRequests : Boolean = autoApproveInvitationRequests
def AutoApproveInvitationRequests_=(autoApprove : Boolean) : Boolean = {
autoApproveInvitationRequests = autoApprove
AutoApproveInvitationRequests
}
def Membership : Array[Member] = membership def Membership : Array[Member] = membership
def Availability : Array[Boolean] = availability def Availability : Array[Boolean] = availability
@ -85,3 +95,16 @@ class Squad(squadId : PlanetSideGUID, alignment : PlanetSideEmpire.Value) extend
def Capacity : Int = availability.count(open => open) def Capacity : Int = availability.count(open => open)
} }
object Squad {
final val Blank = new Squad(PlanetSideGUID(0), PlanetSideEmpire.NEUTRAL) {
override def ZoneId : Int = 0
override def ZoneId_=(id : Int) : Int = 0
override def ZoneId_=(id : Option[Int]) : Int = 0
override def Task_=(assignment : String) : String = ""
override def Listed_=(announce : Boolean) : Boolean = false
override def Membership : Array[Member] = Array.empty[Member]
override def Availability : Array[Boolean] = Array.fill[Boolean](10)(false)
override def LeaderPositionIndex_=(position : Int) : Int = 0
}
}

View file

@ -306,13 +306,13 @@ object SquadAction{
* &nbsp;&nbsp;&nbsp;&nbsp;`36` - UNKNOWN<br> * &nbsp;&nbsp;&nbsp;&nbsp;`36` - UNKNOWN<br>
* &nbsp;&nbsp;`String :: Long :: Int :: Int`<br> * &nbsp;&nbsp;`String :: Long :: Int :: Int`<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`34` - Search for Squads with a Particular Role * &nbsp;&nbsp;&nbsp;&nbsp;`34` - Search for Squads with a Particular Role
* @param unk1 na * @param squad_guid the unique identifier of the squad, if non-zero
* @param unk2 na * @param line the original listing line number, if applicable
* @param action the purpose of this packet; * @param action the purpose of this packet;
* also decides the content of the parameter fields * also decides the content of the parameter fields
*/ */
final case class SquadDefinitionActionMessage(unk1 : Int, final case class SquadDefinitionActionMessage(squad_guid : PlanetSideGUID,
unk2 : Int, line : Int,
action : SquadAction) action : SquadAction)
extends PlanetSideGamePacket { extends PlanetSideGamePacket {
type Packet = SquadDefinitionActionMessage type Packet = SquadDefinitionActionMessage
@ -353,28 +353,28 @@ object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMe
case 35 => cancelSquadSearchCodec case 35 => cancelSquadSearchCodec
case 40 => findLfsSoldiersForRoleCodec case 40 => findLfsSoldiersForRoleCodec
case 41 => cancelFindCodec case 41 => cancelFindCodec
case 1 | 2 | 6 | 9 | case 1 | 2 | 6 | 9 | 11 |
11 | 12 | 13 | 14 | 16 | 12 | 13 | 14 | 16 | 17 |
17 | 18 | 29 | 30 | 33 | 36 | 18 | 29 | 30 | 32 | 33 |
37 | 38 | 42 | 43 => unknownCodec(code) 36 | 37 | 38 | 42 | 43 => unknownCodec(code)
case _ => failureCodec(code) case _ => failureCodec(code)
}).asInstanceOf[Codec[SquadAction]] }).asInstanceOf[Codec[SquadAction]]
} }
implicit val codec : Codec[SquadDefinitionActionMessage] = ( implicit val codec : Codec[SquadDefinitionActionMessage] = (
uintL(6) >>:~ { code => uintL(6) >>:~ { code =>
("unk1" | uint16L) :: ("squad_guid" | PlanetSideGUID.codec) ::
("unk2" | uint4L) :: ("line" | uint4L) ::
("action" | selectFromActionCode(code)) ("action" | selectFromActionCode(code))
} }
).xmap[SquadDefinitionActionMessage] ( ).xmap[SquadDefinitionActionMessage] (
{ {
case _ :: u1 :: u2 :: action :: HNil => case _ :: guid :: line :: action :: HNil =>
SquadDefinitionActionMessage(u1, u2, action) SquadDefinitionActionMessage(guid, line, action)
}, },
{ {
case SquadDefinitionActionMessage(u1, u2, action) => case SquadDefinitionActionMessage(guid, line, action) =>
action.code :: u1 :: u2 :: action :: HNil action.code :: guid :: line :: action :: HNil
} }
) )
} }

View file

@ -51,6 +51,8 @@ object SquadPositionDetail {
def apply(role : String, detailed_orders : String, requirements : Set[CertificationType.Value]) : SquadPositionDetail = SquadPositionDetail(is_closed = false, role, detailed_orders, requirements, 0L, "") def apply(role : String, detailed_orders : String, requirements : Set[CertificationType.Value]) : SquadPositionDetail = SquadPositionDetail(is_closed = false, role, detailed_orders, requirements, 0L, "")
def apply(role : String, detailed_orders : String, name : String) : SquadPositionDetail = SquadPositionDetail(is_closed = false, role, detailed_orders, Set.empty, reliableNameHash(name), name) def apply(role : String, detailed_orders : String, name : String) : SquadPositionDetail = SquadPositionDetail(is_closed = false, role, detailed_orders, Set.empty, reliableNameHash(name), name)
def apply(role : String, detailed_orders : String, requirements : Set[CertificationType.Value], name : String) : SquadPositionDetail = SquadPositionDetail(is_closed = false, role, detailed_orders, requirements, reliableNameHash(name), name)
} }
object SquadDetailDefinitionUpdateMessage extends Marshallable[SquadDetailDefinitionUpdateMessage] { object SquadDetailDefinitionUpdateMessage extends Marshallable[SquadDetailDefinitionUpdateMessage] {

View file

@ -28,7 +28,7 @@ final case class SquadMembershipRequest(request_type : SquadRequestType.Value,
assert(unk3.nonEmpty, s"a $request_type request requires the unk3 field be defined") assert(unk3.nonEmpty, s"a $request_type request requires the unk3 field be defined")
} }
if(request_type == SquadRequestType.Invite) { if(request_type == SquadRequestType.Invite) {
assert(unk5.nonEmpty, "an Invite request requires the unk5 field be undefined") assert(unk5.nonEmpty, "an Invite request requires the unk5 field be defined")
} }
type Packet = SquadMembershipRequest type Packet = SquadMembershipRequest

View file

@ -1,7 +1,7 @@
// Copyright (c) 2019 PSForever // Copyright (c) 2019 PSForever
package services.teamwork package services.teamwork
import net.psforever.packet.game.SquadInfo import net.psforever.packet.game.{PlanetSideGUID, PlanetSideZoneID, SquadInfo, SquadPositionDetail}
object SquadResponse { object SquadResponse {
trait Response trait Response
@ -9,4 +9,6 @@ object SquadResponse {
final case class Init(info : Vector[SquadInfo]) extends Response final case class Init(info : Vector[SquadInfo]) extends Response
final case class Update(infos : Iterable[(Int, SquadInfo)]) extends Response final case class Update(infos : Iterable[(Int, SquadInfo)]) extends Response
final case class Remove(infos : Iterable[Int]) extends Response final case class Remove(infos : Iterable[Int]) extends Response
final case class Detail(guid : PlanetSideGUID, leader : String, task : String, zone : PlanetSideZoneID, member_info : List[SquadPositionDetail]) extends Response
} }

View file

@ -3,9 +3,9 @@ package services.teamwork
import akka.actor.Actor import akka.actor.Actor
import net.psforever.objects.Player import net.psforever.objects.Player
import net.psforever.objects.teamwork.Squad import net.psforever.objects.teamwork.{Member, Squad}
import net.psforever.packet.game._ import net.psforever.packet.game._
import net.psforever.types.PlanetSideEmpire import net.psforever.types.{PlanetSideEmpire, Vector3}
import services.{GenericEventBus, Service} import services.{GenericEventBus, Service}
import scala.collection.concurrent.TrieMap import scala.collection.concurrent.TrieMap
@ -17,7 +17,7 @@ class SquadService extends Actor {
private var memberToSquad : TrieMap[String, Squad] = new TrieMap[String, Squad]() private var memberToSquad : TrieMap[String, Squad] = new TrieMap[String, Squad]()
private var idToSquad : TrieMap[PlanetSideGUID, Squad] = new TrieMap[PlanetSideGUID, Squad]() private var idToSquad : TrieMap[PlanetSideGUID, Squad] = new TrieMap[PlanetSideGUID, Squad]()
private var i : Int = 1 private var i : Int = 1
private var publishedLists : TrieMap[PlanetSideEmpire.Value, ListBuffer[SquadInfo]] = TrieMap[PlanetSideEmpire.Value, ListBuffer[SquadInfo]]( private val publishedLists : TrieMap[PlanetSideEmpire.Value, ListBuffer[SquadInfo]] = TrieMap[PlanetSideEmpire.Value, ListBuffer[SquadInfo]](
PlanetSideEmpire.TR -> ListBuffer.empty, PlanetSideEmpire.TR -> ListBuffer.empty,
PlanetSideEmpire.NC -> ListBuffer.empty, PlanetSideEmpire.NC -> ListBuffer.empty,
PlanetSideEmpire.VS -> ListBuffer.empty PlanetSideEmpire.VS -> ListBuffer.empty
@ -41,28 +41,51 @@ class SquadService extends Actor {
PlanetSideGUID(out) PlanetSideGUID(out)
} }
def GetSquadFromPlayer(player : Player) : Squad = { def GetParticipatingSquad(player : Player, zone : Int) : Option[Squad] = {
val name = player.Name memberToSquad.get(player.Name) match {
val faction = player.Faction case opt @ Some(squad) =>
memberToSquad.get(name) match { squad.Membership.find(_.Name == player.Name).get.ZoneId = zone
case Some(squad) => opt
squad
case None => case None =>
val id = GetNextSquadId() None
val squad = new Squad(id, faction)
val leadPosition = squad.Membership(squad.LeaderPositionIndex)
leadPosition.Name = name
leadPosition.Health = player.Health
leadPosition.Armor = player.Armor
leadPosition.Position = player.Position
leadPosition.ZoneId = 1 //player.Continent //TODO how to resolve this?
log.info(s"$name-$faction has started a new squad")
memberToSquad += name -> squad
idToSquad += id -> squad
squad
} }
} }
def GetLeadingSquad(player : Player, zone : Int, opt : Option[Squad]) : Squad = {
val name = player.Name
val squadOut = opt match {
case Some(squad) =>
if(squad.Leader.equals(name)) {
squad
}
else {
GetLeadingSquad(player, zone, None)
}
case None =>
memberToSquad.get(name) match {
case Some(squad) if squad.Leader.equals(name) =>
squad
case _ =>
val faction = player.Faction
val id = GetNextSquadId()
val squad = new Squad(id, faction)
val leadPosition = squad.Membership(squad.LeaderPositionIndex)
leadPosition.Name = name
leadPosition.Health = player.Health
leadPosition.Armor = player.Armor
leadPosition.Position = player.Position
leadPosition.ZoneId = zone
log.info(s"$name-$faction has started a new squad")
memberToSquad += name -> squad
idToSquad += id -> squad
squad
}
}
squadOut.Membership(squadOut.LeaderPositionIndex).ZoneId = zone
squadOut
}
val SquadEvents = new GenericEventBus[SquadServiceResponse] val SquadEvents = new GenericEventBus[SquadServiceResponse]
def receive : Receive = { def receive : Receive = {
@ -84,167 +107,306 @@ class SquadService extends Actor {
//check for renewable squad information //check for renewable squad information
memberToSquad.get(name) match { memberToSquad.get(name) match {
case None => ; case None => ;
case Some(squad) => case Some(_) =>
sender ! SquadServiceMessage.RecoverSquadMembership() sender ! SquadServiceMessage.RecoverSquadMembership() //TODO?
} }
case Service.Leave(Some(name)) => ; case Service.Leave(Some(name)) => ;
SquadEvents.unsubscribe(sender()) SquadEvents.unsubscribe(sender())
memberToSquad.get(name) match {
case Some(squad) =>
if(squad.Leader.equals(name)) {
//we were the leader
if(squad.Membership.count(p => p.Name.equals("")) > 1) {
//other players were in the squad; publicly disband it
squad.Membership.foreach(position => {
position.Name = ""
position.ZoneId = 0
position.Position = Vector3.Zero
position.Health = 0
position.Armor = 0
})
}
memberToSquad.remove(name)
idToSquad.remove(squad.GUID)
UpdateSquadList(squad, List())
}
else {
//we were just a grunt in the squad
val position = squad.Membership.find(_.Name == name).get
position.Name = ""
position.ZoneId = 0
position.Position = Vector3.Zero
position.Health = 0
position.Armor = 0
UpdateSquadDetail(squad)
}
case None => ;
}
//TODO leave squad, if joined to one, and perform clean-up //TODO leave squad, if joined to one, and perform clean-up
case Service.Leave(None) | Service.LeaveAll() => case Service.Leave(None) | Service.LeaveAll() => ;
SquadEvents.unsubscribe(sender())
//TODO might be better to invalidate these
case SquadServiceMessage.SquadDefinitionAction(tplayer, zone_ordinal_number, _, _, action) => case SquadServiceMessage.SquadDefinitionAction(tplayer, zone_ordinal_number, guid, _, action) =>
import net.psforever.packet.game.SquadAction._ import net.psforever.packet.game.SquadAction._
val squad = GetSquadFromPlayer(tplayer) val squadOpt = GetParticipatingSquad(tplayer, zone_ordinal_number)
val member = squad.Membership.find(_.Name == tplayer.Name).get //should never fail action match {
member.ZoneId = zone_ordinal_number //TODO improve this requirement case ChangeSquadPurpose(purpose) =>
if(tplayer.Name.equals(squad.Leader)) { log.info(s"${tplayer.Name}-${tplayer.Faction} has changed his squad's task to $purpose")
var listingChanged : List[Int] = Nil val squad = GetLeadingSquad(tplayer, zone_ordinal_number, squadOpt)
action match { squad.Task = purpose
case ChangeSquadPurpose(purpose) => UpdateSquadList(squad, List(SquadInfo.Field.Task))
log.info(s"${tplayer.Name}-${tplayer.Faction} has changed his squad's task to $purpose") UpdateSquadDetail(squad)
squad.Description = purpose
listingChanged = List(SquadInfo.Field.Task)
case ChangeSquadZone(zone) => case ChangeSquadZone(zone) =>
log.info(s"${tplayer.Name}-${tplayer.Faction} has changed his squad's ops zone to $zone") log.info(s"${tplayer.Name}-${tplayer.Faction} has changed squad's ops zone to $zone")
squad.ZoneId = zone.zoneId.toInt val squad = GetLeadingSquad(tplayer, zone_ordinal_number, squadOpt)
listingChanged = List(SquadInfo.Field.ZoneId) squad.ZoneId = zone.zoneId.toInt
UpdateSquadList(squad, List(SquadInfo.Field.ZoneId))
UpdateSquadDetail(squad)
case CloseSquadMemberPosition(position) => case CloseSquadMemberPosition(position) =>
if(position != squad.LeaderPositionIndex) { val squad = GetLeadingSquad(tplayer, zone_ordinal_number, squadOpt)
squad.Availability.lift(position) match { squad.Availability.lift(position) match {
case Some(true) => case Some(true) =>
squad.Availability.update(position, false) squad.Availability.update(position, false)
log.info(s"${tplayer.Name}-${tplayer.Faction} has closed the #$position position in his squad") log.info(s"${tplayer.Name}-${tplayer.Faction} has closed the #$position position in squad")
val memberPosition = squad.Membership(position) val memberPosition = squad.Membership(position)
listingChanged = if(memberPosition.Name.nonEmpty) { val listingChanged = if(memberPosition.Name.nonEmpty) {
List(SquadInfo.Field.Size, SquadInfo.Field.Capacity) List(SquadInfo.Field.Size, SquadInfo.Field.Capacity)
}
else {
List(SquadInfo.Field.Capacity)
}
memberPosition.Close()
UpdateSquadList(squad, listingChanged)
UpdateSquadDetail(squad)
case Some(false) | None => ;
}
case AddSquadMemberPosition(position) =>
val squad = GetLeadingSquad(tplayer, zone_ordinal_number, squadOpt)
squad.Availability.lift(position) match {
case Some(false) =>
log.info(s"${tplayer.Name}-${tplayer.Faction} has opened the #$position position in squad")
squad.Availability.update(position, true)
UpdateSquadList(squad, List(SquadInfo.Field.Capacity))
UpdateSquadDetail(squad)
case Some(true) | None => ;
}
case ChangeSquadMemberRequirementsRole(position, role) =>
val squad = GetLeadingSquad(tplayer, zone_ordinal_number, squadOpt)
squad.Availability.lift(position) match {
case Some(true) =>
log.info(s"${tplayer.Name}-${tplayer.Faction} has changed the role of squad position #$position")
squad.Membership(position).Role = role
UpdateSquadDetail(squad)
case Some(false) | None => ;
}
case ChangeSquadMemberRequirementsDetailedOrders(position, orders) =>
val squad = GetLeadingSquad(tplayer, zone_ordinal_number, squadOpt)
squad.Availability.lift(position) match {
case Some(true) =>
log.info(s"${tplayer.Name}-${tplayer.Faction} has changed the orders for squad position #$position")
squad.Membership(position).Orders = orders
UpdateSquadDetail(squad)
case Some(false) | None => ;
}
case ChangeSquadMemberRequirementsCertifications(position, certs) =>
val squad = GetLeadingSquad(tplayer, zone_ordinal_number, squadOpt)
squad.Availability.lift(position) match {
case Some(true) =>
log.info(s"${tplayer.Name}-${tplayer.Faction} has changed the requirements for squad position #$position")
squad.Membership(position).Requirements = certs
UpdateSquadDetail(squad)
case Some(false) | None => ;
}
case LocationFollowsSquadLead(state) =>
val squad = GetLeadingSquad(tplayer, zone_ordinal_number, squadOpt)
if(state) {
log.info(s"${tplayer.Name}-${tplayer.Faction} has moves the rally to the leader's position")
}
else {
log.info(s"${tplayer.Name}-${tplayer.Faction} has let the rally move freely")
}
squad.LocationFollowsSquadLead = state
case AutoApproveInvitationRequests(state) =>
val squad = GetLeadingSquad(tplayer, zone_ordinal_number, squadOpt)
if(state) {
log.info(s"${tplayer.Name}-${tplayer.Faction} is allowing all requests to join the squad")
}
else {
log.info(s"${tplayer.Name}-${tplayer.Faction} has started screening invitation requests")
}
squad.AutoApproveInvitationRequests = state
case SelectRoleForYourself(line) =>
//TODO need to ask permission from the squad leader, unless our character is the squad leader or already currently in the squad
val name = tplayer.Name
squadOpt match {
case Some(squad) =>
{
if(squad.Availability(line))
squad.Membership.lift(line)
else
None
} match {
case Some(desiredPosition : Member)
if desiredPosition.Requirements.intersect(tplayer.Certifications) == desiredPosition.Requirements =>
//our character is qualified for this new position
if(squad.Leader.equals(tplayer.Name)) {
squad.LeaderPositionIndex = line //update
} }
else { val hadPreviousPosition = squad.Membership.find(_.Name == name) match {
List(SquadInfo.Field.Capacity) case Some(currentPosition)=>
currentPosition.Name = ""
currentPosition.ZoneId = 0
currentPosition.Health = 0
currentPosition.Armor = 0
currentPosition.Position = Vector3.Zero
true
case None =>
false
} }
memberPosition.Close() desiredPosition.Name = name
case Some(false) => ; desiredPosition.ZoneId = zone_ordinal_number
desiredPosition.Health = tplayer.Health
desiredPosition.Armor = tplayer.Armor
desiredPosition.Position = tplayer.Position
if(!hadPreviousPosition) {
UpdateSquadList(squad, List(SquadInfo.Field.Size))
}
UpdateSquadDetail(squad)
case None => ; case None => ;
} }
}
else {
log.warn(s"can not close the leader position in squad-${squad.GUID.guid}")
}
case AddSquadMemberPosition(position) => case None => ;
squad.Availability.lift(position) match {
case Some(false) =>
log.info(s"${tplayer.Name}-${tplayer.Faction} has opened the #$position position in his squad")
squad.Availability.update(position, true)
listingChanged = List(SquadInfo.Field.Capacity)
case Some(true) => ;
case None => ;
}
case ChangeSquadMemberRequirementsRole(position, role) =>
squad.Availability.lift(position) match {
case Some(true) =>
log.info(s"${tplayer.Name}-${tplayer.Faction} has changed the role of squad position #$position")
squad.Membership(position).Role = role
case Some(false) => ;
case None => ;
}
case ChangeSquadMemberRequirementsDetailedOrders(position, orders) =>
squad.Availability.lift(position) match {
case Some(true) =>
log.info(s"${tplayer.Name}-${tplayer.Faction} has changed the orders for squad position #$position")
squad.Membership(position).Orders = orders
case Some(false) => ;
case None => ;
}
case ChangeSquadMemberRequirementsCertifications(position, certs) =>
squad.Availability.lift(position) match {
case Some(true) =>
log.info(s"${tplayer.Name}-${tplayer.Faction} has changed the requirements for squad position #$position")
squad.Membership(position).Requirements = certs
case Some(false) => ;
case None => ;
}
case ListSquad() =>
if(!squad.Listed) {
log.info(s"${tplayer.Name}-${tplayer.Faction} has opened recruitment for his squad")
squad.Listed = true
}
case ResetAll() =>
squad.Description = ""
squad.ZoneId = None
squad.Availability.indices.foreach { i =>
squad.Availability.update(i, true)
}
//TODO squad members?
case _ => ;
}
//queue updates
if(squad.Listed) {
val entry = SquadService.Publish(squad)
val faction = squad.Faction
val factionListings = publishedLists(faction)
factionListings.find(info => {
info.squad_guid match {
case Some(guid) => guid == squad.GUID
case _ => false
}
}) match {
case Some(listedSquad) =>
val index = factionListings.indexOf(listedSquad)
val changes = if(listingChanged.nonEmpty) {
SquadService.Differences(listingChanged, entry)
}
else {
SquadService.Differences(listedSquad, entry)
}
if(changes != SquadInfo.Blank) {
//squad information update
log.info(s"Squad will be updated")
factionListings(index) = entry
SquadEvents.publish(
SquadServiceResponse(s"$faction/Squad", SquadResponse.Update(Seq((index, changes))))
)
}
else {
//remove squad from listing
log.info(s"Squad will be removed")
factionListings.remove(index)
SquadEvents.publish(
SquadServiceResponse(s"$faction/Squad", SquadResponse.Remove(Seq(index)))
)
}
case None =>
//first time being published
log.info(s"Squad will be introduced")
factionListings += SquadService.Publish(squad)
SquadEvents.publish(
SquadServiceResponse(s"$faction/Squad", SquadResponse.Init(factionListings.toVector))
)
} }
}
case ListSquad() =>
val squad = GetLeadingSquad(tplayer, zone_ordinal_number, squadOpt)
if(!squad.Listed) {
log.info(s"${tplayer.Name}-${tplayer.Faction} has opened recruitment for this squad")
squad.Listed = true
}
UpdateSquadList(squad, List())
case ResetAll() =>
val squad = GetLeadingSquad(tplayer, zone_ordinal_number, squadOpt)
squad.Task = ""
squad.ZoneId = None
squad.Availability.indices.foreach { i =>
squad.Availability.update(i, true)
}
squad.Membership.foreach(position => {
position.Role = ""
position.Orders = ""
position.Requirements = Set()
})
UpdateSquadList(squad, List(SquadInfo.Field.Task, SquadInfo.Field.ZoneId, SquadInfo.Field.Size, SquadInfo.Field.Capacity))
UpdateSquadDetail(squad)
case DisplaySquad() =>
idToSquad.get(guid) match {
case Some(squad) =>
sender ! SquadServiceResponse(s"${tplayer.Name}/Squad", GenSquadDetail(squad))
case None => ;
}
case _ => ;
} }
case msg => case msg =>
log.info(s"Unhandled message $msg from $sender") log.info(s"Unhandled message $msg from $sender")
} }
def UpdateSquadList(squad : Squad, listingChanged : List[Int]) : Unit = {
//queue updates
if(squad.Listed) {
val entry = SquadService.Publish(squad)
val faction = squad.Faction
val factionListings = publishedLists(faction)
factionListings.find(info => {
info.squad_guid match {
case Some(sguid) => sguid == squad.GUID
case _ => false
}
}) match {
case Some(listedSquad) =>
val index = factionListings.indexOf(listedSquad)
val changes = if(listingChanged.nonEmpty) {
SquadService.Differences(listingChanged, entry)
}
else {
SquadService.Differences(listedSquad, entry)
}
if(changes != SquadInfo.Blank) {
//squad information update
log.info(s"Squad will be updated")
factionListings(index) = entry
SquadEvents.publish(
SquadServiceResponse(s"$faction/Squad", SquadResponse.Update(Seq((index, changes))))
)
}
else {
//remove squad from listing
log.info(s"Squad will be removed")
factionListings.remove(index)
SquadEvents.publish(
SquadServiceResponse(s"$faction/Squad", SquadResponse.Remove(Seq(index)))
)
}
case None =>
//first time being published
log.info(s"Squad will be introduced")
factionListings += SquadService.Publish(squad)
SquadEvents.publish(
SquadServiceResponse(s"$faction/Squad", SquadResponse.Init(factionListings.toVector))
)
}
}
}
def GenSquadDetail(squad : Squad) : SquadResponse.Detail = {
SquadResponse.Detail(
squad.GUID,
squad.Leader,
squad.Task,
PlanetSideZoneID(squad.ZoneId),
squad.Membership.zipWithIndex.map({ case (p, index) =>
if(squad.Availability(index)) {
SquadPositionDetail(p.Role, p.Orders, p.Requirements, p.Name)
}
else {
SquadPositionDetail.Closed
}
}).toList
)
}
def UpdateSquadDetail(squad : Squad) : Unit = {
val detail = GenSquadDetail(squad)
squad.Membership.collect {
case member if !member.Name.equals("") =>
member.Name
}.foreach { name =>
SquadEvents.publish(
SquadServiceResponse(s"$name/Squad", detail)
)
}
}
} }
object SquadService { object SquadService {
def Publish(squad : Squad) : SquadInfo = { def Publish(squad : Squad) : SquadInfo = {
SquadInfo( SquadInfo(
squad.Leader, squad.Leader,
squad.Description, squad.Task,
PlanetSideZoneID(squad.ZoneId), PlanetSideZoneID(squad.ZoneId),
squad.Size, squad.Size,
squad.Capacity, squad.Capacity,

View file

@ -2,12 +2,12 @@
package services.teamwork package services.teamwork
import net.psforever.objects.Player import net.psforever.objects.Player
import net.psforever.packet.game.SquadAction import net.psforever.packet.game.{PlanetSideGUID, SquadAction}
final case class SquadServiceMessage(forChannel : String, actionMessage : Any) final case class SquadServiceMessage(forChannel : String, actionMessage : Any)
object SquadServiceMessage { object SquadServiceMessage {
final case class SquadDefinitionAction(player : Player, zone_ordinal_number : Int, u1 : Int, u2 : Int, action : SquadAction) final case class SquadDefinitionAction(player : Player, zone_ordinal_number : Int, guid : PlanetSideGUID, line : Int, action : SquadAction)
final case class RecoverSquadMembership() final case class RecoverSquadMembership()
} }

View file

@ -41,7 +41,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (00)" in { "decode (00)" in {
PacketCoding.DecodePacket(string_00).require match { PacketCoding.DecodePacket(string_00).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 3 unk1 mustEqual PlanetSideGUID(3)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual DisplaySquad() action mustEqual DisplaySquad()
case _ => case _ =>
@ -52,7 +52,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (03)" in { "decode (03)" in {
PacketCoding.DecodePacket(string_03).require match { PacketCoding.DecodePacket(string_03).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 3 unk2 mustEqual 3
action mustEqual SaveSquadDefinition() action mustEqual SaveSquadDefinition()
case _ => case _ =>
@ -63,7 +63,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (03)" in { "decode (03)" in {
PacketCoding.DecodePacket(string_04).require match { PacketCoding.DecodePacket(string_04).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 3 unk2 mustEqual 3
action mustEqual LoadSquadDefinition() action mustEqual LoadSquadDefinition()
case _ => case _ =>
@ -74,7 +74,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (07)" in { "decode (07)" in {
PacketCoding.DecodePacket(string_07).require match { PacketCoding.DecodePacket(string_07).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 3 unk2 mustEqual 3
action mustEqual ListSquadDefinition("Cops and Military Officers") action mustEqual ListSquadDefinition("Cops and Military Officers")
case _ => case _ =>
@ -85,7 +85,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (08)" in { "decode (08)" in {
PacketCoding.DecodePacket(string_08).require match { PacketCoding.DecodePacket(string_08).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual ListSquad() action mustEqual ListSquad()
case _ => case _ =>
@ -96,7 +96,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (10)" in { "decode (10)" in {
PacketCoding.DecodePacket(string_10).require match { PacketCoding.DecodePacket(string_10).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual SelectRoleForYourself(1) action mustEqual SelectRoleForYourself(1)
case _ => case _ =>
@ -107,7 +107,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (19)" in { "decode (19)" in {
PacketCoding.DecodePacket(string_19).require match { PacketCoding.DecodePacket(string_19).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual ChangeSquadPurpose("A-Team") action mustEqual ChangeSquadPurpose("A-Team")
case _ => case _ =>
@ -118,7 +118,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (20)" in { "decode (20)" in {
PacketCoding.DecodePacket(string_20).require match { PacketCoding.DecodePacket(string_20).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual ChangeSquadZone(PlanetSideZoneID(1)) action mustEqual ChangeSquadZone(PlanetSideZoneID(1))
case _ => case _ =>
@ -129,7 +129,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (21)" in { "decode (21)" in {
PacketCoding.DecodePacket(string_21).require match { PacketCoding.DecodePacket(string_21).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual CloseSquadMemberPosition(2) action mustEqual CloseSquadMemberPosition(2)
case _ => case _ =>
@ -140,7 +140,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (22)" in { "decode (22)" in {
PacketCoding.DecodePacket(string_22).require match { PacketCoding.DecodePacket(string_22).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual AddSquadMemberPosition(2) action mustEqual AddSquadMemberPosition(2)
case _ => case _ =>
@ -151,7 +151,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (23)" in { "decode (23)" in {
PacketCoding.DecodePacket(string_23).require match { PacketCoding.DecodePacket(string_23).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual ChangeSquadMemberRequirementsRole(1, "BLUFOR") action mustEqual ChangeSquadMemberRequirementsRole(1, "BLUFOR")
case _ => case _ =>
@ -162,7 +162,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (24)" in { "decode (24)" in {
PacketCoding.DecodePacket(string_24).require match { PacketCoding.DecodePacket(string_24).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual ChangeSquadMemberRequirementsDetailedOrders(1, "kill bad dudes") action mustEqual ChangeSquadMemberRequirementsDetailedOrders(1, "kill bad dudes")
case _ => case _ =>
@ -173,7 +173,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (25)" in { "decode (25)" in {
PacketCoding.DecodePacket(string_25).require match { PacketCoding.DecodePacket(string_25).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual ChangeSquadMemberRequirementsCertifications( action mustEqual ChangeSquadMemberRequirementsCertifications(
1, 1,
@ -187,7 +187,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (26)" in { "decode (26)" in {
PacketCoding.DecodePacket(string_26).require match { PacketCoding.DecodePacket(string_26).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual ResetAll() action mustEqual ResetAll()
case _ => case _ =>
@ -198,7 +198,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (28)" in { "decode (28)" in {
PacketCoding.DecodePacket(string_28).require match { PacketCoding.DecodePacket(string_28).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual AutoApproveInvitationRequests(true) action mustEqual AutoApproveInvitationRequests(true)
case _ => case _ =>
@ -209,7 +209,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (31)" in { "decode (31)" in {
PacketCoding.DecodePacket(string_31).require match { PacketCoding.DecodePacket(string_31).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual LocationFollowsSquadLead(true) action mustEqual LocationFollowsSquadLead(true)
case _ => case _ =>
@ -220,7 +220,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (34a)" in { "decode (34a)" in {
PacketCoding.DecodePacket(string_34a).require match { PacketCoding.DecodePacket(string_34a).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual SearchForSquadsWithParticularRole("Badass", 0L, 1, 0) action mustEqual SearchForSquadsWithParticularRole("Badass", 0L, 1, 0)
case _ => case _ =>
@ -231,7 +231,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (34b)" in { "decode (34b)" in {
PacketCoding.DecodePacket(string_34b).require match { PacketCoding.DecodePacket(string_34b).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual SearchForSquadsWithParticularRole("Badass", 0L, 2, 0) action mustEqual SearchForSquadsWithParticularRole("Badass", 0L, 2, 0)
case _ => case _ =>
@ -242,7 +242,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (34c)" in { "decode (34c)" in {
PacketCoding.DecodePacket(string_34c).require match { PacketCoding.DecodePacket(string_34c).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual SearchForSquadsWithParticularRole("Badass", 0L, 2, 1) action mustEqual SearchForSquadsWithParticularRole("Badass", 0L, 2, 1)
case _ => case _ =>
@ -253,7 +253,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (34d)" in { "decode (34d)" in {
PacketCoding.DecodePacket(string_34d).require match { PacketCoding.DecodePacket(string_34d).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual SearchForSquadsWithParticularRole("Badass", 536870928L, 2, 2) action mustEqual SearchForSquadsWithParticularRole("Badass", 536870928L, 2, 2)
case _ => case _ =>
@ -264,7 +264,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (34e)" in { "decode (34e)" in {
PacketCoding.DecodePacket(string_34e).require match { PacketCoding.DecodePacket(string_34e).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual SearchForSquadsWithParticularRole("Badass", 536870928L, 2, 3) action mustEqual SearchForSquadsWithParticularRole("Badass", 536870928L, 2, 3)
case _ => case _ =>
@ -275,7 +275,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (35)" in { "decode (35)" in {
PacketCoding.DecodePacket(string_35).require match { PacketCoding.DecodePacket(string_35).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual CancelSquadSearch() action mustEqual CancelSquadSearch()
case _ => case _ =>
@ -286,7 +286,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (40)" in { "decode (40)" in {
PacketCoding.DecodePacket(string_40).require match { PacketCoding.DecodePacket(string_40).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual FindLfsSoldiersForRole(1) action mustEqual FindLfsSoldiersForRole(1)
case _ => case _ =>
@ -297,7 +297,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (41)" in { "decode (41)" in {
PacketCoding.DecodePacket(string_41).require match { PacketCoding.DecodePacket(string_41).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual CancelFind() action mustEqual CancelFind()
case _ => case _ =>
@ -308,7 +308,7 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (43, unknown)" in { "decode (43, unknown)" in {
PacketCoding.DecodePacket(string_43).require match { PacketCoding.DecodePacket(string_43).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) => case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0 unk1 mustEqual PlanetSideGUID(0)
unk2 mustEqual 0 unk2 mustEqual 0
action mustEqual Unknown(43, hex"00".toBitVector.take(6)) action mustEqual Unknown(43, hex"00".toBitVector.take(6))
case _ => case _ =>
@ -321,91 +321,91 @@ class SquadDefinitionActionMessageTest extends Specification {
} }
"encode (00)" in { "encode (00)" in {
val msg = SquadDefinitionActionMessage(3, 0, DisplaySquad()) val msg = SquadDefinitionActionMessage(PlanetSideGUID(3), 0, DisplaySquad())
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_00 pkt mustEqual string_00
} }
"encode (03)" in { "encode (03)" in {
val msg = SquadDefinitionActionMessage(0, 3, SaveSquadDefinition()) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 3, SaveSquadDefinition())
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_03 pkt mustEqual string_03
} }
"encode (03)" in { "encode (03)" in {
val msg = SquadDefinitionActionMessage(0, 3, LoadSquadDefinition()) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 3, LoadSquadDefinition())
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_04 pkt mustEqual string_04
} }
"encode (07)" in { "encode (07)" in {
val msg = SquadDefinitionActionMessage(0, 3, ListSquadDefinition("Cops and Military Officers")) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 3, ListSquadDefinition("Cops and Military Officers"))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_07 pkt mustEqual string_07
} }
"encode (08)" in { "encode (08)" in {
val msg = SquadDefinitionActionMessage(0, 0, ListSquad()) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, ListSquad())
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_08 pkt mustEqual string_08
} }
"encode (10)" in { "encode (10)" in {
val msg = SquadDefinitionActionMessage(0, 0, SelectRoleForYourself(1)) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SelectRoleForYourself(1))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_10 pkt mustEqual string_10
} }
"encode (19)" in { "encode (19)" in {
val msg = SquadDefinitionActionMessage(0, 0, ChangeSquadPurpose("A-Team")) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, ChangeSquadPurpose("A-Team"))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_19 pkt mustEqual string_19
} }
"encode (20)" in { "encode (20)" in {
val msg = SquadDefinitionActionMessage(0, 0, ChangeSquadZone(PlanetSideZoneID(1))) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, ChangeSquadZone(PlanetSideZoneID(1)))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_20 pkt mustEqual string_20
} }
"encode (21)" in { "encode (21)" in {
val msg = SquadDefinitionActionMessage(0, 0, CloseSquadMemberPosition(2)) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, CloseSquadMemberPosition(2))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_21 pkt mustEqual string_21
} }
"encode (22)" in { "encode (22)" in {
val msg = SquadDefinitionActionMessage(0, 0, AddSquadMemberPosition(2)) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, AddSquadMemberPosition(2))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_22 pkt mustEqual string_22
} }
"encode (23)" in { "encode (23)" in {
val msg = SquadDefinitionActionMessage(0, 0, ChangeSquadMemberRequirementsRole(1, "BLUFOR")) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, ChangeSquadMemberRequirementsRole(1, "BLUFOR"))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_23 pkt mustEqual string_23
} }
"encode (24)" in { "encode (24)" in {
val msg = SquadDefinitionActionMessage(0, 0, ChangeSquadMemberRequirementsDetailedOrders(1, "kill bad dudes")) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, ChangeSquadMemberRequirementsDetailedOrders(1, "kill bad dudes"))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_24 pkt mustEqual string_24
} }
"encode (25)" in { "encode (25)" in {
val msg = SquadDefinitionActionMessage(0, 0, ChangeSquadMemberRequirementsCertifications( val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, ChangeSquadMemberRequirementsCertifications(
1, 1,
Set(CertificationType.AntiVehicular, CertificationType.InfiltrationSuit) Set(CertificationType.AntiVehicular, CertificationType.InfiltrationSuit)
)) ))
@ -415,84 +415,84 @@ class SquadDefinitionActionMessageTest extends Specification {
} }
"encode (26)" in { "encode (26)" in {
val msg = SquadDefinitionActionMessage(0, 0, ResetAll()) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, ResetAll())
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_26 pkt mustEqual string_26
} }
"encode (28)" in { "encode (28)" in {
val msg = SquadDefinitionActionMessage(0, 0, AutoApproveInvitationRequests(true)) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, AutoApproveInvitationRequests(true))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_28 pkt mustEqual string_28
} }
"encode (31)" in { "encode (31)" in {
val msg = SquadDefinitionActionMessage(0, 0, LocationFollowsSquadLead(true)) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, LocationFollowsSquadLead(true))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_31 pkt mustEqual string_31
} }
"encode (34a)" in { "encode (34a)" in {
val msg = SquadDefinitionActionMessage(0, 0, SearchForSquadsWithParticularRole("Badass", 0L, 1, 0)) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SearchForSquadsWithParticularRole("Badass", 0L, 1, 0))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_34a pkt mustEqual string_34a
} }
"encode (34b)" in { "encode (34b)" in {
val msg = SquadDefinitionActionMessage(0, 0, SearchForSquadsWithParticularRole("Badass", 0L, 2, 0)) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SearchForSquadsWithParticularRole("Badass", 0L, 2, 0))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_34b pkt mustEqual string_34b
} }
"encode (34c)" in { "encode (34c)" in {
val msg = SquadDefinitionActionMessage(0, 0, SearchForSquadsWithParticularRole("Badass", 0L, 2, 1)) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SearchForSquadsWithParticularRole("Badass", 0L, 2, 1))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_34c pkt mustEqual string_34c
} }
"encode (34d)" in { "encode (34d)" in {
val msg = SquadDefinitionActionMessage(0, 0, SearchForSquadsWithParticularRole("Badass", 536870928L, 2, 2)) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SearchForSquadsWithParticularRole("Badass", 536870928L, 2, 2))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_34d pkt mustEqual string_34d
} }
"encode (34e)" in { "encode (34e)" in {
val msg = SquadDefinitionActionMessage(0, 0, SearchForSquadsWithParticularRole("Badass", 536870928L, 2, 3)) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SearchForSquadsWithParticularRole("Badass", 536870928L, 2, 3))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_34e pkt mustEqual string_34e
} }
"encode (35)" in { "encode (35)" in {
val msg = SquadDefinitionActionMessage(0, 0, CancelSquadSearch()) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, CancelSquadSearch())
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_35 pkt mustEqual string_35
} }
"encode (40)" in { "encode (40)" in {
val msg = SquadDefinitionActionMessage(0, 0, FindLfsSoldiersForRole(1)) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, FindLfsSoldiersForRole(1))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_40 pkt mustEqual string_40
} }
"encode (41)" in { "encode (41)" in {
val msg = SquadDefinitionActionMessage(0, 0, CancelFind()) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, CancelFind())
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_41 pkt mustEqual string_41
} }
"encode (43, unknown)" in { "encode (43, unknown)" in {
val msg = SquadDefinitionActionMessage(0, 0, Unknown(43, BitVector.empty)) val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, Unknown(43, BitVector.empty))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_43 pkt mustEqual string_43

View file

@ -370,6 +370,17 @@ class WorldSessionActor extends Actor with MDCContextAware {
}.toVector }.toVector
) )
) )
case SquadResponse.Detail(guid, leader, task, zone, member_info) =>
sendResponse(
SquadDetailDefinitionUpdateMessage(
guid,
leader,
task,
zone,
member_info
)
)
case _ => ; case _ => ;
} }
@ -2850,7 +2861,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
}) })
//AvatarAwardMessage //AvatarAwardMessage
//DisplayAwardMessage //DisplayAwardMessage
//SquadDefinitionActionMessage and SquadDetailDefinitionUpdateMessage //SquadDefinitionActionMessage and SquadDetailDefinitionUpdateMessage; handled elsewhere
//MapObjectStateBlockMessage and ObjectCreateMessage? //MapObjectStateBlockMessage and ObjectCreateMessage?
//TacticsMessage? //TacticsMessage?
//change the owner on our deployables (re-draw the icons for our deployables too) //change the owner on our deployables (re-draw the icons for our deployables too)
@ -2885,35 +2896,35 @@ class WorldSessionActor extends Actor with MDCContextAware {
interstellarFerryTopLevelGUID = None interstellarFerryTopLevelGUID = None
case _ => ; case _ => ;
} }
sendResponse(ReplicationStreamMessage( // sendResponse(ReplicationStreamMessage(
5, // 5,
Some(6), // Some(6),
Vector( // Vector(
SquadListing(0, SquadInfo(Some("xNick"), Some("FLY,ALL WELCOME!"), Some(PlanetSideZoneID(7)), Some(8), Some(10), Some(PlanetSideGUID(1)))), // SquadListing(0, SquadInfo(Some("xNick"), Some("FLY,ALL WELCOME!"), Some(PlanetSideZoneID(7)), Some(8), Some(10), Some(PlanetSideGUID(1)))),
SquadListing(1, SquadInfo(Some("HofD"), Some("=KOK+SPC+FLY= All Welcome"), Some(PlanetSideZoneID(7)), Some(3), Some(10), Some(PlanetSideGUID(3)))) // SquadListing(1, SquadInfo(Some("HofD"), Some("=KOK+SPC+FLY= All Welcome"), Some(PlanetSideZoneID(7)), Some(3), Some(10), Some(PlanetSideGUID(3))))
) // )
)) // ))
//sendRawResponse(hex"e803008484000c800259e8809fda020043004a0069006d006d0079006e009b48006f006d006900630069006400690061006c00200053006d007500720066007300200041006e006f006e0079006d006f007500730004000000981401064580540061006e006b002000440072006900760065007200a05200650063006f006d006d0065006e00640065006400200074006f0020006800610076006500200065006e00670069006e0065006500720069006e0067002e0000000000800180000c00020c8c46007200650065006200690065002000730070006f007400cf44006f002000770068006100740065007600650072002c0020006200750074002000700072006500660065007200610062006c007900200073007400690063006b002000770069007400680020007400680065002000730071007500610064002e00200044006f006e002700740020006e00650065006400200061006e007900200073007000650063006900660069006300200063006500720074002e0096e27a0290540068006500460069006e0061006c005300740072007500670067006c0065000000000000020c8c46007200650065006200690065002000530070006f007400cf44006f002000770068006100740065007600650072002c0020006200750074002000700072006500660065007200610062006c007900200073007400690063006b002000770069007400680020007400680065002000730071007500610064002e00200044006f006e002700740020006e00650065006400200061006e007900200073007000650063006900660069006300200063006500720074002e0000000000800000000000020c8a41004d0053002000440072006900760065007200b34700690076006500200075007300200073007000610077006e00200070006f0069006e00740073002c0020006800610063006b0069006e006700200061006e006400200069006e00660069006c0020006100720065002000750073006500660075006c002e00fb02790287440030004f004d006700750079000100020c00020c8d410076006500720061006700650020004a0069006d006d007900a05200650069006e0066006f0072006300650064002000450078006f007300750069007400200077006f0075006c00640020006200650020006e0069006300650000000000800300000c00020c8b4100760065007200610067006500200042006f006200a05200650069006e0066006f0072006300650064002000450078006f007300750069007400200077006f0075006c00640020006200650020006e0069006300650000000000800300000c00020c8b410076006500720061006700650020004a006f006500a05200650069006e0066006f0072006300650064002000450078006f007300750069007400200077006f0075006c00640020006200650020006e0069006300650000000000800300000c00020c8753007500700070006f0072007400a2520065007300730075007200650063007400200073006f006c00640069006500720073002c0020006b00650065007000200075007300200061006c006900760065002e0000000000800100000c0c0a0c8845006e00670069006e00650065007200a043006f006d00620061007400200045006e00670069006e0065006500720069006e006700200077006f0075006c00640020006200650020006e0069006300650004b3d101864a0069006d006d0079006e000100000c000a0c854d0065006400690063009a4100640076002e0020004d00650064006900630061006c00200077006f0075006c00640020006200650020006e0069006300650000000000800100000c0400") // //sendRawResponse(hex"e803008484000c800259e8809fda020043004a0069006d006d0079006e009b48006f006d006900630069006400690061006c00200053006d007500720066007300200041006e006f006e0079006d006f007500730004000000981401064580540061006e006b002000440072006900760065007200a05200650063006f006d006d0065006e00640065006400200074006f0020006800610076006500200065006e00670069006e0065006500720069006e0067002e0000000000800180000c00020c8c46007200650065006200690065002000730070006f007400cf44006f002000770068006100740065007600650072002c0020006200750074002000700072006500660065007200610062006c007900200073007400690063006b002000770069007400680020007400680065002000730071007500610064002e00200044006f006e002700740020006e00650065006400200061006e007900200073007000650063006900660069006300200063006500720074002e0096e27a0290540068006500460069006e0061006c005300740072007500670067006c0065000000000000020c8c46007200650065006200690065002000530070006f007400cf44006f002000770068006100740065007600650072002c0020006200750074002000700072006500660065007200610062006c007900200073007400690063006b002000770069007400680020007400680065002000730071007500610064002e00200044006f006e002700740020006e00650065006400200061006e007900200073007000650063006900660069006300200063006500720074002e0000000000800000000000020c8a41004d0053002000440072006900760065007200b34700690076006500200075007300200073007000610077006e00200070006f0069006e00740073002c0020006800610063006b0069006e006700200061006e006400200069006e00660069006c0020006100720065002000750073006500660075006c002e00fb02790287440030004f004d006700750079000100020c00020c8d410076006500720061006700650020004a0069006d006d007900a05200650069006e0066006f0072006300650064002000450078006f007300750069007400200077006f0075006c00640020006200650020006e0069006300650000000000800300000c00020c8b4100760065007200610067006500200042006f006200a05200650069006e0066006f0072006300650064002000450078006f007300750069007400200077006f0075006c00640020006200650020006e0069006300650000000000800300000c00020c8b410076006500720061006700650020004a006f006500a05200650069006e0066006f0072006300650064002000450078006f007300750069007400200077006f0075006c00640020006200650020006e0069006300650000000000800300000c00020c8753007500700070006f0072007400a2520065007300730075007200650063007400200073006f006c00640069006500720073002c0020006b00650065007000200075007300200061006c006900760065002e0000000000800100000c0c0a0c8845006e00670069006e00650065007200a043006f006d00620061007400200045006e00670069006e0065006500720069006e006700200077006f0075006c00640020006200650020006e0069006300650004b3d101864a0069006d006d0079006e000100000c000a0c854d0065006400690063009a4100640076002e0020004d00650064006900630061006c00200077006f0075006c00640020006200650020006e0069006300650000000000800100000c0400")
sendResponse( // sendResponse(
SquadDetailDefinitionUpdateMessage( // SquadDetailDefinitionUpdateMessage(
PlanetSideGUID(3), // PlanetSideGUID(3),
"HofD", // "HofD",
"\\#ffdc00***\\#9640ff=KOK+SPC+FLY=\\#ffdc00***\\#FF4040 All Welcome", // "\\#ffdc00***\\#9640ff=KOK+SPC+FLY=\\#ffdc00***\\#FF4040 All Welcome",
PlanetSideZoneID(7), // PlanetSideZoneID(7),
List( // List(
SquadPositionDetail("\\#ff0000 |||||||||||||||||||||||", "Just a space filler"), // SquadPositionDetail("\\#ff0000 |||||||||||||||||||||||", "Just a space filler"),
SquadPositionDetail("\\#ffdc00 C", ""), // SquadPositionDetail("\\#ffdc00 C", ""),
SquadPositionDetail("\\#ffdc00 H", "", "OpoIE"), // SquadPositionDetail("\\#ffdc00 H", "", "OpoIE"),
SquadPositionDetail("\\#ffdc00 I", "", "BobaF3tt907"), // SquadPositionDetail("\\#ffdc00 I", "", "BobaF3tt907"),
SquadPositionDetail("\\#ffdc00 N", ""), // SquadPositionDetail("\\#ffdc00 N", ""),
SquadPositionDetail("\\#ffdc00 A", ""), // SquadPositionDetail("\\#ffdc00 A", ""),
SquadPositionDetail("\\#ff0000 |||||||||||||||||||||||", "Another space filler"), // SquadPositionDetail("\\#ff0000 |||||||||||||||||||||||", "Another space filler"),
SquadPositionDetail("\\#9640ff K", ""), // SquadPositionDetail("\\#9640ff K", ""),
SquadPositionDetail("\\#9640ff O", "", "HofD"), // SquadPositionDetail("\\#9640ff O", "", "HofD"),
SquadPositionDetail("\\#9640ff K", "") // SquadPositionDetail("\\#9640ff K", "")
) // )
) // )
) // )
} }
def handleControlPkt(pkt : PlanetSideControlPacket) = { def handleControlPkt(pkt : PlanetSideControlPacket) = {
@ -3325,6 +3336,11 @@ class WorldSessionActor extends Actor with MDCContextAware {
case msg @ PlayerStateMessageUpstream(avatar_guid, pos, vel, yaw, pitch, yaw_upper, seq_time, unk3, is_crouching, is_jumping, unk4, is_cloaking, unk5, unk6) => case msg @ PlayerStateMessageUpstream(avatar_guid, pos, vel, yaw, pitch, yaw_upper, seq_time, unk3, is_crouching, is_jumping, unk4, is_cloaking, unk5, unk6) =>
if(deadState == DeadState.Alive) { if(deadState == DeadState.Alive) {
// if(!player.Crouching && is_crouching) {
// sendResponse(
// SquadMembershipRequest(SquadRequestType.Unk01, 1L, Some(1L), "FateJH", Some(None))
// )
// }
player.Position = pos player.Position = pos
player.Velocity = vel player.Velocity = vel
player.Orientation = Vector3(player.Orientation.x, pitch, yaw) player.Orientation = Vector3(player.Orientation.x, pitch, yaw)