mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-04-28 23:35:23 +00:00
added a refactored squad joining entrypoint; initial work and test on SquadWaypointEvent packet; initial work on SquadWaypointRequest packet; squad waypoints up to #5 (squad experience) should be working
This commit is contained in:
parent
56d8748e99
commit
60d65e22d3
8 changed files with 343 additions and 147 deletions
|
|
@ -472,7 +472,7 @@ object GamePacketOpcode extends Enumeration {
|
||||||
case 0x80 => noDecoder(GenericObjectAction2Message)
|
case 0x80 => noDecoder(GenericObjectAction2Message)
|
||||||
case 0x81 => game.DestroyDisplayMessage.decode
|
case 0x81 => game.DestroyDisplayMessage.decode
|
||||||
case 0x82 => noDecoder(TriggerBotAction)
|
case 0x82 => noDecoder(TriggerBotAction)
|
||||||
case 0x83 => noDecoder(SquadWaypointRequest)
|
case 0x83 => game.SquadWaypointRequest.decode
|
||||||
case 0x84 => game.SquadWaypointEvent.decode
|
case 0x84 => game.SquadWaypointEvent.decode
|
||||||
case 0x85 => noDecoder(OffshoreVehicleMessage)
|
case 0x85 => noDecoder(OffshoreVehicleMessage)
|
||||||
case 0x86 => game.ObjectDeployedMessage.decode
|
case 0x86 => game.ObjectDeployedMessage.decode
|
||||||
|
|
|
||||||
|
|
@ -7,16 +7,16 @@ import scodec.{Attempt, Codec, Err}
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
import shapeless.{::, HNil}
|
import shapeless.{::, HNil}
|
||||||
|
|
||||||
final case class WaypointEvent(unk1 : Int,
|
final case class WaypointEvent(zone_number : Int,
|
||||||
pos : Vector3,
|
pos : Vector3,
|
||||||
unk2 : Int)
|
unk : Int)
|
||||||
|
|
||||||
final case class SquadWaypointEvent(unk1 : Int,
|
final case class SquadWaypointEvent(event_type : WaypointEventAction.Value,
|
||||||
unk2 : Int,
|
unk : Int,
|
||||||
unk3 : Long,
|
char_id : Long,
|
||||||
unk4 : Int,
|
waypoint_type : Int,
|
||||||
unk5 : Option[Long],
|
unk5 : Option[Long],
|
||||||
unk6 : Option[WaypointEvent])
|
waypoint_info : Option[WaypointEvent])
|
||||||
extends PlanetSideGamePacket {
|
extends PlanetSideGamePacket {
|
||||||
type Packet = SquadWaypointEvent
|
type Packet = SquadWaypointEvent
|
||||||
def opcode = GamePacketOpcode.SquadWaypointEvent
|
def opcode = GamePacketOpcode.SquadWaypointEvent
|
||||||
|
|
@ -24,55 +24,55 @@ final case class SquadWaypointEvent(unk1 : Int,
|
||||||
}
|
}
|
||||||
|
|
||||||
object SquadWaypointEvent extends Marshallable[SquadWaypointEvent] {
|
object SquadWaypointEvent extends Marshallable[SquadWaypointEvent] {
|
||||||
def apply(unk1 : Int, unk2 : Int, unk3 : Long, unk4 : Int, unk_a : Long) : SquadWaypointEvent =
|
def Add(unk : Int, char_id : Long, waypoint_type : Int, waypoint : WaypointEvent) : SquadWaypointEvent =
|
||||||
SquadWaypointEvent(unk1, unk2, unk3, unk4, Some(unk_a), None)
|
SquadWaypointEvent(WaypointEventAction.Add, unk, char_id, waypoint_type, None, Some(waypoint))
|
||||||
|
|
||||||
def apply(unk1 : Int, unk2 : Int, unk3 : Long, unk4 : Int, unk_a : Int, pos : Vector3, unk_b : Int) : SquadWaypointEvent =
|
def Unknown1(unk : Int, char_id : Long, waypoint_type : Int, unk_a : Long) : SquadWaypointEvent =
|
||||||
SquadWaypointEvent(unk1, unk2, unk3, unk4, None, Some(WaypointEvent(unk_a, pos, unk_b)))
|
SquadWaypointEvent(WaypointEventAction.Unknown1, unk, char_id, waypoint_type, Some(unk_a), None)
|
||||||
|
|
||||||
def apply(unk1 : Int, unk2 : Int, unk3 : Long, unk4 : Int) : SquadWaypointEvent =
|
def Remove(unk : Int, char_id : Long, waypoint_type : Int) : SquadWaypointEvent =
|
||||||
SquadWaypointEvent(unk1, unk2, unk3, unk4, None, None)
|
SquadWaypointEvent(WaypointEventAction.Remove, unk, char_id, waypoint_type, None, None)
|
||||||
|
|
||||||
private val waypoint_codec : Codec[WaypointEvent] = (
|
private val waypoint_codec : Codec[WaypointEvent] = (
|
||||||
("unk1" | uint16L) ::
|
("zone_number" | uint16L) ::
|
||||||
("pos" | Vector3.codec_pos) ::
|
("pos" | Vector3.codec_pos) ::
|
||||||
("unk2" | uint(3))
|
("unk" | uint(3))
|
||||||
).as[WaypointEvent]
|
).as[WaypointEvent]
|
||||||
|
|
||||||
implicit val codec : Codec[SquadWaypointEvent] = (
|
implicit val codec : Codec[SquadWaypointEvent] = (
|
||||||
("unk1" | uint2) >>:~ { unk1 =>
|
("event_type" | WaypointEventAction.codec) >>:~ { event_type =>
|
||||||
("unk2" | uint16L) ::
|
("unk" | uint16L) ::
|
||||||
("unk3" | uint32L) ::
|
("char_id" | uint32L) ::
|
||||||
("unk4" | uint8L) ::
|
("waypoint_type" | uint8L) ::
|
||||||
("unk5" | conditional(unk1 == 1, uint32L)) ::
|
("unk5" | conditional(event_type == WaypointEventAction.Unknown1, uint32L)) ::
|
||||||
("unk6" | conditional(unk1 == 0, waypoint_codec))
|
("waypoint_info" | conditional(event_type == WaypointEventAction.Add, waypoint_codec))
|
||||||
}
|
}
|
||||||
).exmap[SquadWaypointEvent] (
|
).exmap[SquadWaypointEvent] (
|
||||||
{
|
{
|
||||||
case 0 :: a :: b :: c :: None :: Some(d) :: HNil =>
|
case WaypointEventAction.Add :: a :: char_id :: waypoint_type :: None :: Some(waypoint) :: HNil =>
|
||||||
Attempt.Successful(SquadWaypointEvent(0, a, b, c, None, Some(d)))
|
Attempt.Successful(SquadWaypointEvent(WaypointEventAction.Add, a, char_id, waypoint_type, None, Some(waypoint)))
|
||||||
|
|
||||||
case 1 :: a :: b :: c :: Some(d) :: None :: HNil =>
|
case WaypointEventAction.Unknown1 :: a :: char_id :: waypoint_type :: Some(d) :: None :: HNil =>
|
||||||
Attempt.Successful(SquadWaypointEvent(1, a, b, c, Some(d), None))
|
Attempt.Successful(SquadWaypointEvent(WaypointEventAction.Unknown1, a, char_id, waypoint_type, Some(d), None))
|
||||||
|
|
||||||
case a :: b :: c :: d :: None :: None :: HNil =>
|
case event_type :: b :: char_id :: waypoint_type :: None :: None :: HNil =>
|
||||||
Attempt.Successful(SquadWaypointEvent(a, b, c, d, None, None))
|
Attempt.Successful(SquadWaypointEvent(event_type, b, char_id, waypoint_type, None, None))
|
||||||
|
|
||||||
case n :: _ :: _ :: _ :: _ :: _ :: HNil =>
|
case data =>
|
||||||
Attempt.Failure(Err(s"unexpected format for unk1 - $n"))
|
Attempt.Failure(Err(s"unexpected format for $data"))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case SquadWaypointEvent(0, a, b, c, None, Some(d)) =>
|
case SquadWaypointEvent(WaypointEventAction.Add, a, char_id, waypoint_type, None, Some(waypoint)) =>
|
||||||
Attempt.Successful(0 :: a :: b :: c :: None :: Some(d) :: HNil)
|
Attempt.Successful(WaypointEventAction.Add :: a :: char_id :: waypoint_type :: None :: Some(waypoint) :: HNil)
|
||||||
|
|
||||||
case SquadWaypointEvent(1, a, b, c, Some(d), None) =>
|
case SquadWaypointEvent(WaypointEventAction.Unknown1, a, char_id, waypoint_type, Some(d), None) =>
|
||||||
Attempt.Successful(1 :: a :: b :: c :: Some(d) :: None :: HNil)
|
Attempt.Successful(WaypointEventAction.Unknown1 :: a :: char_id :: waypoint_type :: Some(d) :: None :: HNil)
|
||||||
|
|
||||||
case SquadWaypointEvent(a, b, c, d, None, None) =>
|
case SquadWaypointEvent(event_type, b, char_id, waypoint_type, None, None) =>
|
||||||
Attempt.Successful(a :: b :: c :: d :: None :: None :: HNil)
|
Attempt.Successful(event_type :: b :: char_id :: waypoint_type :: None :: None :: HNil)
|
||||||
|
|
||||||
case SquadWaypointEvent(n, _, _, _, _, _) =>
|
case data =>
|
||||||
Attempt.Failure(Err(s"unexpected format for unk1 - $n"))
|
Attempt.Failure(Err(s"unexpected format for $data"))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,115 @@
|
||||||
|
// Copyright (c) 2019 PSForever
|
||||||
|
package net.psforever.packet.game
|
||||||
|
|
||||||
|
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
||||||
|
import net.psforever.types.Vector3
|
||||||
|
import scodec.{Attempt, Codec, Err}
|
||||||
|
import scodec.codecs._
|
||||||
|
import shapeless.{::, HNil}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actions that can be requested of the specific waypoint.
|
||||||
|
*/
|
||||||
|
object WaypointEventAction extends Enumeration {
|
||||||
|
type Type = Value
|
||||||
|
|
||||||
|
val
|
||||||
|
Add,
|
||||||
|
Unknown1,
|
||||||
|
Remove,
|
||||||
|
Unknown3 //unconfirmed
|
||||||
|
= Value
|
||||||
|
|
||||||
|
implicit val codec : Codec[WaypointEventAction.Value] = PacketHelpers.createEnumerationCodec(enum = this, uint2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* na
|
||||||
|
* @param zone_number the zone
|
||||||
|
* @param pos the continental map coordinate location of the waypoint;
|
||||||
|
* the z-coordinate is almost always 0.0
|
||||||
|
*/
|
||||||
|
final case class WaypointInfo(zone_number : Int,
|
||||||
|
pos : Vector3)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* na
|
||||||
|
* @param request_type the action to be performed
|
||||||
|
* @param char_id the unique id of player setting the waypoint
|
||||||
|
* @param waypoint_type the waypoint being updated;
|
||||||
|
* 0-3 for the standard squad waypoints numbered "1-4";
|
||||||
|
* 4 for the squad leader experience waypoint;
|
||||||
|
* cycles through 0-3 continuously
|
||||||
|
*
|
||||||
|
* @param unk4 na
|
||||||
|
* @param waypoint_info essential data about the waypoint
|
||||||
|
*/
|
||||||
|
final case class SquadWaypointRequest(request_type : WaypointEventAction.Value,
|
||||||
|
char_id : Long,
|
||||||
|
waypoint_type : Int,
|
||||||
|
unk4 : Option[Long],
|
||||||
|
waypoint_info : Option[WaypointInfo])
|
||||||
|
extends PlanetSideGamePacket {
|
||||||
|
type Packet = SquadWaypointRequest
|
||||||
|
def opcode = GamePacketOpcode.SquadWaypointRequest
|
||||||
|
def encode = SquadWaypointRequest.encode(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
object SquadWaypointRequest extends Marshallable[SquadWaypointRequest] {
|
||||||
|
def Add(char_id : Long, waypoint_type : Int, waypoint : WaypointInfo) : SquadWaypointRequest =
|
||||||
|
SquadWaypointRequest(WaypointEventAction.Add, char_id, waypoint_type, None, Some(waypoint))
|
||||||
|
|
||||||
|
def Unknown1(char_id : Long, waypoint_type : Int, unk_a : Long) : SquadWaypointRequest =
|
||||||
|
SquadWaypointRequest(WaypointEventAction.Unknown1, char_id, waypoint_type, Some(unk_a), None)
|
||||||
|
|
||||||
|
def Remove(char_id : Long, waypoint_type : Int) : SquadWaypointRequest =
|
||||||
|
SquadWaypointRequest(WaypointEventAction.Remove, char_id, waypoint_type, None, None)
|
||||||
|
|
||||||
|
private val waypoint_codec : Codec[WaypointInfo] = (
|
||||||
|
("zone_number" | uint16L) ::
|
||||||
|
("pos" | Vector3.codec_pos)
|
||||||
|
).xmap[WaypointInfo] (
|
||||||
|
{
|
||||||
|
case zone_number :: pos :: HNil => WaypointInfo(zone_number, pos)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
case WaypointInfo(zone_number, pos) => zone_number :: pos.xy :: HNil
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
implicit val codec : Codec[SquadWaypointRequest] = (
|
||||||
|
("request_type" | WaypointEventAction.codec) >>:~ { request_type =>
|
||||||
|
("char_id" | uint32L) ::
|
||||||
|
("waypoint_type" | uint8L) ::
|
||||||
|
("unk4" | conditional(request_type == WaypointEventAction.Unknown1, uint32L)) ::
|
||||||
|
("waypoint" | conditional(request_type == WaypointEventAction.Add, waypoint_codec))
|
||||||
|
}
|
||||||
|
).exmap[SquadWaypointRequest] (
|
||||||
|
{
|
||||||
|
case WaypointEventAction.Add :: char_id :: waypoint_type :: None :: Some(waypoint) :: HNil =>
|
||||||
|
Attempt.Successful(SquadWaypointRequest(WaypointEventAction.Add, char_id, waypoint_type, None, Some(waypoint)))
|
||||||
|
|
||||||
|
case WaypointEventAction.Unknown1 :: char_id :: waypoint_type :: Some(d) :: None :: HNil =>
|
||||||
|
Attempt.Successful(SquadWaypointRequest(WaypointEventAction.Unknown1, char_id, waypoint_type, Some(d), None))
|
||||||
|
|
||||||
|
case request_type :: char_id :: waypoint_type :: None :: None :: HNil =>
|
||||||
|
Attempt.Successful(SquadWaypointRequest(request_type, char_id, waypoint_type, None, None))
|
||||||
|
|
||||||
|
case data =>
|
||||||
|
Attempt.Failure(Err(s"unexpected format while decoding - $data"))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
case SquadWaypointRequest(WaypointEventAction.Add, char_id, waypoint_type, None, Some(waypoint)) =>
|
||||||
|
Attempt.Successful(WaypointEventAction.Add :: char_id :: waypoint_type :: None :: Some(waypoint) :: HNil)
|
||||||
|
|
||||||
|
case SquadWaypointRequest(WaypointEventAction.Unknown1, char_id, waypoint_type, Some(d), None) =>
|
||||||
|
Attempt.Successful(WaypointEventAction.Unknown1 :: char_id :: waypoint_type :: Some(d) :: None :: HNil)
|
||||||
|
|
||||||
|
case SquadWaypointRequest(request_type, char_id, waypoint_type, None, None) =>
|
||||||
|
Attempt.Successful(request_type :: char_id :: waypoint_type :: None :: None :: HNil)
|
||||||
|
|
||||||
|
case data : SquadWaypointRequest =>
|
||||||
|
Attempt.Failure(Err(s"unexpected format while encoding - $data"))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) 2019 PSForever
|
// Copyright (c) 2019 PSForever
|
||||||
package services.teamwork
|
package services.teamwork
|
||||||
|
|
||||||
import net.psforever.objects.Player
|
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.packet.game._
|
import net.psforever.packet.game._
|
||||||
import net.psforever.types.{SquadRequestType, Vector3}
|
import net.psforever.types.{SquadRequestType, Vector3}
|
||||||
|
|
@ -9,7 +8,8 @@ import net.psforever.types.{SquadRequestType, Vector3}
|
||||||
object SquadAction {
|
object SquadAction {
|
||||||
trait Action
|
trait Action
|
||||||
|
|
||||||
final case class Definition(player : Player, zone : Zone, guid : PlanetSideGUID, line : Int, action : SquadAction) extends Action
|
final case class Definition(zone : Zone, guid : PlanetSideGUID, line : Int, action : SquadAction) extends Action
|
||||||
final case class Membership(request_type : SquadRequestType.Value, unk2 : Long, unk3 : Option[Long], player_name : String, unk5 : Option[Option[String]]) extends Action
|
final case class Membership(request_type : SquadRequestType.Value, unk2 : Long, unk3 : Option[Long], player_name : String, unk5 : Option[Option[String]]) extends Action
|
||||||
|
final case class Waypoint(event_type : WaypointEventAction.Value, waypoint_type : Int, unk : Option[Long], waypoint_info : Option[WaypointInfo]) extends Action
|
||||||
final case class Update(char_id : Long, health : Int, max_health : Int, armor : Int, max_armor : Int, pos : Vector3, zone_number : Int) extends Action
|
final case class Update(char_id : Long, health : Int, max_health : Int, armor : Int, max_armor : Int, pos : Vector3, zone_number : Int) extends Action
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,5 +29,8 @@ object SquadResponse {
|
||||||
|
|
||||||
final case class Detail(guid : PlanetSideGUID, squad_detail : SquadDetail) extends Response
|
final case class Detail(guid : PlanetSideGUID, squad_detail : SquadDetail) extends Response
|
||||||
|
|
||||||
|
final case class InitWaypoints(char_id : Long, waypoints : Iterable[(Int, WaypointInfo, Int)]) extends Response
|
||||||
|
final case class WaypointEvent(event_type : WaypointEventAction.Value, char_id : Long, waypoint_type : Int, unk5 : Option[Long], waypoint_info : Option[WaypointInfo], unk : Int) extends Response
|
||||||
|
|
||||||
final case class SquadSearchResults() extends Response
|
final case class SquadSearchResults() extends Response
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import net.psforever.objects.Player
|
||||||
import net.psforever.objects.definition.converter.StatConverter
|
import net.psforever.objects.definition.converter.StatConverter
|
||||||
import net.psforever.objects.loadouts.SquadLoadout
|
import net.psforever.objects.loadouts.SquadLoadout
|
||||||
import net.psforever.objects.teamwork.{Member, Squad}
|
import net.psforever.objects.teamwork.{Member, Squad}
|
||||||
import net.psforever.objects.zones.Zone
|
|
||||||
import net.psforever.packet.game._
|
import net.psforever.packet.game._
|
||||||
import net.psforever.types._
|
import net.psforever.types._
|
||||||
import services.{GenericEventBus, Service}
|
import services.{GenericEventBus, Service}
|
||||||
|
|
@ -44,6 +43,8 @@ class SquadService extends Actor {
|
||||||
*/
|
*/
|
||||||
private val initialAssociation : ListBuffer[PlanetSideGUID] = new ListBuffer[PlanetSideGUID]()
|
private val initialAssociation : ListBuffer[PlanetSideGUID] = new ListBuffer[PlanetSideGUID]()
|
||||||
private val queuedInvites : mutable.LongMap[List[Invitation]] = mutable.LongMap[List[Invitation]]()
|
private val queuedInvites : mutable.LongMap[List[Invitation]] = mutable.LongMap[List[Invitation]]()
|
||||||
|
private val waypoints : TrieMap[PlanetSideGUID, Array[WaypointData]] =
|
||||||
|
new TrieMap[PlanetSideGUID, Array[WaypointData]]()
|
||||||
private val viewDetails : mutable.LongMap[PlanetSideGUID] = mutable.LongMap[PlanetSideGUID]()
|
private val viewDetails : mutable.LongMap[PlanetSideGUID] = mutable.LongMap[PlanetSideGUID]()
|
||||||
|
|
||||||
private [this] val log = org.log4s.getLogger
|
private [this] val log = org.log4s.getLogger
|
||||||
|
|
@ -122,7 +123,7 @@ class SquadService extends Actor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def GetLeadingSquad(player : Player, zone : Int, opt : Option[Squad]) : Option[Squad] = {
|
def GetLeadingSquad(player : Player, opt : Option[Squad]) : Option[Squad] = {
|
||||||
val charId = player.CharId
|
val charId = player.CharId
|
||||||
opt match {
|
opt match {
|
||||||
case Some(squad) =>
|
case Some(squad) =>
|
||||||
|
|
@ -350,80 +351,31 @@ class SquadService extends Actor {
|
||||||
RemoveQueuedInvites(invitedPlayer) //TODO deal with these somehow
|
RemoveQueuedInvites(invitedPlayer) //TODO deal with these somehow
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
// if(idToSquad.get(guid).isEmpty) {
|
|
||||||
// log.warn("Accept->Invite: the squad no longer exists")
|
|
||||||
// }
|
|
||||||
// else if(memberToSquad.get(invitedPlayer).nonEmpty) {
|
|
||||||
// log.warn("Accept->Invite: player is already a member of a squad and can not join a second one")
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// val squad = idToSquad(guid)
|
|
||||||
// if(!squad.AutoApproveInvitationRequests && squad.Leader.CharId != invitingPlayer) {
|
|
||||||
// //the inviting player was not the squad leader and this decision should be bounced off the squad leader
|
|
||||||
// val bid = IndirectVacancy(tplayer, guid)
|
|
||||||
// AddInvite(squad.Leader.CharId, bid) match {
|
|
||||||
// case out @ Some(_) if out.contains(bid) =>
|
|
||||||
// HandleBidForPosition(bid, tplayer)
|
|
||||||
// case _ => ;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// //if a suitable position in the squad can be found, player may occupy it
|
|
||||||
// squad.Membership.zipWithIndex.find({ case (member, index) =>
|
|
||||||
// ValidOpenSquadPosition(squad, index, member, tplayer.Certifications)
|
|
||||||
// }) match {
|
|
||||||
// case Some((_, line)) =>
|
|
||||||
// SquadEvents.publish(SquadServiceResponse(s"/$invitingPlayer/Squad", SquadResponse.Membership(SquadResponseType.Accept, 0, 0, invitingPlayer, Some(invitedPlayer), tplayer.Name, false, Some(None))))
|
|
||||||
// SquadEvents.publish(SquadServiceResponse(s"/$invitedPlayer/Squad", SquadResponse.Membership(SquadResponseType.Accept, 0, 0, invitedPlayer, Some(invitingPlayer), "", true, Some(None))))
|
|
||||||
// JoinSquad(tplayer, squad, line)
|
|
||||||
// RemoveQueuedInvites(invitedPlayer) //TODO deal with these somehow
|
|
||||||
// case _ => ;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
case Some(SpontaneousInvite(invitingPlayer)) =>
|
case Some(SpontaneousInvite(invitingPlayer)) =>
|
||||||
//we were invited by someone into a new squad they would form
|
//originally, we were invited by someone into a new squad they would form
|
||||||
val invitingPlayerCharId = invitingPlayer.CharId
|
val invitingPlayerCharId = invitingPlayer.CharId
|
||||||
(GetParticipatingSquad(invitingPlayer) match {
|
(GetParticipatingSquad(invitingPlayer) match {
|
||||||
case Some(participating) =>
|
case Some(participating) =>
|
||||||
if(participating.Leader.CharId == invitingPlayerCharId) {
|
//invitingPlayer became part of a squad while invited player was answering the original summons
|
||||||
Some(participating)
|
Some(participating)
|
||||||
}
|
case _ =>
|
||||||
else {
|
//generate a new squad, with invitingPlayer as the leader
|
||||||
//inviter joined a squad and is not its leader; bounce this request off of the squad leader
|
|
||||||
participating.Membership.zipWithIndex.find({ case (member, index) =>
|
|
||||||
ValidOpenSquadPosition(participating, index, member, tplayer.Certifications)
|
|
||||||
}) match {
|
|
||||||
case Some((_, line)) =>
|
|
||||||
val bid = BidForPosition(tplayer, participating.GUID, line)
|
|
||||||
AddInvite(participating.Leader.CharId, bid) match {
|
|
||||||
case out @ Some(_) if out.contains(bid) =>
|
|
||||||
HandleBidForPosition(bid, tplayer)
|
|
||||||
case _ => ;
|
|
||||||
}
|
|
||||||
case _ => ;
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
case None =>
|
|
||||||
val squad = StartSquad(invitingPlayer)
|
val squad = StartSquad(invitingPlayer)
|
||||||
squad.Task = s"${tplayer.Name}'s Squad"
|
squad.Task = s"${invitingPlayer.Name}'s Squad"
|
||||||
SquadEvents.publish(SquadServiceResponse(s"/$invitingPlayer/Squad", SquadResponse.AssociateWithSquad(squad.GUID)))
|
SquadEvents.publish( SquadServiceResponse(s"/$invitingPlayerCharId/Squad", SquadResponse.AssociateWithSquad(squad.GUID)) )
|
||||||
Some(squad)
|
Some(squad)
|
||||||
}) match {
|
}) match {
|
||||||
case Some(squad) =>
|
case Some(squad) =>
|
||||||
squad.Membership.zipWithIndex.find({ case (member, index) =>
|
HandleVacancyInvite(squad.GUID, tplayer.CharId, invitingPlayerCharId, tplayer) match {
|
||||||
ValidOpenSquadPosition(squad, index, member, tplayer.Certifications)
|
|
||||||
}) match {
|
|
||||||
case Some((_, line)) =>
|
case Some((_, line)) =>
|
||||||
SquadEvents.publish( SquadServiceResponse(s"/$invitedPlayer/Squad", SquadResponse.Membership(SquadResponseType.Accept, 0, 0, invitedPlayer, Some(invitingPlayerCharId), "", true, Some(None))) )
|
SquadEvents.publish( SquadServiceResponse(s"/$invitedPlayer/Squad", SquadResponse.Membership(SquadResponseType.Accept, 0, 0, invitedPlayer, Some(invitingPlayerCharId), "", true, Some(None))) )
|
||||||
JoinSquad(tplayer, squad, line)
|
JoinSquad(tplayer, squad, line)
|
||||||
SquadEvents.publish( SquadServiceResponse(s"/$invitingPlayerCharId/Squad", SquadResponse.Membership(SquadResponseType.Accept, 0, 0, invitingPlayerCharId, Some(invitedPlayer), tplayer.Name, false, Some(None))) )
|
SquadEvents.publish( SquadServiceResponse(s"/$invitingPlayerCharId/Squad", SquadResponse.Membership(SquadResponseType.Accept, 0, 0, invitingPlayerCharId, Some(invitedPlayer), tplayer.Name, false, Some(None))) )
|
||||||
RemoveQueuedInvites(invitedPlayer) //TODO deal with these somehow
|
RemoveQueuedInvites(tplayer.CharId) //TODO deal with these somehow
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
case None => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
case None =>
|
case None =>
|
||||||
|
|
@ -566,32 +518,46 @@ class SquadService extends Actor {
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SquadAction.Update(char_id, health, max_health, armor, max_armor, pos, zone_number) =>
|
case SquadAction.Waypoint(_, wtype, _, info) =>
|
||||||
memberToSquad.get(char_id) match {
|
val playerCharId = tplayer.CharId
|
||||||
|
(GetLeadingSquad(tplayer, None) match {
|
||||||
case Some(squad) =>
|
case Some(squad) =>
|
||||||
squad.Membership.find(_.CharId == char_id) match {
|
info match {
|
||||||
case Some(member) =>
|
case Some(winfo) =>
|
||||||
member.Health = StatConverter.Health(health, max_health, min=1, max=64)
|
(Some(squad), AddWaypoint(squad.GUID, wtype, winfo))
|
||||||
member.Armor = StatConverter.Health(armor, max_armor, min=1, max=64)
|
case _ =>
|
||||||
member.Position = pos
|
RemoveWaypoint(squad.GUID, wtype)
|
||||||
member.ZoneId = zone_number
|
(Some(squad), None)
|
||||||
sender ! SquadServiceResponse("", SquadResponse.UpdateMembers(
|
|
||||||
squad,
|
|
||||||
squad.Membership
|
|
||||||
.filterNot { _.CharId == 0 }
|
|
||||||
.map { member => SquadAction.Update(member.CharId, member.Health, 0, member.Armor, 0, member.Position, member.ZoneId) }
|
|
||||||
.toList
|
|
||||||
))
|
|
||||||
case _ => ;
|
|
||||||
}
|
}
|
||||||
|
case _ => (None, None)
|
||||||
case None => ;
|
}) match {
|
||||||
|
case (Some(squad), Some(waypoint)) =>
|
||||||
|
//waypoint added or updated
|
||||||
|
squad.Membership
|
||||||
|
.filterNot { member => member.CharId == tplayer.CharId }
|
||||||
|
.foreach { member =>
|
||||||
|
val charId = member.CharId
|
||||||
|
SquadEvents.publish(
|
||||||
|
SquadServiceResponse(s"/$charId/Squad", SquadResponse.WaypointEvent(WaypointEventAction.Add, playerCharId, wtype, None, info, 1))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
case (Some(squad), None) =>
|
||||||
|
//waypoint removed?
|
||||||
|
squad.Membership
|
||||||
|
.filterNot { member => member.CharId == tplayer.CharId }
|
||||||
|
.foreach { member =>
|
||||||
|
val charId = member.CharId
|
||||||
|
SquadEvents.publish(
|
||||||
|
SquadServiceResponse(s"/$charId/Squad", SquadResponse.WaypointEvent(WaypointEventAction.Remove, playerCharId, wtype, None, None, 0))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SquadAction.Definition(tplayer : Player, zone : Zone, guid : PlanetSideGUID, line : Int, action : SquadAction) =>
|
case SquadAction.Definition(zone, guid, line, action) =>
|
||||||
import net.psforever.packet.game.SquadAction._
|
import net.psforever.packet.game.SquadAction._
|
||||||
val pSquadOpt = GetParticipatingSquad(tplayer)
|
val pSquadOpt = GetParticipatingSquad(tplayer)
|
||||||
val lSquadOpt = GetLeadingSquad(tplayer, zone.Number, pSquadOpt)
|
val lSquadOpt = GetLeadingSquad(tplayer, pSquadOpt)
|
||||||
//the following actions can only be performed by a squad's leader
|
//the following actions can only be performed by a squad's leader
|
||||||
action match {
|
action match {
|
||||||
case SaveSquadFavorite() =>
|
case SaveSquadFavorite() =>
|
||||||
|
|
@ -624,17 +590,17 @@ class SquadService extends Actor {
|
||||||
UpdateSquadListWhenListed(squad, SquadInfo().Task(purpose))
|
UpdateSquadListWhenListed(squad, SquadInfo().Task(purpose))
|
||||||
UpdateSquadDetail(squad.GUID, squad, SquadDetail().Task(purpose))
|
UpdateSquadDetail(squad.GUID, squad, SquadDetail().Task(purpose))
|
||||||
|
|
||||||
case ChangeSquadZone(zone) =>
|
case ChangeSquadZone(zone_id) =>
|
||||||
log.info(s"${tplayer.Name}-${tplayer.Faction} has changed squad's ops zone to $zone")
|
log.info(s"${tplayer.Name}-${tplayer.Faction} has changed squad's ops zone to $zone_id")
|
||||||
val squad = lSquadOpt.getOrElse(StartSquad(tplayer))
|
val squad = lSquadOpt.getOrElse(StartSquad(tplayer))
|
||||||
squad.ZoneId = zone.zoneId.toInt
|
squad.ZoneId = zone_id.zoneId.toInt
|
||||||
UpdateSquadListWhenListed(squad, SquadInfo().ZoneId(zone))
|
UpdateSquadListWhenListed(squad, SquadInfo().ZoneId(zone_id))
|
||||||
InitialAssociation(squad)
|
InitialAssociation(squad)
|
||||||
sender ! SquadServiceResponse("", SquadResponse.Detail(
|
sender ! SquadServiceResponse("", SquadResponse.Detail(
|
||||||
squad.GUID,
|
squad.GUID,
|
||||||
SquadService.Detail.Publish(squad))
|
SquadService.Detail.Publish(squad))
|
||||||
)
|
)
|
||||||
UpdateSquadDetail(squad.GUID, squad.Membership.map { _m => _m.CharId }.filterNot { _ == squad.Leader.CharId }, SquadDetail().ZoneId(zone))
|
UpdateSquadDetail(squad.GUID, squad.Membership.map { _m => _m.CharId }.filterNot { _ == squad.Leader.CharId }, SquadDetail().ZoneId(zone_id))
|
||||||
|
|
||||||
case CloseSquadMemberPosition(position) =>
|
case CloseSquadMemberPosition(position) =>
|
||||||
val squad = lSquadOpt.getOrElse(StartSquad(tplayer))
|
val squad = lSquadOpt.getOrElse(StartSquad(tplayer))
|
||||||
|
|
@ -906,6 +872,12 @@ class SquadService extends Actor {
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//the following action can be peprformed by anyone
|
||||||
|
case (_, SearchForSquadsWithParticularRole(role, requirements, zone_id, search_mode)) =>
|
||||||
|
//though we should be able correctly search squads as is intended
|
||||||
|
//I don't know how search results should be prioritized or even how to return search results to the user
|
||||||
|
sender ! SquadServiceResponse("", SquadResponse.SquadSearchResults())
|
||||||
|
|
||||||
//the following action can be performed by anyone
|
//the following action can be performed by anyone
|
||||||
case (_, DisplaySquad()) =>
|
case (_, DisplaySquad()) =>
|
||||||
idToSquad.get(guid) match {
|
idToSquad.get(guid) match {
|
||||||
|
|
@ -926,6 +898,28 @@ class SquadService extends Actor {
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SquadAction.Update(char_id, health, max_health, armor, max_armor, pos, zone_number) =>
|
||||||
|
memberToSquad.get(char_id) match {
|
||||||
|
case Some(squad) =>
|
||||||
|
squad.Membership.find(_.CharId == char_id) match {
|
||||||
|
case Some(member) =>
|
||||||
|
member.Health = StatConverter.Health(health, max_health, min=1, max=64)
|
||||||
|
member.Armor = StatConverter.Health(armor, max_armor, min=1, max=64)
|
||||||
|
member.Position = pos
|
||||||
|
member.ZoneId = zone_number
|
||||||
|
sender ! SquadServiceResponse("", SquadResponse.UpdateMembers(
|
||||||
|
squad,
|
||||||
|
squad.Membership
|
||||||
|
.filterNot { _.CharId == 0 }
|
||||||
|
.map { member => SquadAction.Update(member.CharId, member.Health, 0, member.Armor, 0, member.Position, member.ZoneId) }
|
||||||
|
.toList
|
||||||
|
))
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
case None => ;
|
||||||
|
}
|
||||||
|
|
||||||
case msg =>
|
case msg =>
|
||||||
log.info(s"Unhandled message $msg from $sender")
|
log.info(s"Unhandled message $msg from $sender")
|
||||||
}
|
}
|
||||||
|
|
@ -1146,6 +1140,7 @@ class SquadService extends Actor {
|
||||||
.filterNot { _.CharId == 0 }
|
.filterNot { _.CharId == 0 }
|
||||||
.foreach { member =>
|
.foreach { member =>
|
||||||
SquadEvents.publish(SquadServiceResponse(s"/${member.CharId}/Squad", SquadResponse.Join(squad, indices)))
|
SquadEvents.publish(SquadServiceResponse(s"/${member.CharId}/Squad", SquadResponse.Join(squad, indices)))
|
||||||
|
InitWaypoints(member.CharId, squad.GUID)
|
||||||
}
|
}
|
||||||
//fully update for all users
|
//fully update for all users
|
||||||
UpdateSquadDetail(squad.GUID, squad)
|
UpdateSquadDetail(squad.GUID, squad)
|
||||||
|
|
@ -1156,6 +1151,7 @@ class SquadService extends Actor {
|
||||||
val indices = squad.Membership.zipWithIndex.collect({ case (member, index) if member.CharId != 0 => index }).toList
|
val indices = squad.Membership.zipWithIndex.collect({ case (member, index) if member.CharId != 0 => index }).toList
|
||||||
SquadEvents.publish(SquadServiceResponse(s"/$charId/Squad", SquadResponse.Join(squad, indices)))
|
SquadEvents.publish(SquadServiceResponse(s"/$charId/Squad", SquadResponse.Join(squad, indices)))
|
||||||
InitSquadDetail(squad.GUID, Seq(charId), squad)
|
InitSquadDetail(squad.GUID, Seq(charId), squad)
|
||||||
|
InitWaypoints(charId, squad.GUID)
|
||||||
//other squad members see new member joining the squad
|
//other squad members see new member joining the squad
|
||||||
val updatedIndex = List(line)
|
val updatedIndex = List(line)
|
||||||
val otherMembers = squad.Membership.filterNot { member => member.CharId == 0 || member.CharId == charId }.map{ _.CharId }
|
val otherMembers = squad.Membership.filterNot { member => member.CharId == 0 || member.CharId == charId }.map{ _.CharId }
|
||||||
|
|
@ -1163,7 +1159,7 @@ class SquadService extends Actor {
|
||||||
SquadEvents.publish(SquadServiceResponse(s"/$member/Squad", SquadResponse.Join(squad, updatedIndex)))
|
SquadEvents.publish(SquadServiceResponse(s"/$member/Squad", SquadResponse.Join(squad, updatedIndex)))
|
||||||
}
|
}
|
||||||
val details = SquadDetail().Members(List(SquadPositionEntry(line, SquadPositionDetail().CharId(charId).Name(player.Name))))
|
val details = SquadDetail().Members(List(SquadPositionEntry(line, SquadPositionDetail().CharId(charId).Name(player.Name))))
|
||||||
UpdateSquadDetail(squad.GUID, Seq(charId), details)
|
UpdateSquadDetail(squad.GUID, otherMembers, details)
|
||||||
}
|
}
|
||||||
UpdateSquadListWhenListed(squad, SquadInfo().Size(size))
|
UpdateSquadListWhenListed(squad, SquadInfo().Size(size))
|
||||||
true
|
true
|
||||||
|
|
@ -1207,7 +1203,6 @@ class SquadService extends Actor {
|
||||||
}
|
}
|
||||||
|
|
||||||
def CloseOutSquad(squad : Squad, membership : Iterable[(Member, Int)], updateList : List[(Long, Int)]) : Unit = {
|
def CloseOutSquad(squad : Squad, membership : Iterable[(Member, Int)], updateList : List[(Long, Int)]) : Unit = {
|
||||||
val leaderCharId = squad.Leader.CharId
|
|
||||||
membership.foreach {
|
membership.foreach {
|
||||||
case (member, _) =>
|
case (member, _) =>
|
||||||
val charId = member.CharId
|
val charId = member.CharId
|
||||||
|
|
@ -1217,6 +1212,7 @@ class SquadService extends Actor {
|
||||||
SquadEvents.publish( SquadServiceResponse(s"/$charId/Squad", SquadResponse.Leave(squad, updateList)) )
|
SquadEvents.publish( SquadServiceResponse(s"/$charId/Squad", SquadResponse.Leave(squad, updateList)) )
|
||||||
}
|
}
|
||||||
idToSquad.remove(squad.GUID)
|
idToSquad.remove(squad.GUID)
|
||||||
|
waypoints.remove(squad.GUID)
|
||||||
UpdateSquadList(squad, None)
|
UpdateSquadList(squad, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1332,9 +1328,70 @@ class SquadService extends Actor {
|
||||||
toMembers.foreach { charId => SquadEvents.publish(SquadServiceResponse(s"/$charId/Squad", output)) }
|
toMembers.foreach { charId => SquadEvents.publish(SquadServiceResponse(s"/$charId/Squad", output)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def AddWaypoint(guid : PlanetSideGUID, waypointType : Int, info : WaypointInfo) : Option[WaypointData] = {
|
||||||
|
(waypoints.get(guid) match {
|
||||||
|
case Some(array) =>
|
||||||
|
array
|
||||||
|
case None if idToSquad.get(guid).nonEmpty =>
|
||||||
|
log.debug(s"initializing squad waypoint system for squad #${guid.guid}")
|
||||||
|
val array = Array.fill[WaypointData](5)(new WaypointData())
|
||||||
|
waypoints(guid) = array
|
||||||
|
array
|
||||||
|
case _ =>
|
||||||
|
log.warn(s"squad #${guid.guid} does not currently exist so it can not render waypoints")
|
||||||
|
Array.empty[WaypointData]
|
||||||
|
}).lift(waypointType) match {
|
||||||
|
case Some(point) =>
|
||||||
|
//update the waypoint
|
||||||
|
log.debug(s"rendering squad waypoint $waypointType for squad #${guid.guid}")
|
||||||
|
point.zone_number = info.zone_number
|
||||||
|
point.pos = info.pos
|
||||||
|
Some(point)
|
||||||
|
case _ =>
|
||||||
|
log.warn(s"no squad waypoint $waypointType found")
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def RemoveWaypoint(guid : PlanetSideGUID, waypointType : Int) : Unit = {
|
||||||
|
(waypoints.get(guid) match {
|
||||||
|
case Some(array) =>
|
||||||
|
array
|
||||||
|
case None =>
|
||||||
|
Array.empty[WaypointData]
|
||||||
|
}).lift(waypointType) match {
|
||||||
|
case Some(point) =>
|
||||||
|
//update the waypoint
|
||||||
|
log.debug(s"removing squad waypoint $waypointType for squad #${guid.guid}")
|
||||||
|
point.zone_number = 1
|
||||||
|
point.pos = Vector3.z(1)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def InitWaypoints(toCharId : Long, guid : PlanetSideGUID) : Unit = {
|
||||||
|
(idToSquad.get(guid), waypoints.get(guid)) match {
|
||||||
|
case (Some(squad), Some(list)) =>
|
||||||
|
val vz1 = Vector3.z(1)
|
||||||
|
SquadEvents.publish(
|
||||||
|
SquadServiceResponse(s"/$toCharId/Squad", SquadResponse.InitWaypoints(squad.Leader.CharId,
|
||||||
|
list.zipWithIndex.collect { case (point, index) if point.pos != vz1 =>
|
||||||
|
(index, WaypointInfo(point.zone_number, point.pos), 1)
|
||||||
|
}
|
||||||
|
))
|
||||||
|
)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object SquadService {
|
object SquadService {
|
||||||
|
class WaypointData() {
|
||||||
|
var zone_number : Int = 1
|
||||||
|
var pos : Vector3 = Vector3.z(1) //a waypoint with a non-zero z-coordinate will flag as not getting drawn
|
||||||
|
}
|
||||||
|
|
||||||
abstract class Invitation(char_id : Long, name : String) {
|
abstract class Invitation(char_id : Long, name : String) {
|
||||||
def InviterCharId : Long = char_id
|
def InviterCharId : Long = char_id
|
||||||
def InviterName : String = name
|
def InviterName : String = name
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package game
|
||||||
|
|
||||||
import org.specs2.mutable._
|
import org.specs2.mutable._
|
||||||
import net.psforever.packet._
|
import net.psforever.packet._
|
||||||
import net.psforever.packet.game.{SquadWaypointEvent, WaypointEvent}
|
import net.psforever.packet.game.{SquadWaypointEvent, WaypointEventAction, WaypointEvent}
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.Vector3
|
||||||
import scodec.bits._
|
import scodec.bits._
|
||||||
|
|
||||||
|
|
@ -16,12 +16,12 @@ class SquadWaypointEventTest extends Specification {
|
||||||
"decode (1)" in {
|
"decode (1)" in {
|
||||||
PacketCoding.DecodePacket(string_1).require match {
|
PacketCoding.DecodePacket(string_1).require match {
|
||||||
case SquadWaypointEvent(unk1, unk2, unk3, unk4, unk5, unk6) =>
|
case SquadWaypointEvent(unk1, unk2, unk3, unk4, unk5, unk6) =>
|
||||||
unk1 mustEqual 2
|
unk1 mustEqual WaypointEventAction.Remove
|
||||||
unk2 mustEqual 11
|
unk2 mustEqual 11
|
||||||
unk3 mustEqual 31155863L
|
unk3 mustEqual 31155863L
|
||||||
unk4 mustEqual 0
|
unk4 mustEqual 0
|
||||||
unk5 mustEqual None
|
unk5.isEmpty mustEqual true
|
||||||
unk6 mustEqual None
|
unk6.isEmpty mustEqual true
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
}
|
}
|
||||||
|
|
@ -30,12 +30,12 @@ class SquadWaypointEventTest extends Specification {
|
||||||
"decode (2)" in {
|
"decode (2)" in {
|
||||||
PacketCoding.DecodePacket(string_2).require match {
|
PacketCoding.DecodePacket(string_2).require match {
|
||||||
case SquadWaypointEvent(unk1, unk2, unk3, unk4, unk5, unk6) =>
|
case SquadWaypointEvent(unk1, unk2, unk3, unk4, unk5, unk6) =>
|
||||||
unk1 mustEqual 2
|
unk1 mustEqual WaypointEventAction.Remove
|
||||||
unk2 mustEqual 10
|
unk2 mustEqual 10
|
||||||
unk3 mustEqual 0L
|
unk3 mustEqual 0L
|
||||||
unk4 mustEqual 4
|
unk4 mustEqual 4
|
||||||
unk5 mustEqual None
|
unk5.isEmpty mustEqual true
|
||||||
unk6 mustEqual None
|
unk6.isEmpty mustEqual true
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
}
|
}
|
||||||
|
|
@ -44,12 +44,12 @@ class SquadWaypointEventTest extends Specification {
|
||||||
"decode (3)" in {
|
"decode (3)" in {
|
||||||
PacketCoding.DecodePacket(string_3).require match {
|
PacketCoding.DecodePacket(string_3).require match {
|
||||||
case SquadWaypointEvent(unk1, unk2, unk3, unk4, unk5, unk6) =>
|
case SquadWaypointEvent(unk1, unk2, unk3, unk4, unk5, unk6) =>
|
||||||
unk1 mustEqual 0
|
unk1 mustEqual WaypointEventAction.Add
|
||||||
unk2 mustEqual 3
|
unk2 mustEqual 3
|
||||||
unk3 mustEqual 41581052L
|
unk3 mustEqual 41581052L
|
||||||
unk4 mustEqual 1
|
unk4 mustEqual 1
|
||||||
unk5 mustEqual None
|
unk5.isEmpty mustEqual true
|
||||||
unk6 mustEqual Some(WaypointEvent(10, Vector3(3457.9688f, 5514.4688f, 0.0f), 1))
|
unk6.contains( WaypointEvent(10, Vector3(3457.9688f, 5514.4688f, 0.0f), 1) ) mustEqual true
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
}
|
}
|
||||||
|
|
@ -58,40 +58,40 @@ class SquadWaypointEventTest extends Specification {
|
||||||
"decode (4)" in {
|
"decode (4)" in {
|
||||||
PacketCoding.DecodePacket(string_4).require match {
|
PacketCoding.DecodePacket(string_4).require match {
|
||||||
case SquadWaypointEvent(unk1, unk2, unk3, unk4, unk5, unk6) =>
|
case SquadWaypointEvent(unk1, unk2, unk3, unk4, unk5, unk6) =>
|
||||||
unk1 mustEqual 1
|
unk1 mustEqual WaypointEventAction.Unknown1
|
||||||
unk2 mustEqual 3
|
unk2 mustEqual 3
|
||||||
unk3 mustEqual 41581052L
|
unk3 mustEqual 41581052L
|
||||||
unk4 mustEqual 1
|
unk4 mustEqual 1
|
||||||
unk5 mustEqual Some(4L)
|
unk5.contains( 4L ) mustEqual true
|
||||||
unk6 mustEqual None
|
unk6.isEmpty mustEqual true
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode (1)" in {
|
"encode (1)" in {
|
||||||
val msg = SquadWaypointEvent(2, 11, 31155863L, 0)
|
val msg = SquadWaypointEvent.Remove(11, 31155863L, 0)
|
||||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual string_1
|
pkt mustEqual string_1
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode (2)" in {
|
"encode (2)" in {
|
||||||
val msg = SquadWaypointEvent(2, 10, 0L, 4)
|
val msg = SquadWaypointEvent.Remove(10, 0L, 4)
|
||||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual string_2
|
pkt mustEqual string_2
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode (3)" in {
|
"encode (3)" in {
|
||||||
val msg = SquadWaypointEvent(0, 3, 41581052L, 1, 10, Vector3(3457.9688f, 5514.4688f, 0.0f), 1)
|
val msg = SquadWaypointEvent.Add(3, 41581052L, 1, WaypointEvent(10, Vector3(3457.9688f, 5514.4688f, 0.0f), 1))
|
||||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual string_3
|
pkt mustEqual string_3
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode (4)" in {
|
"encode (4)" in {
|
||||||
val msg = SquadWaypointEvent(1, 3, 41581052L, 1, 4L)
|
val msg = SquadWaypointEvent.Unknown1(3, 41581052L, 1, 4L)
|
||||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual string_4
|
pkt mustEqual string_4
|
||||||
|
|
|
||||||
|
|
@ -516,15 +516,32 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
log.info(s"SquadCards: ${squadUI.map { case(id, card) => s"[${card.index}:${card.name}/$id]" }.mkString}")
|
log.info(s"SquadCards: ${squadUI.map { case(id, card) => s"[${card.index}:${card.name}/$id]" }.mkString}")
|
||||||
|
|
||||||
case SquadResponse.PromoteMember(squad, char_id, from_index, to_index) =>
|
case SquadResponse.PromoteMember(squad, char_id, from_index, to_index) =>
|
||||||
//promotion will swap visual cards, but we must fix the backend
|
//promotion will swap cards visually, but we must fix the backend
|
||||||
val id = 11
|
val id = 11
|
||||||
sendResponse(SquadMemberEvent.Promote(id, char_id))
|
sendResponse(SquadMemberEvent.Promote(id, char_id))
|
||||||
SwapSquadUIElements(squad, from_index, to_index)
|
SwapSquadUIElements(squad, from_index, to_index)
|
||||||
log.info(s"SquadCards: ${squadUI.map { case(id, card) => s"[${card.index}:${card.name}/$id]" }.mkString}")
|
log.info(s"SquadCards: ${squadUI.map { case(id, card) => s"[${card.index}:${card.name}/$id]" }.mkString}")
|
||||||
|
|
||||||
case SquadResponse.SquadSearchResults() =>
|
case SquadResponse.SquadSearchResults() =>
|
||||||
|
//I don't actually know how to return search results
|
||||||
sendResponse(SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SquadAction.NoSquadSearchResults()))
|
sendResponse(SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SquadAction.NoSquadSearchResults()))
|
||||||
|
|
||||||
|
case SquadResponse.InitWaypoints(char_id, waypoints) =>
|
||||||
|
val id = 11
|
||||||
|
StartBundlingPackets()
|
||||||
|
waypoints.foreach { case (waypoint_type, info, unk) =>
|
||||||
|
sendResponse(SquadWaypointEvent.Add(id, char_id, waypoint_type, WaypointEvent(info.zone_number, info.pos, unk)))
|
||||||
|
}
|
||||||
|
StopBundlingPackets()
|
||||||
|
|
||||||
|
case SquadResponse.WaypointEvent(WaypointEventAction.Add, char_id, waypoint_type, _, Some(info), unk) =>
|
||||||
|
val id = 11
|
||||||
|
sendResponse(SquadWaypointEvent.Add(id, char_id, waypoint_type, WaypointEvent(info.zone_number, info.pos, unk)))
|
||||||
|
|
||||||
|
case SquadResponse.WaypointEvent(WaypointEventAction.Remove, char_id, waypoint_type, _, _, _) =>
|
||||||
|
val id = 11
|
||||||
|
sendResponse(SquadWaypointEvent.Remove(id, char_id, waypoint_type))
|
||||||
|
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4960,12 +4977,16 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
|
|
||||||
case msg @ SquadDefinitionActionMessage(u1, u2, action) =>
|
case msg @ SquadDefinitionActionMessage(u1, u2, action) =>
|
||||||
log.info(s"SquadDefinitionAction: $msg")
|
log.info(s"SquadDefinitionAction: $msg")
|
||||||
squadService ! SquadServiceMessage(player, SquadServiceAction.Definition(player, continent, u1, u2, action))
|
squadService ! SquadServiceMessage(player, SquadServiceAction.Definition(continent, u1, u2, action))
|
||||||
|
|
||||||
case msg @ SquadMembershipRequest(request_type, unk2, unk3, player_name, unk5) =>
|
case msg @ SquadMembershipRequest(request_type, unk2, unk3, player_name, unk5) =>
|
||||||
log.info(s"$msg")
|
log.info(s"$msg")
|
||||||
squadService ! SquadServiceMessage(player, SquadServiceAction.Membership(request_type, unk2, unk3, player_name, unk5))
|
squadService ! SquadServiceMessage(player, SquadServiceAction.Membership(request_type, unk2, unk3, player_name, unk5))
|
||||||
|
|
||||||
|
case msg @ SquadWaypointRequest(request, _, wtype, unk, info) =>
|
||||||
|
log.info(s"Waypoint Request: $msg")
|
||||||
|
squadService ! SquadServiceMessage(player, SquadServiceAction.Waypoint(request, wtype, unk, info))
|
||||||
|
|
||||||
case msg @ GenericCollisionMsg(u1, p, t, php, thp, pv, tv, ppos, tpos, u2, u3, u4) =>
|
case msg @ GenericCollisionMsg(u1, p, t, php, thp, pv, tv, ppos, tpos, u2, u3, u4) =>
|
||||||
log.info("Ouch! " + msg)
|
log.info("Ouch! " + msg)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue