mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-13 15:34:42 +00:00
better support for the various ways to join a squad, and the various ways to leave a squad; squad-based messages; jury-rigged 'player wants to join' operations
This commit is contained in:
parent
24691ec239
commit
e5b2efd381
7 changed files with 681 additions and 331 deletions
|
|
@ -16,9 +16,26 @@ import shapeless.{::, HNil}
|
||||||
abstract class SquadAction(val code : Int)
|
abstract class SquadAction(val code : Int)
|
||||||
|
|
||||||
object SquadAction{
|
object SquadAction{
|
||||||
|
object SearchMode extends Enumeration {
|
||||||
|
type Type = Value
|
||||||
|
|
||||||
|
val
|
||||||
|
AnyPositions,
|
||||||
|
AvailablePositions,
|
||||||
|
SomeCertifications,
|
||||||
|
AllCertifications
|
||||||
|
= Value
|
||||||
|
|
||||||
|
implicit val codec : Codec[SearchMode.Value] = PacketHelpers.createEnumerationCodec(enum = this, uint(bits = 3))
|
||||||
|
}
|
||||||
|
|
||||||
final case class DisplaySquad() extends SquadAction(0)
|
final case class DisplaySquad() extends SquadAction(0)
|
||||||
|
|
||||||
final case class AnswerSquadJoinRequest() extends SquadAction(1)
|
/**
|
||||||
|
* Dispatched from client to server to indicate a squad detail update that has no foundation entry to update?
|
||||||
|
* Not dissimilar from `DisplaySquad`.
|
||||||
|
*/
|
||||||
|
final case class DisplayFullSquad() extends SquadAction(1)
|
||||||
|
|
||||||
final case class SaveSquadFavorite() extends SquadAction(3)
|
final case class SaveSquadFavorite() extends SquadAction(3)
|
||||||
|
|
||||||
|
|
@ -58,12 +75,14 @@ object SquadAction{
|
||||||
|
|
||||||
final case class LocationFollowsSquadLead(state : Boolean) extends SquadAction(31)
|
final case class LocationFollowsSquadLead(state : Boolean) extends SquadAction(31)
|
||||||
|
|
||||||
final case class SearchForSquadsWithParticularRole(u1: String, u2 : Long, u3: Int, u4 : Int) extends SquadAction(34)
|
final case class SearchForSquadsWithParticularRole(role: String, requirements : Set[CertificationType.Value], zone_id: Int, mode : SearchMode.Value) extends SquadAction(34)
|
||||||
|
|
||||||
final case class CancelSquadSearch() extends SquadAction(35)
|
final case class CancelSquadSearch() extends SquadAction(35)
|
||||||
|
|
||||||
final case class AssignSquadMemberToRole(position : Int, char_id : Long) extends SquadAction(38)
|
final case class AssignSquadMemberToRole(position : Int, char_id : Long) extends SquadAction(38)
|
||||||
|
|
||||||
|
final case class NoSquadSearchResults() extends SquadAction(39)
|
||||||
|
|
||||||
final case class FindLfsSoldiersForRole(state : Int) extends SquadAction(40)
|
final case class FindLfsSoldiersForRole(state : Int) extends SquadAction(40)
|
||||||
|
|
||||||
final case class CancelFind() extends SquadAction(41)
|
final case class CancelFind() extends SquadAction(41)
|
||||||
|
|
@ -91,10 +110,10 @@ object SquadAction{
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
val answerSquadJoinRequestCodec = everFailCondition.xmap[AnswerSquadJoinRequest] (
|
val displayFullSquadCodec = everFailCondition.xmap[DisplayFullSquad] (
|
||||||
_ => AnswerSquadJoinRequest(),
|
_ => DisplayFullSquad(),
|
||||||
{
|
{
|
||||||
case AnswerSquadJoinRequest() => None
|
case DisplayFullSquad() => None
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -243,12 +262,12 @@ object SquadAction{
|
||||||
PacketHelpers.encodedWideStringAligned(6) ::
|
PacketHelpers.encodedWideStringAligned(6) ::
|
||||||
ulongL(46) ::
|
ulongL(46) ::
|
||||||
uint16L ::
|
uint16L ::
|
||||||
uintL(3)).xmap[SearchForSquadsWithParticularRole] (
|
SearchMode.codec).xmap[SearchForSquadsWithParticularRole] (
|
||||||
{
|
{
|
||||||
case u1 :: u2 :: u3 :: u4 :: HNil => SearchForSquadsWithParticularRole(u1, u2, u3, u4)
|
case u1 :: u2 :: u3 :: u4 :: HNil => SearchForSquadsWithParticularRole(u1, CertificationType.fromEncodedLong(u2), u3, u4)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case SearchForSquadsWithParticularRole(u1, u2, u3, u4) => u1 :: u2 :: u3 :: u4 :: HNil
|
case SearchForSquadsWithParticularRole(u1, u2, u3, u4) => u1 :: CertificationType.toEncodedLong(u2) :: u3 :: u4 :: HNil
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -268,6 +287,13 @@ object SquadAction{
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val noSquadSearchResultsCodec = everFailCondition.xmap[NoSquadSearchResults] (
|
||||||
|
_ => NoSquadSearchResults(),
|
||||||
|
{
|
||||||
|
case NoSquadSearchResults() => None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
val findLfsSoldiersForRoleCodec = uint4.xmap[FindLfsSoldiersForRole] (
|
val findLfsSoldiersForRoleCodec = uint4.xmap[FindLfsSoldiersForRole] (
|
||||||
state => FindLfsSoldiersForRole(state),
|
state => FindLfsSoldiersForRole(state),
|
||||||
{
|
{
|
||||||
|
|
@ -326,6 +352,7 @@ object SquadAction{
|
||||||
* `18` - UNKNOWN<br>
|
* `18` - UNKNOWN<br>
|
||||||
* `26` - Reset All<br>
|
* `26` - Reset All<br>
|
||||||
* `35` - Cancel Squad Search<br>
|
* `35` - Cancel Squad Search<br>
|
||||||
|
* `39` - No Squad Search Results<br>
|
||||||
* `41` - Cancel Find<br>
|
* `41` - Cancel Find<br>
|
||||||
* `42` - UNKNOWN<br>
|
* `42` - UNKNOWN<br>
|
||||||
* `43` - UNKNOWN<br>
|
* `43` - UNKNOWN<br>
|
||||||
|
|
@ -388,7 +415,7 @@ object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMe
|
||||||
import scala.annotation.switch
|
import scala.annotation.switch
|
||||||
((code : @switch) match {
|
((code : @switch) match {
|
||||||
case 0 => displaySquadCodec
|
case 0 => displaySquadCodec
|
||||||
case 1 => answerSquadJoinRequestCodec
|
case 1 => displayFullSquadCodec
|
||||||
case 3 => saveSquadFavoriteCodec
|
case 3 => saveSquadFavoriteCodec
|
||||||
case 4 => loadSquadFavoriteCodec
|
case 4 => loadSquadFavoriteCodec
|
||||||
case 5 => deleteSquadFavoriteCodec
|
case 5 => deleteSquadFavoriteCodec
|
||||||
|
|
@ -411,12 +438,13 @@ object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMe
|
||||||
case 34 => searchForSquadsWithParticularRoleCodec
|
case 34 => searchForSquadsWithParticularRoleCodec
|
||||||
case 35 => cancelSquadSearchCodec
|
case 35 => cancelSquadSearchCodec
|
||||||
case 38 => assignSquadMemberToRoleCodec
|
case 38 => assignSquadMemberToRoleCodec
|
||||||
|
case 39 => noSquadSearchResultsCodec
|
||||||
case 40 => findLfsSoldiersForRoleCodec
|
case 40 => findLfsSoldiersForRoleCodec
|
||||||
case 41 => cancelFindCodec
|
case 41 => cancelFindCodec
|
||||||
case 2 | 6 | 11 |
|
case 2 | 6 | 11 |
|
||||||
12 | 13 | 14 | 16 |
|
12 | 13 | 14 | 16 |
|
||||||
18 | 29 | 30 | 32 | 33 |
|
18 | 29 | 30 | 32 | 33 |
|
||||||
36 | 37 | 39 | 42 | 43 => unknownCodec(code)
|
36 | 37 | 42 | 43 => unknownCodec(code)
|
||||||
case _ => failureCodec(code)
|
case _ => failureCodec(code)
|
||||||
}).asInstanceOf[Codec[SquadAction]]
|
}).asInstanceOf[Codec[SquadAction]]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,18 +12,18 @@ object MemberEvent extends Enumeration {
|
||||||
val
|
val
|
||||||
Add,
|
Add,
|
||||||
Remove,
|
Remove,
|
||||||
Unknown2,
|
Promote,
|
||||||
UpdateZone,
|
UpdateZone,
|
||||||
Unknown4
|
Unknown4
|
||||||
= Value
|
= Value
|
||||||
|
|
||||||
implicit val codec = PacketHelpers.createEnumerationCodec(this, uint(3))
|
implicit val codec = PacketHelpers.createEnumerationCodec(enum = this, uint(bits = 3))
|
||||||
}
|
}
|
||||||
|
|
||||||
final case class SquadMemberEvent(unk1 : Int,
|
final case class SquadMemberEvent(action : MemberEvent.Value,
|
||||||
unk2 : Int,
|
unk2 : Int,
|
||||||
char_id : Long,
|
char_id : Long,
|
||||||
member_position : Int,
|
position : Int,
|
||||||
player_name : Option[String],
|
player_name : Option[String],
|
||||||
zone_number : Option[Int],
|
zone_number : Option[Int],
|
||||||
unk7 : Option[Long])
|
unk7 : Option[Long])
|
||||||
|
|
@ -34,40 +34,46 @@ final case class SquadMemberEvent(unk1 : Int,
|
||||||
}
|
}
|
||||||
|
|
||||||
object SquadMemberEvent extends Marshallable[SquadMemberEvent] {
|
object SquadMemberEvent extends Marshallable[SquadMemberEvent] {
|
||||||
def apply(unk1 : Int, unk2 : Int, char_id : Long, member_position : Int) : SquadMemberEvent =
|
def apply(action : MemberEvent.Value, unk2 : Int, char_id : Long, position : Int) : SquadMemberEvent =
|
||||||
SquadMemberEvent(unk1, unk2, char_id, member_position, None, None, None)
|
SquadMemberEvent(action, unk2, char_id, position, None, None, None)
|
||||||
|
|
||||||
def apply(unk2 : Int, char_id : Long, member_position : Int, player_name : String, zone_number : Int, unk7 : Long) : SquadMemberEvent =
|
def Add(unk2 : Int, char_id : Long, position : Int, player_name : String, zone_number : Int, unk7 : Long) : SquadMemberEvent =
|
||||||
SquadMemberEvent(0, unk2, char_id, member_position, Some(player_name), Some(zone_number), Some(unk7))
|
SquadMemberEvent(MemberEvent.Add, unk2, char_id, position, Some(player_name), Some(zone_number), Some(unk7))
|
||||||
|
|
||||||
def apply(unk2 : Int, char_id : Long, member_position : Int, zone_number : Int) : SquadMemberEvent =
|
def Remove(unk2 : Int, char_id : Long, position : Int) : SquadMemberEvent =
|
||||||
SquadMemberEvent(3, unk2, char_id, member_position, None, Some(zone_number), None)
|
SquadMemberEvent(MemberEvent.Remove, unk2, char_id, position, None, None, None)
|
||||||
|
|
||||||
def apply(unk2 : Int, char_id : Long, member_position : Int, unk7 : Long) : SquadMemberEvent =
|
def Promote(unk2 : Int, char_id : Long) : SquadMemberEvent =
|
||||||
SquadMemberEvent(4, unk2, char_id, member_position, None, None, Some(unk7))
|
SquadMemberEvent(MemberEvent.Promote, unk2, char_id, 0, None, None, None)
|
||||||
|
|
||||||
|
def UpdateZone(unk2 : Int, char_id : Long, position : Int, zone_number : Int) : SquadMemberEvent =
|
||||||
|
SquadMemberEvent(MemberEvent.UpdateZone, unk2, char_id, position, None, Some(zone_number), None)
|
||||||
|
|
||||||
|
def Unknown4(unk2 : Int, char_id : Long, position : Int, unk7 : Long) : SquadMemberEvent =
|
||||||
|
SquadMemberEvent(MemberEvent.Unknown4, unk2, char_id, position, None, None, Some(unk7))
|
||||||
|
|
||||||
implicit val codec : Codec[SquadMemberEvent] = (
|
implicit val codec : Codec[SquadMemberEvent] = (
|
||||||
("unk1" | uint(3)) >>:~ { unk1 =>
|
("action" | MemberEvent.codec) >>:~ { action =>
|
||||||
("unk2" | uint16L) ::
|
("unk2" | uint16L) ::
|
||||||
("char_id" | uint32L) ::
|
("char_id" | uint32L) ::
|
||||||
("member_position" | uint4) ::
|
("position" | uint4) ::
|
||||||
conditional(unk1 == 0, "player_name" | PacketHelpers.encodedWideStringAligned(1)) ::
|
conditional(action == MemberEvent.Add, "player_name" | PacketHelpers.encodedWideStringAligned(1)) ::
|
||||||
conditional(unk1 == 0 || unk1 == 3, "zone_number" | uint16L) ::
|
conditional(action == MemberEvent.Add || action == MemberEvent.UpdateZone, "zone_number" | uint16L) ::
|
||||||
conditional(unk1 == 0 || unk1 == 4, "unk7" | uint32L)
|
conditional(action == MemberEvent.Add || action == MemberEvent.Unknown4, "unk7" | uint32L)
|
||||||
}).exmap[SquadMemberEvent] (
|
}).exmap[SquadMemberEvent] (
|
||||||
{
|
{
|
||||||
case unk1 :: unk2 :: char_id :: member_position :: player_name :: zone_number :: unk7 :: HNil =>
|
case action :: unk2 :: char_id :: member_position :: player_name :: zone_number :: unk7 :: HNil =>
|
||||||
Attempt.Successful(SquadMemberEvent(unk1, unk2, char_id, member_position, player_name, zone_number, unk7))
|
Attempt.Successful(SquadMemberEvent(action, unk2, char_id, member_position, player_name, zone_number, unk7))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case data @ SquadMemberEvent(0, unk2, char_id, member_position, Some(player_name), Some(zone_number), Some(unk7)) =>
|
case SquadMemberEvent(MemberEvent.Add, unk2, char_id, member_position, Some(player_name), Some(zone_number), Some(unk7)) =>
|
||||||
Attempt.Successful(0 :: unk2 :: char_id :: member_position :: Some(player_name) :: Some(zone_number) :: Some(unk7) :: HNil)
|
Attempt.Successful(MemberEvent.Add :: unk2 :: char_id :: member_position :: Some(player_name) :: Some(zone_number) :: Some(unk7) :: HNil)
|
||||||
case data @ SquadMemberEvent(3, unk2, char_id, member_position, None, Some(zone_number), None) =>
|
case SquadMemberEvent(MemberEvent.UpdateZone, unk2, char_id, member_position, None, Some(zone_number), None) =>
|
||||||
Attempt.Successful(3 :: unk2 :: char_id :: member_position :: None :: Some(zone_number) :: None :: HNil)
|
Attempt.Successful(MemberEvent.UpdateZone :: unk2 :: char_id :: member_position :: None :: Some(zone_number) :: None :: HNil)
|
||||||
case data @ SquadMemberEvent(4, unk2, char_id, member_position, None, None, Some(unk7)) =>
|
case SquadMemberEvent(MemberEvent.Unknown4, unk2, char_id, member_position, None, None, Some(unk7)) =>
|
||||||
Attempt.Successful(4 :: unk2 :: char_id :: member_position :: None :: None :: Some(unk7) :: HNil)
|
Attempt.Successful(MemberEvent.Unknown4 :: unk2 :: char_id :: member_position :: None :: None :: Some(unk7) :: HNil)
|
||||||
case data @ SquadMemberEvent(unk1, unk2, char_id, member_position, None, None, None) =>
|
case SquadMemberEvent(action, unk2, char_id, member_position, None, None, None) =>
|
||||||
Attempt.Successful(unk1 :: unk2 :: char_id :: member_position :: None :: None :: None :: HNil)
|
Attempt.Successful(action :: unk2 :: char_id :: member_position :: None :: None :: None :: HNil)
|
||||||
case data =>
|
case data =>
|
||||||
Attempt.Failure(Err(s"SquadMemberEvent can not encode with this pattern - $data"))
|
Attempt.Failure(Err(s"SquadMemberEvent can not encode with this pattern - $data"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,14 @@ object SquadResponse {
|
||||||
final case class Unknown17(squad : Squad, char_id : Long) extends Response
|
final case class Unknown17(squad : Squad, char_id : Long) extends Response
|
||||||
final case class Membership(request_type : SquadResponseType.Value, unk1 : Int, unk2 : Int, unk3 : Long, unk4 : Option[Long], player_name : String, unk5 : Boolean, unk6 : Option[Option[String]]) extends Response //see SquadMembershipResponse
|
final case class Membership(request_type : SquadResponseType.Value, unk1 : Int, unk2 : Int, unk3 : Long, unk4 : Option[Long], player_name : String, unk5 : Boolean, unk6 : Option[Option[String]]) extends Response //see SquadMembershipResponse
|
||||||
final case class Invite(from_char_id : Long, to_char_id : Long, name : String) extends Response
|
final case class Invite(from_char_id : Long, to_char_id : Long, name : String) extends Response
|
||||||
|
final case class WantsSquadPosition(bid_name : String) extends Response
|
||||||
final case class Join(squad : Squad, positionsToUpdate : List[Int]) extends Response
|
final case class Join(squad : Squad, positionsToUpdate : List[Int]) extends Response
|
||||||
final case class Leave(squad : Squad, positionsToUpdate : List[(Long, Int)]) extends Response
|
final case class Leave(squad : Squad, positionsToUpdate : List[(Long, Int)]) extends Response
|
||||||
final case class UpdateMembers(squad : Squad, update_info : List[SquadAction.Update]) extends Response
|
final case class UpdateMembers(squad : Squad, update_info : List[SquadAction.Update]) extends Response
|
||||||
final case class AssignMember(squad : Squad, from_index : Int, to_index : Int) extends Response
|
final case class AssignMember(squad : Squad, from_index : Int, to_index : Int) extends Response
|
||||||
|
final case class PromoteMember(squad : Squad, char_id : Long, from_index : Int, to_index : Int) extends Response
|
||||||
|
|
||||||
final case class Detail(guid : PlanetSideGUID, squad_detail : SquadDetail) extends Response
|
final case class Detail(guid : PlanetSideGUID, squad_detail : SquadDetail) extends Response
|
||||||
|
|
||||||
|
final case class SquadSearchResults() extends Response
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,14 @@ class SquadService extends Actor {
|
||||||
private var memberToSquad : mutable.LongMap[Squad] = mutable.LongMap[Squad]()
|
private var memberToSquad : mutable.LongMap[Squad] = mutable.LongMap[Squad]()
|
||||||
private var idToSquad : TrieMap[PlanetSideGUID, Squad] = new TrieMap[PlanetSideGUID, Squad]()
|
private var idToSquad : TrieMap[PlanetSideGUID, Squad] = new TrieMap[PlanetSideGUID, Squad]()
|
||||||
private var idToSwitchboard : TrieMap[PlanetSideGUID, ActorRef] = new TrieMap[PlanetSideGUID, ActorRef]()
|
private var idToSwitchboard : TrieMap[PlanetSideGUID, ActorRef] = new TrieMap[PlanetSideGUID, ActorRef]()
|
||||||
private var i : Int = 1
|
private var sid : Int = 1
|
||||||
private val publishedLists : TrieMap[PlanetSideEmpire.Value, ListBuffer[SquadInfo]] = TrieMap[PlanetSideEmpire.Value, ListBuffer[SquadInfo]](
|
private val publishedLists : TrieMap[PlanetSideEmpire.Value, ListBuffer[SquadInfo]] = TrieMap[PlanetSideEmpire.Value, ListBuffer[SquadInfo]](
|
||||||
PlanetSideEmpire.TR -> ListBuffer.empty,
|
PlanetSideEmpire.TR -> ListBuffer.empty,
|
||||||
PlanetSideEmpire.NC -> ListBuffer.empty,
|
PlanetSideEmpire.NC -> ListBuffer.empty,
|
||||||
PlanetSideEmpire.VS -> ListBuffer.empty
|
PlanetSideEmpire.VS -> ListBuffer.empty
|
||||||
)
|
)
|
||||||
private val bids : mutable.LongMap[PositionBid] = mutable.LongMap[PositionBid]()
|
private val invites : mutable.LongMap[Invitation] = mutable.LongMap[Invitation]()
|
||||||
|
private val queuedInvites : mutable.LongMap[List[Invitation]] = mutable.LongMap[List[Invitation]]()
|
||||||
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
|
||||||
|
|
@ -36,56 +37,70 @@ class SquadService extends Actor {
|
||||||
override def preStart : Unit = {
|
override def preStart : Unit = {
|
||||||
log.info("Starting...")
|
log.info("Starting...")
|
||||||
|
|
||||||
val testSquad = new Squad(PlanetSideGUID(3), PlanetSideEmpire.VS)
|
// val testSquad = new Squad(PlanetSideGUID(3), PlanetSideEmpire.VS)
|
||||||
testSquad.Task = "\\#66CCFF Sentinels of Auraxis\\#FFFFFF ... \\#40FF40 Squad Up!!"
|
// testSquad.Task = "\\#66CCFF Sentinels of Auraxis\\#FFFFFF ... \\#40FF40 Squad Up!!"
|
||||||
testSquad.ZoneId = 5
|
// testSquad.ZoneId = 5
|
||||||
testSquad.Membership(0).Name = "Wizkid45"
|
// testSquad.Membership(0).Name = "Wizkid45"
|
||||||
testSquad.Membership(0).Role = "Fearless Leader"
|
// testSquad.Membership(0).Role = "Fearless Leader"
|
||||||
testSquad.Membership(0).CharId = 30910985L
|
// testSquad.Membership(0).CharId = 30910985L
|
||||||
testSquad.Membership(0).ZoneId = 5
|
// testSquad.Membership(0).ZoneId = 5
|
||||||
testSquad.Membership(0).Health = 64
|
// testSquad.Membership(0).Health = 64
|
||||||
testSquad.Membership(0).Armor = 34
|
// testSquad.Membership(0).Armor = 34
|
||||||
testSquad.Membership(0).Position = Vector3(5526.5234f, 3818.7344f, 54.59375f)
|
// testSquad.Membership(0).Position = Vector3(5526.5234f, 3818.7344f, 54.59375f)
|
||||||
testSquad.Membership(1).Name = "xoBLADEox"
|
// testSquad.Membership(1).Name = "xoBLADEox"
|
||||||
testSquad.Membership(1).Role = "Right Hand"
|
// testSquad.Membership(1).Role = "Right Hand"
|
||||||
testSquad.Membership(1).CharId = 42781919L
|
// testSquad.Membership(1).CharId = 42781919L
|
||||||
testSquad.Membership(1).ZoneId = 5
|
// testSquad.Membership(1).ZoneId = 5
|
||||||
testSquad.Membership(1).Health = 54
|
// testSquad.Membership(1).Health = 54
|
||||||
testSquad.Membership(1).Armor = 44
|
// testSquad.Membership(1).Armor = 44
|
||||||
testSquad.Membership(1).Position = Vector3(4673.5312f, 2604.8047f, 40.015625f)
|
// testSquad.Membership(1).Position = Vector3(4673.5312f, 2604.8047f, 40.015625f)
|
||||||
testSquad.Membership(3).Name = "cabal0428"
|
// testSquad.Membership(3).Name = "cabal0428"
|
||||||
testSquad.Membership(3).Role = "Left Hand"
|
// testSquad.Membership(3).Role = "Left Hand"
|
||||||
testSquad.Membership(3).CharId = 353380L
|
// testSquad.Membership(3).CharId = 353380L
|
||||||
testSquad.Membership(3).ZoneId = 5
|
// testSquad.Membership(3).ZoneId = 5
|
||||||
testSquad.Membership(3).Health = 44
|
// testSquad.Membership(3).Health = 44
|
||||||
testSquad.Membership(3).Armor = 54
|
// testSquad.Membership(3).Armor = 54
|
||||||
testSquad.Membership(3).Position = Vector3(4727.492f, 2613.5312f, 51.390625f)
|
// testSquad.Membership(3).Position = Vector3(4727.492f, 2613.5312f, 51.390625f)
|
||||||
testSquad.Membership(4).Name = "xSkiku"
|
// testSquad.Membership(4).Name = "xSkiku"
|
||||||
testSquad.Membership(4).Role = "Right Foot's Middle Toe's Nail"
|
// testSquad.Membership(4).Role = "Right Foot's Middle Toe's Nail"
|
||||||
testSquad.Membership(4).CharId = 41588340L
|
// testSquad.Membership(4).CharId = 41588340L
|
||||||
testSquad.Membership(4).ZoneId = 5
|
// testSquad.Membership(4).ZoneId = 5
|
||||||
testSquad.Membership(4).Health = 34
|
// testSquad.Membership(4).Health = 34
|
||||||
testSquad.Membership(4).Armor = 64
|
// testSquad.Membership(4).Armor = 64
|
||||||
testSquad.Membership(4).Position = Vector3(3675.0f, 4789.8047f, 63.21875f)
|
// testSquad.Membership(4).Position = Vector3(3675.0f, 4789.8047f, 63.21875f)
|
||||||
idToSquad(PlanetSideGUID(3)) = testSquad
|
// idToSquad(PlanetSideGUID(3)) = testSquad
|
||||||
testSquad.Listed = true
|
// testSquad.Listed = true
|
||||||
UpdateSquadList(testSquad, None)
|
// UpdateSquadList(testSquad, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
def GetNextSquadId() : PlanetSideGUID = {
|
def GetNextSquadId() : PlanetSideGUID = {
|
||||||
val out = i
|
val out = sid
|
||||||
val j = i + 1
|
val j = sid + 1
|
||||||
if(j == 65536) {
|
if(j == 65536) {
|
||||||
i = 1
|
sid = 1
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
i = j
|
sid = j
|
||||||
}
|
}
|
||||||
PlanetSideGUID(out)
|
PlanetSideGUID(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def TryResetSquadId() : Boolean = {
|
||||||
|
if(idToSquad.isEmpty) {
|
||||||
|
sid = 1
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def GetParticipatingSquad(player : Player) : Option[Squad] = {
|
def GetParticipatingSquad(player : Player) : Option[Squad] = {
|
||||||
memberToSquad.get(player.CharId) match {
|
GetParticipatingSquad(player.CharId)
|
||||||
|
}
|
||||||
|
|
||||||
|
def GetParticipatingSquad(charId : Long) : Option[Squad] = {
|
||||||
|
memberToSquad.get(charId) match {
|
||||||
case opt @ Some(_) =>
|
case opt @ Some(_) =>
|
||||||
opt
|
opt
|
||||||
case None =>
|
case None =>
|
||||||
|
|
@ -114,24 +129,49 @@ class SquadService extends Actor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def StartSquad(player : Player) : Squad = {
|
def GetLeadingSquad(charId : Long, opt : Option[Squad]) : Option[Squad] = {
|
||||||
|
opt.orElse(memberToSquad.get(charId)) match {
|
||||||
|
case Some(squad) =>
|
||||||
|
if(squad.Leader.CharId == charId) {
|
||||||
|
Some(squad)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
case _ =>
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def CreateSquad(player : Player) : Squad = {
|
||||||
val charId = player.CharId
|
val charId = player.CharId
|
||||||
val faction = player.Faction
|
val faction = player.Faction
|
||||||
val id = GetNextSquadId()
|
|
||||||
val name = player.Name
|
val name = player.Name
|
||||||
val squad = new Squad(id, faction)
|
val squad = new Squad(GetNextSquadId(), faction)
|
||||||
val leadPosition = squad.Membership(squad.LeaderPositionIndex)
|
val leadPosition = squad.Membership(squad.LeaderPositionIndex)
|
||||||
leadPosition.Name = name
|
leadPosition.Name = name
|
||||||
leadPosition.CharId = charId
|
leadPosition.CharId = player.CharId
|
||||||
leadPosition.Health = player.Health
|
leadPosition.Health = player.Health
|
||||||
leadPosition.Armor = player.Armor
|
leadPosition.Armor = player.Armor
|
||||||
leadPosition.Position = player.Position
|
leadPosition.Position = player.Position
|
||||||
leadPosition.ZoneId = 1
|
leadPosition.ZoneId = 1
|
||||||
|
log.info(s"$name-$faction has started a new squad")
|
||||||
|
squad
|
||||||
|
}
|
||||||
|
|
||||||
|
def StartSquad(squad : Squad) : Squad = {
|
||||||
|
val charId = squad.Leader.CharId
|
||||||
|
val id = squad.GUID
|
||||||
val switchboard = context.actorOf(Props[SquadSwitchboard], s"squad${id.guid}")
|
val switchboard = context.actorOf(Props[SquadSwitchboard], s"squad${id.guid}")
|
||||||
memberToSquad += charId -> squad
|
memberToSquad += charId -> squad
|
||||||
idToSquad += id -> squad
|
idToSquad += id -> squad
|
||||||
idToSwitchboard += id -> switchboard
|
idToSwitchboard += id -> switchboard
|
||||||
log.info(s"$name-$faction has started a new squad")
|
squad
|
||||||
|
}
|
||||||
|
|
||||||
|
def StartSquad(player : Player) : Squad = {
|
||||||
|
val squad = CreateSquad(player)
|
||||||
|
StartSquad(squad)
|
||||||
squad
|
squad
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -199,137 +239,253 @@ class SquadService extends Actor {
|
||||||
case Service.Leave(None) | Service.LeaveAll() => ;
|
case Service.Leave(None) | Service.LeaveAll() => ;
|
||||||
|
|
||||||
case SquadServiceMessage(tplayer, squad_action) => squad_action match {
|
case SquadServiceMessage(tplayer, squad_action) => squad_action match {
|
||||||
case SquadAction.Membership(request_type, char_id, optional_char_id, _, _) => request_type match {
|
case SquadAction.Membership(SquadRequestType.Invite, invitingPlayer, Some(invitedPlayer), _, _) =>
|
||||||
case SquadRequestType.Invite =>
|
//this is just busy work; for actual joining operations, see SquadRequestType.Accept
|
||||||
//char_id is the inviter, e.g., the (prospective) squad leader
|
// FindBid(invitingPlayer, invitedPlayer) match {
|
||||||
//this is just busy work; for actual joining operations, see SquadRequestType.Accept
|
// case Some(bid) =>
|
||||||
(optional_char_id, memberToSquad.get(char_id)) match {
|
// //invitingPlayer and invitedPlayer have both tried to join each others's squads
|
||||||
case (Some(invitee), Some(squad)) =>
|
// //treat this junction as consent
|
||||||
bids(invitee) = VacancyBid(char_id, squad.GUID)
|
// self ! SquadServiceMessage(tplayer, SquadAction.Membership(SquadRequestType.Accept, invitingPlayer, Some(invitedPlayer), "", None))
|
||||||
log.info(s"$invitee has been invited to squad ${squad.Task} by $char_id")
|
// case _ => ;
|
||||||
SquadEvents.publish( SquadServiceResponse(s"/$invitee/Squad", SquadResponse.Membership(SquadResponseType.Invite, 0, 0, char_id, Some(invitee), tplayer.Name, false, Some(None))) )
|
// }
|
||||||
SquadEvents.publish( SquadServiceResponse(s"/$char_id/Squad", SquadResponse.Membership(SquadResponseType.Invite, 0, 0, invitee, Some(char_id), tplayer.Name, true, Some(None))) )
|
(memberToSquad.get(invitingPlayer), memberToSquad.get(invitedPlayer)) match {
|
||||||
case (Some(invitee), None) =>
|
case (Some(squad1), Some(squad2)) =>
|
||||||
//the inviter does not currently belong to a squad; check for an existing placeholder, or create a new one
|
//both players are in squads
|
||||||
val ourSquad = {
|
if(squad1.GUID == squad2.GUID) {
|
||||||
bids.find { case (inviter, _) => inviter == char_id } match {
|
//both players are in the same squad; no need to do anything
|
||||||
case Some((_, SpontaneousBid(_, _squad))) =>
|
}
|
||||||
_squad //borrow
|
else {
|
||||||
case _ =>
|
//we might do some platoon chicanery with this case later
|
||||||
val _squad = StartSquad(tplayer)
|
//TODO platoons
|
||||||
memberToSquad.remove(char_id) //completely unlist until assured the squad is necessary
|
}
|
||||||
_squad
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bids(invitee) = SpontaneousBid(char_id, ourSquad)
|
|
||||||
SquadEvents.publish( SquadServiceResponse(s"/$invitee/Squad", SquadResponse.Membership(SquadResponseType.Invite, 0, 0, char_id, Some(invitee), tplayer.Name, false, Some(None))) )
|
|
||||||
SquadEvents.publish( SquadServiceResponse(s"/$char_id/Squad", SquadResponse.Membership(SquadResponseType.Invite, 0, 0, invitee, Some(char_id), tplayer.Name, true, Some(None))) )
|
|
||||||
case _ => ;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SquadRequestType.Accept =>
|
case (Some(squad), None) =>
|
||||||
//char_id is the invitee, e.g., the person joining the squad
|
//the classic situation
|
||||||
bids.remove(char_id) match {
|
log.info(s"$invitedPlayer has been invited to squad ${squad.Task} by $invitingPlayer")
|
||||||
case Some(NormalBid(_/*inviterCharId*/, squadGUID, line)) if idToSquad.get(squadGUID).nonEmpty =>
|
val leader = squad.Leader
|
||||||
//player requested to join a squad's specific position
|
val leaderCharId = leader.CharId
|
||||||
JoinSquad(tplayer, idToSquad(squadGUID), line)
|
val bid = VacancyInvite(leaderCharId, leader.Name, squad.GUID)
|
||||||
|
AddInvite(invitedPlayer, bid) match {
|
||||||
|
case out @ Some(_) if out.contains(bid) =>
|
||||||
|
SquadEvents.publish(SquadServiceResponse(s"/$invitedPlayer/Squad", SquadResponse.Membership(SquadResponseType.Invite, 0, 0, leaderCharId, Some(invitedPlayer), tplayer.Name, false, Some(None))))
|
||||||
|
SquadEvents.publish(SquadServiceResponse(s"/$leaderCharId/Squad", SquadResponse.Membership(SquadResponseType.Invite, 0, 0, invitedPlayer, Some(leaderCharId), tplayer.Name, true, Some(None))))
|
||||||
|
case Some(_) =>
|
||||||
|
SquadEvents.publish(SquadServiceResponse(s"/$leaderCharId/Squad", SquadResponse.Membership(SquadResponseType.Invite, 0, 0, invitedPlayer, Some(leaderCharId), tplayer.Name, true, Some(None))))
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
case Some(VacancyBid(inviterCharId, squadGUID)) if idToSquad.get(squadGUID).nonEmpty =>
|
case (None, Some(squad)) =>
|
||||||
//we were invited by the squad leader into an existing squad
|
//flip around the roles - the inviting becomes the invited
|
||||||
val squad = idToSquad(squadGUID)
|
//TODO needs work
|
||||||
|
log.info(s"$invitedPlayer has asked $invitingPlayer for an invition to squad ${squad.Task}")
|
||||||
|
val bid = VacancyInvite(invitedPlayer, "", squad.GUID)
|
||||||
|
AddInvite(invitingPlayer, bid) match {
|
||||||
|
case out @ Some(_) if out.contains(bid) =>
|
||||||
|
SquadEvents.publish(SquadServiceResponse(s"/$invitingPlayer/Squad", SquadResponse.Membership(SquadResponseType.Invite, 0, 0, invitedPlayer, Some(invitingPlayer), tplayer.Name, false, Some(None))))
|
||||||
|
SquadEvents.publish(SquadServiceResponse(s"/$invitedPlayer/Squad", SquadResponse.Membership(SquadResponseType.Invite, 0, 0, invitingPlayer, Some(invitedPlayer), tplayer.Name, true, Some(None))))
|
||||||
|
case Some(_) =>
|
||||||
|
SquadEvents.publish(SquadServiceResponse(s"/$invitedPlayer/Squad", SquadResponse.Membership(SquadResponseType.Invite, 0, 0, invitingPlayer, Some(invitedPlayer), tplayer.Name, true, Some(None))))
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
case (None, None) =>
|
||||||
|
//neither the invited player nor the inviting player belong to any squad
|
||||||
|
log.info(s"$invitedPlayer has been invited to join $invitingPlayer's spontaneous squad")
|
||||||
|
val bid = SpontaneousInvite(tplayer)
|
||||||
|
AddInvite(invitedPlayer, bid) match {
|
||||||
|
case out @ Some(_) if out.contains(bid) =>
|
||||||
|
SquadEvents.publish(SquadServiceResponse(s"/$invitedPlayer/Squad", SquadResponse.Membership(SquadResponseType.Invite, 0, 0, invitingPlayer, Some(invitedPlayer), tplayer.Name, false, Some(None))))
|
||||||
|
SquadEvents.publish(SquadServiceResponse(s"/$invitingPlayer/Squad", SquadResponse.Membership(SquadResponseType.Invite, 0, 0, invitedPlayer, Some(invitingPlayer), tplayer.Name, true, Some(None))))
|
||||||
|
case Some(_) =>
|
||||||
|
SquadEvents.publish(SquadServiceResponse(s"/$invitingPlayer/Squad", SquadResponse.Membership(SquadResponseType.Invite, 0, 0, invitedPlayer, Some(invitingPlayer), tplayer.Name, true, Some(None))))
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SquadAction.Membership(SquadRequestType.Accept, invitedPlayer, _, _, _) =>
|
||||||
|
val acceptedInvite = RemoveInvite(invitedPlayer)
|
||||||
|
acceptedInvite match {
|
||||||
|
case Some(BidForPosition(petitioner, guid, position)) if idToSquad.get(guid).nonEmpty =>
|
||||||
|
//player requested to join a squad's specific position
|
||||||
|
//invitedPlayer is actually the squad leader; petitioner is the actual "invitedPlayer"
|
||||||
|
if(memberToSquad.get(petitioner.CharId).isEmpty) {
|
||||||
|
JoinSquad(petitioner, idToSquad(guid), position)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.warn("Accept -> Bid: the invited player is already a member of a squad and can not join a second one")
|
||||||
|
}
|
||||||
|
|
||||||
|
case Some(VacancyInvite(invitingPlayer, _, guid))
|
||||||
|
if idToSquad.get(guid).nonEmpty =>
|
||||||
|
//we were invited by the squad leader into an existing squad
|
||||||
|
if(memberToSquad.get(invitedPlayer).isEmpty) {
|
||||||
|
val squad = idToSquad(guid)
|
||||||
squad.Membership.zipWithIndex.find({ case (member, index) =>
|
squad.Membership.zipWithIndex.find({ case (member, index) =>
|
||||||
ValidOpenSquadPosition(squad, index, member, tplayer.Certifications)
|
ValidOpenSquadPosition(squad, index, member, tplayer.Certifications)
|
||||||
}) match {
|
}) match {
|
||||||
case Some((_, line)) =>
|
case Some((_, line)) =>
|
||||||
SquadEvents.publish( SquadServiceResponse(s"/$inviterCharId/Squad", SquadResponse.Membership(SquadResponseType.Accept, 0, 0, inviterCharId, Some(char_id), tplayer.Name, false, Some(None))) )
|
SquadEvents.publish(SquadServiceResponse(s"/$invitingPlayer/Squad", SquadResponse.Membership(SquadResponseType.Accept, 0, 0, invitingPlayer, Some(invitedPlayer), tplayer.Name, false, Some(None))))
|
||||||
SquadEvents.publish( SquadServiceResponse(s"/$char_id/Squad", SquadResponse.Membership(SquadResponseType.Accept, 0, 0, char_id, Some(inviterCharId), "", true, Some(None))) )
|
SquadEvents.publish(SquadServiceResponse(s"/$invitedPlayer/Squad", SquadResponse.Membership(SquadResponseType.Accept, 0, 0, invitedPlayer, Some(invitingPlayer), "", true, Some(None))))
|
||||||
JoinSquad(tplayer, squad, line)
|
JoinSquad(tplayer, squad, line)
|
||||||
|
RemoveQueuedInvites(invitedPlayer) //TODO deal with these somehow
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.warn("Accept -> Invite: the invited player is already a member of a squad and can not join a second one")
|
||||||
|
}
|
||||||
|
|
||||||
case Some(SpontaneousBid(inviterCharId, placeholderSquad)) =>
|
case Some(SpontaneousInvite(invitingPlayer)) =>
|
||||||
//we were invited by someone into a new squad they would form
|
//we were invited by someone into a new squad they would form
|
||||||
(GetParticipatingSquad(tplayer) match {
|
val invitingPlayerCharId = invitingPlayer.CharId
|
||||||
case Some(participating) =>
|
(GetParticipatingSquad(invitingPlayer) match {
|
||||||
if(participating.Leader.CharId == inviterCharId) {
|
case Some(participating) =>
|
||||||
Some(participating)
|
if(participating.Leader.CharId == invitingPlayerCharId) {
|
||||||
|
Some(participating)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//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 _ => ;
|
||||||
}
|
}
|
||||||
else {
|
None
|
||||||
//inviter joined a squad and is not its leader; bounce this request off of the squad leader
|
}
|
||||||
//TODO squad leader receives "<player> wants to join squad" prompt
|
case None =>
|
||||||
val leaderCharId = participating.Leader.CharId
|
val squad = StartSquad(invitingPlayer)
|
||||||
bids(char_id) = VacancyBid(leaderCharId, participating.GUID) //reframed request
|
squad.Task = s"${tplayer.Name}'s Squad"
|
||||||
SquadEvents.publish(SquadServiceResponse(s"/$leaderCharId/Squad", SquadResponse.Invite(char_id, leaderCharId, tplayer.Name)))
|
SquadEvents.publish(SquadServiceResponse(s"/$invitingPlayer/Squad", SquadResponse.InitSquad(squad.GUID)))
|
||||||
None
|
Some(squad)
|
||||||
}
|
}) match {
|
||||||
case None =>
|
|
||||||
placeholderSquad.Task = s"${tplayer.Name}'s Squad"
|
|
||||||
memberToSquad(inviterCharId) = placeholderSquad
|
|
||||||
SquadEvents.publish(SquadServiceResponse(s"/$inviterCharId/Squad", SquadResponse.InitSquad(placeholderSquad.GUID)))
|
|
||||||
Some(placeholderSquad)
|
|
||||||
}) match {
|
|
||||||
case Some(squad) =>
|
case Some(squad) =>
|
||||||
squad.Membership.zipWithIndex.find({ case (member, index) =>
|
squad.Membership.zipWithIndex.find({ case (member, index) =>
|
||||||
ValidOpenSquadPosition(squad, index, member, tplayer.Certifications)
|
ValidOpenSquadPosition(squad, index, member, tplayer.Certifications)
|
||||||
}) match {
|
}) match {
|
||||||
case Some((_, line)) =>
|
case Some((_, line)) =>
|
||||||
SquadEvents.publish( SquadServiceResponse(s"/$inviterCharId/Squad", SquadResponse.Membership(SquadResponseType.Accept, 0, 0, inviterCharId, Some(char_id), tplayer.Name, false, Some(None))) )
|
SquadEvents.publish( SquadServiceResponse(s"/$invitedPlayer/Squad", SquadResponse.Membership(SquadResponseType.Accept, 0, 0, invitedPlayer, Some(invitingPlayerCharId), "", true, Some(None))) )
|
||||||
SquadEvents.publish( SquadServiceResponse(s"/$char_id/Squad", SquadResponse.Membership(SquadResponseType.Accept, 0, 0, char_id, Some(inviterCharId), "", 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))) )
|
||||||
|
RemoveQueuedInvites(invitedPlayer) //TODO deal with these somehow
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
case None => ;
|
case None => ;
|
||||||
}
|
|
||||||
|
|
||||||
case _ => ;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SquadRequestType.Leave =>
|
|
||||||
//char_id is the player leaving
|
|
||||||
val squad = memberToSquad(char_id)
|
|
||||||
val leader = squad.Leader.CharId
|
|
||||||
if(char_id == leader) {
|
|
||||||
//squad leader is leaving his own squad, so it will be disbanded
|
|
||||||
squad.Membership
|
|
||||||
.filterNot { _.CharId == leader }
|
|
||||||
.foreach { member =>
|
|
||||||
val charId = member.CharId
|
|
||||||
SquadEvents.publish(SquadServiceResponse(s"/$charId/Squad", SquadResponse.Membership(SquadResponseType.Disband, 0, 0, charId, None, "", false, Some(None))))
|
|
||||||
}
|
|
||||||
CloseOutSquad(squad)
|
|
||||||
SquadEvents.publish(SquadServiceResponse(s"/$leader/Squad", SquadResponse.Membership(SquadResponseType.Disband, 0, 0, leader, None, "", true, Some(None))))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(optional_char_id.contains(char_id)) {
|
|
||||||
//leaving the squad of our own accord
|
|
||||||
LeaveSquad(tplayer, squad)
|
|
||||||
}
|
}
|
||||||
else if(optional_char_id.contains(leader)) {
|
|
||||||
//kicked by the squad leader
|
case None =>
|
||||||
SquadEvents.publish( SquadServiceResponse(s"/$char_id/Squad", SquadResponse.Membership(SquadResponseType.Leave, 0, 0, char_id, Some(leader), tplayer.Name, false, Some(None))) )
|
//the invite either timed-out or was withdrawn; select a new one?
|
||||||
SquadEvents.publish( SquadServiceResponse(s"/$leader/Squad", SquadResponse.Membership(SquadResponseType.Leave, 0, 0, leader, Some(char_id), "", true, Some(None))) )
|
NextInvite(invitedPlayer) match {
|
||||||
LeaveSquad(tplayer, squad)
|
case Some(bid : BidForPosition) if !acceptedInvite.contains(bid) =>
|
||||||
|
HandleBidForPosition(bid, tplayer)
|
||||||
|
case Some(bid) if !acceptedInvite.contains(bid) =>
|
||||||
|
SquadEvents.publish(SquadServiceResponse(s"/$invitedPlayer/Squad", SquadResponse.Membership(SquadResponseType.Invite, 0, 0, bid.InviterCharId, Some(invitedPlayer), bid.InviterName, false, Some(None))))
|
||||||
|
case None => ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case SquadRequestType.Reject =>
|
case SquadAction.Membership(SquadRequestType.Leave, leavingPlayer, optionalPlayer, _, _) =>
|
||||||
//a player has opted out of joining a squad
|
val squad = memberToSquad(leavingPlayer)
|
||||||
(bids.remove(char_id) match {
|
val leader = squad.Leader.CharId
|
||||||
case Some(SpontaneousBid(inviterCharId, squad)) if squad.Leader.CharId != char_id =>
|
if(leavingPlayer == leader || squad.Size == 2) {
|
||||||
(inviterCharId, squad)
|
//squad leader is leaving his own squad, so it will be disbanded
|
||||||
case Some(VacancyBid(inviterCharId, guid)) if idToSquad(guid).Leader.CharId != char_id =>
|
//alternately, squad is only composed of two people, so it will be closed-out when one of them leaves
|
||||||
(inviterCharId, idToSquad.get(guid))
|
val membership = squad.Membership.collect { case member if member.CharId > 0 => member.CharId }
|
||||||
case _ => ;
|
membership.foreach { charId =>
|
||||||
(0L, None)
|
SquadEvents.publish(SquadServiceResponse(s"/$charId/Squad", SquadResponse.Membership(SquadResponseType.Leave, 0, 0, charId, None, "", false, Some(None))))
|
||||||
}) match {
|
|
||||||
case (inviterCharId, Some(squad)) =>
|
|
||||||
SquadEvents.publish( SquadServiceResponse(s"/$inviterCharId/Squad", SquadResponse.Membership(SquadResponseType.Reject, 0, 0, inviterCharId, Some(char_id), tplayer.Name, false, Some(None))) )
|
|
||||||
SquadEvents.publish( SquadServiceResponse(s"/$char_id/Squad", SquadResponse.Membership(SquadResponseType.Reject, 0, 0, char_id, Some(inviterCharId), "", true, Some(None))) )
|
|
||||||
case _ => ;
|
|
||||||
}
|
}
|
||||||
|
CloseOutSquad(squad)
|
||||||
|
SquadEvents.publish(SquadServiceResponse(s"/$leader/Squad", SquadResponse.Membership(SquadResponseType.Disband, 0, 0, leader, None, "", true, Some(None))))
|
||||||
|
membership
|
||||||
|
.filterNot(_ == leader)
|
||||||
|
.foreach { charId =>
|
||||||
|
SquadEvents.publish(SquadServiceResponse(s"/$charId/Squad", SquadResponse.Membership(SquadResponseType.Disband, 0, 0, charId, None, "", false, Some(None))))
|
||||||
|
}
|
||||||
|
SquadEvents.publish( SquadServiceResponse(s"/$leader/Squad", SquadResponse.InitSquad(PlanetSideGUID(0))) )
|
||||||
|
SquadEvents.publish( SquadServiceResponse(s"/$leader/Squad", SquadResponse.Detail(PlanetSideGUID(0), SquadDetail().Complete)) )
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(optionalPlayer.contains(leavingPlayer)) {
|
||||||
|
//leaving the squad of own accord
|
||||||
|
LeaveSquad(tplayer, squad)
|
||||||
|
}
|
||||||
|
else if(optionalPlayer.contains(leader)) {
|
||||||
|
//kicked by the squad leader
|
||||||
|
SquadEvents.publish( SquadServiceResponse(s"/$leavingPlayer/Squad", SquadResponse.Membership(SquadResponseType.Leave, 0, 0, leavingPlayer, Some(leader), tplayer.Name, false, Some(None))) )
|
||||||
|
SquadEvents.publish( SquadServiceResponse(s"/$leader/Squad", SquadResponse.Membership(SquadResponseType.Leave, 0, 0, leader, Some(leavingPlayer), "", true, Some(None))) )
|
||||||
|
LeaveSquad(tplayer, squad)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case _ => ;
|
case SquadAction.Membership(SquadRequestType.Reject, rejectingPlayer, optionalPlayer, _, _) =>
|
||||||
}
|
val rejectedBid = RemoveInvite(rejectingPlayer)
|
||||||
|
//(A, B) -> person who made the rejection, person who was rejected
|
||||||
|
(rejectedBid match {
|
||||||
|
case Some(SpontaneousInvite(invitingPlayer)) =>
|
||||||
|
//rejectingPlayer is the would-be squad member
|
||||||
|
(Some(rejectingPlayer), Some(invitingPlayer.CharId))
|
||||||
|
case Some(VacancyInvite(invitingPlayer, _, guid)) if idToSquad(guid).Leader.CharId != rejectingPlayer =>
|
||||||
|
//rejectingPlayer is the would-be squad member
|
||||||
|
(Some(rejectingPlayer), Some(invitingPlayer))
|
||||||
|
case Some(BidForPosition(_, guid, _)) if idToSquad(guid).Leader.CharId != rejectingPlayer =>
|
||||||
|
//rejectingPlayer is the squad leader
|
||||||
|
(Some(rejectingPlayer), None)
|
||||||
|
case _ => ;
|
||||||
|
(None, None)
|
||||||
|
}) match {
|
||||||
|
case (Some(rejected), Some(invited)) =>
|
||||||
|
SquadEvents.publish( SquadServiceResponse(s"/$rejected/Squad", SquadResponse.Membership(SquadResponseType.Reject, 0, 0, rejected, Some(invited), "", true, Some(None))) )
|
||||||
|
SquadEvents.publish( SquadServiceResponse(s"/$invited/Squad", SquadResponse.Membership(SquadResponseType.Reject, 0, 0, invited, Some(rejected), tplayer.Name, false, Some(None))) )
|
||||||
|
case (Some(rejected), None) =>
|
||||||
|
SquadEvents.publish( SquadServiceResponse(s"/$rejected/Squad", SquadResponse.Membership(SquadResponseType.Reject, 0, 0, rejected, Some(rejected), "", true, Some(None))) )
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
NextInvite(rejectingPlayer) match {
|
||||||
|
case Some(bid : BidForPosition) if rejectedBid.isEmpty || !rejectedBid.contains(bid) =>
|
||||||
|
HandleBidForPosition(bid, tplayer)
|
||||||
|
case Some(bid) if rejectedBid.isEmpty || !rejectedBid.contains(bid) =>
|
||||||
|
SquadEvents.publish(SquadServiceResponse(s"/$rejectingPlayer/Squad", SquadResponse.Membership(SquadResponseType.Invite, 0, 0, bid.InviterCharId, Some(rejectingPlayer), bid.InviterName, false, Some(None))))
|
||||||
|
case None => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SquadAction.Membership(SquadRequestType.Promote, promotingPlayer, Some(promotedPlayer), _, _) =>
|
||||||
|
(memberToSquad.get(promotingPlayer), memberToSquad.get(promotedPlayer)) match {
|
||||||
|
case (Some(squad), Some(squad2)) if squad.GUID == squad2.GUID && squad.Leader.CharId == promotingPlayer =>
|
||||||
|
val membership = squad.Membership.filter { _member => _member.CharId > 0 }
|
||||||
|
val (leader, position) = (squad.Leader, 0)
|
||||||
|
val (member, index) = membership.zipWithIndex.find { case (_member, _) => _member.CharId == promotedPlayer }.get
|
||||||
|
SwapMemberPosition(squad, leader, member)
|
||||||
|
log.info(s"Promoting player ${leader.Name} to be the leader of ${squad.Task}")
|
||||||
|
membership.foreach { _member =>
|
||||||
|
SquadEvents.publish(SquadServiceResponse(s"/${_member.CharId}/Squad", SquadResponse.PromoteMember(squad, promotedPlayer, index, position)))
|
||||||
|
}
|
||||||
|
SquadEvents.publish(SquadServiceResponse(s"/$promotingPlayer/Squad", SquadResponse.InitSquad(PlanetSideGUID(0))))
|
||||||
|
SquadEvents.publish(SquadServiceResponse(s"/$promotedPlayer/Squad", SquadResponse.InitSquad(squad.GUID)))
|
||||||
|
UpdateSquadListWhenListed(
|
||||||
|
squad,
|
||||||
|
SquadInfo().Leader(leader.Name)
|
||||||
|
)
|
||||||
|
UpdateSquadDetail(squad.GUID, squad,
|
||||||
|
SquadDetail()
|
||||||
|
.LeaderCharId(leader.CharId)
|
||||||
|
.Field3(value = 0L)
|
||||||
|
.LeaderName(leader.Name)
|
||||||
|
.Members(List(
|
||||||
|
SquadPositionEntry(position, SquadPositionDetail().CharId(member.CharId).Name(member.Name)),
|
||||||
|
SquadPositionEntry(index, SquadPositionDetail().CharId(leader.CharId).Name(leader.Name))
|
||||||
|
))
|
||||||
|
)
|
||||||
|
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
case SquadAction.Update(char_id, health, max_health, armor, max_armor, pos, zone_number) =>
|
case SquadAction.Update(char_id, health, max_health, armor, max_armor, pos, zone_number) =>
|
||||||
memberToSquad.get(char_id) match {
|
memberToSquad.get(char_id) match {
|
||||||
|
|
@ -387,14 +543,14 @@ class SquadService extends Actor {
|
||||||
val squad = lSquadOpt.getOrElse(StartSquad(tplayer))
|
val squad = lSquadOpt.getOrElse(StartSquad(tplayer))
|
||||||
squad.Task = purpose
|
squad.Task = purpose
|
||||||
UpdateSquadListWhenListed(squad, SquadInfo().Task(purpose))
|
UpdateSquadListWhenListed(squad, SquadInfo().Task(purpose))
|
||||||
UpdateSquadDetailWhenListed(squad.GUID, squad, SquadDetail().Task(purpose))
|
UpdateSquadDetail(squad.GUID, squad, SquadDetail().Task(purpose))
|
||||||
|
|
||||||
case ChangeSquadZone(zone) =>
|
case ChangeSquadZone(zone) =>
|
||||||
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")
|
||||||
val squad = lSquadOpt.getOrElse(StartSquad(tplayer))
|
val squad = lSquadOpt.getOrElse(StartSquad(tplayer))
|
||||||
squad.ZoneId = zone.zoneId.toInt
|
squad.ZoneId = zone.zoneId.toInt
|
||||||
UpdateSquadListWhenListed(squad, SquadInfo().ZoneId(zone))
|
UpdateSquadListWhenListed(squad, SquadInfo().ZoneId(zone))
|
||||||
UpdateSquadDetailWhenListed(squad.GUID, squad, SquadDetail().ZoneId(zone))
|
UpdateSquadDetail(squad.GUID, squad, SquadDetail().ZoneId(zone))
|
||||||
|
|
||||||
case CloseSquadMemberPosition(position) =>
|
case CloseSquadMemberPosition(position) =>
|
||||||
val squad = lSquadOpt.getOrElse(StartSquad(tplayer))
|
val squad = lSquadOpt.getOrElse(StartSquad(tplayer))
|
||||||
|
|
@ -411,7 +567,7 @@ class SquadService extends Actor {
|
||||||
}
|
}
|
||||||
memberPosition.Close()
|
memberPosition.Close()
|
||||||
UpdateSquadListWhenListed(squad, listingChanged)
|
UpdateSquadListWhenListed(squad, listingChanged)
|
||||||
UpdateSquadDetailWhenListed(squad.GUID, squad,
|
UpdateSquadDetail(squad.GUID, squad,
|
||||||
SquadDetail().Members(List(SquadPositionEntry(position, SquadPositionDetail.Closed)))
|
SquadDetail().Members(List(SquadPositionEntry(position, SquadPositionDetail.Closed)))
|
||||||
)
|
)
|
||||||
case Some(false) | None => ;
|
case Some(false) | None => ;
|
||||||
|
|
@ -424,7 +580,7 @@ class SquadService extends Actor {
|
||||||
log.info(s"${tplayer.Name}-${tplayer.Faction} has opened the #$position position in squad")
|
log.info(s"${tplayer.Name}-${tplayer.Faction} has opened the #$position position in squad")
|
||||||
squad.Availability.update(position, true)
|
squad.Availability.update(position, true)
|
||||||
UpdateSquadListWhenListed(squad, SquadInfo().Capacity(squad.Capacity))
|
UpdateSquadListWhenListed(squad, SquadInfo().Capacity(squad.Capacity))
|
||||||
UpdateSquadDetailWhenListed(squad.GUID, squad,
|
UpdateSquadDetail(squad.GUID, squad,
|
||||||
SquadDetail().Members(List(SquadPositionEntry(position, SquadPositionDetail.Open)))
|
SquadDetail().Members(List(SquadPositionEntry(position, SquadPositionDetail.Open)))
|
||||||
)
|
)
|
||||||
case Some(true) | None => ;
|
case Some(true) | None => ;
|
||||||
|
|
@ -436,7 +592,7 @@ class SquadService extends Actor {
|
||||||
case Some(true) =>
|
case Some(true) =>
|
||||||
log.info(s"${tplayer.Name}-${tplayer.Faction} has changed the role of squad position #$position")
|
log.info(s"${tplayer.Name}-${tplayer.Faction} has changed the role of squad position #$position")
|
||||||
squad.Membership(position).Role = role
|
squad.Membership(position).Role = role
|
||||||
UpdateSquadDetailWhenListed(squad.GUID, squad,
|
UpdateSquadDetail(squad.GUID, squad,
|
||||||
SquadDetail().Members(List(SquadPositionEntry(position, SquadPositionDetail().Role(role))))
|
SquadDetail().Members(List(SquadPositionEntry(position, SquadPositionDetail().Role(role))))
|
||||||
)
|
)
|
||||||
case Some(false) | None => ;
|
case Some(false) | None => ;
|
||||||
|
|
@ -448,7 +604,7 @@ class SquadService extends Actor {
|
||||||
case Some(true) =>
|
case Some(true) =>
|
||||||
log.info(s"${tplayer.Name}-${tplayer.Faction} has changed the orders for squad position #$position")
|
log.info(s"${tplayer.Name}-${tplayer.Faction} has changed the orders for squad position #$position")
|
||||||
squad.Membership(position).Orders = orders
|
squad.Membership(position).Orders = orders
|
||||||
UpdateSquadDetailWhenListed(squad.GUID, squad,
|
UpdateSquadDetail(squad.GUID, squad,
|
||||||
SquadDetail().Members(List(SquadPositionEntry(position, SquadPositionDetail().DetailedOrders(orders))))
|
SquadDetail().Members(List(SquadPositionEntry(position, SquadPositionDetail().DetailedOrders(orders))))
|
||||||
)
|
)
|
||||||
case Some(false) | None => ;
|
case Some(false) | None => ;
|
||||||
|
|
@ -460,7 +616,7 @@ class SquadService extends Actor {
|
||||||
case Some(true) =>
|
case Some(true) =>
|
||||||
log.info(s"${tplayer.Name}-${tplayer.Faction} has changed the requirements for squad position #$position")
|
log.info(s"${tplayer.Name}-${tplayer.Faction} has changed the requirements for squad position #$position")
|
||||||
squad.Membership(position).Requirements = certs
|
squad.Membership(position).Requirements = certs
|
||||||
UpdateSquadDetailWhenListed(squad.GUID, squad,
|
UpdateSquadDetail(squad.GUID, squad,
|
||||||
SquadDetail().Members(List(SquadPositionEntry(position, SquadPositionDetail().Requirements(certs))))
|
SquadDetail().Members(List(SquadPositionEntry(position, SquadPositionDetail().Requirements(certs))))
|
||||||
)
|
)
|
||||||
case Some(false) | None => ;
|
case Some(false) | None => ;
|
||||||
|
|
@ -519,7 +675,7 @@ class SquadService extends Actor {
|
||||||
squad.LocationFollowsSquadLead = false
|
squad.LocationFollowsSquadLead = false
|
||||||
squad.AutoApproveInvitationRequests = false
|
squad.AutoApproveInvitationRequests = false
|
||||||
UpdateSquadListWhenListed(squad, SquadInfo().Task("").ZoneId(None).Capacity(squad.Capacity))
|
UpdateSquadListWhenListed(squad, SquadInfo().Task("").ZoneId(None).Capacity(squad.Capacity))
|
||||||
UpdateSquadDetailWhenListed(squad.GUID, squad)
|
UpdateSquadDetail(squad.GUID, squad)
|
||||||
|
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
|
|
@ -530,6 +686,9 @@ class SquadService extends Actor {
|
||||||
log.info(s"${tplayer.Name} would like the #${position+1} spot in this squad")
|
log.info(s"${tplayer.Name} would like the #${position+1} spot in this squad")
|
||||||
val membership = squad.Membership.zipWithIndex
|
val membership = squad.Membership.zipWithIndex
|
||||||
val toMember = squad.Membership(position)
|
val toMember = squad.Membership(position)
|
||||||
|
if(squad.Leader.CharId == tplayer.CharId) {
|
||||||
|
//TODO squad leader currently disallowed
|
||||||
|
} else
|
||||||
//the squad leader may swap to any open position; a normal member has to validate against requirements
|
//the squad leader may swap to any open position; a normal member has to validate against requirements
|
||||||
if((squad.Leader.CharId == tplayer.CharId && toMember.CharId == 0) || ValidOpenSquadPosition(squad, position, toMember, tplayer.Certifications)) {
|
if((squad.Leader.CharId == tplayer.CharId && toMember.CharId == 0) || ValidOpenSquadPosition(squad, position, toMember, tplayer.Certifications)) {
|
||||||
membership.find { case (member, _) => member.CharId == tplayer.CharId } match {
|
membership.find { case (member, _) => member.CharId == tplayer.CharId } match {
|
||||||
|
|
@ -538,12 +697,15 @@ class SquadService extends Actor {
|
||||||
if(fromIndex == squad.LeaderPositionIndex) {
|
if(fromIndex == squad.LeaderPositionIndex) {
|
||||||
squad.LeaderPositionIndex = position
|
squad.LeaderPositionIndex = position
|
||||||
}
|
}
|
||||||
|
//RemoveInvite(tplayer.CharId).foreach { _ =>
|
||||||
|
//close the old bids out
|
||||||
|
//}
|
||||||
membership
|
membership
|
||||||
.filter { case (_member, _) => _member.CharId > 0 }
|
.filter { case (_member, _) => _member.CharId > 0 }
|
||||||
.foreach { case (_member, _) =>
|
.foreach { case (_member, _) =>
|
||||||
SquadEvents.publish(SquadServiceResponse(s"/${_member.CharId}/Squad", SquadResponse.AssignMember(squad, fromIndex, position)))
|
SquadEvents.publish(SquadServiceResponse(s"/${_member.CharId}/Squad", SquadResponse.AssignMember(squad, fromIndex, position)))
|
||||||
}
|
}
|
||||||
UpdateSquadDetailWhenListed(squad.GUID, squad)
|
UpdateSquadDetail(squad.GUID, squad)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
//somehow, this is not our squad; do nothing, for now
|
//somehow, this is not our squad; do nothing, for now
|
||||||
}
|
}
|
||||||
|
|
@ -561,10 +723,14 @@ class SquadService extends Actor {
|
||||||
if(ValidOpenSquadPosition(squad, position, toMember, tplayer.Certifications)) {
|
if(ValidOpenSquadPosition(squad, position, toMember, tplayer.Certifications)) {
|
||||||
//we could join but we may need permission from the squad leader first
|
//we could join but we may need permission from the squad leader first
|
||||||
log.info(s"Player ${tplayer.Name} would like to join the squad ${squad.Task}.")
|
log.info(s"Player ${tplayer.Name} would like to join the squad ${squad.Task}.")
|
||||||
bids(tplayer.CharId) = NormalBid(squad.Leader.CharId, guid, position)
|
val leader = squad.Leader
|
||||||
//val leader = squad.Leader
|
val bid = BidForPosition(tplayer, guid, position)
|
||||||
//TODO ask permission from the squad leader, unless auto-approve is in effect
|
val leaderCharId = leader.CharId
|
||||||
self ! SquadServiceMessage(tplayer, SquadAction.Membership(SquadRequestType.Accept, tplayer.CharId, None, "", None))
|
AddInvite(leaderCharId, bid) match {
|
||||||
|
case out @ Some(_) if out.contains(bid) =>
|
||||||
|
HandleBidForPosition(bid, tplayer)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case None => ;
|
case None => ;
|
||||||
//squad does not exist? assume old local data; force update to correct discrepancy
|
//squad does not exist? assume old local data; force update to correct discrepancy
|
||||||
|
|
@ -574,16 +740,19 @@ class SquadService extends Actor {
|
||||||
case (Some(squad), AssignSquadMemberToRole(position, char_id)) =>
|
case (Some(squad), AssignSquadMemberToRole(position, char_id)) =>
|
||||||
val membership = squad.Membership.zipWithIndex
|
val membership = squad.Membership.zipWithIndex
|
||||||
(membership.find({ case (member, _) => member.CharId == char_id}), membership(position)) match {
|
(membership.find({ case (member, _) => member.CharId == char_id}), membership(position)) match {
|
||||||
case (Some((fromMember, fromPosition)), (toMember, _)) =>
|
//TODO squad leader currently disallowed
|
||||||
|
case (Some((fromMember, fromPosition)), (toMember, _)) if fromPosition != 0 =>
|
||||||
val name = fromMember.Name
|
val name = fromMember.Name
|
||||||
SwapMemberPosition(squad, toMember, fromMember)
|
SwapMemberPosition(squad, toMember, fromMember)
|
||||||
//
|
if(fromPosition == squad.LeaderPositionIndex) {
|
||||||
|
squad.LeaderPositionIndex = position
|
||||||
|
}
|
||||||
membership
|
membership
|
||||||
.filter({ case (_member, _) => _member.CharId > 0 })
|
.filter({ case (_member, _) => _member.CharId > 0 })
|
||||||
.foreach { case (_member, _) =>
|
.foreach { case (_member, _) =>
|
||||||
SquadEvents.publish(SquadServiceResponse(s"/${_member.CharId}/Squad", SquadResponse.AssignMember(squad, fromPosition, position)))
|
SquadEvents.publish(SquadServiceResponse(s"/${_member.CharId}/Squad", SquadResponse.AssignMember(squad, fromPosition, position)))
|
||||||
}
|
}
|
||||||
UpdateSquadDetailWhenListed(squad.GUID, squad,
|
UpdateSquadDetail(squad.GUID, squad,
|
||||||
SquadDetail().Members(List(
|
SquadDetail().Members(List(
|
||||||
SquadPositionEntry(position, SquadPositionDetail().CharId(fromMember.CharId).Name(fromMember.Name)),
|
SquadPositionEntry(position, SquadPositionDetail().CharId(fromMember.CharId).Name(fromMember.Name)),
|
||||||
SquadPositionEntry(fromPosition, SquadPositionDetail().CharId(char_id).Name(name))
|
SquadPositionEntry(fromPosition, SquadPositionDetail().CharId(char_id).Name(name))
|
||||||
|
|
@ -597,7 +766,15 @@ class SquadService extends Actor {
|
||||||
idToSquad.get(guid) match {
|
idToSquad.get(guid) match {
|
||||||
case Some(squad) =>
|
case Some(squad) =>
|
||||||
viewDetails(tplayer.CharId) = guid
|
viewDetails(tplayer.CharId) = guid
|
||||||
sender ! SquadServiceResponse(s"/${tplayer.CharId}/Squad", SquadResponse.Detail(squad.GUID, SquadService.Detail.Publish(squad)))
|
sender ! SquadServiceResponse("", SquadResponse.Detail(squad.GUID, SquadService.Detail.Publish(squad)))
|
||||||
|
case None => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
//the following message is feedback from a specific client, awaiting proper initialization
|
||||||
|
case (_, DisplayFullSquad()) =>
|
||||||
|
idToSquad.get(guid) match {
|
||||||
|
case Some(squad) =>
|
||||||
|
sender ! SquadServiceResponse("", SquadResponse.InitSquad(squad.GUID))
|
||||||
case None => ;
|
case None => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -609,6 +786,122 @@ class SquadService extends Actor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param invitedPlayer
|
||||||
|
* @param bid
|
||||||
|
* @return an optional invite;
|
||||||
|
* if added to the active invite position, return the parameter bid;
|
||||||
|
* if added to the queued invite, return the invite in the active position;
|
||||||
|
* if not added, return `None`
|
||||||
|
*/
|
||||||
|
def AddInvite(invitedPlayer : Long, bid : Invitation) : Option[Invitation] = {
|
||||||
|
invites.get(invitedPlayer) match {
|
||||||
|
case Some(_bid) =>
|
||||||
|
queuedInvites.get(invitedPlayer) match {
|
||||||
|
case Some(bidList) =>
|
||||||
|
if(_bid.InviterCharId != bid.InviterCharId && !bidList.exists { eachBid => eachBid.InviterCharId == bid.InviterCharId }) {
|
||||||
|
log.debug(s"Invite from ${bid.InviterCharId} to $invitedPlayer stored in queue while active invite request pending")
|
||||||
|
queuedInvites(invitedPlayer) = bid match {
|
||||||
|
case _: BidForPosition =>
|
||||||
|
val (normals, others) = bidList.partition(_.isInstanceOf[BidForPosition])
|
||||||
|
(normals :+ bid) ++ others
|
||||||
|
case _ =>
|
||||||
|
bidList :+ bid
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Some(_bid)
|
||||||
|
}
|
||||||
|
case None =>
|
||||||
|
if(_bid.InviterCharId != bid.InviterCharId) {
|
||||||
|
log.debug(s"Invite from ${bid.InviterCharId} to $invitedPlayer stored while active invite request pending")
|
||||||
|
queuedInvites(invitedPlayer) = List[Invitation](bid)
|
||||||
|
}
|
||||||
|
Some(_bid)
|
||||||
|
}
|
||||||
|
|
||||||
|
case None =>
|
||||||
|
invites(invitedPlayer) = bid
|
||||||
|
Some(bid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def RemoveInvite(invitedPlayer : Long) : Option[Invitation] = {
|
||||||
|
invites.remove(invitedPlayer)
|
||||||
|
}
|
||||||
|
|
||||||
|
def RemoveQueuedInvites(invitedPlayer : Long) : List[Invitation] = {
|
||||||
|
queuedInvites.remove(invitedPlayer) match {
|
||||||
|
case Some(_bidList) => _bidList.toList
|
||||||
|
case None => Nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def RemoveInvites(invitedPlayer : Long, invitingPlayer : Long) : Unit = {
|
||||||
|
queuedInvites.get(invitedPlayer) match {
|
||||||
|
case Some(bidList) =>
|
||||||
|
val list = bidList.filterNot { _.InviterCharId == invitingPlayer }
|
||||||
|
if(list.nonEmpty) {
|
||||||
|
queuedInvites(invitedPlayer) = list
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
queuedInvites.remove(invitedPlayer)
|
||||||
|
}
|
||||||
|
case None => ;
|
||||||
|
}
|
||||||
|
invites.get(invitedPlayer) match {
|
||||||
|
case Some(_bid) =>
|
||||||
|
if(_bid.InviterCharId == invitingPlayer) {
|
||||||
|
//drop bid, try reload new bid
|
||||||
|
}
|
||||||
|
case None => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def NextInvite(invitedPlayer : Long) : Option[Invitation] = {
|
||||||
|
invites.get(invitedPlayer) match {
|
||||||
|
case None =>
|
||||||
|
queuedInvites.get(invitedPlayer) match {
|
||||||
|
case Some(list) =>
|
||||||
|
list match {
|
||||||
|
case Nil =>
|
||||||
|
None
|
||||||
|
case x :: Nil =>
|
||||||
|
invites(invitedPlayer) = x
|
||||||
|
queuedInvites.remove(invitedPlayer)
|
||||||
|
Some(x)
|
||||||
|
case x :: xs =>
|
||||||
|
invites(invitedPlayer) = x
|
||||||
|
queuedInvites(invitedPlayer) = xs
|
||||||
|
Some(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
case None =>
|
||||||
|
None
|
||||||
|
}
|
||||||
|
case Some(_) =>
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def HandleBidForPosition(bid : BidForPosition, player : Player) : Unit = {
|
||||||
|
idToSquad.get(bid.squad_guid) match {
|
||||||
|
case Some(squad) =>
|
||||||
|
val leaderCharId = squad.Leader.CharId
|
||||||
|
if(squad.AutoApproveInvitationRequests) {
|
||||||
|
self ! SquadServiceMessage(player, SquadAction.Membership(SquadRequestType.Accept, leaderCharId, None, "", None))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SquadEvents.publish(SquadServiceResponse(s"/$leaderCharId/Squad", SquadResponse.WantsSquadPosition(bid.player.Name)))
|
||||||
|
}
|
||||||
|
case _ =>
|
||||||
|
//squad is missing; will this properly short-circuit?
|
||||||
|
log.error(s"Attempted to process ${bid.InviterName}'s bid for a position in a squad (id:${bid.squad_guid.guid}) that does not exist")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def JoinSquad(player : Player, squad : Squad, line : Int) : Boolean = {
|
def JoinSquad(player : Player, squad : Squad, line : Int) : Boolean = {
|
||||||
val charId = player.CharId
|
val charId = player.CharId
|
||||||
val position = squad.Membership(line)
|
val position = squad.Membership(line)
|
||||||
|
|
@ -652,7 +945,7 @@ class SquadService extends Actor {
|
||||||
.foreach { member =>
|
.foreach { member =>
|
||||||
SquadEvents.publish(SquadServiceResponse(s"/${member.CharId}/Squad", SquadResponse.Join(squad, updatedIndex)))
|
SquadEvents.publish(SquadServiceResponse(s"/${member.CharId}/Squad", SquadResponse.Join(squad, updatedIndex)))
|
||||||
}
|
}
|
||||||
UpdateSquadDetailWhenListed(squad.GUID, squad,
|
UpdateSquadDetail(squad.GUID, squad,
|
||||||
SquadDetail().Members(List(SquadPositionEntry(line, SquadPositionDetail().CharId(charId).Name(player.Name))))
|
SquadDetail().Members(List(SquadPositionEntry(line, SquadPositionDetail().CharId(charId).Name(player.Name))))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -670,30 +963,18 @@ class SquadService extends Actor {
|
||||||
membership.find { case (_member, _) => _member.CharId == charId } match {
|
membership.find { case (_member, _) => _member.CharId == charId } match {
|
||||||
case Some((member, index)) =>
|
case Some((member, index)) =>
|
||||||
val updateList = membership.collect({ case (_member, _index) if _member.CharId > 0 => (_member.CharId, _index) }).toList
|
val updateList = membership.collect({ case (_member, _index) if _member.CharId > 0 => (_member.CharId, _index) }).toList
|
||||||
|
//member leaves the squad completely
|
||||||
memberToSquad.remove(charId)
|
memberToSquad.remove(charId)
|
||||||
member.Name = ""
|
member.Name = ""
|
||||||
member.CharId = 0
|
member.CharId = 0
|
||||||
|
sender ! SquadServiceResponse("", SquadResponse.Leave(squad, updateList))
|
||||||
val size = squad.Size
|
//other squad members see the member leaving
|
||||||
if(size < 2) {
|
val leavingMember = List((charId, index))
|
||||||
//squad is rendered to just one person or less; collapse it
|
membership
|
||||||
squad.Membership.foreach { _member =>
|
.filter { case (_member, _) => _member.CharId > 0 }
|
||||||
SquadEvents.publish(SquadServiceResponse(s"/${_member.CharId}/Squad", SquadResponse.Membership(SquadResponseType.Disband, 0, 0, charId, None, "", false, Some(None))))
|
.foreach { case (_member, _) =>
|
||||||
|
SquadEvents.publish( SquadServiceResponse(s"/${_member.CharId}/Squad", SquadResponse.Leave(squad, leavingMember)) )
|
||||||
}
|
}
|
||||||
CloseOutSquad(squad, membership, updateList)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//squad continues, despite player's parting
|
|
||||||
//member leaves the squad completely
|
|
||||||
sender ! SquadServiceResponse("", SquadResponse.Leave(squad, updateList))
|
|
||||||
//other squad members see the member leaving
|
|
||||||
val leavingMember = List((charId, index))
|
|
||||||
membership
|
|
||||||
.filter { case (_member, _) => _member.CharId > 0 }
|
|
||||||
.foreach { case (_member, _) =>
|
|
||||||
SquadEvents.publish( SquadServiceResponse(s"/${_member.CharId}/Squad", SquadResponse.Leave(squad, leavingMember)) )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
true
|
||||||
case None =>
|
case None =>
|
||||||
false
|
false
|
||||||
|
|
@ -720,6 +1001,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)
|
||||||
|
UpdateSquadList(squad, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
def SwapMemberPosition(squad : Squad, toMember : Member, fromMember : Member) : Unit = {
|
def SwapMemberPosition(squad : Squad, toMember : Member, fromMember : Member) : Unit = {
|
||||||
|
|
@ -744,6 +1026,13 @@ class SquadService extends Actor {
|
||||||
toMember.Armor = armor
|
toMember.Armor = armor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def UpdateSquadList(faction : PlanetSideEmpire.Value): Unit = {
|
||||||
|
val factionListings = publishedLists(faction)
|
||||||
|
SquadEvents.publish(
|
||||||
|
SquadServiceResponse(s"/$faction/Squad", SquadResponse.InitList(factionListings.toVector))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def UpdateSquadList(squad : Squad, changes : SquadInfo) : Unit = {
|
def UpdateSquadList(squad : Squad, changes : SquadInfo) : Unit = {
|
||||||
UpdateSquadList(squad, Some(changes))
|
UpdateSquadList(squad, Some(changes))
|
||||||
}
|
}
|
||||||
|
|
@ -759,7 +1048,6 @@ class SquadService extends Actor {
|
||||||
}
|
}
|
||||||
|
|
||||||
def UpdateSquadList(squad : Squad, changes : Option[SquadInfo]) : Unit = {
|
def UpdateSquadList(squad : Squad, changes : Option[SquadInfo]) : Unit = {
|
||||||
val entry = SquadService.SquadList.Publish(squad)
|
|
||||||
val faction = squad.Faction
|
val faction = squad.Faction
|
||||||
val factionListings = publishedLists(faction)
|
val factionListings = publishedLists(faction)
|
||||||
factionListings.find(info => {
|
factionListings.find(info => {
|
||||||
|
|
@ -774,7 +1062,7 @@ class SquadService extends Actor {
|
||||||
case Some(changedFields) =>
|
case Some(changedFields) =>
|
||||||
//squad information update
|
//squad information update
|
||||||
log.info(s"Squad will be updated")
|
log.info(s"Squad will be updated")
|
||||||
factionListings(index) = entry
|
factionListings(index) = SquadService.SquadList.Publish(squad)
|
||||||
SquadEvents.publish(
|
SquadEvents.publish(
|
||||||
SquadServiceResponse(s"/$faction/Squad", SquadResponse.UpdateList(Seq((index, changedFields))))
|
SquadServiceResponse(s"/$faction/Squad", SquadResponse.UpdateList(Seq((index, changedFields))))
|
||||||
)
|
)
|
||||||
|
|
@ -790,7 +1078,7 @@ class SquadService extends Actor {
|
||||||
case None =>
|
case None =>
|
||||||
//first time being published
|
//first time being published
|
||||||
log.info(s"Squad will be introduced")
|
log.info(s"Squad will be introduced")
|
||||||
factionListings += entry
|
factionListings += SquadService.SquadList.Publish(squad)
|
||||||
SquadEvents.publish(
|
SquadEvents.publish(
|
||||||
SquadServiceResponse(s"/$faction/Squad", SquadResponse.InitList(factionListings.toVector))
|
SquadServiceResponse(s"/$faction/Squad", SquadResponse.InitList(factionListings.toVector))
|
||||||
)
|
)
|
||||||
|
|
@ -798,19 +1086,7 @@ class SquadService extends Actor {
|
||||||
}
|
}
|
||||||
|
|
||||||
def UpdateSquadDetail(guid : PlanetSideGUID, squad : Squad) : Unit = {
|
def UpdateSquadDetail(guid : PlanetSideGUID, squad : Squad) : Unit = {
|
||||||
UpdateSquadDetailWhenListed(guid, squad, SquadService.Detail.Publish(squad))
|
UpdateSquadDetail(guid, squad, SquadService.Detail.Publish(squad))
|
||||||
}
|
|
||||||
|
|
||||||
def UpdateSquadDetailWhenListed(guid : PlanetSideGUID, squad : Squad) : Unit = {
|
|
||||||
if(squad.Listed || squad.Size > 1) {
|
|
||||||
UpdateSquadDetail(guid, squad, SquadService.Detail.Publish(squad))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def UpdateSquadDetailWhenListed(guid : PlanetSideGUID, squad : Squad, detail : SquadDetail) : Unit = {
|
|
||||||
if(squad.Listed || squad.Size > 1) {
|
|
||||||
UpdateSquadDetail(guid, squad, detail)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def UpdateSquadDetail(guid : PlanetSideGUID, squad : Squad, detail : SquadDetail) : Unit = {
|
def UpdateSquadDetail(guid : PlanetSideGUID, squad : Squad, detail : SquadDetail) : Unit = {
|
||||||
|
|
@ -824,13 +1100,19 @@ class SquadService extends Actor {
|
||||||
}
|
}
|
||||||
|
|
||||||
object SquadService {
|
object SquadService {
|
||||||
trait PositionBid
|
abstract class Invitation(char_id : Long, name : String) {
|
||||||
|
def InviterCharId : Long = char_id
|
||||||
|
def InviterName : String = name
|
||||||
|
}
|
||||||
|
|
||||||
final case class NormalBid(char_id : Long, squad_guid : PlanetSideGUID, position : Int) extends PositionBid
|
final case class BidForPosition(player : Player, squad_guid : PlanetSideGUID, position : Int)
|
||||||
|
extends Invitation(player.CharId, player.Name)
|
||||||
|
|
||||||
final case class VacancyBid(char_id : Long, squad_guid : PlanetSideGUID) extends PositionBid
|
final case class VacancyInvite(char_id : Long, name : String, squad_guid : PlanetSideGUID)
|
||||||
|
extends Invitation(char_id, name)
|
||||||
|
|
||||||
final case class SpontaneousBid(char_id : Long, placeholder : Squad) extends PositionBid
|
final case class SpontaneousInvite(player : Player)
|
||||||
|
extends Invitation(player.CharId, player.Name)
|
||||||
|
|
||||||
object SquadList {
|
object SquadList {
|
||||||
def Publish(squad : Squad) : SquadInfo = {
|
def Publish(squad : Squad) : SquadInfo = {
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,7 @@ class SquadDefinitionActionMessageTest extends Specification {
|
||||||
case SquadDefinitionActionMessage(unk1, unk2, action) =>
|
case SquadDefinitionActionMessage(unk1, unk2, action) =>
|
||||||
unk1 mustEqual PlanetSideGUID(0)
|
unk1 mustEqual PlanetSideGUID(0)
|
||||||
unk2 mustEqual 0
|
unk2 mustEqual 0
|
||||||
action mustEqual SearchForSquadsWithParticularRole("Badass", 0L, 1, 0)
|
action mustEqual SearchForSquadsWithParticularRole("Badass", Set(), 1, SearchMode.AnyPositions)
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
}
|
}
|
||||||
|
|
@ -233,7 +233,7 @@ class SquadDefinitionActionMessageTest extends Specification {
|
||||||
case SquadDefinitionActionMessage(unk1, unk2, action) =>
|
case SquadDefinitionActionMessage(unk1, unk2, action) =>
|
||||||
unk1 mustEqual PlanetSideGUID(0)
|
unk1 mustEqual PlanetSideGUID(0)
|
||||||
unk2 mustEqual 0
|
unk2 mustEqual 0
|
||||||
action mustEqual SearchForSquadsWithParticularRole("Badass", 0L, 2, 0)
|
action mustEqual SearchForSquadsWithParticularRole("Badass", Set(), 2, SearchMode.AnyPositions)
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
}
|
}
|
||||||
|
|
@ -244,7 +244,7 @@ class SquadDefinitionActionMessageTest extends Specification {
|
||||||
case SquadDefinitionActionMessage(unk1, unk2, action) =>
|
case SquadDefinitionActionMessage(unk1, unk2, action) =>
|
||||||
unk1 mustEqual PlanetSideGUID(0)
|
unk1 mustEqual PlanetSideGUID(0)
|
||||||
unk2 mustEqual 0
|
unk2 mustEqual 0
|
||||||
action mustEqual SearchForSquadsWithParticularRole("Badass", 0L, 2, 1)
|
action mustEqual SearchForSquadsWithParticularRole("Badass", Set(), 2, SearchMode.AvailablePositions)
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
}
|
}
|
||||||
|
|
@ -255,7 +255,7 @@ class SquadDefinitionActionMessageTest extends Specification {
|
||||||
case SquadDefinitionActionMessage(unk1, unk2, action) =>
|
case SquadDefinitionActionMessage(unk1, unk2, action) =>
|
||||||
unk1 mustEqual PlanetSideGUID(0)
|
unk1 mustEqual PlanetSideGUID(0)
|
||||||
unk2 mustEqual 0
|
unk2 mustEqual 0
|
||||||
action mustEqual SearchForSquadsWithParticularRole("Badass", 536870928L, 2, 2)
|
action mustEqual SearchForSquadsWithParticularRole("Badass", Set(CertificationType.InfiltrationSuit, CertificationType.AntiVehicular), 2, SearchMode.SomeCertifications)
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
}
|
}
|
||||||
|
|
@ -266,7 +266,7 @@ class SquadDefinitionActionMessageTest extends Specification {
|
||||||
case SquadDefinitionActionMessage(unk1, unk2, action) =>
|
case SquadDefinitionActionMessage(unk1, unk2, action) =>
|
||||||
unk1 mustEqual PlanetSideGUID(0)
|
unk1 mustEqual PlanetSideGUID(0)
|
||||||
unk2 mustEqual 0
|
unk2 mustEqual 0
|
||||||
action mustEqual SearchForSquadsWithParticularRole("Badass", 536870928L, 2, 3)
|
action mustEqual SearchForSquadsWithParticularRole("Badass", Set(CertificationType.InfiltrationSuit, CertificationType.AntiVehicular), 2, SearchMode.AllCertifications)
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
}
|
}
|
||||||
|
|
@ -436,35 +436,35 @@ class SquadDefinitionActionMessageTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode (34a)" in {
|
"encode (34a)" in {
|
||||||
val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SearchForSquadsWithParticularRole("Badass", 0L, 1, 0))
|
val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SearchForSquadsWithParticularRole("Badass", Set(), 1, SearchMode.AnyPositions))
|
||||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual string_34a
|
pkt mustEqual string_34a
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode (34b)" in {
|
"encode (34b)" in {
|
||||||
val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SearchForSquadsWithParticularRole("Badass", 0L, 2, 0))
|
val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SearchForSquadsWithParticularRole("Badass", Set(), 2, SearchMode.AnyPositions))
|
||||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual string_34b
|
pkt mustEqual string_34b
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode (34c)" in {
|
"encode (34c)" in {
|
||||||
val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SearchForSquadsWithParticularRole("Badass", 0L, 2, 1))
|
val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SearchForSquadsWithParticularRole("Badass", Set(), 2, SearchMode.AvailablePositions))
|
||||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual string_34c
|
pkt mustEqual string_34c
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode (34d)" in {
|
"encode (34d)" in {
|
||||||
val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SearchForSquadsWithParticularRole("Badass", 536870928L, 2, 2))
|
val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SearchForSquadsWithParticularRole("Badass", Set(CertificationType.InfiltrationSuit, CertificationType.AntiVehicular), 2, SearchMode.SomeCertifications))
|
||||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual string_34d
|
pkt mustEqual string_34d
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode (34e)" in {
|
"encode (34e)" in {
|
||||||
val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SearchForSquadsWithParticularRole("Badass", 536870928L, 2, 3))
|
val msg = SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SearchForSquadsWithParticularRole("Badass", Set(CertificationType.InfiltrationSuit, CertificationType.AntiVehicular), 2, SearchMode.AllCertifications))
|
||||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual string_34e
|
pkt mustEqual string_34e
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ class SquadMemberEventTest extends Specification {
|
||||||
"decode" in {
|
"decode" in {
|
||||||
PacketCoding.DecodePacket(string).require match {
|
PacketCoding.DecodePacket(string).require match {
|
||||||
case SquadMemberEvent(u1, u2, u3, u4, u5, u6, u7) =>
|
case SquadMemberEvent(u1, u2, u3, u4, u5, u6, u7) =>
|
||||||
u1 mustEqual 0
|
u1 mustEqual MemberEvent.Add
|
||||||
u2 mustEqual 7
|
u2 mustEqual 7
|
||||||
u3 mustEqual 42771010L
|
u3 mustEqual 42771010L
|
||||||
u4 mustEqual 0
|
u4 mustEqual 0
|
||||||
|
|
@ -25,7 +25,7 @@ class SquadMemberEventTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode" in {
|
"encode" in {
|
||||||
val msg = SquadMemberEvent(0, 7, 42771010L, 0, Some("HofD"), Some(7), Some(529745L))
|
val msg = SquadMemberEvent(MemberEvent.Add, 7, 42771010L, 0, Some("HofD"), Some(7), Some(529745L))
|
||||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
pkt mustEqual string
|
pkt mustEqual string
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ import net.psforever.objects.serverobject.terminals._
|
||||||
import net.psforever.objects.serverobject.terminals.Terminal.TerminalMessage
|
import net.psforever.objects.serverobject.terminals.Terminal.TerminalMessage
|
||||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||||
import net.psforever.objects.serverobject.turret.{FacilityTurret, TurretUpgrade, WeaponTurret}
|
import net.psforever.objects.serverobject.turret.{FacilityTurret, TurretUpgrade, WeaponTurret}
|
||||||
|
import net.psforever.objects.teamwork.Squad
|
||||||
import net.psforever.objects.vehicles.{AccessPermissionGroup, Cargo, Utility, VehicleLockState, _}
|
import net.psforever.objects.vehicles.{AccessPermissionGroup, Cargo, Utility, VehicleLockState, _}
|
||||||
import net.psforever.objects.vital._
|
import net.psforever.objects.vital._
|
||||||
import net.psforever.objects.zones.{InterstellarCluster, Zone, ZoneHotSpotProjector}
|
import net.psforever.objects.zones.{InterstellarCluster, Zone, ZoneHotSpotProjector}
|
||||||
|
|
@ -358,7 +359,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
SquadListing(index, squadInfo)
|
SquadListing(index, squadInfo)
|
||||||
}.toVector
|
}.toVector
|
||||||
)
|
)
|
||||||
log.info(s"updating squad with msg $o")
|
|
||||||
sendResponse(
|
sendResponse(
|
||||||
ReplicationStreamMessage(6, None,
|
ReplicationStreamMessage(6, None,
|
||||||
infos.map { case (index, squadInfo) =>
|
infos.map { case (index, squadInfo) =>
|
||||||
|
|
@ -388,12 +388,33 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
SquadDefinitionActionMessage(squad.GUID, 0, SquadAction.Unknown(33))
|
SquadDefinitionActionMessage(squad.GUID, 0, SquadAction.Unknown(33))
|
||||||
)
|
)
|
||||||
|
|
||||||
case SquadResponse.Membership(request_type, unk1, unk2, unk3, unk4, player_name, unk5, unk6) =>
|
case SquadResponse.Membership(request_type, unk1, unk2, char_id, opt_char_id, player_name, unk5, unk6) =>
|
||||||
sendResponse(SquadMembershipResponse(request_type, unk1, unk2, unk3, unk4, player_name, unk5, unk6))
|
val name = request_type match {
|
||||||
|
case SquadResponseType.Invite if unk5 =>
|
||||||
|
//player_name is our name; the name of the player indicated by unk3 is needed
|
||||||
|
LivePlayerList.WorldPopulation({ case (_, a : Avatar) => char_id == a.CharId }).headOption match {
|
||||||
|
case Some(player) =>
|
||||||
|
player.name
|
||||||
|
case None =>
|
||||||
|
player_name
|
||||||
|
}
|
||||||
|
case _ =>
|
||||||
|
player_name
|
||||||
|
}
|
||||||
|
sendResponse(SquadMembershipResponse(request_type, unk1, unk2, char_id, opt_char_id, name, unk5, unk6))
|
||||||
|
|
||||||
case SquadResponse.Invite(from_char_id, to_char_id, name) =>
|
case SquadResponse.Invite(from_char_id, to_char_id, name) =>
|
||||||
sendResponse(SquadMembershipResponse(SquadResponseType.Invite, 0, 0, from_char_id, Some(to_char_id), s"$name", false, Some(None)))
|
sendResponse(SquadMembershipResponse(SquadResponseType.Invite, 0, 0, from_char_id, Some(to_char_id), s"$name", false, Some(None)))
|
||||||
|
|
||||||
|
case SquadResponse.WantsSquadPosition(name : String) =>
|
||||||
|
sendResponse(
|
||||||
|
ChatMsg(
|
||||||
|
ChatMessageType.CMT_TELL, true, "",
|
||||||
|
s"\\#6[SQUAD] \\#3$name\\#6 would like to join your squad. (respond with \\#3/accept\\#6 or \\#3/reject\\#6)",
|
||||||
|
None
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
case SquadResponse.Join(squad, positionsToUpdate) =>
|
case SquadResponse.Join(squad, positionsToUpdate) =>
|
||||||
val leader = squad.Leader
|
val leader = squad.Leader
|
||||||
val id = 11
|
val id = 11
|
||||||
|
|
@ -405,20 +426,20 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
//we are joining the squad
|
//we are joining the squad
|
||||||
//load each member's entry (our own too)
|
//load each member's entry (our own too)
|
||||||
membershipPositions.foreach { case(member, index) =>
|
membershipPositions.foreach { case(member, index) =>
|
||||||
sendResponse(SquadMemberEvent(0, id, member.CharId, index, Some(member.Name), Some(member.ZoneId), Some(0)))
|
sendResponse(SquadMemberEvent.Add(id, member.CharId, index, member.Name, member.ZoneId, unk7 = 0))
|
||||||
squadUI(member.CharId) = SquadUIElement(member.Name, index, member.ZoneId, member.Health, member.Armor, member.Position)
|
squadUI(member.CharId) = SquadUIElement(member.Name, index, member.ZoneId, member.Health, member.Armor, member.Position)
|
||||||
}
|
}
|
||||||
//initialization
|
//initialization
|
||||||
sendResponse(SquadMemberEvent(0, id, ourMember.CharId, ourIndex, Some(ourMember.Name), Some(ourMember.ZoneId), Some(0))) //repeat of our entry
|
sendResponse(SquadMemberEvent.Add(id, ourMember.CharId, ourIndex, ourMember.Name, ourMember.ZoneId, unk7 = 0)) //repeat of our entry
|
||||||
sendResponse(PlanetsideAttributeMessage(player.GUID, 31, id)) //associate with squad?
|
sendResponse(PlanetsideAttributeMessage(player.GUID, 31, id)) //associate with squad?
|
||||||
sendResponse(PlanetsideAttributeMessage(player.GUID, 32, ourIndex)) //associate with member position in squad?
|
sendResponse(PlanetsideAttributeMessage(player.GUID, 32, ourIndex)) //associate with member position in squad?
|
||||||
//a finalization? what does this do?
|
//a finalization? what does this do?
|
||||||
sendResponse(SquadDefinitionActionMessage(squad.GUID, 0, SquadAction.Unknown(18)))
|
sendResponse(SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SquadAction.Unknown(18)))
|
||||||
case _ =>
|
case _ =>
|
||||||
//other player is joining our squad
|
//other player is joining our squad
|
||||||
//load each member's entry
|
//load each member's entry
|
||||||
membershipPositions.foreach { case(member, index) =>
|
membershipPositions.foreach { case(member, index) =>
|
||||||
sendResponse(SquadMemberEvent(0, id, member.CharId, index, Some(member.Name), Some(member.ZoneId), Some(0)))
|
sendResponse(SquadMemberEvent.Add(id, member.CharId, index, member.Name, member.ZoneId, unk7 = 0))
|
||||||
squadUI(member.CharId) = SquadUIElement(member.Name, index, member.ZoneId, member.Health, member.Armor, member.Position)
|
squadUI(member.CharId) = SquadUIElement(member.Name, index, member.ZoneId, member.Health, member.Armor, member.Position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -429,6 +450,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
.map{ case (member, _) => SquadStateInfo(member.CharId, member.Health, member.Armor, member.Position, 2,2, false, 429, None,None) }
|
.map{ case (member, _) => SquadStateInfo(member.CharId, member.Health, member.Armor, member.Position, 2,2, false, 429, None,None) }
|
||||||
.toList
|
.toList
|
||||||
))
|
))
|
||||||
|
log.info(s"SquadCards: ${squadUI.map { case(id, card) => s"[${card.index}:${card.name}/$id]" }.mkString}")
|
||||||
|
|
||||||
case SquadResponse.Leave(_, positionsToUpdate) =>
|
case SquadResponse.Leave(_, positionsToUpdate) =>
|
||||||
val id = 11
|
val id = 11
|
||||||
|
|
@ -437,11 +459,11 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
//we are leaving the squad
|
//we are leaving the squad
|
||||||
//remove each member's entry (our own too)
|
//remove each member's entry (our own too)
|
||||||
positionsToUpdate.foreach { case(member, index) =>
|
positionsToUpdate.foreach { case(member, index) =>
|
||||||
sendResponse(SquadMemberEvent(1, id, member, index, None, None, None))
|
sendResponse(SquadMemberEvent.Remove(id, member, index))
|
||||||
squadUI.remove(member)
|
squadUI.remove(member)
|
||||||
}
|
}
|
||||||
//uninitialize
|
//uninitialize
|
||||||
sendResponse(SquadMemberEvent(1, id, ourMember, ourIndex, None, None, None)) //repeat of our entry
|
sendResponse(SquadMemberEvent.Remove(id, ourMember, ourIndex)) //repeat of our entry
|
||||||
sendResponse(PlanetsideAttributeMessage(player.GUID, 31, 0)) //disassociate with squad?
|
sendResponse(PlanetsideAttributeMessage(player.GUID, 31, 0)) //disassociate with squad?
|
||||||
sendResponse(PlanetsideAttributeMessage(player.GUID, 32, 0)) //disassociate with member position in squad?
|
sendResponse(PlanetsideAttributeMessage(player.GUID, 32, 0)) //disassociate with member position in squad?
|
||||||
sendResponse(PlanetsideAttributeMessage(player.GUID, 34, 4294967295L)) //unknown, perhaps unrelated?
|
sendResponse(PlanetsideAttributeMessage(player.GUID, 34, 4294967295L)) //unknown, perhaps unrelated?
|
||||||
|
|
@ -450,9 +472,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case _ =>
|
case _ =>
|
||||||
//remove each member's entry
|
//remove each member's entry
|
||||||
positionsToUpdate.foreach { case(member, index) =>
|
positionsToUpdate.foreach { case(member, index) =>
|
||||||
sendResponse(SquadMemberEvent(1, id, member, index, None, None, None))
|
sendResponse(SquadMemberEvent.Remove(id, member, index))
|
||||||
squadUI.remove(member)
|
squadUI.remove(member)
|
||||||
}
|
}
|
||||||
|
log.info(s"SquadCards: ${squadUI.map { case(id, card) => s"[${card.index}:${card.name}/$id]" }.mkString}")
|
||||||
}
|
}
|
||||||
|
|
||||||
case SquadResponse.UpdateMembers(squad, positions) =>
|
case SquadResponse.UpdateMembers(squad, positions) =>
|
||||||
|
|
@ -467,7 +490,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
.collect({
|
.collect({
|
||||||
case (entry, element) if entry.zone_number != element.zone =>
|
case (entry, element) if entry.zone_number != element.zone =>
|
||||||
//zone gets updated for these entries
|
//zone gets updated for these entries
|
||||||
sendResponse(SquadMemberEvent(3, 11, entry.char_id, element.index, None, Some(entry.zone_number), None))
|
sendResponse(SquadMemberEvent.UpdateZone(11, entry.char_id, element.index, entry.zone_number))
|
||||||
squadUI(entry.char_id) = SquadUIElement(element.name, element.index, entry.zone_number, entry.health, entry.armor, entry.pos)
|
squadUI(entry.char_id) = SquadUIElement(element.name, element.index, entry.zone_number, entry.health, entry.armor, entry.pos)
|
||||||
entry
|
entry
|
||||||
case (entry, element) if entry.health != element.health || entry.armor != element.armor || entry.pos != element.position =>
|
case (entry, element) if entry.health != element.health || entry.armor != element.armor || entry.pos != element.position =>
|
||||||
|
|
@ -486,53 +509,19 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
|
|
||||||
case SquadResponse.AssignMember(squad, from_index, to_index) =>
|
case SquadResponse.AssignMember(squad, from_index, to_index) =>
|
||||||
if(squadUI.nonEmpty) {
|
//we've already swapped position internally; now we swap the cards
|
||||||
val toMember = squad.Membership(to_index)
|
SwapSquadUIElements(squad, from_index, to_index)
|
||||||
val toCharId = toMember.CharId
|
log.info(s"SquadCards: ${squadUI.map { case(id, card) => s"[${card.index}:${card.name}/$id]" }.mkString}")
|
||||||
val fromMember = squad.Membership(from_index)
|
|
||||||
val fromCharId = fromMember.CharId
|
case SquadResponse.PromoteMember(squad, char_id, from_index, to_index) =>
|
||||||
val id = 11
|
//promotion will swap visual cards, but we must fix the backend
|
||||||
if(fromCharId > 0) {
|
val id = 11
|
||||||
//toMember and fromMember have swapped places
|
sendResponse(SquadMemberEvent.Promote(id, char_id))
|
||||||
val fromElem = squadUI(fromCharId)
|
SwapSquadUIElements(squad, from_index, to_index)
|
||||||
val toElem = squadUI(toCharId)
|
log.info(s"SquadCards: ${squadUI.map { case(id, card) => s"[${card.index}:${card.name}/$id]" }.mkString}")
|
||||||
sendResponse(SquadMemberEvent(1, id, toCharId, from_index, None, None, None))
|
|
||||||
sendResponse(SquadMemberEvent(1, id, fromCharId, to_index, None, None, None))
|
case SquadResponse.SquadSearchResults() =>
|
||||||
squadUI(toCharId) = SquadUIElement(fromElem.name, to_index, fromElem.zone, fromElem.health, fromElem.armor, fromElem.position)
|
sendResponse(SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SquadAction.NoSquadSearchResults()))
|
||||||
squadUI(fromCharId) = SquadUIElement(toElem.name, from_index, toElem.zone, toElem.health, toElem.armor, toElem.position)
|
|
||||||
sendResponse(SquadMemberEvent(0, id, toCharId, to_index, Some(fromElem.name), Some(fromElem.zone), Some(0)))
|
|
||||||
sendResponse(SquadMemberEvent(0, id, fromCharId, from_index, Some(toElem.name), Some(toElem.zone), Some(0)))
|
|
||||||
sendResponse(
|
|
||||||
SquadState(
|
|
||||||
PlanetSideGUID(id),
|
|
||||||
List(
|
|
||||||
SquadStateInfo(fromCharId, toElem.health, toElem.armor, toElem.position, 2, 2, false, 429, None, None),
|
|
||||||
SquadStateInfo(toCharId, fromElem.health, fromElem.armor, fromElem.position, 2, 2, false, 429, None, None)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//previous fromMember has moved toMember
|
|
||||||
val elem = squadUI(fromCharId)
|
|
||||||
sendResponse(SquadMemberEvent(1, id, toCharId, from_index, None, None, None))
|
|
||||||
squadUI(toCharId) = SquadUIElement(elem.name, to_index, elem.zone, elem.health, elem.armor, elem.position)
|
|
||||||
sendResponse(SquadMemberEvent(0, id, toCharId, to_index, Some(elem.name), Some(elem.zone), Some(0)))
|
|
||||||
sendResponse(
|
|
||||||
SquadState(
|
|
||||||
PlanetSideGUID(id),
|
|
||||||
List(SquadStateInfo(toCharId, elem.health, elem.armor, elem.position, 2, 2, false, 429, None, None))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
val charId = avatar.CharId
|
|
||||||
if(toCharId == charId) {
|
|
||||||
sendResponse(PlanetsideAttributeMessage(player.GUID, 32, to_index))
|
|
||||||
}
|
|
||||||
else if(fromCharId == charId) {
|
|
||||||
sendResponse(PlanetsideAttributeMessage(player.GUID, 32, from_index))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
@ -3478,25 +3467,16 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
"Degrado",
|
"Degrado",
|
||||||
Set(
|
Set(
|
||||||
CertificationType.StandardAssault,
|
CertificationType.StandardAssault,
|
||||||
CertificationType.ArmoredAssault1,
|
|
||||||
CertificationType.MediumAssault,
|
|
||||||
CertificationType.ReinforcedExoSuit,
|
|
||||||
CertificationType.Harasser,
|
|
||||||
CertificationType.Engineering,
|
|
||||||
CertificationType.GroundSupport,
|
|
||||||
CertificationType.AgileExoSuit,
|
CertificationType.AgileExoSuit,
|
||||||
CertificationType.AIMAX,
|
CertificationType.StandardExoSuit
|
||||||
CertificationType.StandardExoSuit,
|
|
||||||
CertificationType.AAMAX,
|
|
||||||
CertificationType.ArmoredAssault2
|
|
||||||
),
|
),
|
||||||
9,
|
37,
|
||||||
0,
|
5,
|
||||||
PlanetSideGUID(1)
|
PlanetSideGUID(7)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
sendResponse(SquadInvitationRequestMessage(PlanetSideGUID(1), 9, 41577140L, "Degrado"))
|
sendResponse(SquadInvitationRequestMessage(PlanetSideGUID(1), 4, 41577140L, "Degrado"))
|
||||||
}
|
}
|
||||||
player.Position = pos
|
player.Position = pos
|
||||||
player.Velocity = vel
|
player.Velocity = vel
|
||||||
|
|
@ -9136,6 +9116,56 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def SwapSquadUIElements(squad : Squad, fromIndex : Int, toIndex : Int) : Unit = {
|
||||||
|
if(squadUI.nonEmpty) {
|
||||||
|
val fromMember = squad.Membership(fromIndex)
|
||||||
|
val fromCharId = fromMember.CharId
|
||||||
|
val toMember = squad.Membership(toIndex)
|
||||||
|
val toCharId = toMember.CharId
|
||||||
|
val id = 11
|
||||||
|
if(fromCharId > 0) {
|
||||||
|
//toMember and fromMember have swapped places
|
||||||
|
val fromElem = squadUI(fromCharId)
|
||||||
|
val toElem = squadUI(toCharId)
|
||||||
|
sendResponse(SquadMemberEvent.Remove(id, toCharId, fromIndex))
|
||||||
|
sendResponse(SquadMemberEvent.Remove(id, fromCharId, toIndex))
|
||||||
|
squadUI(toCharId) = SquadUIElement(fromElem.name, toIndex, fromElem.zone, fromElem.health, fromElem.armor, fromElem.position)
|
||||||
|
squadUI(fromCharId) = SquadUIElement(toElem.name, fromIndex, toElem.zone, toElem.health, toElem.armor, toElem.position)
|
||||||
|
sendResponse(SquadMemberEvent.Add(id, toCharId, toIndex, fromElem.name, fromElem.zone, unk7 = 0))
|
||||||
|
sendResponse(SquadMemberEvent.Add(id, fromCharId, fromIndex, toElem.name, toElem.zone, unk7 = 0))
|
||||||
|
sendResponse(
|
||||||
|
SquadState(
|
||||||
|
PlanetSideGUID(id),
|
||||||
|
List(
|
||||||
|
SquadStateInfo(fromCharId, toElem.health, toElem.armor, toElem.position, 2, 2, false, 429, None, None),
|
||||||
|
SquadStateInfo(toCharId, fromElem.health, fromElem.armor, fromElem.position, 2, 2, false, 429, None, None)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//previous fromMember has moved toMember
|
||||||
|
val elem = squadUI(toCharId)
|
||||||
|
sendResponse(SquadMemberEvent.Remove(id, toCharId, fromIndex))
|
||||||
|
squadUI(toCharId) = SquadUIElement(elem.name, toIndex, elem.zone, elem.health, elem.armor, elem.position)
|
||||||
|
sendResponse(SquadMemberEvent.Add(id, toCharId, toIndex, elem.name, elem.zone, unk7 = 0))
|
||||||
|
sendResponse(
|
||||||
|
SquadState(
|
||||||
|
PlanetSideGUID(id),
|
||||||
|
List(SquadStateInfo(toCharId, elem.health, elem.armor, elem.position, 2, 2, false, 429, None, None))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val charId = avatar.CharId
|
||||||
|
if(toCharId == charId) {
|
||||||
|
sendResponse(PlanetsideAttributeMessage(player.GUID, 32, toIndex))
|
||||||
|
}
|
||||||
|
else if(fromCharId == charId) {
|
||||||
|
sendResponse(PlanetsideAttributeMessage(player.GUID, 32, fromIndex))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def failWithError(error : String) = {
|
def failWithError(error : String) = {
|
||||||
log.error(error)
|
log.error(error)
|
||||||
sendResponse(ConnectionClose())
|
sendResponse(ConnectionClose())
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue