mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-03-24 22:39:07 +00:00
in the middle of character decode test implementation
This commit is contained in:
parent
ee87e1c6ec
commit
b0b5a7005b
2 changed files with 184 additions and 140 deletions
|
|
@ -1,7 +1,8 @@
|
|||
package net.psforever.packet.game
|
||||
|
||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
||||
//import net.psforever.types.Vector3
|
||||
import scodec.DecodeResult
|
||||
import net.psforever.types.Vector3
|
||||
import scodec.bits._
|
||||
import scodec.{Attempt, Codec, Err}
|
||||
import scodec.codecs._
|
||||
|
|
@ -19,25 +20,25 @@ object AmmoBoxData extends Marshallable[AmmoBoxData] {
|
|||
ignore(15) ::
|
||||
("magazine" | uint16L)
|
||||
).exmap[AmmoBoxData] (
|
||||
{
|
||||
case 0xC8 :: _ :: mag :: HNil =>
|
||||
Attempt.successful(AmmoBoxData(mag))
|
||||
case x :: _ :: _ :: HNil =>
|
||||
Attempt.failure(Err("code wrong - looking for 200, found "+x))
|
||||
},
|
||||
{
|
||||
case AmmoBoxData(mag) =>
|
||||
Attempt.successful(0xC8 :: () :: mag :: HNil)
|
||||
}
|
||||
).as[AmmoBoxData]
|
||||
{
|
||||
case 0xC8 :: _ :: mag :: HNil =>
|
||||
Attempt.successful(AmmoBoxData(mag))
|
||||
case x :: _ :: _ :: HNil =>
|
||||
Attempt.failure(Err("looking for 200, found "+x))
|
||||
},
|
||||
{
|
||||
case AmmoBoxData(mag) =>
|
||||
Attempt.successful(0xC8 :: () :: mag :: HNil)
|
||||
}
|
||||
).as[AmmoBoxData]
|
||||
}
|
||||
|
||||
case class WeaponData(unk : Int,
|
||||
ammo : InternalMold) extends ConstructorData
|
||||
ammo : InternalSlot) extends ConstructorData
|
||||
|
||||
object WeaponData extends Marshallable[WeaponData] {
|
||||
def apply(unk : Int, cls : Int, guid : PlanetSideGUID, parentSlot : Int, ammo : AmmoBoxData) : WeaponData =
|
||||
new WeaponData(unk, InternalMold(cls, guid, parentSlot, Some(ammo)))
|
||||
new WeaponData(unk, InternalSlot(cls, guid, parentSlot, Some(ammo)))
|
||||
|
||||
implicit val codec : Codec[WeaponData] = (
|
||||
("unk" | uint4L) ::
|
||||
|
|
@ -46,13 +47,13 @@ object WeaponData extends Marshallable[WeaponData] {
|
|||
uint4L ::
|
||||
ignore(16) ::
|
||||
uintL(11) ::
|
||||
InternalMold.codec
|
||||
("ammo" | InternalSlot.codec)
|
||||
).exmap[WeaponData] (
|
||||
{
|
||||
case code :: 8 :: _ :: 2 :: _ :: 0x2C0 :: ammo :: HNil =>
|
||||
Attempt.successful(WeaponData(code, ammo))
|
||||
case _ :: x :: _ :: y :: _ :: z :: _ :: HNil =>
|
||||
Attempt.failure(Err("looking for 8-2-704 pattern, found %d-%d-%d".format(x,y,z)))
|
||||
Attempt.failure(Err("looking for 8-2-704 pattern, found %d-%d-%d".format(x,y,z))) //TODO I actually don't know what of this is actually important
|
||||
},
|
||||
{
|
||||
case WeaponData(code, ammo) =>
|
||||
|
|
@ -61,26 +62,39 @@ object WeaponData extends Marshallable[WeaponData] {
|
|||
).as[WeaponData]
|
||||
}
|
||||
|
||||
//case class CharacterData(pos : Vector3,
|
||||
// obj_yaw : Int,
|
||||
// faction : Int,
|
||||
// bops : Boolean,
|
||||
// name : String,
|
||||
// exosuit : Int,
|
||||
// sex : Int,
|
||||
// face1 : Int,
|
||||
// face2 : Int,
|
||||
// voice : Int,
|
||||
// unk1 : Int, //0x8080
|
||||
// unk2 : Int, //0xFFFF or 0x0
|
||||
// unk3 : Int, //2
|
||||
// anchor : Boolean,
|
||||
// viewPitch : Int,
|
||||
// viewYaw : Int,
|
||||
// upperMerit : Int, //0xFFFF means no merit (for all ...)
|
||||
// middleMerit : Int,
|
||||
// lowerMerit : Int,
|
||||
// termOfServiceMerit : Int,
|
||||
case class RibbonBars(upper : Int, //0xFFFF means no merit (for all ...)
|
||||
middle : Int,
|
||||
lower : Int,
|
||||
tos : Int)
|
||||
|
||||
object RibbonBars extends Marshallable[RibbonBars] {
|
||||
implicit val codec : Codec[RibbonBars] = (
|
||||
("upper" | uint16L) ::
|
||||
("middle" | uint16L) ::
|
||||
("lower" | uint16L) ::
|
||||
("tos" | uint16L)
|
||||
).as[RibbonBars]
|
||||
}
|
||||
|
||||
case class CharacterData(pos : Vector3,
|
||||
objYaw : Int,
|
||||
faction : Int,
|
||||
bops : Boolean,
|
||||
name : String,
|
||||
exosuit : Int,
|
||||
sex : Int,
|
||||
face1 : Int,
|
||||
face2 : Int,
|
||||
voice : Int,
|
||||
unk1 : Int, //0x8080
|
||||
unk2 : Int, //0xFFFF or 0x0
|
||||
unk3 : Int, //2
|
||||
viewPitch : Int,
|
||||
viewYaw : Int,
|
||||
upperMerit : Int, //0xFFFF means no merit (for all ...)
|
||||
middleMerit : Int,
|
||||
lowerMerit : Int,
|
||||
termOfServiceMerit : Int,
|
||||
// healthMax : Int,
|
||||
// health : Int,
|
||||
// armor : Int,
|
||||
|
|
@ -96,72 +110,62 @@ object WeaponData extends Marshallable[WeaponData] {
|
|||
// unk11 : Int, //134
|
||||
// unk12 : Int, //199
|
||||
// firstTimeEvent_length : Long,
|
||||
// firstEntry : String,
|
||||
// firstTimEvent_list : List[String],
|
||||
// firstEntry : Option[String],
|
||||
// firstTimeEvent_list : List[String],
|
||||
// tutorial_list : List[String],
|
||||
// inventory : BitVector
|
||||
// ) extends ConstructorData
|
||||
//
|
||||
//object CharacterData extends Marshallable[CharacterData] {
|
||||
// //all ignore()s are intentional; please do not mess with them
|
||||
// implicit val codec : Codec[CharacterData] = (
|
||||
// ("pos" | Vector3.codec_pos) ::
|
||||
// ignore(16) ::
|
||||
// ("obj_yaw" | uint8L) ::
|
||||
// ignore(1) ::
|
||||
// ("faction" | uintL(2)) ::
|
||||
// ("bops" | bool) ::
|
||||
// ignore(4) ::
|
||||
// ignore(16) ::
|
||||
// ("name" | PacketHelpers.encodedWideStringAligned(4)) ::
|
||||
// ("exosuit" | uintL(3)) ::
|
||||
// ignore(1) ::
|
||||
// ignore(1) ::
|
||||
// ("sex" | uintL(2)) ::
|
||||
// ("face1" | uint4L) ::
|
||||
// ("face2" | uint4L) ::
|
||||
// ("voice" | uintL(3)) ::
|
||||
// ignore(2) ::
|
||||
// ignore(4) ::
|
||||
// ignore(16) ::
|
||||
// ("unk1" | uint16L) ::
|
||||
// ignore(40) ::
|
||||
// ignore(2) ::
|
||||
// ("unk2" | uint16L) ::
|
||||
// ignore(2) ::
|
||||
// ignore(28) ::
|
||||
// ("unk3" | uintL(4)) ::
|
||||
// ignore(4) ::
|
||||
// ignore(16) ::
|
||||
// ignore(2) ::
|
||||
// ("anchor" | bool) ::
|
||||
// ignore(1) ::
|
||||
// ("viewPitch" | uint8L) ::
|
||||
// ("viewYaw" | uint8L) ::
|
||||
// ignore(4) ::
|
||||
// ignore(4) ::
|
||||
// ignore(2) ::
|
||||
// ("upperMerit" | uint16L) ::
|
||||
// ("middleMerit" | uint16L) ::
|
||||
// ("lowerMerit" | uint16L) ::
|
||||
// ("termOfServiceMerit" | uint16L) ::
|
||||
// ignore(2) ::
|
||||
// ignore(156) ::
|
||||
// ignore(2) ::
|
||||
inventory : BitVector
|
||||
) extends ConstructorData
|
||||
|
||||
object CharacterData extends Marshallable[CharacterData] {
|
||||
val ribbonBars : Codec[RibbonBars] = (
|
||||
("upper" | uint16L) ::
|
||||
("middle" | uint16L) ::
|
||||
("lower" | uint16L) ::
|
||||
("tos" | uint16L)
|
||||
).as[RibbonBars]
|
||||
|
||||
implicit val codec : Codec[CharacterData] = (
|
||||
("pos" | Vector3.codec_pos) ::
|
||||
ignore(16) ::
|
||||
("objYaw" | uint8L) ::
|
||||
ignore(1) ::
|
||||
("faction" | uintL(2)) ::
|
||||
("bops" | bool) ::
|
||||
ignore(20) ::
|
||||
("name" | PacketHelpers.encodedWideStringAligned(4)) ::
|
||||
("exosuit" | uintL(3)) ::
|
||||
ignore(2) ::
|
||||
("sex" | uintL(2)) ::
|
||||
("face1" | uint4L) ::
|
||||
("face2" | uint4L) ::
|
||||
("voice" | uintL(3)) ::
|
||||
ignore(22) ::
|
||||
("unk1" | uint16L) ::
|
||||
ignore(42) ::
|
||||
("unk2" | uint16L) ::
|
||||
ignore(30) ::
|
||||
("unk3" | uintL(4)) ::
|
||||
ignore(24) ::
|
||||
("viewPitch" | uint8L) ::
|
||||
("viewYaw" | uint8L) ::
|
||||
ignore(10) ::
|
||||
("upperMerit" | uint16L) ::
|
||||
("middleMerit" | uint16L) ::
|
||||
("lowerMerit" | uint16L) ::
|
||||
("termOfServiceMerit" | uint16L) ::
|
||||
// ignore(160) ::
|
||||
// ("healthMax" | uint16L) ::
|
||||
// ("health" | uint16L) ::
|
||||
// ignore(1) ::
|
||||
// ("armor" | uint16L) ::
|
||||
// ignore(1) ::
|
||||
// ignore(8) ::
|
||||
// ignore(9) ::
|
||||
// ("unk4" | uint8L) ::
|
||||
// ignore(8) ::
|
||||
// ("unk5" | uint4L) ::
|
||||
// ("unk6" | uintL(3)) ::
|
||||
// ("staminaMax" | uint16L) ::
|
||||
// ("stamina" | uint16L) ::
|
||||
// ignore(148) ::
|
||||
// ignore(4) ::
|
||||
// ignore(152) ::
|
||||
// ("unk7" | uint16L) ::
|
||||
// ("unk8" | uint8L) ::
|
||||
// ("unk9" | uint8L) ::
|
||||
|
|
@ -170,49 +174,49 @@ object WeaponData extends Marshallable[WeaponData] {
|
|||
// ("unk12" | uintL(12)) ::
|
||||
// ignore(3) ::
|
||||
// (("firstTimeEvent_length" | uint32L) >>:~ { len =>
|
||||
// ("firstEntry" | PacketHelpers.encodedStringAligned(5)) ::
|
||||
// ("firstTimeEvent_list" | PacketHelpers.listOfNSized(len - 1, PacketHelpers.encodedString))
|
||||
// }) ::
|
||||
// ("tutorial_list" | PacketHelpers.listOfNAligned(uint32L, 0, PacketHelpers.encodedString)) ::
|
||||
// ignore(204) ::
|
||||
// ignore(3) ::
|
||||
// ("inventory" | bits)
|
||||
// ).as[CharacterData]
|
||||
//}
|
||||
// conditional(len > 0, "firstEntry" | PacketHelpers.encodedStringAligned(5)) ::
|
||||
// ("firstTimeEvent_list" | PacketHelpers.listOfNSized(len - 1, PacketHelpers.encodedString)) ::
|
||||
// ("tutorial_list" | PacketHelpers.listOfNAligned(uint32L, 0, PacketHelpers.encodedString)) ::
|
||||
// ignore(207) ::
|
||||
("inventory" | bits)
|
||||
// })
|
||||
).as[CharacterData]
|
||||
}
|
||||
|
||||
/**
|
||||
* na
|
||||
* The same kind of data as required for a formal ObjectCreateMessage but with a required and implicit parent relationship.
|
||||
* Data preceding this entry will define the existence of the parent.
|
||||
* @param objectClass na
|
||||
* @param guid na
|
||||
* @param parentSlot na
|
||||
* @param obj na
|
||||
*/
|
||||
case class InternalMold(objectClass : Int,
|
||||
case class InternalSlot(objectClass : Int,
|
||||
guid : PlanetSideGUID,
|
||||
parentSlot : Int,
|
||||
obj : Option[ConstructorData])
|
||||
|
||||
object InternalMold extends Marshallable[InternalMold] {
|
||||
object InternalSlot extends Marshallable[InternalSlot] {
|
||||
type objPattern = Int :: PlanetSideGUID :: Int :: Option[ConstructorData] :: HNil
|
||||
|
||||
implicit val codec : Codec[InternalMold] = (
|
||||
implicit val codec : Codec[InternalSlot] = (
|
||||
ignore(1) :: //TODO determine what this bit does
|
||||
("objectClass" | uintL(11)) ::
|
||||
("guid" | PlanetSideGUID.codec) ::
|
||||
("parentSlot" | PacketHelpers.encodedStringSize) ::
|
||||
("data" | bits)
|
||||
bits
|
||||
).exmap[objPattern] (
|
||||
{
|
||||
case _ :: cls :: guid :: slot :: data :: HNil =>
|
||||
Attempt.successful(cls :: guid :: slot :: Mold.selectMold(cls, data) :: HNil)
|
||||
Attempt.successful(cls :: guid :: slot :: Mold.decode(cls, data) :: HNil)
|
||||
},
|
||||
{
|
||||
case cls :: guid :: slot :: None :: HNil =>
|
||||
Attempt.failure(Err("no constuctor data could be found"))
|
||||
case cls :: guid :: slot :: mold :: HNil =>
|
||||
Attempt.successful(() :: cls :: guid :: slot :: Mold.serialize(cls, mold.get) :: HNil)
|
||||
Attempt.successful(() :: cls :: guid :: slot :: Mold.encode(cls, mold.get) :: HNil)
|
||||
}
|
||||
).exmap[objPattern] (
|
||||
).exmap[objPattern] (
|
||||
{
|
||||
case cls :: guid :: slot :: None :: HNil =>
|
||||
Attempt.failure(Err("no decoded constructor data"))
|
||||
|
|
@ -225,12 +229,12 @@ object InternalMold extends Marshallable[InternalMold] {
|
|||
case cls :: guid :: slot :: data :: HNil =>
|
||||
Attempt.successful(cls :: guid :: slot :: data :: HNil)
|
||||
}
|
||||
).as[InternalMold]
|
||||
).as[InternalSlot]
|
||||
}
|
||||
|
||||
case class Mold(objectClass : Int,
|
||||
data : BitVector) {
|
||||
private var obj : Option[ConstructorData] = Mold.selectMold(objectClass, data)
|
||||
private var obj : Option[ConstructorData] = Mold.decode(objectClass, data)
|
||||
|
||||
def isDefined : Boolean = this.obj.isDefined
|
||||
|
||||
|
|
@ -248,55 +252,59 @@ case class Mold(objectClass : Int,
|
|||
|
||||
object Mold {
|
||||
def apply(objectClass : Int, obj : ConstructorData) : Mold =
|
||||
new Mold( objectClass, Mold.serialize(objectClass, obj) )
|
||||
new Mold( objectClass, Mold.encode(objectClass, obj) )
|
||||
|
||||
def selectMold(objClass : Int, data : BitVector) : Option[ConstructorData] = {
|
||||
def decode(objClass : Int, data : BitVector) : Option[ConstructorData] = {
|
||||
var out : Option[ConstructorData] = None
|
||||
if(!data.isEmpty) {
|
||||
(objClass : @switch) match {
|
||||
case 0x1C => //9mm
|
||||
val opt = AmmoBoxData.codec.decode(data).toOption
|
||||
if(opt.isDefined)
|
||||
out = Some(opt.get.value)
|
||||
case 0x46 => //beamer
|
||||
val opt = WeaponData.codec.decode(data).toOption
|
||||
if(opt.isDefined)
|
||||
out = Some(opt.get.value)
|
||||
case 0x159 => //gauss
|
||||
val opt = WeaponData.codec.decode(data).toOption
|
||||
if(opt.isDefined)
|
||||
out = Some(opt.get.value)
|
||||
case _ =>
|
||||
var outOpt : Option[DecodeResult[_]] = None
|
||||
try {
|
||||
(objClass : @switch) match {
|
||||
case 0x79 => //avatars
|
||||
outOpt = CharacterData.codec.decode(data).toOption
|
||||
case 0x1C => //9mm
|
||||
outOpt = AmmoBoxData.codec.decode(data).toOption
|
||||
case 0x46 => //beamer
|
||||
outOpt = WeaponData.codec.decode(data).toOption
|
||||
case 0x159 => //gauss
|
||||
outOpt = WeaponData.codec.decode(data).toOption
|
||||
case _ =>
|
||||
}
|
||||
if(outOpt.isDefined)
|
||||
out = Some(outOpt.get.value.asInstanceOf[ConstructorData])
|
||||
}
|
||||
catch {
|
||||
case ex : ClassCastException =>
|
||||
//TODO generate and log wrong class error message
|
||||
case ex : Exception =>
|
||||
//TODO generic error
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
def serialize(objClass : Int, obj : ConstructorData) : BitVector = {
|
||||
def encode(objClass : Int, obj : ConstructorData) : BitVector = {
|
||||
var out = BitVector.empty
|
||||
try {
|
||||
var outOpt : Option[BitVector] = None
|
||||
(objClass : @switch) match {
|
||||
case 0x1C => //9mm
|
||||
val opt = AmmoBoxData.codec.encode(obj.asInstanceOf[AmmoBoxData]).toOption
|
||||
if(opt.isDefined)
|
||||
out = opt.get
|
||||
outOpt = AmmoBoxData.codec.encode(obj.asInstanceOf[AmmoBoxData]).toOption
|
||||
case 0x46 => //beamer
|
||||
val opt = WeaponData.codec.encode(obj.asInstanceOf[WeaponData]).toOption
|
||||
if(opt.isDefined)
|
||||
out = opt.get
|
||||
outOpt = WeaponData.codec.encode(obj.asInstanceOf[WeaponData]).toOption
|
||||
case 0x159 => //gauss
|
||||
val opt = WeaponData.codec.encode(obj.asInstanceOf[WeaponData]).toOption
|
||||
if(opt.isDefined)
|
||||
out = opt.get
|
||||
outOpt = WeaponData.codec.encode(obj.asInstanceOf[WeaponData]).toOption
|
||||
case _ =>
|
||||
throw new ClassCastException("cannot find object code - "+objClass)
|
||||
}
|
||||
if(outOpt.isDefined)
|
||||
out = outOpt.get
|
||||
}
|
||||
catch {
|
||||
case ex : ClassCastException =>
|
||||
//TODO generate and log wrong class error message
|
||||
//TODO generate and log wrong class error message
|
||||
case ex : Exception =>
|
||||
//TODO generic error
|
||||
//TODO generic error
|
||||
}
|
||||
out
|
||||
}
|
||||
|
|
@ -453,7 +461,6 @@ object ObjectCreateMessage extends Marshallable[ObjectCreateMessage] {
|
|||
ObjectCreateMessage(len, cls, guid, info, Mold(cls, data))
|
||||
},
|
||||
{
|
||||
//the user should not have to manually supply a proper stream length, that's a restrictive requirement
|
||||
case ObjectCreateMessage(_, cls, guid, info, mold) =>
|
||||
streamLen(info, mold.data) :: cls :: guid :: info :: mold.data :: HNil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue