From 1f629cf117dd74784076c3ba59ac02148c4eef09 Mon Sep 17 00:00:00 2001 From: FateJH Date: Sat, 26 Nov 2016 22:40:19 -0500 Subject: [PATCH] working encode and decode tests --- .../packet/game/ObjectCreateMessage.scala | 96 +++++++++++++------ common/src/test/scala/GamePacketTest.scala | 13 ++- 2 files changed, 78 insertions(+), 31 deletions(-) diff --git a/common/src/main/scala/net/psforever/packet/game/ObjectCreateMessage.scala b/common/src/main/scala/net/psforever/packet/game/ObjectCreateMessage.scala index 3730482cc..b397ff552 100644 --- a/common/src/main/scala/net/psforever/packet/game/ObjectCreateMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/ObjectCreateMessage.scala @@ -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] = ( diff --git a/common/src/test/scala/GamePacketTest.scala b/common/src/test/scala/GamePacketTest.scala index 6366f785f..54be73b6b 100644 --- a/common/src/test/scala/GamePacketTest.scala +++ b/common/src/test/scala/GamePacketTest.scala @@ -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 {