From 9cf1cd92ccab54ce7580a645ba2bd104e431dc36 Mon Sep 17 00:00:00 2001 From: FateJH Date: Thu, 6 Jun 2019 14:54:53 -0400 Subject: [PATCH] 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 --- .../psforever/objects/teamwork/Squad.scala | 41 +- .../game/SquadDefinitionActionMessage.scala | 28 +- .../SquadDetailDefinitionUpdateMessage.scala | 2 + .../packet/game/SquadMembershipRequest.scala | 2 +- .../services/teamwork/SquadResponse.scala | 4 +- .../services/teamwork/SquadService.scala | 472 ++++++++++++------ .../teamwork/SquadServiceMessage.scala | 4 +- .../SquadDefinitionActionMessageTest.scala | 100 ++-- .../src/main/scala/WorldSessionActor.scala | 76 +-- 9 files changed, 467 insertions(+), 262 deletions(-) diff --git a/common/src/main/scala/net/psforever/objects/teamwork/Squad.scala b/common/src/main/scala/net/psforever/objects/teamwork/Squad.scala index 4ac3cfc2c..21a48cb35 100644 --- a/common/src/main/scala/net/psforever/objects/teamwork/Squad.scala +++ b/common/src/main/scala/net/psforever/objects/teamwork/Squad.scala @@ -10,18 +10,21 @@ class Squad(squadId : PlanetSideGUID, alignment : PlanetSideEmpire.Value) extend private val faction : PlanetSideEmpire.Value = alignment //does not change private var zoneId : Option[Int] = None private var task : String = "" - private var description : String = "" private val membership : Array[Member] = Array.fill[Member](10)(new Member) private val availability : Array[Boolean] = Array.fill[Boolean](10)(true) private var listed : Boolean = false private var leaderPositionIndex : Int = 0 + private var autoApproveInvitationRequests : Boolean = false + private var locationFollowsSquadLead : Boolean = false override def GUID_=(d : PlanetSideGUID) : PlanetSideGUID = GUID def Faction : PlanetSideEmpire.Value = faction + def CustomZoneId : Boolean = zoneId.isDefined + def ZoneId : Int = zoneId.getOrElse({ - membership.headOption match { + membership.lift(leaderPositionIndex) match { case Some(leader) => leader.ZoneId case _ => @@ -45,13 +48,6 @@ class Squad(squadId : PlanetSideGUID, alignment : PlanetSideEmpire.Value) extend Task } - def Description : String = description - - def Description_=(desc : String) : String = { - description = desc - Description - } - def Listed : Boolean = listed def Listed_=(announce : Boolean) : Boolean = { @@ -59,6 +55,20 @@ class Squad(squadId : PlanetSideGUID, alignment : PlanetSideEmpire.Value) extend 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 Availability : Array[Boolean] = availability @@ -85,3 +95,16 @@ class Squad(squadId : PlanetSideGUID, alignment : PlanetSideEmpire.Value) extend 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 + } +} diff --git a/common/src/main/scala/net/psforever/packet/game/SquadDefinitionActionMessage.scala b/common/src/main/scala/net/psforever/packet/game/SquadDefinitionActionMessage.scala index 401937306..7709a0d65 100644 --- a/common/src/main/scala/net/psforever/packet/game/SquadDefinitionActionMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/SquadDefinitionActionMessage.scala @@ -306,13 +306,13 @@ object SquadAction{ *     `36` - UNKNOWN
*   `String :: Long :: Int :: Int`
*     `34` - Search for Squads with a Particular Role - * @param unk1 na - * @param unk2 na + * @param squad_guid the unique identifier of the squad, if non-zero + * @param line the original listing line number, if applicable * @param action the purpose of this packet; * also decides the content of the parameter fields */ -final case class SquadDefinitionActionMessage(unk1 : Int, - unk2 : Int, +final case class SquadDefinitionActionMessage(squad_guid : PlanetSideGUID, + line : Int, action : SquadAction) extends PlanetSideGamePacket { type Packet = SquadDefinitionActionMessage @@ -353,28 +353,28 @@ object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMe case 35 => cancelSquadSearchCodec case 40 => findLfsSoldiersForRoleCodec case 41 => cancelFindCodec - case 1 | 2 | 6 | 9 | - 11 | 12 | 13 | 14 | 16 | - 17 | 18 | 29 | 30 | 33 | 36 | - 37 | 38 | 42 | 43 => unknownCodec(code) + case 1 | 2 | 6 | 9 | 11 | + 12 | 13 | 14 | 16 | 17 | + 18 | 29 | 30 | 32 | 33 | + 36 | 37 | 38 | 42 | 43 => unknownCodec(code) case _ => failureCodec(code) }).asInstanceOf[Codec[SquadAction]] } implicit val codec : Codec[SquadDefinitionActionMessage] = ( uintL(6) >>:~ { code => - ("unk1" | uint16L) :: - ("unk2" | uint4L) :: + ("squad_guid" | PlanetSideGUID.codec) :: + ("line" | uint4L) :: ("action" | selectFromActionCode(code)) } ).xmap[SquadDefinitionActionMessage] ( { - case _ :: u1 :: u2 :: action :: HNil => - SquadDefinitionActionMessage(u1, u2, action) + case _ :: guid :: line :: action :: HNil => + SquadDefinitionActionMessage(guid, line, action) }, { - case SquadDefinitionActionMessage(u1, u2, action) => - action.code :: u1 :: u2 :: action :: HNil + case SquadDefinitionActionMessage(guid, line, action) => + action.code :: guid :: line :: action :: HNil } ) } diff --git a/common/src/main/scala/net/psforever/packet/game/SquadDetailDefinitionUpdateMessage.scala b/common/src/main/scala/net/psforever/packet/game/SquadDetailDefinitionUpdateMessage.scala index 291ef219f..418fbd2f0 100644 --- a/common/src/main/scala/net/psforever/packet/game/SquadDetailDefinitionUpdateMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/SquadDetailDefinitionUpdateMessage.scala @@ -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, 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] { diff --git a/common/src/main/scala/net/psforever/packet/game/SquadMembershipRequest.scala b/common/src/main/scala/net/psforever/packet/game/SquadMembershipRequest.scala index 55d731977..27cf2b79d 100644 --- a/common/src/main/scala/net/psforever/packet/game/SquadMembershipRequest.scala +++ b/common/src/main/scala/net/psforever/packet/game/SquadMembershipRequest.scala @@ -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") } 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 diff --git a/common/src/main/scala/services/teamwork/SquadResponse.scala b/common/src/main/scala/services/teamwork/SquadResponse.scala index 09f05fb36..b898580b5 100644 --- a/common/src/main/scala/services/teamwork/SquadResponse.scala +++ b/common/src/main/scala/services/teamwork/SquadResponse.scala @@ -1,7 +1,7 @@ // Copyright (c) 2019 PSForever package services.teamwork -import net.psforever.packet.game.SquadInfo +import net.psforever.packet.game.{PlanetSideGUID, PlanetSideZoneID, SquadInfo, SquadPositionDetail} object SquadResponse { trait Response @@ -9,4 +9,6 @@ object SquadResponse { final case class Init(info : Vector[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 Detail(guid : PlanetSideGUID, leader : String, task : String, zone : PlanetSideZoneID, member_info : List[SquadPositionDetail]) extends Response } diff --git a/common/src/main/scala/services/teamwork/SquadService.scala b/common/src/main/scala/services/teamwork/SquadService.scala index 3572bd969..f7b96aa0f 100644 --- a/common/src/main/scala/services/teamwork/SquadService.scala +++ b/common/src/main/scala/services/teamwork/SquadService.scala @@ -3,9 +3,9 @@ package services.teamwork import akka.actor.Actor 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.types.PlanetSideEmpire +import net.psforever.types.{PlanetSideEmpire, Vector3} import services.{GenericEventBus, Service} 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 idToSquad : TrieMap[PlanetSideGUID, Squad] = new TrieMap[PlanetSideGUID, Squad]() 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.NC -> ListBuffer.empty, PlanetSideEmpire.VS -> ListBuffer.empty @@ -41,28 +41,51 @@ class SquadService extends Actor { PlanetSideGUID(out) } - def GetSquadFromPlayer(player : Player) : Squad = { - val name = player.Name - val faction = player.Faction - memberToSquad.get(name) match { - case Some(squad) => - squad + def GetParticipatingSquad(player : Player, zone : Int) : Option[Squad] = { + memberToSquad.get(player.Name) match { + case opt @ Some(squad) => + squad.Membership.find(_.Name == player.Name).get.ZoneId = zone + opt case None => - 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 = 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 + None } } + 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] def receive : Receive = { @@ -84,167 +107,306 @@ class SquadService extends Actor { //check for renewable squad information memberToSquad.get(name) match { case None => ; - case Some(squad) => - sender ! SquadServiceMessage.RecoverSquadMembership() + case Some(_) => + sender ! SquadServiceMessage.RecoverSquadMembership() //TODO? } case Service.Leave(Some(name)) => ; 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 - case Service.Leave(None) | Service.LeaveAll() => - SquadEvents.unsubscribe(sender()) - //TODO might be better to invalidate these + case Service.Leave(None) | Service.LeaveAll() => ; - case SquadServiceMessage.SquadDefinitionAction(tplayer, zone_ordinal_number, _, _, action) => + case SquadServiceMessage.SquadDefinitionAction(tplayer, zone_ordinal_number, guid, _, action) => import net.psforever.packet.game.SquadAction._ - val squad = GetSquadFromPlayer(tplayer) - val member = squad.Membership.find(_.Name == tplayer.Name).get //should never fail - member.ZoneId = zone_ordinal_number //TODO improve this requirement - if(tplayer.Name.equals(squad.Leader)) { - var listingChanged : List[Int] = Nil - action match { - case ChangeSquadPurpose(purpose) => - log.info(s"${tplayer.Name}-${tplayer.Faction} has changed his squad's task to $purpose") - squad.Description = purpose - listingChanged = List(SquadInfo.Field.Task) + val squadOpt = GetParticipatingSquad(tplayer, zone_ordinal_number) + action match { + case ChangeSquadPurpose(purpose) => + log.info(s"${tplayer.Name}-${tplayer.Faction} has changed his squad's task to $purpose") + val squad = GetLeadingSquad(tplayer, zone_ordinal_number, squadOpt) + squad.Task = purpose + UpdateSquadList(squad, List(SquadInfo.Field.Task)) + UpdateSquadDetail(squad) - case ChangeSquadZone(zone) => - log.info(s"${tplayer.Name}-${tplayer.Faction} has changed his squad's ops zone to $zone") - squad.ZoneId = zone.zoneId.toInt - listingChanged = List(SquadInfo.Field.ZoneId) + case ChangeSquadZone(zone) => + log.info(s"${tplayer.Name}-${tplayer.Faction} has changed squad's ops zone to $zone") + val squad = GetLeadingSquad(tplayer, zone_ordinal_number, squadOpt) + squad.ZoneId = zone.zoneId.toInt + UpdateSquadList(squad, List(SquadInfo.Field.ZoneId)) + UpdateSquadDetail(squad) - case CloseSquadMemberPosition(position) => - if(position != squad.LeaderPositionIndex) { - squad.Availability.lift(position) match { - case Some(true) => - squad.Availability.update(position, false) - log.info(s"${tplayer.Name}-${tplayer.Faction} has closed the #$position position in his squad") - val memberPosition = squad.Membership(position) - listingChanged = if(memberPosition.Name.nonEmpty) { - List(SquadInfo.Field.Size, SquadInfo.Field.Capacity) + case CloseSquadMemberPosition(position) => + val squad = GetLeadingSquad(tplayer, zone_ordinal_number, squadOpt) + squad.Availability.lift(position) match { + case Some(true) => + squad.Availability.update(position, false) + log.info(s"${tplayer.Name}-${tplayer.Faction} has closed the #$position position in squad") + val memberPosition = squad.Membership(position) + val listingChanged = if(memberPosition.Name.nonEmpty) { + 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 { - List(SquadInfo.Field.Capacity) + val hadPreviousPosition = squad.Membership.find(_.Name == name) match { + case Some(currentPosition)=> + currentPosition.Name = "" + currentPosition.ZoneId = 0 + currentPosition.Health = 0 + currentPosition.Armor = 0 + currentPosition.Position = Vector3.Zero + true + case None => + false } - memberPosition.Close() - case Some(false) => ; + desiredPosition.Name = name + 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 => ; } - } - else { - log.warn(s"can not close the leader position in squad-${squad.GUID.guid}") - } - case AddSquadMemberPosition(position) => - 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 None => ; } - } + + 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 => 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 { def Publish(squad : Squad) : SquadInfo = { SquadInfo( squad.Leader, - squad.Description, + squad.Task, PlanetSideZoneID(squad.ZoneId), squad.Size, squad.Capacity, diff --git a/common/src/main/scala/services/teamwork/SquadServiceMessage.scala b/common/src/main/scala/services/teamwork/SquadServiceMessage.scala index 5f9187878..2157d44cc 100644 --- a/common/src/main/scala/services/teamwork/SquadServiceMessage.scala +++ b/common/src/main/scala/services/teamwork/SquadServiceMessage.scala @@ -2,12 +2,12 @@ package services.teamwork 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) 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() } diff --git a/common/src/test/scala/game/SquadDefinitionActionMessageTest.scala b/common/src/test/scala/game/SquadDefinitionActionMessageTest.scala index 0acd6c8f0..f36b61c54 100644 --- a/common/src/test/scala/game/SquadDefinitionActionMessageTest.scala +++ b/common/src/test/scala/game/SquadDefinitionActionMessageTest.scala @@ -41,7 +41,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (00)" in { PacketCoding.DecodePacket(string_00).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 3 + unk1 mustEqual PlanetSideGUID(3) unk2 mustEqual 0 action mustEqual DisplaySquad() case _ => @@ -52,7 +52,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (03)" in { PacketCoding.DecodePacket(string_03).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 3 action mustEqual SaveSquadDefinition() case _ => @@ -63,7 +63,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (03)" in { PacketCoding.DecodePacket(string_04).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 3 action mustEqual LoadSquadDefinition() case _ => @@ -74,7 +74,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (07)" in { PacketCoding.DecodePacket(string_07).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 3 action mustEqual ListSquadDefinition("Cops and Military Officers") case _ => @@ -85,7 +85,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (08)" in { PacketCoding.DecodePacket(string_08).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual ListSquad() case _ => @@ -96,7 +96,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (10)" in { PacketCoding.DecodePacket(string_10).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual SelectRoleForYourself(1) case _ => @@ -107,7 +107,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (19)" in { PacketCoding.DecodePacket(string_19).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual ChangeSquadPurpose("A-Team") case _ => @@ -118,7 +118,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (20)" in { PacketCoding.DecodePacket(string_20).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual ChangeSquadZone(PlanetSideZoneID(1)) case _ => @@ -129,7 +129,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (21)" in { PacketCoding.DecodePacket(string_21).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual CloseSquadMemberPosition(2) case _ => @@ -140,7 +140,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (22)" in { PacketCoding.DecodePacket(string_22).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual AddSquadMemberPosition(2) case _ => @@ -151,7 +151,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (23)" in { PacketCoding.DecodePacket(string_23).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual ChangeSquadMemberRequirementsRole(1, "BLUFOR") case _ => @@ -162,7 +162,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (24)" in { PacketCoding.DecodePacket(string_24).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual ChangeSquadMemberRequirementsDetailedOrders(1, "kill bad dudes") case _ => @@ -173,7 +173,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (25)" in { PacketCoding.DecodePacket(string_25).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual ChangeSquadMemberRequirementsCertifications( 1, @@ -187,7 +187,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (26)" in { PacketCoding.DecodePacket(string_26).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual ResetAll() case _ => @@ -198,7 +198,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (28)" in { PacketCoding.DecodePacket(string_28).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual AutoApproveInvitationRequests(true) case _ => @@ -209,7 +209,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (31)" in { PacketCoding.DecodePacket(string_31).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual LocationFollowsSquadLead(true) case _ => @@ -220,7 +220,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (34a)" in { PacketCoding.DecodePacket(string_34a).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual SearchForSquadsWithParticularRole("Badass", 0L, 1, 0) case _ => @@ -231,7 +231,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (34b)" in { PacketCoding.DecodePacket(string_34b).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual SearchForSquadsWithParticularRole("Badass", 0L, 2, 0) case _ => @@ -242,7 +242,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (34c)" in { PacketCoding.DecodePacket(string_34c).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual SearchForSquadsWithParticularRole("Badass", 0L, 2, 1) case _ => @@ -253,7 +253,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (34d)" in { PacketCoding.DecodePacket(string_34d).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual SearchForSquadsWithParticularRole("Badass", 536870928L, 2, 2) case _ => @@ -264,7 +264,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (34e)" in { PacketCoding.DecodePacket(string_34e).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual SearchForSquadsWithParticularRole("Badass", 536870928L, 2, 3) case _ => @@ -275,7 +275,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (35)" in { PacketCoding.DecodePacket(string_35).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual CancelSquadSearch() case _ => @@ -286,7 +286,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (40)" in { PacketCoding.DecodePacket(string_40).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual FindLfsSoldiersForRole(1) case _ => @@ -297,7 +297,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (41)" in { PacketCoding.DecodePacket(string_41).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual CancelFind() case _ => @@ -308,7 +308,7 @@ class SquadDefinitionActionMessageTest extends Specification { "decode (43, unknown)" in { PacketCoding.DecodePacket(string_43).require match { case SquadDefinitionActionMessage(unk1, unk2, action) => - unk1 mustEqual 0 + unk1 mustEqual PlanetSideGUID(0) unk2 mustEqual 0 action mustEqual Unknown(43, hex"00".toBitVector.take(6)) case _ => @@ -321,91 +321,91 @@ class SquadDefinitionActionMessageTest extends Specification { } "encode (00)" in { - val msg = SquadDefinitionActionMessage(3, 0, DisplaySquad()) + val msg = SquadDefinitionActionMessage(PlanetSideGUID(3), 0, DisplaySquad()) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual string_00 } "encode (03)" in { - val msg = SquadDefinitionActionMessage(0, 3, SaveSquadDefinition()) + val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 3, SaveSquadDefinition()) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual string_03 } "encode (03)" in { - val msg = SquadDefinitionActionMessage(0, 3, LoadSquadDefinition()) + val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 3, LoadSquadDefinition()) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual string_04 } "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 pkt mustEqual string_07 } "encode (08)" in { - val msg = SquadDefinitionActionMessage(0, 0, ListSquad()) + val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, ListSquad()) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual string_08 } "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 pkt mustEqual string_10 } "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 pkt mustEqual string_19 } "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 pkt mustEqual string_20 } "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 pkt mustEqual string_21 } "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 pkt mustEqual string_22 } "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 pkt mustEqual string_23 } "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 pkt mustEqual string_24 } "encode (25)" in { - val msg = SquadDefinitionActionMessage(0, 0, ChangeSquadMemberRequirementsCertifications( + val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, ChangeSquadMemberRequirementsCertifications( 1, Set(CertificationType.AntiVehicular, CertificationType.InfiltrationSuit) )) @@ -415,84 +415,84 @@ class SquadDefinitionActionMessageTest extends Specification { } "encode (26)" in { - val msg = SquadDefinitionActionMessage(0, 0, ResetAll()) + val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, ResetAll()) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual string_26 } "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 pkt mustEqual string_28 } "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 pkt mustEqual string_31 } "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 pkt mustEqual string_34a } "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 pkt mustEqual string_34b } "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 pkt mustEqual string_34c } "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 pkt mustEqual string_34d } "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 pkt mustEqual string_34e } "encode (35)" in { - val msg = SquadDefinitionActionMessage(0, 0, CancelSquadSearch()) + val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, CancelSquadSearch()) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual string_35 } "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 pkt mustEqual string_40 } "encode (41)" in { - val msg = SquadDefinitionActionMessage(0, 0, CancelFind()) + val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, CancelFind()) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual string_41 } "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 pkt mustEqual string_43 diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index 9b83272ab..8f22f2779 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -370,6 +370,17 @@ class WorldSessionActor extends Actor with MDCContextAware { }.toVector ) ) + + case SquadResponse.Detail(guid, leader, task, zone, member_info) => + sendResponse( + SquadDetailDefinitionUpdateMessage( + guid, + leader, + task, + zone, + member_info + ) + ) case _ => ; } @@ -2850,7 +2861,7 @@ class WorldSessionActor extends Actor with MDCContextAware { }) //AvatarAwardMessage //DisplayAwardMessage - //SquadDefinitionActionMessage and SquadDetailDefinitionUpdateMessage + //SquadDefinitionActionMessage and SquadDetailDefinitionUpdateMessage; handled elsewhere //MapObjectStateBlockMessage and ObjectCreateMessage? //TacticsMessage? //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 case _ => ; } - sendResponse(ReplicationStreamMessage( - 5, - Some(6), - Vector( - 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)))) - ) - )) - //sendRawResponse(hex"e803008484000c800259e8809fda020043004a0069006d006d0079006e009b48006f006d006900630069006400690061006c00200053006d007500720066007300200041006e006f006e0079006d006f007500730004000000981401064580540061006e006b002000440072006900760065007200a05200650063006f006d006d0065006e00640065006400200074006f0020006800610076006500200065006e00670069006e0065006500720069006e0067002e0000000000800180000c00020c8c46007200650065006200690065002000730070006f007400cf44006f002000770068006100740065007600650072002c0020006200750074002000700072006500660065007200610062006c007900200073007400690063006b002000770069007400680020007400680065002000730071007500610064002e00200044006f006e002700740020006e00650065006400200061006e007900200073007000650063006900660069006300200063006500720074002e0096e27a0290540068006500460069006e0061006c005300740072007500670067006c0065000000000000020c8c46007200650065006200690065002000530070006f007400cf44006f002000770068006100740065007600650072002c0020006200750074002000700072006500660065007200610062006c007900200073007400690063006b002000770069007400680020007400680065002000730071007500610064002e00200044006f006e002700740020006e00650065006400200061006e007900200073007000650063006900660069006300200063006500720074002e0000000000800000000000020c8a41004d0053002000440072006900760065007200b34700690076006500200075007300200073007000610077006e00200070006f0069006e00740073002c0020006800610063006b0069006e006700200061006e006400200069006e00660069006c0020006100720065002000750073006500660075006c002e00fb02790287440030004f004d006700750079000100020c00020c8d410076006500720061006700650020004a0069006d006d007900a05200650069006e0066006f0072006300650064002000450078006f007300750069007400200077006f0075006c00640020006200650020006e0069006300650000000000800300000c00020c8b4100760065007200610067006500200042006f006200a05200650069006e0066006f0072006300650064002000450078006f007300750069007400200077006f0075006c00640020006200650020006e0069006300650000000000800300000c00020c8b410076006500720061006700650020004a006f006500a05200650069006e0066006f0072006300650064002000450078006f007300750069007400200077006f0075006c00640020006200650020006e0069006300650000000000800300000c00020c8753007500700070006f0072007400a2520065007300730075007200650063007400200073006f006c00640069006500720073002c0020006b00650065007000200075007300200061006c006900760065002e0000000000800100000c0c0a0c8845006e00670069006e00650065007200a043006f006d00620061007400200045006e00670069006e0065006500720069006e006700200077006f0075006c00640020006200650020006e0069006300650004b3d101864a0069006d006d0079006e000100000c000a0c854d0065006400690063009a4100640076002e0020004d00650064006900630061006c00200077006f0075006c00640020006200650020006e0069006300650000000000800100000c0400") - sendResponse( - SquadDetailDefinitionUpdateMessage( - PlanetSideGUID(3), - "HofD", - "\\#ffdc00***\\#9640ff=KOK+SPC+FLY=\\#ffdc00***\\#FF4040 All Welcome", - PlanetSideZoneID(7), - List( - SquadPositionDetail("\\#ff0000 |||||||||||||||||||||||", "Just a space filler"), - SquadPositionDetail("\\#ffdc00 C", ""), - SquadPositionDetail("\\#ffdc00 H", "", "OpoIE"), - SquadPositionDetail("\\#ffdc00 I", "", "BobaF3tt907"), - SquadPositionDetail("\\#ffdc00 N", ""), - SquadPositionDetail("\\#ffdc00 A", ""), - SquadPositionDetail("\\#ff0000 |||||||||||||||||||||||", "Another space filler"), - SquadPositionDetail("\\#9640ff K", ""), - SquadPositionDetail("\\#9640ff O", "", "HofD"), - SquadPositionDetail("\\#9640ff K", "") - ) - ) - ) +// sendResponse(ReplicationStreamMessage( +// 5, +// Some(6), +// Vector( +// 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)))) +// ) +// )) +// //sendRawResponse(hex"e803008484000c800259e8809fda020043004a0069006d006d0079006e009b48006f006d006900630069006400690061006c00200053006d007500720066007300200041006e006f006e0079006d006f007500730004000000981401064580540061006e006b002000440072006900760065007200a05200650063006f006d006d0065006e00640065006400200074006f0020006800610076006500200065006e00670069006e0065006500720069006e0067002e0000000000800180000c00020c8c46007200650065006200690065002000730070006f007400cf44006f002000770068006100740065007600650072002c0020006200750074002000700072006500660065007200610062006c007900200073007400690063006b002000770069007400680020007400680065002000730071007500610064002e00200044006f006e002700740020006e00650065006400200061006e007900200073007000650063006900660069006300200063006500720074002e0096e27a0290540068006500460069006e0061006c005300740072007500670067006c0065000000000000020c8c46007200650065006200690065002000530070006f007400cf44006f002000770068006100740065007600650072002c0020006200750074002000700072006500660065007200610062006c007900200073007400690063006b002000770069007400680020007400680065002000730071007500610064002e00200044006f006e002700740020006e00650065006400200061006e007900200073007000650063006900660069006300200063006500720074002e0000000000800000000000020c8a41004d0053002000440072006900760065007200b34700690076006500200075007300200073007000610077006e00200070006f0069006e00740073002c0020006800610063006b0069006e006700200061006e006400200069006e00660069006c0020006100720065002000750073006500660075006c002e00fb02790287440030004f004d006700750079000100020c00020c8d410076006500720061006700650020004a0069006d006d007900a05200650069006e0066006f0072006300650064002000450078006f007300750069007400200077006f0075006c00640020006200650020006e0069006300650000000000800300000c00020c8b4100760065007200610067006500200042006f006200a05200650069006e0066006f0072006300650064002000450078006f007300750069007400200077006f0075006c00640020006200650020006e0069006300650000000000800300000c00020c8b410076006500720061006700650020004a006f006500a05200650069006e0066006f0072006300650064002000450078006f007300750069007400200077006f0075006c00640020006200650020006e0069006300650000000000800300000c00020c8753007500700070006f0072007400a2520065007300730075007200650063007400200073006f006c00640069006500720073002c0020006b00650065007000200075007300200061006c006900760065002e0000000000800100000c0c0a0c8845006e00670069006e00650065007200a043006f006d00620061007400200045006e00670069006e0065006500720069006e006700200077006f0075006c00640020006200650020006e0069006300650004b3d101864a0069006d006d0079006e000100000c000a0c854d0065006400690063009a4100640076002e0020004d00650064006900630061006c00200077006f0075006c00640020006200650020006e0069006300650000000000800100000c0400") +// sendResponse( +// SquadDetailDefinitionUpdateMessage( +// PlanetSideGUID(3), +// "HofD", +// "\\#ffdc00***\\#9640ff=KOK+SPC+FLY=\\#ffdc00***\\#FF4040 All Welcome", +// PlanetSideZoneID(7), +// List( +// SquadPositionDetail("\\#ff0000 |||||||||||||||||||||||", "Just a space filler"), +// SquadPositionDetail("\\#ffdc00 C", ""), +// SquadPositionDetail("\\#ffdc00 H", "", "OpoIE"), +// SquadPositionDetail("\\#ffdc00 I", "", "BobaF3tt907"), +// SquadPositionDetail("\\#ffdc00 N", ""), +// SquadPositionDetail("\\#ffdc00 A", ""), +// SquadPositionDetail("\\#ff0000 |||||||||||||||||||||||", "Another space filler"), +// SquadPositionDetail("\\#9640ff K", ""), +// SquadPositionDetail("\\#9640ff O", "", "HofD"), +// SquadPositionDetail("\\#9640ff K", "") +// ) +// ) +// ) } 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) => if(deadState == DeadState.Alive) { +// if(!player.Crouching && is_crouching) { +// sendResponse( +// SquadMembershipRequest(SquadRequestType.Unk01, 1L, Some(1L), "FateJH", Some(None)) +// ) +// } player.Position = pos player.Velocity = vel player.Orientation = Vector3(player.Orientation.x, pitch, yaw)