mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-01-19 18:14:44 +00:00
OutfitMemberEvent now supports the two main packet types Unk0 and Unk1.
Support for Unk0's subtypes Unk0 and Padding have been removed in favour of the main type. Should be reimplemented at some point, but I don't know how yet.
This commit is contained in:
parent
7528388eb1
commit
e3fe9b69bf
|
|
@ -8,21 +8,11 @@ import scodec.bits.BitVector
|
|||
import scodec.codecs._
|
||||
import shapeless.{::, HNil}
|
||||
|
||||
/*
|
||||
packet_type is unimplemented! if packet_type == 0 only outfit_id and member_id are sent
|
||||
action is unimplemented! if action == 0 unk2 will contain one additional uint32L
|
||||
unk0_padding contains one byte of padding. may contain 4byte of unknown data depending on action
|
||||
*/
|
||||
final case class OutfitMemberEvent(
|
||||
packet_type: Int, // only 0 is known // TODO: needs implementation
|
||||
packet_type: OutfitMemberEvent.PacketType.Type,
|
||||
outfit_id: Long,
|
||||
member_id: Long,
|
||||
member_name: String, // from here is packet_type == 0 only
|
||||
rank: Int, // 0-7
|
||||
points: Long, // client divides this by 100
|
||||
last_login: Long, // seconds ago from current time, 0 if online
|
||||
action: OutfitMemberEvent.PacketType.Type, // this should always be 1, otherwise there will be actual data in unk0_padding!
|
||||
unk0_padding: OutfitMemberEventAction // only contains information if action is 0, 1 byte of padding otherwise
|
||||
action: OutfitMemberEventAction
|
||||
) extends PlanetSideGamePacket {
|
||||
type Packet = OutfitMemberEvent
|
||||
|
||||
|
|
@ -34,12 +24,30 @@ final case class OutfitMemberEvent(
|
|||
abstract class OutfitMemberEventAction(val code: Int)
|
||||
object OutfitMemberEventAction {
|
||||
|
||||
object PacketType extends Enumeration {
|
||||
type Type = Value
|
||||
|
||||
val Unk0: PacketType.Value = Value(0)
|
||||
val Padding: PacketType.Value = Value(1)
|
||||
|
||||
implicit val codec: Codec[Type] = PacketHelpers.createEnumerationCodec(this, uintL(1))
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
action is unimplemented! if action == 0 unk2 will contain one additional uint32L
|
||||
unk0_padding contains one byte of padding. may contain 4byte of unknown data depending on action
|
||||
*/
|
||||
final case class Unk0(
|
||||
unk0: Long
|
||||
member_name: String,
|
||||
rank: Int,
|
||||
points: Long, // client divides this by 100
|
||||
last_login: Long, // seconds ago from current time, 0 if online
|
||||
action: PacketType.Type, // should always be 1, otherwise there will be actual data in padding. not implemented!
|
||||
padding: Int // should always be 0, 4 bits of padding // only contains data if action is 0
|
||||
) extends OutfitMemberEventAction(code = 0)
|
||||
|
||||
final case class Padding(
|
||||
padding: Int
|
||||
final case class Unk1(
|
||||
) extends OutfitMemberEventAction(code = 1)
|
||||
|
||||
final case class Unknown(badCode: Int, data: BitVector) extends OutfitMemberEventAction(badCode)
|
||||
|
|
@ -51,31 +59,25 @@ object OutfitMemberEventAction {
|
|||
object Codecs {
|
||||
private val everFailCondition = conditional(included = false, bool)
|
||||
|
||||
val UnkNonPaddingCodec: Codec[Unk0] = (
|
||||
("unk0" | uint32L)
|
||||
val Unk0Codec: Codec[Unk0] = (
|
||||
("member_name" | PacketHelpers.encodedWideStringAligned(6)) :: // from here is packet_type == 0 only
|
||||
("rank" | uint(3)) ::
|
||||
("points" | uint32L) ::
|
||||
("last_login" | uint32L) ::
|
||||
("action" | OutfitMemberEventAction.PacketType.codec) ::
|
||||
("padding" | uint4L)
|
||||
).xmap[Unk0](
|
||||
{
|
||||
case u0 =>
|
||||
Unk0(u0)
|
||||
case member_name :: rank :: points :: last_login :: action :: padding :: HNil =>
|
||||
Unk0(member_name, rank, points, last_login, action, padding)
|
||||
},
|
||||
{
|
||||
case Unk0(u0) =>
|
||||
u0
|
||||
case Unk0(member_name, rank, points, last_login, action, padding) =>
|
||||
member_name :: rank :: points :: last_login :: action :: padding :: HNil
|
||||
}
|
||||
)
|
||||
|
||||
val PaddingCodec: Codec[Padding] = (
|
||||
("padding" | uint4L)
|
||||
).xmap[Padding](
|
||||
{
|
||||
case padding =>
|
||||
Padding(padding)
|
||||
},
|
||||
{
|
||||
case Padding(padding) =>
|
||||
padding
|
||||
}
|
||||
)
|
||||
val Unk1Codec: Codec[Unk1] = PacketHelpers.emptyCodec(Unk1())
|
||||
|
||||
/**
|
||||
* A common form for known action code indexes with an unknown purpose and transformation is an "Unknown" object.
|
||||
|
|
@ -109,9 +111,9 @@ object OutfitMemberEvent extends Marshallable[OutfitMemberEvent] {
|
|||
type Type = Value
|
||||
|
||||
val Unk0: PacketType.Value = Value(0)
|
||||
val Padding: PacketType.Value = Value(1) // Info: Player has been invited / response to OutfitMembershipRequest Unk2 for that player
|
||||
val Unk1: PacketType.Value = Value(1) // Info: Player has been invited / response to OutfitMembershipRequest Unk2 for that player
|
||||
|
||||
implicit val codec: Codec[Type] = PacketHelpers.createEnumerationCodec(this, uintL(1))
|
||||
implicit val codec: Codec[Type] = PacketHelpers.createEnumerationCodec(this, uintL(2))
|
||||
}
|
||||
|
||||
private def selectFromType(code: Int): Codec[OutfitMemberEventAction] = {
|
||||
|
|
@ -119,34 +121,27 @@ object OutfitMemberEvent extends Marshallable[OutfitMemberEvent] {
|
|||
import scala.annotation.switch
|
||||
|
||||
((code: @switch) match {
|
||||
case 0 => UnkNonPaddingCodec
|
||||
case 1 => PaddingCodec
|
||||
case 0 => Unk0Codec
|
||||
case 1 => Unk1Codec
|
||||
|
||||
case _ => failureCodec(code)
|
||||
}).asInstanceOf[Codec[OutfitMemberEventAction]]
|
||||
}
|
||||
|
||||
implicit val codec: Codec[OutfitMemberEvent] = (
|
||||
("packet_type" | uintL(2)) :: // this should selectFromType
|
||||
("packet_type" | PacketType.codec) >>:~ { packet_type =>
|
||||
("outfit_id" | uint32L) ::
|
||||
("member_id" | uint32L) ::
|
||||
("member_name" | PacketHelpers.encodedWideStringAligned(6)) :: // from here is packet_type == 0 only
|
||||
("rank" | uint(3)) ::
|
||||
("points" | uint32L) ::
|
||||
("last_login" | uint32L) ::
|
||||
(("action" | PacketType.codec) >>:~ { action =>
|
||||
("action_part" | selectFromType(action.id)).hlist
|
||||
})
|
||||
("action" | selectFromType(packet_type.id)).hlist
|
||||
}
|
||||
).xmap[OutfitMemberEvent](
|
||||
{
|
||||
case packet_type :: outfit_id :: member_id :: member_name :: rank :: points :: last_login :: action :: unk0_padding :: HNil =>
|
||||
OutfitMemberEvent(packet_type, outfit_id, member_id, member_name, rank, points, last_login, action, unk0_padding)
|
||||
case packet_type :: outfit_id :: member_id:: action :: HNil =>
|
||||
OutfitMemberEvent(packet_type, outfit_id, member_id, action)
|
||||
},
|
||||
{
|
||||
// TODO: remove once implemented
|
||||
// ensure we send packet_type 0 only
|
||||
case OutfitMemberEvent(_, outfit_id, member_id, member_name, rank, points, last_login, action, unk0_padding) =>
|
||||
0 :: outfit_id :: member_id :: member_name :: rank :: points :: last_login :: action :: unk0_padding :: HNil
|
||||
case OutfitMemberEvent(packet_type, outfit_id, member_id, action) =>
|
||||
packet_type :: outfit_id :: member_id :: action :: HNil
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
package game
|
||||
|
||||
import net.psforever.packet._
|
||||
import net.psforever.packet.game.OutfitMemberEvent
|
||||
import net.psforever.packet.game.OutfitMemberEventAction.Padding
|
||||
import net.psforever.packet.game.{OutfitMemberEvent, OutfitMemberEventAction}
|
||||
import net.psforever.packet.game.OutfitMemberEventAction._
|
||||
import org.specs2.mutable._
|
||||
import scodec.bits._
|
||||
|
||||
|
|
@ -18,20 +18,20 @@ class OutfitMemberEventTest extends Specification {
|
|||
val PvtPa = hex"90 0 4864 0000 1e69 e80a 2c 0 500076007400500061006e00630061006b0065007300 705e a080 0a85 e060 10"
|
||||
val Night = hex"90 0 4864 0002 4cf0 3802 28 0 4e006900670068007400770069006e0067003100 b8fb 9a40 0da6 ec80 50"
|
||||
|
||||
val Unk1 = hex"90 5 40542002 3f61e808 0"
|
||||
val unk1 = hex"90 5 40542002 3f61e808 0"
|
||||
|
||||
"decode Lazer padding" in {
|
||||
PacketCoding.decodePacket(Lazer).require match {
|
||||
case OutfitMemberEvent(packet_type, outfit_id, member_id, member_name, rank, points, last_login, action, unk0_padding) =>
|
||||
packet_type mustEqual 0
|
||||
outfit_id mustEqual 6418
|
||||
member_id mustEqual 705344
|
||||
member_name mustEqual "Lazer1982"
|
||||
rank mustEqual 7
|
||||
points mustEqual 3134113
|
||||
last_login mustEqual 156506
|
||||
action mustEqual OutfitMemberEvent.PacketType.Padding
|
||||
unk0_padding mustEqual Padding(0)
|
||||
case OutfitMemberEvent(packet_type, outfit_id, member_id, Unk0(member_name, rank, points, last_login, action, padding)) =>
|
||||
packet_type mustEqual OutfitMemberEvent.PacketType.Unk0
|
||||
outfit_id mustEqual 6418
|
||||
member_id mustEqual 705344
|
||||
member_name mustEqual "Lazer1982"
|
||||
rank mustEqual 7
|
||||
points mustEqual 3134113
|
||||
last_login mustEqual 156506
|
||||
action mustEqual OutfitMemberEventAction.PacketType.Padding
|
||||
padding mustEqual 0
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
|
|
@ -39,15 +39,17 @@ class OutfitMemberEventTest extends Specification {
|
|||
|
||||
"encode Lazer padding" in {
|
||||
val msg = OutfitMemberEvent(
|
||||
packet_type = 0,
|
||||
packet_type = OutfitMemberEvent.PacketType.Unk0,
|
||||
outfit_id = 6418,
|
||||
member_id = 705344,
|
||||
member_name = "Lazer1982",
|
||||
rank = 7,
|
||||
points = 3134113,
|
||||
last_login = 156506,
|
||||
action = OutfitMemberEvent.PacketType.Padding,
|
||||
unk0_padding = Padding(0)
|
||||
Unk0(
|
||||
member_name = "Lazer1982",
|
||||
rank = 7,
|
||||
points = 3134113,
|
||||
last_login = 156506,
|
||||
action = OutfitMemberEventAction.PacketType.Padding,
|
||||
padding = 0
|
||||
)
|
||||
)
|
||||
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
||||
|
||||
|
|
@ -56,16 +58,16 @@ class OutfitMemberEventTest extends Specification {
|
|||
|
||||
"decode OpolE padding" in {
|
||||
PacketCoding.decodePacket(OpolE).require match {
|
||||
case OutfitMemberEvent(packet_type, outfit_id, member_id, member_name, rank, points, last_login, action, unk0_padding) =>
|
||||
packet_type mustEqual 0
|
||||
case OutfitMemberEvent(packet_type, outfit_id, member_id, Unk0(member_name, rank, points, last_login, action, unk0_padding)) =>
|
||||
packet_type mustEqual OutfitMemberEvent.PacketType.Unk0
|
||||
outfit_id mustEqual 6418
|
||||
member_id mustEqual 42644970
|
||||
member_name mustEqual "OpolE"
|
||||
rank mustEqual 6
|
||||
points mustEqual 461901
|
||||
last_login mustEqual 137576
|
||||
action mustEqual OutfitMemberEvent.PacketType.Padding
|
||||
unk0_padding mustEqual Padding(0)
|
||||
action mustEqual OutfitMemberEventAction.PacketType.Padding
|
||||
unk0_padding mustEqual 0
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
|
|
@ -73,44 +75,44 @@ class OutfitMemberEventTest extends Specification {
|
|||
|
||||
"encode OpolE padding" in {
|
||||
val msg = OutfitMemberEvent(
|
||||
packet_type = 0,
|
||||
packet_type = OutfitMemberEvent.PacketType.Unk0,
|
||||
outfit_id = 6418,
|
||||
member_id = 42644970,
|
||||
member_name = "OpolE",
|
||||
rank = 6,
|
||||
points = 461901,
|
||||
last_login = 137576,
|
||||
action = OutfitMemberEvent.PacketType.Padding,
|
||||
unk0_padding = Padding(0)
|
||||
Unk0(
|
||||
member_name = "OpolE",
|
||||
rank = 6,
|
||||
points = 461901,
|
||||
last_login = 137576,
|
||||
action = OutfitMemberEventAction.PacketType.Padding,
|
||||
padding = 0
|
||||
)
|
||||
|
||||
)
|
||||
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
||||
|
||||
pkt mustEqual OpolE
|
||||
}
|
||||
|
||||
// TODO: these are broken because the decoder can only handle packet_type 0
|
||||
|
||||
/*
|
||||
"decode Unk0" in {
|
||||
PacketCoding.decodePacket(Unk1).require match {
|
||||
case OutfitMemberEvent(packet_type, outfit_id, member_id) =>
|
||||
packet_type mustEqual 1
|
||||
outfit_id mustEqual 6418
|
||||
member_id mustEqual 42644970
|
||||
"decode Unk1" in {
|
||||
PacketCoding.decodePacket(unk1).require match {
|
||||
case OutfitMemberEvent(packet_type,outfit_id, member_id, Unk1()) =>
|
||||
packet_type mustEqual OutfitMemberEvent.PacketType.Unk1
|
||||
outfit_id mustEqual 529744
|
||||
member_id mustEqual 41605263
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"encode Unk0" in {
|
||||
"encode Unk1" in {
|
||||
val msg = OutfitMemberEvent(
|
||||
packet_type = 1,
|
||||
outfit_id = 6418,
|
||||
member_id = 42644970,
|
||||
packet_type = OutfitMemberEvent.PacketType.Unk1,
|
||||
outfit_id = 529744,
|
||||
member_id = 41605263,
|
||||
Unk1()
|
||||
)
|
||||
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
||||
|
||||
pkt mustEqual Unk1
|
||||
pkt mustEqual unk1
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue