evict players from the outfit. no longer shall you spy on our stale info!

update packet types
This commit is contained in:
Resaec 2025-08-31 03:05:31 +02:00
parent 8dcf678045
commit c84bf9ae74
12 changed files with 163 additions and 119 deletions

View file

@ -30,7 +30,7 @@ import net.psforever.objects.vehicles.Utility
import net.psforever.objects.vital.Vitality import net.psforever.objects.vital.Vitality
import net.psforever.objects.zones.{ZoneProjectile, Zoning} import net.psforever.objects.zones.{ZoneProjectile, Zoning}
import net.psforever.packet.PlanetSideGamePacket import net.psforever.packet.PlanetSideGamePacket
import net.psforever.packet.game.OutfitEventAction.{OutfitInfo, OutfitRankNames, Unk0, Unk1} import net.psforever.packet.game.OutfitEventAction.{OutfitInfo, OutfitRankNames, Initial, Unk1}
import net.psforever.packet.game.{ActionCancelMessage, AvatarFirstTimeEventMessage, AvatarImplantMessage, AvatarJumpMessage, BattleplanMessage, BindPlayerMessage, BugReportMessage, ChangeFireModeMessage, ChangeShortcutBankMessage, CharacterCreateRequestMessage, CharacterRequestMessage, ChatMsg, CollisionIs, ConnectToWorldRequestMessage, CreateShortcutMessage, DeadState, DeployObjectMessage, DisplayedAwardMessage, DropItemMessage, EmoteMsg, FacilityBenefitShieldChargeRequestMessage, FriendsRequest, GenericAction, GenericActionMessage, GenericCollisionMsg, GenericObjectActionAtPositionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HitHint, InvalidTerrainMessage, LootItemMessage, MoveItemMessage, ObjectDetectedMessage, ObjectHeldMessage, OutfitEvent, OutfitMemberEvent, OutfitMembershipRequest, OutfitMembershipResponse, OutfitRequest, OutfitRequestAction, PickupItemMessage, PlanetsideAttributeMessage, PlayerStateMessageUpstream, RequestDestroyMessage, TargetingImplantRequest, TerrainCondition, TradeMessage, UnuseItemMessage, UseItemMessage, VoiceHostInfo, VoiceHostRequest, ZipLineMessage} import net.psforever.packet.game.{ActionCancelMessage, AvatarFirstTimeEventMessage, AvatarImplantMessage, AvatarJumpMessage, BattleplanMessage, BindPlayerMessage, BugReportMessage, ChangeFireModeMessage, ChangeShortcutBankMessage, CharacterCreateRequestMessage, CharacterRequestMessage, ChatMsg, CollisionIs, ConnectToWorldRequestMessage, CreateShortcutMessage, DeadState, DeployObjectMessage, DisplayedAwardMessage, DropItemMessage, EmoteMsg, FacilityBenefitShieldChargeRequestMessage, FriendsRequest, GenericAction, GenericActionMessage, GenericCollisionMsg, GenericObjectActionAtPositionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HitHint, InvalidTerrainMessage, LootItemMessage, MoveItemMessage, ObjectDetectedMessage, ObjectHeldMessage, OutfitEvent, OutfitMemberEvent, OutfitMembershipRequest, OutfitMembershipResponse, OutfitRequest, OutfitRequestAction, PickupItemMessage, PlanetsideAttributeMessage, PlayerStateMessageUpstream, RequestDestroyMessage, TargetingImplantRequest, TerrainCondition, TradeMessage, UnuseItemMessage, UseItemMessage, VoiceHostInfo, VoiceHostRequest, ZipLineMessage}
import net.psforever.services.RemoverActor import net.psforever.services.RemoverActor
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
@ -673,9 +673,9 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
def handleOutfitRequest(pkt: OutfitRequest): Unit = { def handleOutfitRequest(pkt: OutfitRequest): Unit = {
pkt match { pkt match {
case OutfitRequest(_, OutfitRequestAction.Unk3(true)) => case OutfitRequest(_, OutfitRequestAction.OutfitWindowOpen(true)) =>
case OutfitRequest(_, OutfitRequestAction.Unk3(false)) => case OutfitRequest(_, OutfitRequestAction.OutfitWindowOpen(false)) =>
case _ => case _ =>
} }

View file

@ -37,7 +37,7 @@ import net.psforever.objects.vital.etc.SuicideReason
import net.psforever.objects.vital.interaction.DamageInteraction import net.psforever.objects.vital.interaction.DamageInteraction
import net.psforever.objects.zones.{ZoneProjectile, Zoning} import net.psforever.objects.zones.{ZoneProjectile, Zoning}
import net.psforever.packet.PlanetSideGamePacket import net.psforever.packet.PlanetSideGamePacket
import net.psforever.packet.game.OutfitEventAction.{OutfitInfo, OutfitRankNames, Unk2} import net.psforever.packet.game.OutfitEventAction.{OutfitInfo, OutfitRankNames, Update}
import net.psforever.packet.game.{ActionCancelMessage, ActionResultMessage, AvatarFirstTimeEventMessage, AvatarImplantMessage, AvatarJumpMessage, BattleplanMessage, BindPlayerMessage, BugReportMessage, ChangeFireModeMessage, ChangeShortcutBankMessage, CharacterCreateRequestMessage, CharacterRequestAction, CharacterRequestMessage, ChatMsg, CollisionIs, ConnectToWorldRequestMessage, CreateShortcutMessage, DeadState, DeployObjectMessage, DisplayedAwardMessage, DropItemMessage, EmoteMsg, FacilityBenefitShieldChargeRequestMessage, FriendsRequest, GenericAction, GenericActionMessage, GenericCollisionMsg, GenericObjectActionAtPositionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HitHint, InvalidTerrainMessage, LootItemMessage, MoveItemMessage, ObjectDetectedMessage, ObjectHeldMessage, OutfitEvent, OutfitMembershipRequest, OutfitMembershipRequestAction, OutfitMembershipResponse, OutfitRequest, OutfitRequestAction, PickupItemMessage, PlanetsideAttributeMessage, PlayerStateMessageUpstream, RequestDestroyMessage, TargetingImplantRequest, TerrainCondition, TradeMessage, UnuseItemMessage, UseItemMessage, VoiceHostInfo, VoiceHostRequest, ZipLineMessage} import net.psforever.packet.game.{ActionCancelMessage, ActionResultMessage, AvatarFirstTimeEventMessage, AvatarImplantMessage, AvatarJumpMessage, BattleplanMessage, BindPlayerMessage, BugReportMessage, ChangeFireModeMessage, ChangeShortcutBankMessage, CharacterCreateRequestMessage, CharacterRequestAction, CharacterRequestMessage, ChatMsg, CollisionIs, ConnectToWorldRequestMessage, CreateShortcutMessage, DeadState, DeployObjectMessage, DisplayedAwardMessage, DropItemMessage, EmoteMsg, FacilityBenefitShieldChargeRequestMessage, FriendsRequest, GenericAction, GenericActionMessage, GenericCollisionMsg, GenericObjectActionAtPositionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HitHint, InvalidTerrainMessage, LootItemMessage, MoveItemMessage, ObjectDetectedMessage, ObjectHeldMessage, OutfitEvent, OutfitMembershipRequest, OutfitMembershipRequestAction, OutfitMembershipResponse, OutfitRequest, OutfitRequestAction, PickupItemMessage, PlanetsideAttributeMessage, PlayerStateMessageUpstream, RequestDestroyMessage, TargetingImplantRequest, TerrainCondition, TradeMessage, UnuseItemMessage, UseItemMessage, VoiceHostInfo, VoiceHostRequest, ZipLineMessage}
import net.psforever.services.account.{AccountPersistenceService, RetrieveAccountData} import net.psforever.services.account.{AccountPersistenceService, RetrieveAccountData}
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
@ -836,12 +836,12 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
case OutfitRequest(_, OutfitRequestAction.Ranks(List(r1, r2, r3, r4, r5, r6, r7, r8))) => case OutfitRequest(_, OutfitRequestAction.Ranks(List(r1, r2, r3, r4, r5, r6, r7, r8))) =>
SessionOutfitHandlers.HandleOutfitRank(zones, List(r1, r2, r3, r4, r5, r6, r7, r8), player) SessionOutfitHandlers.HandleOutfitRank(zones, List(r1, r2, r3, r4, r5, r6, r7, r8), player)
case OutfitRequest(_, OutfitRequestAction.Unk3(true)) => case OutfitRequest(_, OutfitRequestAction.OutfitWindowOpen(true)) =>
SessionOutfitHandlers.HandleViewOutfitWindow(zones, player, player.outfit_id) SessionOutfitHandlers.HandleViewOutfitWindow(zones, player, player.outfit_id)
case OutfitRequest(_, OutfitRequestAction.Unk3(false)) => case OutfitRequest(_, OutfitRequestAction.OutfitWindowOpen(false)) =>
case OutfitRequest(_, OutfitRequestAction.Unk4(true)) => case OutfitRequest(_, OutfitRequestAction.OutfitListWindowOpen(true)) =>
SessionOutfitHandlers.HandleGetOutfitList(player) SessionOutfitHandlers.HandleGetOutfitList(player)
case _ => case _ =>

View file

@ -5,7 +5,7 @@ import io.getquill.{ActionReturning, EntityQuery, Insert, PostgresJAsyncContext,
import net.psforever.objects.avatar.PlayerControl import net.psforever.objects.avatar.PlayerControl
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.objects.Player import net.psforever.objects.Player
import net.psforever.packet.game.OutfitEventAction.{OutfitInfo, OutfitRankNames, Unk0, Unk1, Unk2} import net.psforever.packet.game.OutfitEventAction.{Leaving, OutfitInfo, OutfitRankNames, Initial, Unk1, Update, UpdateMemberCount}
import net.psforever.packet.game.OutfitMembershipResponse.PacketType.CreateResponse import net.psforever.packet.game.OutfitMembershipResponse.PacketType.CreateResponse
import net.psforever.packet.game._ import net.psforever.packet.game._
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
@ -63,7 +63,7 @@ object SessionOutfitHandlers {
outfit.created.atZone(java.time.ZoneOffset.UTC).toInstant.toEpochMilli / 1000 outfit.created.atZone(java.time.ZoneOffset.UTC).toInstant.toEpochMilli / 1000
PlayerControl.sendResponse(player.Zone, player.Name, PlayerControl.sendResponse(player.Zone, player.Name,
OutfitEvent(outfit.id, Unk2( OutfitEvent(outfit.id, Update(
OutfitInfo( OutfitInfo(
outfit.name, 0, 0, 1, outfit.name, 0, 0, 1,
OutfitRankNames("", "", "", "", "", "", "", ""), OutfitRankNames("", "", "", "", "", "", "", ""),
@ -143,16 +143,16 @@ object SessionOutfitHandlers {
invited.CharId, outfitInvite.sentFrom.CharId, invited.Name, outfit.name, flag = true)) invited.CharId, outfitInvite.sentFrom.CharId, invited.Name, outfit.name, flag = true))
PlayerControl.sendResponse(outfitInvite.sentFrom.Zone, outfitInvite.sentFrom.Name, PlayerControl.sendResponse(outfitInvite.sentFrom.Zone, outfitInvite.sentFrom.Name,
OutfitEvent(outfitId, OutfitEventAction.Unk5(memberCount))) OutfitEvent(outfitId, UpdateMemberCount(memberCount)))
PlayerControl.sendResponse(outfitInvite.sentFrom.Zone, outfitInvite.sentFrom.Name, PlayerControl.sendResponse(outfitInvite.sentFrom.Zone, outfitInvite.sentFrom.Name,
OutfitMemberEvent(outfitId, invited.CharId, OutfitMemberEvent(outfitId, invited.CharId,
OutfitMemberEventAction.Unk0(invited.Name, 0, 0, 0, OutfitMemberEventAction.Update(invited.Name, 0, 0, 0,
OutfitMemberEventAction.PacketType.Padding, 0))) OutfitMemberEventAction.PacketType.Padding, 0)))
val seconds: Long = outfit.created.atZone(java.time.ZoneOffset.UTC).toInstant.toEpochMilli / 1000 val seconds: Long = outfit.created.atZone(java.time.ZoneOffset.UTC).toInstant.toEpochMilli / 1000
PlayerControl.sendResponse(invited.Zone, invited.Name, PlayerControl.sendResponse(invited.Zone, invited.Name,
OutfitEvent(outfitId, Unk0(OutfitInfo( OutfitEvent(outfitId, Initial(OutfitInfo(
outfit.name, points, points, memberCount, outfit.name, points, points, memberCount,
OutfitRankNames("", "", "", "", "", "", "", ""), OutfitRankNames("", "", "", "", "", "", "", ""),
outfit.motd.getOrElse(""), outfit.motd.getOrElse(""),
@ -211,12 +211,12 @@ object SessionOutfitHandlers {
case (deleted, _) => case (deleted, _) =>
if (deleted > 0) { if (deleted > 0) {
PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name, PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name,
OutfitMemberEvent(kickedBy.outfit_id, kickedId, OutfitMemberEventAction.Unk1())) OutfitMemberEvent(kickedBy.outfit_id, kickedId, OutfitMemberEventAction.Kicked()))
zones.filter(z => z.AllPlayers.nonEmpty).flatMap(_.AllPlayers) zones.filter(z => z.AllPlayers.nonEmpty).flatMap(_.AllPlayers)
.filter(p => p.outfit_id == kickedBy.outfit_id).foreach(outfitMember => .filter(p => p.outfit_id == kickedBy.outfit_id).foreach(outfitMember =>
PlayerControl.sendResponse(outfitMember.Zone, outfitMember.Name, PlayerControl.sendResponse(outfitMember.Zone, outfitMember.Name,
OutfitMemberEvent(kickedBy.outfit_id, kickedId, OutfitMemberEventAction.Unk1())) OutfitMemberEvent(kickedBy.outfit_id, kickedId, OutfitMemberEventAction.Kicked()))
) )
session.chat.LeaveChannel(OutfitChannel(kickedBy.outfit_id)) session.chat.LeaveChannel(OutfitChannel(kickedBy.outfit_id))
@ -238,8 +238,13 @@ object SessionOutfitHandlers {
case (deleted, _) => case (deleted, _) =>
if (deleted > 0) { if (deleted > 0) {
findPlayerByIdForOutfitAction(zones, kickedId, kickedBy).foreach { kicked => findPlayerByIdForOutfitAction(zones, kickedId, kickedBy).foreach { kicked =>
PlayerControl.sendResponse(kicked.Zone, kicked.Name, PlayerControl.sendResponse(kicked.Zone, kicked.Name,
OutfitMembershipResponse(OutfitMembershipResponse.PacketType.Kick, 0, 1, OutfitEvent(kickedBy.outfit_id, Leaving())
)
PlayerControl.sendResponse(kicked.Zone, kicked.Name,
OutfitMembershipResponse(OutfitMembershipResponse.PacketType.YouGotKicked, 0, 1,
kickedBy.CharId, kicked.CharId, kicked.Name, kickedBy.Name, flag = false)) kickedBy.CharId, kicked.CharId, kicked.Name, kickedBy.Name, flag = false))
kicked.Zone.AvatarEvents ! AvatarServiceMessage(kicked.Zone.id, kicked.Zone.AvatarEvents ! AvatarServiceMessage(kicked.Zone.id,
@ -251,7 +256,7 @@ object SessionOutfitHandlers {
kicked.outfit_id = 0 kicked.outfit_id = 0
kicked.outfit_name = "" kicked.outfit_name = ""
PlayerControl.sendResponse(kicked.Zone, kicked.Name, PlayerControl.sendResponse(kicked.Zone, kicked.Name,
OutfitMemberEvent(kickedBy.outfit_id, kickedId, OutfitMemberEventAction.Unk1())) OutfitMemberEvent(kickedBy.outfit_id, kickedId, OutfitMemberEventAction.Kicked()))
} }
val avatarName: Future[Option[String]] = val avatarName: Future[Option[String]] =
ctx.run( ctx.run(
@ -260,15 +265,15 @@ object SessionOutfitHandlers {
avatarName.foreach { avatarName.foreach {
case Some(name) => PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name, case Some(name) => PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name,
OutfitMembershipResponse(OutfitMembershipResponse.PacketType.Kick, 0, 1, kickedBy.CharId, kickedId, name, "", flag = true)) OutfitMembershipResponse(OutfitMembershipResponse.PacketType.YouKicked, 0, 1, kickedBy.CharId, kickedId, name, "", flag = true))
case None => PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name, case None => PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name,
OutfitMembershipResponse(OutfitMembershipResponse.PacketType.Kick, 0, 1, kickedBy.CharId, kickedId, "NameNotFound", "", flag = true)) OutfitMembershipResponse(OutfitMembershipResponse.PacketType.YouKicked, 0, 1, kickedBy.CharId, kickedId, "NameNotFound", "", flag = true))
} }
zones.filter(z => z.AllPlayers.nonEmpty).flatMap(_.AllPlayers) zones.filter(z => z.AllPlayers.nonEmpty).flatMap(_.AllPlayers)
.filter(p => p.outfit_id == kickedBy.outfit_id).foreach(outfitMember => .filter(p => p.outfit_id == kickedBy.outfit_id).foreach(outfitMember =>
PlayerControl.sendResponse(outfitMember.Zone, outfitMember.Name, PlayerControl.sendResponse(outfitMember.Zone, outfitMember.Name,
OutfitMemberEvent(kickedBy.outfit_id, kickedId, OutfitMemberEventAction.Unk1())) OutfitMemberEvent(kickedBy.outfit_id, kickedId, OutfitMemberEventAction.Kicked()))
) )
// this needs to be the kicked player // this needs to be the kicked player
// session.chat.LeaveChannel(OutfitChannel(kickedBy.outfit_id)) // session.chat.LeaveChannel(OutfitChannel(kickedBy.outfit_id))
@ -303,7 +308,7 @@ object SessionOutfitHandlers {
PlayerControl.sendResponse( PlayerControl.sendResponse(
zone, outfitMember.Name, zone, outfitMember.Name,
OutfitMemberEvent(outfit_id, promoter.avatar.id, OutfitMemberEvent(outfit_id, promoter.avatar.id,
OutfitMemberEventAction.Unk0(promoter.Name, 6, owner_points, 0, OutfitMemberEventAction.PacketType.Padding, 0))) OutfitMemberEventAction.Update(promoter.Name, 6, owner_points, 0, OutfitMemberEventAction.PacketType.Padding, 0)))
}) })
}) })
} }
@ -327,7 +332,7 @@ object SessionOutfitHandlers {
PlayerControl.sendResponse( PlayerControl.sendResponse(
zone, player.Name, zone, player.Name,
OutfitMemberEvent(outfit_id, promoted.avatar.id, OutfitMemberEvent(outfit_id, promoted.avatar.id,
OutfitMemberEventAction.Unk0(promoted.Name, newRank, member_points, 0, OutfitMemberEventAction.PacketType.Padding, 0))) OutfitMemberEventAction.Update(promoted.Name, newRank, member_points, 0, OutfitMemberEventAction.PacketType.Padding, 0)))
}) })
}) })
} }
@ -356,7 +361,7 @@ object SessionOutfitHandlers {
val seconds: Long = outfit.created.atZone(java.time.ZoneOffset.UTC).toInstant.toEpochMilli / 1000 val seconds: Long = outfit.created.atZone(java.time.ZoneOffset.UTC).toInstant.toEpochMilli / 1000
PlayerControl.sendResponse(player.Zone, player.Name, PlayerControl.sendResponse(player.Zone, player.Name,
OutfitEvent(outfit.id, Unk0(OutfitInfo( OutfitEvent(outfit.id, Initial(OutfitInfo(
outfit.name, outfit.name,
totalPoints, totalPoints,
totalPoints, totalPoints,
@ -382,7 +387,7 @@ object SessionOutfitHandlers {
} }
PlayerControl.sendResponse(player.Zone, player.Name, PlayerControl.sendResponse(player.Zone, player.Name,
OutfitMemberEvent(outfit.id, avatarId, OutfitMemberEvent(outfit.id, avatarId,
OutfitMemberEventAction.Unk0( OutfitMemberEventAction.Update(
avatarName, avatarName,
rank, rank,
points, points,
@ -438,7 +443,7 @@ object SessionOutfitHandlers {
// send to all online players in outfit // send to all online players in outfit
val outfit_event = OutfitEvent( val outfit_event = OutfitEvent(
outfit_id, outfit_id,
Unk2( Update(
OutfitInfo( OutfitInfo(
outfit_name = outfit.name, outfit_name = outfit.name,
outfit_points1 = totalPoints, outfit_points1 = totalPoints,
@ -500,7 +505,7 @@ object SessionOutfitHandlers {
// send to all online players in outfit // send to all online players in outfit
val outfit_event = OutfitEvent( val outfit_event = OutfitEvent(
outfit_id, outfit_id,
Unk2( Update(
OutfitInfo( OutfitInfo(
outfit_name = outfit.name, outfit_name = outfit.name,
outfit_points1 = totalPoints, outfit_points1 = totalPoints,
@ -555,7 +560,7 @@ object SessionOutfitHandlers {
val seconds: Long = outfit.created.atZone(java.time.ZoneOffset.UTC).toInstant.toEpochMilli / 1000 val seconds: Long = outfit.created.atZone(java.time.ZoneOffset.UTC).toInstant.toEpochMilli / 1000
PlayerControl.sendResponse(player.Zone, player.Name, PlayerControl.sendResponse(player.Zone, player.Name,
OutfitEvent(outfitId, Unk2(OutfitInfo( OutfitEvent(outfitId, Update(OutfitInfo(
outfit.name, points, points, memberCount, outfit.name, points, points, memberCount,
OutfitRankNames(outfit.rank0.getOrElse(""), outfit.rank1.getOrElse(""), outfit.rank2.getOrElse(""), OutfitRankNames(outfit.rank0.getOrElse(""), outfit.rank1.getOrElse(""), outfit.rank2.getOrElse(""),
outfit.rank3.getOrElse(""), outfit.rank4.getOrElse(""), outfit.rank5.getOrElse(""), outfit.rank3.getOrElse(""), outfit.rank4.getOrElse(""), outfit.rank5.getOrElse(""),
@ -744,7 +749,7 @@ object SessionOutfitHandlers {
} }
} }
def updateMemberRankById(outfit_id: Long, avatar_id: Long, rank: Int): Quoted[Update[Outfitmember]] = quote { def updateMemberRankById(outfit_id: Long, avatar_id: Long, rank: Int): Quoted[io.getquill.Update[Outfitmember]] = quote {
query[Outfitmember] query[Outfitmember]
.filter(_.outfit_id == lift(outfit_id)) .filter(_.outfit_id == lift(outfit_id))
.filter(_.avatar_id == lift(avatar_id)) .filter(_.avatar_id == lift(avatar_id))
@ -759,7 +764,7 @@ object SessionOutfitHandlers {
} }
} }
def updateOutfitOwnerById(outfit_id: Long, owner_id: Long): Quoted[Update[Outfit]] = quote { def updateOutfitOwnerById(outfit_id: Long, owner_id: Long): Quoted[io.getquill.Update[Outfit]] = quote {
query[Outfit] query[Outfit]
.filter(_.id == lift(outfit_id)) .filter(_.id == lift(outfit_id))
.update(_.owner_id -> lift(owner_id)) .update(_.owner_id -> lift(owner_id))
@ -775,7 +780,7 @@ object SessionOutfitHandlers {
} }
} }
def updateOutfitMotdById(outfit_id: Long, motd: Option[String]): Quoted[Update[Outfit]] = quote { def updateOutfitMotdById(outfit_id: Long, motd: Option[String]): Quoted[io.getquill.Update[Outfit]] = quote {
query[Outfit] query[Outfit]
.filter(_.id == lift(outfit_id)) .filter(_.id == lift(outfit_id))
.update(_.motd -> lift(motd)) .update(_.motd -> lift(motd))
@ -789,7 +794,7 @@ object SessionOutfitHandlers {
} }
} }
def updateOutfitRanksById(outfit_id: Long, list: List[Option[String]]): Quoted[Update[Outfit]] = { def updateOutfitRanksById(outfit_id: Long, list: List[Option[String]]): Quoted[io.getquill.Update[Outfit]] = {
// Normalize: turn empty strings into None // Normalize: turn empty strings into None
val normalized = list.map { val normalized = list.map {

View file

@ -50,26 +50,55 @@ object OutfitEventAction {
unk25: Long, unk25: Long,
) )
final case class Unk0( /**
* Initial
*
* Send at the start of an OutfitWindow info dump.
*
* Not always complete, seen as an initialization after login, join or while outfit is in formation.
* @param outfit_info
*/
final case class Initial(
outfit_info: OutfitInfo outfit_info: OutfitInfo
) extends OutfitEventAction(code = 0) ) extends OutfitEventAction(code = 0)
final case class Unk1( final case class Unk1(
) extends OutfitEventAction(code = 1) ) extends OutfitEventAction(code = 1)
final case class Unk2( /**
* Update
*
* Send after changing outfit Ranks, MOTD and other situations.
* @param outfit_info
*/
final case class Update(
outfit_info: OutfitInfo, outfit_info: OutfitInfo,
) extends OutfitEventAction(code = 2) ) extends OutfitEventAction(code = 2)
final case class Unk3( /**
* Send to players to tell them they left the outfit.
*
* Resets them to behave like they have no outfit.
* Will have them open the OutfitListWindow instead of the OutfitWindow.
*/
final case class Leaving(
) extends OutfitEventAction(code = 3) ) extends OutfitEventAction(code = 3)
/**
* Used to switch from the temporary "invalid" outfit ID used while formation to a valid ID used from that point on.
* @param new_outfit_id the new ID that represents this specific outfit in the DB
*/
final case class UpdateOutfitId( final case class UpdateOutfitId(
new_outfit_id: Long, new_outfit_id: Long,
) extends OutfitEventAction(code = 4) ) extends OutfitEventAction(code = 4)
final case class Unk5( /**
unk1: Long, * Used to tell outfit members that the member count changed.
* Send after InviteAccept or Kick actions
* @param member_count
*/
final case class UpdateMemberCount(
member_count: Long,
) extends OutfitEventAction(code = 5) ) extends OutfitEventAction(code = 5)
final case class Unknown(badCode: Int, data: BitVector) extends OutfitEventAction(badCode) final case class Unknown(badCode: Int, data: BitVector) extends OutfitEventAction(badCode)
@ -126,35 +155,35 @@ object OutfitEventAction {
} }
) )
val Unk0Codec: Codec[Unk0] = ( val Unk0Codec: Codec[Initial] = (
("outfit_info" | InfoCodec) ("outfit_info" | InfoCodec)
).xmap[Unk0]( ).xmap[Initial](
{ {
case info => case info =>
Unk0(info) Initial(info)
}, },
{ {
case Unk0(info) => case Initial(info) =>
info info
} }
) )
val Unk1Codec: Codec[Unk1] = PacketHelpers.emptyCodec(Unk1()) val Unk1Codec: Codec[Unk1] = PacketHelpers.emptyCodec(Unk1())
val Unk2Codec: Codec[Unk2] = ( val Unk2Codec: Codec[Update] = (
("outfit_info" | InfoCodec) ("outfit_info" | InfoCodec)
).xmap[Unk2]( ).xmap[Update](
{ {
case info => case info =>
Unk2(info) Update(info)
}, },
{ {
case Unk2(info) => case Update(info) =>
info info
} }
) )
val Unk3Codec: Codec[Unk3] = PacketHelpers.emptyCodec(Unk3()) val Unk3Codec: Codec[Leaving] = PacketHelpers.emptyCodec(Leaving())
val UpdateOutfitIdCodec: Codec[UpdateOutfitId] = ( // update outfit_id? // 2016.03.18 #10640 // after this packet the referenced id changes to the new one, old is not used again val UpdateOutfitIdCodec: Codec[UpdateOutfitId] = ( // update outfit_id? // 2016.03.18 #10640 // after this packet the referenced id changes to the new one, old is not used again
("new_outfit_id" | uint32L) ("new_outfit_id" | uint32L)
@ -169,15 +198,15 @@ object OutfitEventAction {
} }
) )
val Unk5Codec: Codec[Unk5] = ( val UpdateMemberCountCodec: Codec[UpdateMemberCount] = (
("" | uint32L) ("" | uint32L)
).xmap[Unk5]( ).xmap[UpdateMemberCount](
{ {
case u1 => case u1 =>
Unk5(u1) UpdateMemberCount(u1)
}, },
{ {
case Unk5(u1) => case UpdateMemberCount(u1) =>
u1 u1
} }
) )
@ -220,7 +249,7 @@ object OutfitEvent extends Marshallable[OutfitEvent] {
val Unk2: PacketType.Value = Value(2) // send after creating an outfit // normal info, same as Unk0 val Unk2: PacketType.Value = Value(2) // send after creating an outfit // normal info, same as Unk0
val Unk3: PacketType.Value = Value(3) // below val Unk3: PacketType.Value = Value(3) // below
val UpdateOutfitId: PacketType.Value = Value(4) val UpdateOutfitId: PacketType.Value = Value(4)
val Unk5: PacketType.Value = Value(5) val UpdateMemberCount: PacketType.Value = Value(5)
val Unk6: PacketType.Value = Value(6) val Unk6: PacketType.Value = Value(6)
val Unk7: PacketType.Value = Value(7) val Unk7: PacketType.Value = Value(7)
@ -237,7 +266,7 @@ object OutfitEvent extends Marshallable[OutfitEvent] {
case 2 => Unk2Codec // sent after /outfitcreate and on login if in an outfit case 2 => Unk2Codec // sent after /outfitcreate and on login if in an outfit
case 3 => Unk3Codec case 3 => Unk3Codec
case 4 => UpdateOutfitIdCodec case 4 => UpdateOutfitIdCodec
case 5 => Unk5Codec case 5 => UpdateMemberCountCodec
case 6 => unknownCodec(action = code) case 6 => unknownCodec(action = code)
case 7 => unknownCodec(action = code) case 7 => unknownCodec(action = code)

View file

@ -33,20 +33,30 @@ object OutfitMemberEventAction {
} }
/* /**
action is unimplemented! if action == 0 unk2 will contain one additional uint32L *
padding contains one uint4L of padding. may contain uint32L of unknown data depending on action * Update
*
* Update is used to inform outfit members about a new member.
* Gets send after an InviteAccept or Rank changes.
*
* @param member_name
* @param rank
* @param points client divides this by 100
* @param last_online seconds ago from current time, 0 if online
* @param action should always be 1, otherwise there will be actual data in padding. not implemented!
* @param padding should always be 0, 4 bits of padding // only contains data if action is 0
*/ */
final case class Unk0( final case class Update(
member_name: String, member_name: String,
rank: Int, rank: Int,
points: Long, // client divides this by 100 points: Long,
last_online: Long, // seconds ago from current time, 0 if online last_online: Long,
action: PacketType.Type, // should always be 1, otherwise there will be actual data in padding. not implemented! action: PacketType.Type,
padding: Int // should always be 0, 4 bits of padding // only contains data if action is 0 padding: Int
) extends OutfitMemberEventAction(code = 0) ) extends OutfitMemberEventAction(code = 0)
final case class Unk1( final case class Kicked(
) extends OutfitMemberEventAction(code = 1) ) extends OutfitMemberEventAction(code = 1)
final case class Unknown(badCode: Int, data: BitVector) extends OutfitMemberEventAction(badCode) final case class Unknown(badCode: Int, data: BitVector) extends OutfitMemberEventAction(badCode)
@ -58,25 +68,25 @@ object OutfitMemberEventAction {
object Codecs { object Codecs {
private val everFailCondition = conditional(included = false, bool) private val everFailCondition = conditional(included = false, bool)
val Unk0Codec: Codec[Unk0] = ( val UpdateCodec: Codec[Update] = (
("member_name" | PacketHelpers.encodedWideStringAligned(6)) :: // from here is packet_type == 0 only ("member_name" | PacketHelpers.encodedWideStringAligned(6)) ::
("rank" | uint(3)) :: ("rank" | uint(3)) ::
("points" | uint32L) :: ("points" | uint32L) ::
("last_login" | uint32L) :: ("last_login" | uint32L) ::
("action" | OutfitMemberEventAction.PacketType.codec) :: ("action" | OutfitMemberEventAction.PacketType.codec) ::
("padding" | uint4L) ("padding" | uint4L)
).xmap[Unk0]( ).xmap[Update](
{ {
case member_name :: rank :: points :: last_login :: action :: padding :: HNil => case member_name :: rank :: points :: last_login :: action :: padding :: HNil =>
Unk0(member_name, rank, points, last_login, action, padding) Update(member_name, rank, points, last_login, action, padding)
}, },
{ {
case Unk0(member_name, rank, points, last_login, action, padding) => case Update(member_name, rank, points, last_login, action, padding) =>
member_name :: rank :: points :: last_login :: action :: padding :: HNil member_name :: rank :: points :: last_login :: action :: padding :: HNil
} }
) )
val Unk1Codec: Codec[Unk1] = PacketHelpers.emptyCodec(Unk1()) val KickedCodec: Codec[Kicked] = PacketHelpers.emptyCodec(Kicked())
/** /**
* A common form for known action code indexes with an unknown purpose and transformation is an "Unknown" object. * A common form for known action code indexes with an unknown purpose and transformation is an "Unknown" object.
@ -109,8 +119,8 @@ object OutfitMemberEvent extends Marshallable[OutfitMemberEvent] {
object PacketType extends Enumeration { object PacketType extends Enumeration {
type Type = Value type Type = Value
val Unk0: PacketType.Value = Value(0) val Update: PacketType.Value = Value(0)
val Unk1: PacketType.Value = Value(1) // Info: Player has been invited / response to OutfitMembershipRequest Unk2 for that player val Kicked: PacketType.Value = Value(1)
val Unk2: PacketType.Value = Value(2) val Unk2: PacketType.Value = Value(2)
val Unk3: PacketType.Value = Value(3) val Unk3: PacketType.Value = Value(3)
@ -122,8 +132,8 @@ object OutfitMemberEvent extends Marshallable[OutfitMemberEvent] {
import scala.annotation.switch import scala.annotation.switch
((code: @switch) match { ((code: @switch) match {
case 0 => Unk0Codec case 0 => UpdateCodec
case 1 => Unk1Codec case 1 => KickedCodec
case 2 => unknownCodec(code) case 2 => unknownCodec(code)
case 3 => unknownCodec(code) case 3 => unknownCodec(code)

View file

@ -9,7 +9,7 @@ import scodec.codecs._
import shapeless.{::, HNil} import shapeless.{::, HNil}
final case class OutfitMembershipRequest( final case class OutfitMembershipRequest(
outfit_id: Long, requester_id: Long,
action: OutfitMembershipRequestAction action: OutfitMembershipRequestAction
) extends PlanetSideGamePacket { ) extends PlanetSideGamePacket {
type Packet = OutfitMembershipRequest type Packet = OutfitMembershipRequest
@ -37,8 +37,8 @@ object OutfitMembershipRequestAction {
) extends OutfitMembershipRequestAction(code = 1) ) extends OutfitMembershipRequestAction(code = 1)
final case class Invite( final case class Invite(
avatar_id: Long, target_id: Long,
member_name: String, target_name: String,
) extends OutfitMembershipRequestAction(code = 2) ) extends OutfitMembershipRequestAction(code = 2)
final case class AcceptInvite( final case class AcceptInvite(
@ -50,19 +50,19 @@ object OutfitMembershipRequestAction {
) extends OutfitMembershipRequestAction(code = 4) ) extends OutfitMembershipRequestAction(code = 4)
final case class CancelInvite( final case class CancelInvite(
avatar_id: Long, target_id: Long,
member_name: String, target_name: String,
) extends OutfitMembershipRequestAction(code = 5) ) extends OutfitMembershipRequestAction(code = 5)
final case class Kick( final case class Kick(
avatar_id: Long, target_id: Long,
member_name: String, target_name: String,
) extends OutfitMembershipRequestAction(code = 6) ) extends OutfitMembershipRequestAction(code = 6)
final case class SetRank( final case class SetRank(
avatar_id: Long, target_id: Long,
rank: Int, rank: Int,
member_name: String, target_name: String,
) extends OutfitMembershipRequestAction(code = 7) ) extends OutfitMembershipRequestAction(code = 7)
final case class Unknown(badCode: Int, data: BitVector) extends OutfitMembershipRequestAction(badCode) final case class Unknown(badCode: Int, data: BitVector) extends OutfitMembershipRequestAction(badCode)

View file

@ -12,7 +12,7 @@ final case class OutfitMembershipResponse(
packet_type: OutfitMembershipResponse.PacketType.Type, packet_type: OutfitMembershipResponse.PacketType.Type,
unk0: Int, unk0: Int,
unk1: Int, unk1: Int,
outfit_id: Long, requester_id: Long,
target_id: Long, target_id: Long,
str1: String, str1: String,
str2: String, str2: String,
@ -34,8 +34,8 @@ object OutfitMembershipResponse extends Marshallable[OutfitMembershipResponse] {
val Invite: PacketType.Value = Value(1) // response to OutfitMembershipRequest Unk2 for that player val Invite: PacketType.Value = Value(1) // response to OutfitMembershipRequest Unk2 for that player
val InviteAccepted: PacketType.Value = Value(2) val InviteAccepted: PacketType.Value = Value(2)
val InviteRejected: PacketType.Value = Value(3) val InviteRejected: PacketType.Value = Value(3)
val Unk4: PacketType.Value = Value(4) val YouGotKicked: PacketType.Value = Value(4)
val Kick: PacketType.Value = Value(5) val YouKicked: PacketType.Value = Value(5)
val Unk6: PacketType.Value = Value(6) // 6 and 7 seen as failed decodes, validity unknown val Unk6: PacketType.Value = Value(6) // 6 and 7 seen as failed decodes, validity unknown
val Unk7: PacketType.Value = Value(7) val Unk7: PacketType.Value = Value(7)

View file

@ -8,7 +8,7 @@ import scodec.codecs._
import shapeless.{::, HNil} import shapeless.{::, HNil}
final case class OutfitRequest( final case class OutfitRequest(
outfit_id: Long, requester_id: Long,
action: OutfitRequestAction action: OutfitRequestAction
) extends PlanetSideGamePacket { ) extends PlanetSideGamePacket {
type Packet = OutfitRequest type Packet = OutfitRequest
@ -42,13 +42,13 @@ object OutfitRequestAction {
* na * na
* @param unk na * @param unk na
*/ */
final case class Unk3(menuOpen: Boolean) extends OutfitRequestAction(code = 3) final case class OutfitWindowOpen(menuOpen: Boolean) extends OutfitRequestAction(code = 3)
/** /**
* na * na
* @param unk na * @param unk na
*/ */
final case class Unk4(menuOpen: Boolean) extends OutfitRequestAction(code = 4) final case class OutfitListWindowOpen(menuOpen: Boolean) extends OutfitRequestAction(code = 4)
/** /**
* na * na
@ -116,24 +116,24 @@ object OutfitRequest extends Marshallable[OutfitRequest] {
/** /**
* na * na
*/ */
private val unk3Codec: Codec[OutfitRequestAction] = bool.hlist.xmap[OutfitRequestAction] ( private val OutfitWindowOpenCodec: Codec[OutfitRequestAction] = bool.hlist.xmap[OutfitRequestAction] (
{ {
case value :: HNil => OutfitRequestAction.Unk3(value) case value :: HNil => OutfitRequestAction.OutfitWindowOpen(value)
}, },
{ {
case OutfitRequestAction.Unk3(value) => value :: HNil case OutfitRequestAction.OutfitWindowOpen(value) => value :: HNil
} }
) )
/** /**
* na * na
*/ */
private val unk4Codec: Codec[OutfitRequestAction] = bool.hlist.xmap[OutfitRequestAction] ( private val OutfitListWindowOpenCodec: Codec[OutfitRequestAction] = bool.hlist.xmap[OutfitRequestAction] (
{ {
case value :: HNil => OutfitRequestAction.Unk4(value) case value :: HNil => OutfitRequestAction.OutfitListWindowOpen(value)
}, },
{ {
case OutfitRequestAction.Unk4(value) => value :: HNil case OutfitRequestAction.OutfitListWindowOpen(value) => value :: HNil
} }
) )
@ -151,8 +151,8 @@ object OutfitRequest extends Marshallable[OutfitRequest] {
val Motd: PacketType.Value = Value(0) val Motd: PacketType.Value = Value(0)
val Rank: PacketType.Value = Value(1) val Rank: PacketType.Value = Value(1)
val Unk2: PacketType.Value = Value(2) val Unk2: PacketType.Value = Value(2)
val Detail: PacketType.Value = Value(3) val OutfitWindowOpen: PacketType.Value = Value(3)
val List: PacketType.Value = Value(4) // sent by client if menu is either open (true) or closed (false) val OutfitListWindowOpen: PacketType.Value = Value(4) // sent by client if menu is either open (true) or closed (false)
implicit val codec: Codec[Type] = PacketHelpers.createEnumerationCodec(this, uintL(3)) implicit val codec: Codec[Type] = PacketHelpers.createEnumerationCodec(this, uintL(3))
} }
@ -165,8 +165,8 @@ object OutfitRequest extends Marshallable[OutfitRequest] {
case 0 => MotdCodec case 0 => MotdCodec
case 1 => RankCodec case 1 => RankCodec
case 2 => unk2Codec case 2 => unk2Codec
case 3 => unk3Codec case 3 => OutfitWindowOpenCodec
case 4 => unk4Codec case 4 => OutfitListWindowOpenCodec
case _ => failCodec(code) case _ => failCodec(code)
} }
} }

View file

@ -53,7 +53,7 @@ class OutfitEventTest extends Specification {
PacketCoding.decodePacket(unk0_ABC).require match { PacketCoding.decodePacket(unk0_ABC).require match {
case OutfitEvent(outfit_guid, action) => case OutfitEvent(outfit_guid, action) =>
outfit_guid mustEqual 25044 outfit_guid mustEqual 25044
action mustEqual Unk0( action mustEqual Initial(
OutfitInfo( OutfitInfo(
outfit_name = "Black Armored Reapers", outfit_name = "Black Armored Reapers",
outfit_points1 = 223190045, outfit_points1 = 223190045,
@ -78,7 +78,7 @@ class OutfitEventTest extends Specification {
"encode Unk0 ABC" in { "encode Unk0 ABC" in {
val msg = OutfitEvent( val msg = OutfitEvent(
25044, 25044,
Unk0( Initial(
OutfitInfo( OutfitInfo(
outfit_name = "Black Armored Reapers", outfit_name = "Black Armored Reapers",
outfit_points1 = 223190045, outfit_points1 = 223190045,
@ -125,7 +125,7 @@ class OutfitEventTest extends Specification {
PacketCoding.decodePacket(unk2_ABC).require match { PacketCoding.decodePacket(unk2_ABC).require match {
case OutfitEvent(outfit_guid, action) => case OutfitEvent(outfit_guid, action) =>
outfit_guid mustEqual 2147418113L outfit_guid mustEqual 2147418113L
action mustEqual Unk2(OutfitInfo( action mustEqual Update(OutfitInfo(
outfit_name = "PlanetSide_Forever_Vanu", outfit_name = "PlanetSide_Forever_Vanu",
outfit_points1 = 0, outfit_points1 = 0,
outfit_points2 = 0, outfit_points2 = 0,
@ -148,7 +148,7 @@ class OutfitEventTest extends Specification {
"encode Unk2 ABC" in { "encode Unk2 ABC" in {
val msg = OutfitEvent( val msg = OutfitEvent(
2147418113L, 2147418113L,
Unk2( Update(
OutfitInfo( OutfitInfo(
outfit_name = "PlanetSide_Forever_Vanu", outfit_name = "PlanetSide_Forever_Vanu",
outfit_points1 = 0, outfit_points1 = 0,
@ -175,7 +175,7 @@ class OutfitEventTest extends Specification {
PacketCoding.decodePacket(unk3_ABC).require match { PacketCoding.decodePacket(unk3_ABC).require match {
case OutfitEvent(outfit_guid, action) => case OutfitEvent(outfit_guid, action) =>
outfit_guid mustEqual 2147418113L outfit_guid mustEqual 2147418113L
action mustEqual Unk3() action mustEqual Leaving()
case _ => case _ =>
ko ko
} }
@ -184,7 +184,7 @@ class OutfitEventTest extends Specification {
"encode Unk3 ABC" in { "encode Unk3 ABC" in {
val msg = OutfitEvent( val msg = OutfitEvent(
2147418113L, 2147418113L,
Unk3() Leaving()
) )
val pkt = PacketCoding.encodePacket(msg).require.toByteVector val pkt = PacketCoding.encodePacket(msg).require.toByteVector
@ -219,8 +219,8 @@ class OutfitEventTest extends Specification {
PacketCoding.decodePacket(unk5_ABC).require match { PacketCoding.decodePacket(unk5_ABC).require match {
case OutfitEvent(outfit_guid, action) => case OutfitEvent(outfit_guid, action) =>
outfit_guid mustEqual 2147418113L outfit_guid mustEqual 2147418113L
action mustEqual Unk5( action mustEqual UpdateMemberCount(
unk1 = 2, member_count = 2,
) )
case _ => case _ =>
ko ko
@ -230,8 +230,8 @@ class OutfitEventTest extends Specification {
"encode Unk5 ABC" in { "encode Unk5 ABC" in {
val msg = OutfitEvent( val msg = OutfitEvent(
2147418113L, 2147418113L,
Unk5( UpdateMemberCount(
unk1 = 2, member_count = 2,
) )
) )
val pkt = PacketCoding.encodePacket(msg).require.toByteVector val pkt = PacketCoding.encodePacket(msg).require.toByteVector

View file

@ -22,7 +22,7 @@ class OutfitMemberEventTest extends Specification {
"decode Lazer padding" in { "decode Lazer padding" in {
PacketCoding.decodePacket(Lazer).require match { PacketCoding.decodePacket(Lazer).require match {
case OutfitMemberEvent(outfit_id, member_id, Unk0(member_name, rank, points, last_login, action, padding)) => case OutfitMemberEvent(outfit_id, member_id, Update(member_name, rank, points, last_login, action, padding)) =>
outfit_id mustEqual 6418 outfit_id mustEqual 6418
member_id mustEqual 705344 member_id mustEqual 705344
member_name mustEqual "Lazer1982" member_name mustEqual "Lazer1982"
@ -40,7 +40,7 @@ class OutfitMemberEventTest extends Specification {
val msg = OutfitMemberEvent( val msg = OutfitMemberEvent(
outfit_id = 6418, outfit_id = 6418,
member_id = 705344, member_id = 705344,
Unk0( Update(
member_name = "Lazer1982", member_name = "Lazer1982",
rank = 7, rank = 7,
points = 3134113, points = 3134113,
@ -56,7 +56,7 @@ class OutfitMemberEventTest extends Specification {
"decode OpolE padding" in { "decode OpolE padding" in {
PacketCoding.decodePacket(OpolE).require match { PacketCoding.decodePacket(OpolE).require match {
case OutfitMemberEvent(outfit_id, member_id, Unk0(member_name, rank, points, last_login, action, unk0_padding)) => case OutfitMemberEvent(outfit_id, member_id, Update(member_name, rank, points, last_login, action, unk0_padding)) =>
outfit_id mustEqual 6418 outfit_id mustEqual 6418
member_id mustEqual 42644970 member_id mustEqual 42644970
member_name mustEqual "OpolE" member_name mustEqual "OpolE"
@ -74,7 +74,7 @@ class OutfitMemberEventTest extends Specification {
val msg = OutfitMemberEvent( val msg = OutfitMemberEvent(
outfit_id = 6418, outfit_id = 6418,
member_id = 42644970, member_id = 42644970,
Unk0( Update(
member_name = "OpolE", member_name = "OpolE",
rank = 6, rank = 6,
points = 461901, points = 461901,
@ -91,7 +91,7 @@ class OutfitMemberEventTest extends Specification {
"decode Unk1" in { "decode Unk1" in {
PacketCoding.decodePacket(unk1).require match { PacketCoding.decodePacket(unk1).require match {
case OutfitMemberEvent(outfit_id, member_id, Unk1()) => case OutfitMemberEvent(outfit_id, member_id, Kicked()) =>
outfit_id mustEqual 529744 outfit_id mustEqual 529744
member_id mustEqual 41605263 member_id mustEqual 41605263
case _ => case _ =>
@ -103,7 +103,7 @@ class OutfitMemberEventTest extends Specification {
val msg = OutfitMemberEvent( val msg = OutfitMemberEvent(
outfit_id = 529744, outfit_id = 529744,
member_id = 41605263, member_id = 41605263,
Unk1() Kicked()
) )
val pkt = PacketCoding.encodePacket(msg).require.toByteVector val pkt = PacketCoding.encodePacket(msg).require.toByteVector

View file

@ -111,7 +111,7 @@ class OutfitMembershipResponseTest extends Specification {
"decode unk4" in { "decode unk4" in {
PacketCoding.decodePacket(unk4).require match { PacketCoding.decodePacket(unk4).require match {
case OutfitMembershipResponse(packet_type, unk0, unk1, outfit_id, target_id, str1, str2, flag) => case OutfitMembershipResponse(packet_type, unk0, unk1, outfit_id, target_id, str1, str2, flag) =>
packet_type mustEqual PacketType.Unk4 packet_type mustEqual PacketType.YouGotKicked
unk0 mustEqual 0 unk0 mustEqual 0
unk1 mustEqual 0 unk1 mustEqual 0
outfit_id mustEqual 41593365 outfit_id mustEqual 41593365
@ -125,7 +125,7 @@ class OutfitMembershipResponseTest extends Specification {
} }
"encode unk4" in { "encode unk4" in {
val msg = OutfitMembershipResponse(PacketType.Unk4, 0, 0, 41593365, 0, "", "", flag = true) val msg = OutfitMembershipResponse(PacketType.YouGotKicked, 0, 0, 41593365, 0, "", "", flag = true)
val pkt = PacketCoding.encodePacket(msg).require.toByteVector val pkt = PacketCoding.encodePacket(msg).require.toByteVector
pkt mustEqual unk4 pkt mustEqual unk4
@ -134,7 +134,7 @@ class OutfitMembershipResponseTest extends Specification {
"decode unk5" in { "decode unk5" in {
PacketCoding.decodePacket(unk5).require match { PacketCoding.decodePacket(unk5).require match {
case OutfitMembershipResponse(packet_type, unk0, unk1, outfit_id, target_id, str1, str2, flag) => case OutfitMembershipResponse(packet_type, unk0, unk1, outfit_id, target_id, str1, str2, flag) =>
packet_type mustEqual PacketType.Kick packet_type mustEqual PacketType.YouKicked
unk0 mustEqual 0 unk0 mustEqual 0
unk1 mustEqual 1 unk1 mustEqual 1
outfit_id mustEqual 41593365 outfit_id mustEqual 41593365
@ -148,7 +148,7 @@ class OutfitMembershipResponseTest extends Specification {
} }
"encode unk5" in { "encode unk5" in {
val msg = OutfitMembershipResponse(PacketType.Kick, 0, 1, 41593365, 41605263, "PSFoutfittest1", "", flag = true) val msg = OutfitMembershipResponse(PacketType.YouKicked, 0, 1, 41593365, 41605263, "PSFoutfittest1", "", flag = true)
val pkt = PacketCoding.encodePacket(msg).require.toByteVector val pkt = PacketCoding.encodePacket(msg).require.toByteVector
pkt mustEqual unk5 pkt mustEqual unk5

View file

@ -46,7 +46,7 @@ class OutfitRequestTest extends Specification {
"decode Unk3" in { "decode Unk3" in {
PacketCoding.decodePacket(string6).require match { PacketCoding.decodePacket(string6).require match {
case OutfitRequest(id, OutfitRequestAction.Unk3(value)) => case OutfitRequest(id, OutfitRequestAction.OutfitWindowOpen(value)) =>
id mustEqual 1176612L id mustEqual 1176612L
value mustEqual true value mustEqual true
case _ => case _ =>
@ -56,7 +56,7 @@ class OutfitRequestTest extends Specification {
"decode Unk4" in { "decode Unk4" in {
PacketCoding.decodePacket(string8).require match { PacketCoding.decodePacket(string8).require match {
case OutfitRequest(id, OutfitRequestAction.Unk4(value)) => case OutfitRequest(id, OutfitRequestAction.OutfitListWindowOpen(value)) =>
id mustEqual 41588237L id mustEqual 41588237L
value mustEqual true value mustEqual true
case _ => case _ =>
@ -88,14 +88,14 @@ class OutfitRequestTest extends Specification {
} }
"encode Unk3" in { "encode Unk3" in {
val msg = OutfitRequest(1176612L, OutfitRequestAction.Unk3(true)) val msg = OutfitRequest(1176612L, OutfitRequestAction.OutfitWindowOpen(true))
val pkt = PacketCoding.encodePacket(msg).require.toByteVector val pkt = PacketCoding.encodePacket(msg).require.toByteVector
pkt mustEqual string6 pkt mustEqual string6
} }
"encode Unk4" in { "encode Unk4" in {
val msg = OutfitRequest(41588237L, OutfitRequestAction.Unk4(true)) val msg = OutfitRequest(41588237L, OutfitRequestAction.OutfitListWindowOpen(true))
val pkt = PacketCoding.encodePacket(msg).require.toByteVector val pkt = PacketCoding.encodePacket(msg).require.toByteVector
pkt mustEqual string8 pkt mustEqual string8