mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-19 18:44:45 +00:00
working encode and decode tests
This commit is contained in:
parent
811bf858f8
commit
1f629cf117
|
|
@ -7,48 +7,85 @@ import scodec.codecs._
|
|||
import shapeless._
|
||||
|
||||
import scala.annotation.switch
|
||||
import scala.util.Try
|
||||
|
||||
case class AmmoBox(magazine : Int)
|
||||
abstract class ConstructorData
|
||||
|
||||
object AmmoBox extends Marshallable[AmmoBox] {
|
||||
implicit val codec : Codec[AmmoBox] = (
|
||||
case class AmmoBoxData(magazine : Int) extends ConstructorData
|
||||
|
||||
object AmmoBoxData extends Marshallable[AmmoBoxData] {
|
||||
implicit val codec : Codec[AmmoBoxData] = (
|
||||
("code" | uintL(23)) ::
|
||||
("magazine" | uint16L)
|
||||
).exmap[AmmoBox] (
|
||||
).exmap[AmmoBoxData] (
|
||||
{
|
||||
case 0xC8 :: mag :: HNil =>
|
||||
Attempt.successful(AmmoBox(mag))
|
||||
Attempt.successful(AmmoBoxData(mag))
|
||||
case x :: _ :: HNil =>
|
||||
Attempt.failure(Err("code wrong - looking for 200, found "+x))
|
||||
},
|
||||
{
|
||||
case AmmoBox(mag) =>
|
||||
case AmmoBoxData(mag) =>
|
||||
Attempt.successful(0xC8 :: mag :: HNil)
|
||||
}
|
||||
).as[AmmoBox]
|
||||
).as[AmmoBoxData]
|
||||
}
|
||||
|
||||
case class Mold(objectClass : Int,
|
||||
data : BitVector) {
|
||||
private val obj : Option[Any] = Mold.selectMold(objectClass, data)
|
||||
private var obj : Option[ConstructorData] = Mold.selectMold(objectClass, data)
|
||||
|
||||
def isDefined : Boolean = this.obj.isDefined
|
||||
|
||||
def get : T forSome { type T } = this.obj.get
|
||||
def get : ConstructorData = this.obj.get
|
||||
|
||||
def set(data : ConstructorData) : Boolean = {
|
||||
var ret = false
|
||||
if(Some(data).isDefined) {
|
||||
obj = Some(data)
|
||||
ret = true
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
object Mold {
|
||||
def apply(objectClass : Int,
|
||||
obj : T forSome { type T }) : Mold =
|
||||
new Mold(objectClass, bin"")
|
||||
def apply(objectClass : Int, obj : ConstructorData) : Mold =
|
||||
new Mold( objectClass, Mold.serialize(objectClass, obj) )
|
||||
|
||||
def selectMold(objClass : Int, data : BitVector) : Option[_] = {
|
||||
(objClass : @switch) match {
|
||||
case 0x1C =>
|
||||
Some(AmmoBox.codec.decode(data))
|
||||
case _ =>
|
||||
None
|
||||
private def selectMold(objClass : Int, data : BitVector) : Option[ConstructorData] = {
|
||||
var out : Option[ConstructorData] = None
|
||||
if(!data.isEmpty) {
|
||||
(objClass : @switch) match {
|
||||
case 0x1C =>
|
||||
val opt = AmmoBoxData.codec.decode(data).toOption
|
||||
if(opt.isDefined) {
|
||||
out = Some(opt.get.value)
|
||||
}
|
||||
case _ =>
|
||||
out = None
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
private def serialize(objClass : Int, obj : ConstructorData) : BitVector = {
|
||||
var out = BitVector.empty
|
||||
try {
|
||||
(objClass : @switch) match {
|
||||
case 0x1C =>
|
||||
val opt = AmmoBoxData.codec.encode(obj.asInstanceOf[AmmoBoxData]).toOption
|
||||
if(opt.isDefined) {
|
||||
out = opt.get
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
case ex : ClassCastException => {
|
||||
//TODO generate and log wrong class error message
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -106,14 +143,6 @@ case class ObjectCreateMessage(streamLength : Long,
|
|||
def encode = ObjectCreateMessage.encode(this)
|
||||
}
|
||||
|
||||
object ObjectCreateMessageParent extends Marshallable[ObjectCreateMessageParent] {
|
||||
implicit val codec : Codec[ObjectCreateMessageParent] = (
|
||||
("guid" | PlanetSideGUID.codec) ::
|
||||
("slot" | PacketHelpers.encodedStringSize)
|
||||
).as[ObjectCreateMessageParent]
|
||||
}
|
||||
|
||||
|
||||
object ObjectCreateMessage extends Marshallable[ObjectCreateMessage] {
|
||||
type Pattern = Int :: PlanetSideGUID :: Option[ObjectCreateMessageParent] :: HNil
|
||||
/**
|
||||
|
|
@ -167,13 +196,20 @@ object ObjectCreateMessage extends Marshallable[ObjectCreateMessage] {
|
|||
* @return the total length of the stream in bits
|
||||
*/
|
||||
private def streamLen(parentInfo : Option[ObjectCreateMessageParent], data : BitVector) : Long = {
|
||||
(if(parentInfo.isDefined) {
|
||||
if(parentInfo.get.slot > 127) 92 else 84 //60u + 16u + (8u or 16u)
|
||||
//known length
|
||||
val first : Long = if(parentInfo.isDefined) {
|
||||
if(parentInfo.get.slot > 127) 92L else 84L //60u + 16u + (8u or 16u)
|
||||
}
|
||||
else {
|
||||
60
|
||||
60L
|
||||
}
|
||||
+ data.size)
|
||||
//variant length
|
||||
var second : Long = data.size
|
||||
val secondMod4 : Long = second % 4L
|
||||
if(secondMod4 > 0L) { //pad to include last whole nibble
|
||||
second += 4L - secondMod4
|
||||
}
|
||||
first + second
|
||||
}
|
||||
|
||||
implicit val codec : Codec[ObjectCreateMessage] = (
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ class GamePacketTest extends Specification {
|
|||
"decode (2)" in {
|
||||
PacketCoding.DecodePacket(packet2).require match {
|
||||
case obj @ ObjectCreateMessage(len, cls, guid, parent, mold) =>
|
||||
len mustEqual 248
|
||||
len mustEqual 248 //60 + 188
|
||||
cls mustEqual 121
|
||||
guid mustEqual PlanetSideGUID(2497)
|
||||
parent mustEqual None
|
||||
|
|
@ -174,6 +174,9 @@ class GamePacketTest extends Specification {
|
|||
parent.get.guid mustEqual PlanetSideGUID(75)
|
||||
parent.get.slot mustEqual 33
|
||||
mold.isDefined mustEqual true
|
||||
|
||||
val obj = mold.get.asInstanceOf[AmmoBoxData]
|
||||
obj.magazine mustEqual 50
|
||||
case default =>
|
||||
ko
|
||||
}
|
||||
|
|
@ -185,6 +188,14 @@ class GamePacketTest extends Specification {
|
|||
|
||||
pkt mustEqual packet2
|
||||
}
|
||||
|
||||
"encode (9mm)" in {
|
||||
val obj = Mold(28, AmmoBoxData(50))
|
||||
val msg = ObjectCreateMessage(0, 28, PlanetSideGUID(1280), Some(ObjectCreateMessageParent(PlanetSideGUID(75), 33)), obj)
|
||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||
|
||||
pkt mustEqual string_9mm
|
||||
}
|
||||
}
|
||||
|
||||
"ChatMsg" should {
|
||||
|
|
|
|||
Loading…
Reference in a new issue