mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-04-22 20:35:21 +00:00
initial work on SquadInvitationRequestMessage packet, originally by aphedox; initial work on packet and tests for CharacterKnowledgeMessage; re-organization of SquadService workflow; prototyping for SquadSwitchboard
This commit is contained in:
parent
f81c87ce22
commit
24691ec239
8 changed files with 765 additions and 393 deletions
|
|
@ -595,8 +595,8 @@ object GamePacketOpcode extends Enumeration {
|
||||||
case 0xe8 => game.SquadDetailDefinitionUpdateMessage.decode
|
case 0xe8 => game.SquadDetailDefinitionUpdateMessage.decode
|
||||||
case 0xe9 => noDecoder(TacticsMessage)
|
case 0xe9 => noDecoder(TacticsMessage)
|
||||||
case 0xea => noDecoder(RabbitUpdateMessage)
|
case 0xea => noDecoder(RabbitUpdateMessage)
|
||||||
case 0xeb => noDecoder(SquadInvitationRequestMessage)
|
case 0xeb => game.SquadInvitationRequestMessage.decode
|
||||||
case 0xec => noDecoder(CharacterKnowledgeMessage)
|
case 0xec => game.CharacterKnowledgeMessage.decode
|
||||||
case 0xed => noDecoder(GameScoreUpdateMessage)
|
case 0xed => noDecoder(GameScoreUpdateMessage)
|
||||||
case 0xee => noDecoder(UnknownMessage238)
|
case 0xee => noDecoder(UnknownMessage238)
|
||||||
case 0xef => noDecoder(OrderTerminalBugMessage)
|
case 0xef => noDecoder(OrderTerminalBugMessage)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
// Copyright (c) 2019 PSForever
|
||||||
|
package net.psforever.packet.game
|
||||||
|
|
||||||
|
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
||||||
|
import net.psforever.types.CertificationType
|
||||||
|
import scodec.Codec
|
||||||
|
import scodec.codecs._
|
||||||
|
import shapeless.{::, HNil}
|
||||||
|
|
||||||
|
final case class CharacterKnowledgeInfo(name : String,
|
||||||
|
permissions : Set[CertificationType.Value],
|
||||||
|
unk1 : Int,
|
||||||
|
unk2 : Int,
|
||||||
|
unk3 : PlanetSideGUID)
|
||||||
|
|
||||||
|
final case class CharacterKnowledgeMessage(char_id : Long,
|
||||||
|
info : Option[CharacterKnowledgeInfo])
|
||||||
|
extends PlanetSideGamePacket {
|
||||||
|
type Packet = CharacterKnowledgeMessage
|
||||||
|
def opcode = GamePacketOpcode.CharacterKnowledgeMessage
|
||||||
|
def encode = CharacterKnowledgeMessage.encode(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
object CharacterKnowledgeMessage extends Marshallable[CharacterKnowledgeMessage] {
|
||||||
|
def apply(char_id : Long) : CharacterKnowledgeMessage =
|
||||||
|
CharacterKnowledgeMessage(char_id, None)
|
||||||
|
|
||||||
|
def apply(char_id : Long, info : CharacterKnowledgeInfo) : CharacterKnowledgeMessage =
|
||||||
|
CharacterKnowledgeMessage(char_id, Some(info))
|
||||||
|
|
||||||
|
private val inverter : Codec[Boolean] = bool.xmap[Boolean] (
|
||||||
|
state => !state,
|
||||||
|
state => !state
|
||||||
|
)
|
||||||
|
|
||||||
|
private val info_codec : Codec[CharacterKnowledgeInfo] = (
|
||||||
|
("name" | PacketHelpers.encodedWideStringAligned(adjustment = 7)) ::
|
||||||
|
("permissions" | ulongL(bits = 46)) ::
|
||||||
|
("unk1" | uint(bits = 6)) ::
|
||||||
|
("unk2" | uint(bits = 3)) ::
|
||||||
|
("unk3" | PlanetSideGUID.codec)
|
||||||
|
).xmap[CharacterKnowledgeInfo] (
|
||||||
|
{
|
||||||
|
case name :: permissions :: u1 :: u2 :: u3 :: HNil =>
|
||||||
|
CharacterKnowledgeInfo(name, CertificationType.fromEncodedLong(permissions), u1, u2, u3)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
case CharacterKnowledgeInfo(name, permissions, u1, u2, u3) =>
|
||||||
|
name :: CertificationType.toEncodedLong(permissions) :: u1 :: u2 :: u3 :: HNil
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
implicit val codec : Codec[CharacterKnowledgeMessage] = (
|
||||||
|
("char_id" | uint32L) ::
|
||||||
|
("info" | optional(inverter, info_codec))
|
||||||
|
).as[CharacterKnowledgeMessage]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
// Copyright (c) 2019 PSForever
|
||||||
|
package net.psforever.packet.game
|
||||||
|
|
||||||
|
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
||||||
|
import scodec.Codec
|
||||||
|
import scodec.codecs._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message for communicating squad invitation.
|
||||||
|
* When received by a client, the event message "You have invited `name` to join your squad" is produced
|
||||||
|
* and a `SquadMembershipRequest` packet of type `Invite`
|
||||||
|
* using `char_id` as the optional unique character identifier field is dispatched to the server.
|
||||||
|
* The message is equivalent to a dispatched packet of type `SquadMembershipResponse`
|
||||||
|
* with an `Invite` event with the referral field set to `true`.
|
||||||
|
* @see `SquadMembershipResponse`
|
||||||
|
* @param squad_guid the squad's GUID
|
||||||
|
* @param slot a potentially valid slot index;
|
||||||
|
* 0-9; higher numbers produce no response
|
||||||
|
* @param char_id the unique character identifier
|
||||||
|
* @param name the character's name;
|
||||||
|
* frequently, though that does not produce a coherent message,
|
||||||
|
* the avatar's own name is supplied in the event message instead of the name of another player
|
||||||
|
*/
|
||||||
|
final case class SquadInvitationRequestMessage(squad_guid : PlanetSideGUID,
|
||||||
|
slot : Int,
|
||||||
|
char_id : Long,
|
||||||
|
name : String)
|
||||||
|
extends PlanetSideGamePacket {
|
||||||
|
type Packet = SquadInvitationRequestMessage
|
||||||
|
def opcode = GamePacketOpcode.SquadInvitationRequestMessage
|
||||||
|
def encode = SquadInvitationRequestMessage.encode(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
object SquadInvitationRequestMessage extends Marshallable[SquadInvitationRequestMessage] {
|
||||||
|
implicit val codec : Codec[SquadInvitationRequestMessage] = (
|
||||||
|
("squad_guid" | PlanetSideGUID.codec) ::
|
||||||
|
("slot" | uint4) ::
|
||||||
|
("char_id" | uint32L) ::
|
||||||
|
("name" | PacketHelpers.encodedWideStringAligned(adjustment = 4))
|
||||||
|
).as[SquadInvitationRequestMessage]
|
||||||
|
}
|
||||||
|
|
@ -21,7 +21,7 @@ object SquadResponse {
|
||||||
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 SwapMember(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 Detail(guid : PlanetSideGUID, leader : String, task : String, zone : PlanetSideZoneID, member_info : List[SquadPositionDetail]) extends Response
|
final case class Detail(guid : PlanetSideGUID, squad_detail : SquadDetail) extends Response
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
142
common/src/main/scala/services/teamwork/SquadSwitchboard.scala
Normal file
142
common/src/main/scala/services/teamwork/SquadSwitchboard.scala
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
// Copyright (c) 2019 PSForever
|
||||||
|
package services.teamwork
|
||||||
|
|
||||||
|
import akka.actor.{Actor, ActorRef, Terminated}
|
||||||
|
|
||||||
|
import scala.collection.mutable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The dedicated messaging switchboard for members and observers of a given squad.
|
||||||
|
* It almost always dispatches messages to `WorldSessionActor` instances, much like any other `Service`.
|
||||||
|
* The sole purpose of this `ActorBus` container is to manage a subscription model
|
||||||
|
* that can involuntarily drop subscribers without informing them explicitly
|
||||||
|
* or can just vanish without having to properly clean itself up.
|
||||||
|
*/
|
||||||
|
class SquadSwitchboard extends Actor {
|
||||||
|
/**
|
||||||
|
* This collection contains the message-sending contact reference for squad members.
|
||||||
|
* Users are added to this collection via the `SquadSwitchboard.Join` message, or a
|
||||||
|
* combination of the `SquadSwitchboard.DelayJoin` message followed by a
|
||||||
|
* `SquadSwitchboard.Join` message with or without an `ActorRef` hook.
|
||||||
|
* The message `SquadSwitchboard.Leave` removes the user from this collection.
|
||||||
|
* key - unique character id; value - `Actor` reference for that character
|
||||||
|
*/
|
||||||
|
val UserActorMap : mutable.LongMap[ActorRef] = mutable.LongMap[ActorRef]()
|
||||||
|
/**
|
||||||
|
* This collection contains the message-sending contact information for would-be squad members.
|
||||||
|
* Users are added to this collection via the `SquadSwitchboard.DelayJoin` message
|
||||||
|
* and are promoted to an actual squad member through a `SquadSwitchboard.Join` message.
|
||||||
|
* The message `SquadSwitchboard.Leave` removes the user from this collection.
|
||||||
|
* key - unique character id; value - `Actor` reference for that character
|
||||||
|
*/
|
||||||
|
val DelayedJoin : mutable.LongMap[ActorRef] = mutable.LongMap[ActorRef]()
|
||||||
|
/**
|
||||||
|
* This collection contains the message-sending contact information for squad observers.
|
||||||
|
* Squad observers only get "details" messages as opposed to the sort of messages squad members receive.
|
||||||
|
* Squad observers are promoted to an actual squad member through a `SquadSwitchboard.Watch` message.
|
||||||
|
* The message `SquadSwitchboard.Leave` removes the user from this collection.
|
||||||
|
* The message `SquadSwitchboard.Unwatch` also removes the user from this collection.
|
||||||
|
* key - unique character id; value - `Actor` reference for that character
|
||||||
|
*/
|
||||||
|
val Watchers : mutable.LongMap[ActorRef] = mutable.LongMap[ActorRef]()
|
||||||
|
|
||||||
|
override def postStop() : Unit = {
|
||||||
|
UserActorMap.clear()
|
||||||
|
DelayedJoin.clear()
|
||||||
|
Watchers.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
def receive : Receive = {
|
||||||
|
case SquadSwitchboard.Join(char_id, Some(actor)) =>
|
||||||
|
UserActorMap(char_id) = DelayedJoin.remove(char_id).orElse( Watchers.remove(char_id)) match {
|
||||||
|
case Some(_actor) =>
|
||||||
|
context.watch(_actor)
|
||||||
|
_actor
|
||||||
|
case None =>
|
||||||
|
context.watch(actor)
|
||||||
|
actor
|
||||||
|
}
|
||||||
|
|
||||||
|
case SquadSwitchboard.Join(char_id, None) =>
|
||||||
|
DelayedJoin.remove(char_id).orElse( Watchers.remove(char_id)) match {
|
||||||
|
case Some(actor) =>
|
||||||
|
UserActorMap(char_id) = actor
|
||||||
|
case None => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SquadSwitchboard.DelayJoin(char_id, actor) =>
|
||||||
|
context.watch(actor)
|
||||||
|
DelayedJoin(char_id) = actor
|
||||||
|
|
||||||
|
case SquadSwitchboard.Leave(char_id) =>
|
||||||
|
UserActorMap.find { case(charId, _) => charId == char_id }
|
||||||
|
.orElse(DelayedJoin.find { case(charId, _) => charId == char_id })
|
||||||
|
.orElse(Watchers.find { case(charId, _) => charId == char_id }) match {
|
||||||
|
case Some((member, actor)) =>
|
||||||
|
context.unwatch(actor)
|
||||||
|
UserActorMap.remove(member)
|
||||||
|
DelayedJoin.remove(member)
|
||||||
|
Watchers.remove(member)
|
||||||
|
case None => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SquadSwitchboard.Watch(char_id, actor) =>
|
||||||
|
context.watch(actor)
|
||||||
|
Watchers(char_id) = actor
|
||||||
|
|
||||||
|
case SquadSwitchboard.Unwatch(char_id) =>
|
||||||
|
Watchers.remove(char_id)
|
||||||
|
|
||||||
|
case SquadSwitchboard.To(member, msg) =>
|
||||||
|
UserActorMap.find { case (char_id, _) => char_id == member } match {
|
||||||
|
case Some((_, actor)) =>
|
||||||
|
actor ! msg
|
||||||
|
case None => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SquadSwitchboard.ToAll(msg) =>
|
||||||
|
UserActorMap
|
||||||
|
.foreach { case (_, actor) =>
|
||||||
|
actor ! msg
|
||||||
|
}
|
||||||
|
|
||||||
|
case SquadSwitchboard.Except(excluded, msg) =>
|
||||||
|
UserActorMap
|
||||||
|
.filterNot { case (char_id, _) => char_id == excluded }
|
||||||
|
.foreach { case (_, actor) =>
|
||||||
|
actor ! msg
|
||||||
|
}
|
||||||
|
|
||||||
|
case Terminated(actorRef) =>
|
||||||
|
UserActorMap.find { case(_, ref) => ref == actorRef }
|
||||||
|
.orElse(DelayedJoin.find { case(_, ref) => ref == actorRef })
|
||||||
|
.orElse(Watchers.find { case(_, ref) => ref == actorRef }) match {
|
||||||
|
case Some((member, actor)) =>
|
||||||
|
context.unwatch(actor)
|
||||||
|
UserActorMap.remove(member)
|
||||||
|
DelayedJoin.remove(member)
|
||||||
|
Watchers.remove(member)
|
||||||
|
case None => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object SquadSwitchboard {
|
||||||
|
final case class Join(char_id : Long, actor : Option[ActorRef])
|
||||||
|
|
||||||
|
final case class DelayJoin(char_id : Long, actor : ActorRef)
|
||||||
|
|
||||||
|
final case class Leave(char_id : Long)
|
||||||
|
|
||||||
|
final case class Watch(char_id : Long, actor : ActorRef)
|
||||||
|
|
||||||
|
final case class Unwatch(char_id : Long)
|
||||||
|
|
||||||
|
final case class To(member : Long, msg : SquadServiceResponse)
|
||||||
|
|
||||||
|
final case class ToAll(msg : SquadServiceResponse)
|
||||||
|
|
||||||
|
final case class Except(excluded_member : Long, msg : SquadServiceResponse)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package game
|
||||||
|
|
||||||
|
import org.specs2.mutable._
|
||||||
|
import net.psforever.packet._
|
||||||
|
import net.psforever.packet.game._
|
||||||
|
import net.psforever.types.CertificationType
|
||||||
|
import scodec.bits._
|
||||||
|
|
||||||
|
class CharacterKnowledgeMessageTest extends Specification {
|
||||||
|
val string = hex"ec cc637a02 45804600720061006e006b0065006e00740061006e006b0003c022dc0008f01800"
|
||||||
|
|
||||||
|
"decode" in {
|
||||||
|
PacketCoding.DecodePacket(string).require match {
|
||||||
|
case CharacterKnowledgeMessage(char_id, Some(info)) =>
|
||||||
|
char_id mustEqual 41575372L
|
||||||
|
info mustEqual CharacterKnowledgeInfo(
|
||||||
|
"Frankentank",
|
||||||
|
Set(
|
||||||
|
CertificationType.StandardAssault,
|
||||||
|
CertificationType.ArmoredAssault1,
|
||||||
|
CertificationType.MediumAssault,
|
||||||
|
CertificationType.ReinforcedExoSuit,
|
||||||
|
CertificationType.Harasser,
|
||||||
|
CertificationType.Engineering,
|
||||||
|
CertificationType.GroundSupport,
|
||||||
|
CertificationType.AgileExoSuit,
|
||||||
|
CertificationType.AIMAX,
|
||||||
|
CertificationType.StandardExoSuit,
|
||||||
|
CertificationType.AAMAX,
|
||||||
|
CertificationType.ArmoredAssault2
|
||||||
|
),
|
||||||
|
15,
|
||||||
|
0,
|
||||||
|
PlanetSideGUID(12)
|
||||||
|
)
|
||||||
|
case _ =>
|
||||||
|
ko
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"encode" in {
|
||||||
|
val msg = CharacterKnowledgeMessage(
|
||||||
|
41575372L,
|
||||||
|
CharacterKnowledgeInfo(
|
||||||
|
"Frankentank",
|
||||||
|
Set(
|
||||||
|
CertificationType.StandardAssault,
|
||||||
|
CertificationType.ArmoredAssault1,
|
||||||
|
CertificationType.MediumAssault,
|
||||||
|
CertificationType.ReinforcedExoSuit,
|
||||||
|
CertificationType.Harasser,
|
||||||
|
CertificationType.Engineering,
|
||||||
|
CertificationType.GroundSupport,
|
||||||
|
CertificationType.AgileExoSuit,
|
||||||
|
CertificationType.AIMAX,
|
||||||
|
CertificationType.StandardExoSuit,
|
||||||
|
CertificationType.AAMAX,
|
||||||
|
CertificationType.ArmoredAssault2
|
||||||
|
),
|
||||||
|
15,
|
||||||
|
0,
|
||||||
|
PlanetSideGUID(12)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
|
pkt mustEqual string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -376,19 +376,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
case SquadResponse.Detail(guid, leader, task, zone, member_info) =>
|
case SquadResponse.Detail(guid, detail) =>
|
||||||
sendResponse(
|
sendResponse(SquadDetailDefinitionUpdateMessage(guid, detail))
|
||||||
SquadDetailDefinitionUpdateMessage(
|
|
||||||
guid,
|
|
||||||
SquadDetail()
|
|
||||||
.LeaderCharId(member_info.find(_.name.contains(leader)).get.char_id.get)
|
|
||||||
.LeaderName(leader)
|
|
||||||
.Task(task)
|
|
||||||
.ZoneId(zone)
|
|
||||||
.Members(member_info.zipWithIndex.map { case (a, b) => SquadPositionEntry(b, a) })
|
|
||||||
.Complete
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
case SquadResponse.InitSquad(squad_guid) =>
|
case SquadResponse.InitSquad(squad_guid) =>
|
||||||
sendResponse(SquadDefinitionActionMessage(squad_guid, 0, SquadAction.Unknown(16)))
|
sendResponse(SquadDefinitionActionMessage(squad_guid, 0, SquadAction.Unknown(16)))
|
||||||
|
|
@ -414,7 +403,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
membershipPositions.find({ case(member, _) => member.CharId == avatar.CharId }) match {
|
membershipPositions.find({ case(member, _) => member.CharId == avatar.CharId }) match {
|
||||||
case Some((ourMember, ourIndex)) =>
|
case Some((ourMember, ourIndex)) =>
|
||||||
//we are joining the squad
|
//we are joining the squad
|
||||||
sendResponse(SquadMembershipResponse(SquadResponseType.Accept, 0, 0, player.CharId, Some(leader.CharId), player.Name, true, Some(None)))
|
|
||||||
//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(0, id, member.CharId, index, Some(member.Name), Some(member.ZoneId), Some(0)))
|
||||||
|
|
@ -447,7 +435,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
positionsToUpdate.find({ case(member, _) => member == avatar.CharId }) match {
|
positionsToUpdate.find({ case(member, _) => member == avatar.CharId }) match {
|
||||||
case Some((ourMember, ourIndex)) =>
|
case Some((ourMember, ourIndex)) =>
|
||||||
//we are leaving the squad
|
//we are leaving the squad
|
||||||
sendResponse(SquadMembershipResponse(SquadResponseType.Leave, 0,1, avatar.CharId, Some(avatar.CharId), avatar.name, true, Some(None)))
|
|
||||||
//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(1, id, member, index, None, None, None))
|
||||||
|
|
@ -498,23 +485,53 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
case SquadResponse.SwapMember(squad, to_index, from_index) =>
|
case SquadResponse.AssignMember(squad, from_index, to_index) =>
|
||||||
//this failsafe is not supported by normal squad member operations
|
if(squadUI.nonEmpty) {
|
||||||
val member = squad.Membership(to_index)
|
val toMember = squad.Membership(to_index)
|
||||||
val charId = member.CharId
|
val toCharId = toMember.CharId
|
||||||
val elem = squadUI(charId)
|
val fromMember = squad.Membership(from_index)
|
||||||
val id = 11
|
val fromCharId = fromMember.CharId
|
||||||
squadUI(charId) = SquadUIElement(elem.name, to_index, elem.zone, elem.health, elem.armor, elem.position)
|
val id = 11
|
||||||
sendResponse(SquadMemberEvent(1, id, charId, from_index, None, None, None))
|
if(fromCharId > 0) {
|
||||||
sendResponse(SquadMemberEvent(0, id, charId, to_index, Some(elem.name), Some(elem.zone), Some(0)))
|
//toMember and fromMember have swapped places
|
||||||
sendResponse(
|
val fromElem = squadUI(fromCharId)
|
||||||
SquadState(
|
val toElem = squadUI(toCharId)
|
||||||
PlanetSideGUID(id),
|
sendResponse(SquadMemberEvent(1, id, toCharId, from_index, None, None, None))
|
||||||
List(SquadStateInfo(charId, elem.health, elem.armor, elem.position, 2,2, false, 429, None,None))
|
sendResponse(SquadMemberEvent(1, id, fromCharId, to_index, None, None, None))
|
||||||
)
|
squadUI(toCharId) = SquadUIElement(fromElem.name, to_index, fromElem.zone, fromElem.health, fromElem.armor, fromElem.position)
|
||||||
)
|
squadUI(fromCharId) = SquadUIElement(toElem.name, from_index, toElem.zone, toElem.health, toElem.armor, toElem.position)
|
||||||
if(charId == avatar.CharId) {
|
sendResponse(SquadMemberEvent(0, id, toCharId, to_index, Some(fromElem.name), Some(fromElem.zone), Some(0)))
|
||||||
sendResponse(PlanetsideAttributeMessage(player.GUID, 32, to_index))
|
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 _ => ;
|
||||||
|
|
@ -3454,7 +3471,32 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case msg @ PlayerStateMessageUpstream(avatar_guid, pos, vel, yaw, pitch, yaw_upper, seq_time, unk3, is_crouching, is_jumping, unk4, is_cloaking, unk5, unk6) =>
|
case msg @ PlayerStateMessageUpstream(avatar_guid, pos, vel, yaw, pitch, yaw_upper, seq_time, unk3, is_crouching, is_jumping, unk4, is_cloaking, unk5, unk6) =>
|
||||||
if(deadState == DeadState.Alive) {
|
if(deadState == DeadState.Alive) {
|
||||||
if(!player.Crouching && is_crouching) { //SQUAD TESTING CODE
|
if(!player.Crouching && is_crouching) { //SQUAD TESTING CODE
|
||||||
sendResponse(SquadMembershipResponse(SquadResponseType.Unk01, 0, 0, player.CharId, None, "Dummy", false, Some(None)))
|
sendResponse(
|
||||||
|
CharacterKnowledgeMessage(
|
||||||
|
41577140L,
|
||||||
|
CharacterKnowledgeInfo(
|
||||||
|
"Degrado",
|
||||||
|
Set(
|
||||||
|
CertificationType.StandardAssault,
|
||||||
|
CertificationType.ArmoredAssault1,
|
||||||
|
CertificationType.MediumAssault,
|
||||||
|
CertificationType.ReinforcedExoSuit,
|
||||||
|
CertificationType.Harasser,
|
||||||
|
CertificationType.Engineering,
|
||||||
|
CertificationType.GroundSupport,
|
||||||
|
CertificationType.AgileExoSuit,
|
||||||
|
CertificationType.AIMAX,
|
||||||
|
CertificationType.StandardExoSuit,
|
||||||
|
CertificationType.AAMAX,
|
||||||
|
CertificationType.ArmoredAssault2
|
||||||
|
),
|
||||||
|
9,
|
||||||
|
0,
|
||||||
|
PlanetSideGUID(1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
sendResponse(SquadInvitationRequestMessage(PlanetSideGUID(1), 9, 41577140L, "Degrado"))
|
||||||
}
|
}
|
||||||
player.Position = pos
|
player.Position = pos
|
||||||
player.Velocity = vel
|
player.Velocity = vel
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue