mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-04-29 16:25:30 +00:00
prototype for weapon data codec
This commit is contained in:
parent
1f629cf117
commit
72b400e1d0
2 changed files with 316 additions and 28 deletions
|
|
@ -74,38 +74,35 @@ object PlanetSidePacketFlags extends Marshallable[PlanetSidePacketFlags] {
|
||||||
object PacketHelpers {
|
object PacketHelpers {
|
||||||
/** Used in certain instances where Codec defintions are stubbed out */
|
/** Used in certain instances where Codec defintions are stubbed out */
|
||||||
def emptyCodec[T](instance : T) = {
|
def emptyCodec[T](instance : T) = {
|
||||||
def to(pkt: T) = HNil
|
def to(pkt : T) = HNil
|
||||||
def from(a: HNil) = instance
|
def from(a : HNil) = instance
|
||||||
Codec[HNil].xmap[T](from, to)
|
Codec[HNil].xmap[T](from, to)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Create a Codec for an enumeration type that can correctly represent its value
|
/** Create a Codec for an enumeration type that can correctly represent its value
|
||||||
*
|
* @param enum the enumeration type to create a codec for
|
||||||
* @param enum the enumeration type to create a codec for
|
|
||||||
* @param storageCodec the Codec used for actually representing the value
|
* @param storageCodec the Codec used for actually representing the value
|
||||||
* @tparam E The inferred type
|
* @tparam E The inferred type
|
||||||
* @return Generated codec
|
* @return Generated codec
|
||||||
*/
|
*/
|
||||||
def createEnumerationCodec[E <: Enumeration](enum : E, storageCodec : Codec[Int]) : Codec[E#Value] = {
|
def createEnumerationCodec[E <: Enumeration](enum : E, storageCodec : Codec[Int]) : Codec[E#Value] = {
|
||||||
type Struct = Int :: HNil
|
type Struct = Int :: HNil
|
||||||
val struct: Codec[Struct] = storageCodec.hlist
|
val struct : Codec[Struct] = storageCodec.hlist
|
||||||
val primitiveLimit = Math.pow(2, storageCodec.sizeBound.exact.get)
|
val primitiveLimit = Math.pow(2, storageCodec.sizeBound.exact.get)
|
||||||
|
|
||||||
// Assure that the enum will always be able to fit in a N-bit int
|
// Assure that the enum will always be able to fit in a N-bit int
|
||||||
assert(enum.maxId <= primitiveLimit,
|
assert(enum.maxId <= primitiveLimit,
|
||||||
enum.getClass.getCanonicalName + s": maxId exceeds primitive type (limit of $primitiveLimit, maxId ${enum.maxId})")
|
enum.getClass.getCanonicalName + s": maxId exceeds primitive type (limit of $primitiveLimit, maxId ${enum.maxId})")
|
||||||
|
|
||||||
def to(pkt: E#Value): Struct = {
|
def to(pkt : E#Value) : Struct = {
|
||||||
pkt.id :: HNil
|
pkt.id :: HNil
|
||||||
}
|
}
|
||||||
|
|
||||||
def from(struct: Struct): Attempt[E#Value] = struct match {
|
def from(struct : Struct) : Attempt[E#Value] = struct match {
|
||||||
case enumVal :: HNil =>
|
case enumVal :: HNil =>
|
||||||
// verify that this int can match the enum
|
// verify that this int can match the enum
|
||||||
val first = enum.values.firstKey.id
|
val first = enum.values.firstKey.id
|
||||||
val last = enum.maxId-1
|
val last = enum.maxId - 1
|
||||||
|
|
||||||
if(enumVal >= first && enumVal <= last)
|
if(enumVal >= first && enumVal <= last)
|
||||||
Attempt.successful(enum(enumVal))
|
Attempt.successful(enum(enumVal))
|
||||||
|
|
@ -144,13 +141,11 @@ object PacketHelpers {
|
||||||
/** Codec for how PlanetSide represents strings on the wire */
|
/** Codec for how PlanetSide represents strings on the wire */
|
||||||
def encodedString : Codec[String] = variableSizeBytes(encodedStringSize, ascii)
|
def encodedString : Codec[String] = variableSizeBytes(encodedStringSize, ascii)
|
||||||
|
|
||||||
|
|
||||||
/** Same as [[encodedString]] but with a bit adjustment
|
/** Same as [[encodedString]] but with a bit adjustment
|
||||||
*
|
*
|
||||||
* This comes in handy when a PlanetSide string is decoded on a non-byte boundary. The PlanetSide client
|
* This comes in handy when a PlanetSide string is decoded on a non-byte boundary. The PlanetSide client
|
||||||
* will byte align after decoding the string lenght, but BEFORE the string itself. Scodec doesn't like this
|
* will byte align after decoding the string lenght, but BEFORE the string itself. Scodec doesn't like this
|
||||||
* variability and there doesn't appear to be a way to fix this issue.
|
* variability and there doesn't appear to be a way to fix this issue.
|
||||||
*
|
|
||||||
* @param adjustment The adjustment amount in bits
|
* @param adjustment The adjustment amount in bits
|
||||||
* @return Generated string decoding codec with adjustment
|
* @return Generated string decoding codec with adjustment
|
||||||
*/
|
*/
|
||||||
|
|
@ -165,15 +160,15 @@ object PacketHelpers {
|
||||||
* input string. We use xmap to transform the [[encodedString]] codec as this change is just a division and multiply
|
* input string. We use xmap to transform the [[encodedString]] codec as this change is just a division and multiply
|
||||||
*/
|
*/
|
||||||
def encodedWideString : Codec[String] = variableSizeBytes(encodedStringSize.xmap(
|
def encodedWideString : Codec[String] = variableSizeBytes(encodedStringSize.xmap(
|
||||||
insize => insize*2, // number of symbols -> number of bytes (decode)
|
insize => insize * 2, // number of symbols -> number of bytes (decode)
|
||||||
outSize => outSize/2 // number of bytes -> number of symbols (encode)
|
outSize => outSize / 2 // number of bytes -> number of symbols (encode)
|
||||||
), utf16)
|
), utf16)
|
||||||
|
|
||||||
/** Same as [[encodedWideString]] but with a bit alignment after the decoded size
|
/** Same as [[encodedWideString]] but with a bit alignment after the decoded size
|
||||||
*/
|
*/
|
||||||
def encodedWideStringAligned(adjustment : Int) : Codec[String] = variableSizeBytes(encodedStringSizeWithPad(adjustment).xmap(
|
def encodedWideStringAligned(adjustment : Int) : Codec[String] = variableSizeBytes(encodedStringSizeWithPad(adjustment).xmap(
|
||||||
insize => insize*2,
|
insize => insize * 2,
|
||||||
outSize => outSize/2
|
outSize => outSize / 2
|
||||||
), utf16)
|
), utf16)
|
||||||
|
|
||||||
// TODO: make the function below work as there are places it should be used
|
// TODO: make the function below work as there are places it should be used
|
||||||
|
|
@ -203,4 +198,105 @@ object PacketHelpers {
|
||||||
|
|
||||||
def encodedStringWithLimit(limit : Int) : Codec[String] = variableSizeBytes(encodedStringSizeWithLimit(limit), ascii)
|
def encodedStringWithLimit(limit : Int) : Codec[String] = variableSizeBytes(encodedStringSizeWithLimit(limit), ascii)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode and decode a byte-aligned `List`.<br>
|
||||||
|
* <br>
|
||||||
|
* This function is copied almost verbatim from its source, with exception of swapping the normal `ListCodec` for a new `AlignedListCodec`.
|
||||||
|
* @param countCodec the codec that represents the prefixed size of the `List`
|
||||||
|
* @param alignment the number of bits padded between the `List` size and the `List` contents
|
||||||
|
* @param valueCodec a codec that describes each of the contents of the `List`
|
||||||
|
* @tparam A the type of the `List` contents
|
||||||
|
* @see codec\package.scala, listOfN
|
||||||
|
* @return a codec that works on a List of A
|
||||||
|
*/
|
||||||
|
def listOfNAligned[A](countCodec : Codec[Long], alignment : Int, valueCodec : Codec[A]) : Codec[List[A]] = {
|
||||||
|
countCodec.
|
||||||
|
flatZip { count => new AlignedListCodec(countCodec, valueCodec, alignment, Some(count)) }.
|
||||||
|
narrow[List[A]]({ case (cnt, xs) =>
|
||||||
|
if(xs.size == cnt) Attempt.successful(xs)
|
||||||
|
else Attempt.failure(Err(s"Insufficient number of elements: decoded ${xs.size} but should have decoded $cnt"))
|
||||||
|
}, xs => (xs.size, xs)).
|
||||||
|
withToString(s"listOfN($countCodec, $valueCodec)")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Codec that encodes/decodes a list of `n` elements, where `n` is known at compile time.<br>
|
||||||
|
* <br>
|
||||||
|
* This function is copied almost verbatim from its source, with exception of swapping the parameter that is normally a `Nat` `literal`.
|
||||||
|
* The modified function takes a normal unsigned `Integer` and assures that the parameter is non-negative before further processing.
|
||||||
|
* @param size the known size of the `List`
|
||||||
|
* @param codec a codec that describes each of the contents of the `List`
|
||||||
|
* @tparam A the type of the `List` contents
|
||||||
|
* @see codec\package.scala, sizedList
|
||||||
|
* @see codec\package.scala, listOfN
|
||||||
|
* @see codec\package.scala, provides
|
||||||
|
* @return a codec that works on a List of A but excludes the size from the encoding
|
||||||
|
*/
|
||||||
|
def listOfNSized[A](size : Long, codec : Codec[A]) : Codec[List[A]] = PacketHelpers.listOfNAligned(provide(if(size < 0) 0 else size), 0, codec)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The codec that encodes and decodes a byte-aligned `List`.<br>
|
||||||
|
* <br>
|
||||||
|
* This class is copied almost verbatim from its source, with only heavy modifications to its `encode` process.
|
||||||
|
* @param countCodec the codec that represents the prefixed size of the `List`
|
||||||
|
* @param valueCodec a codec that describes each of the contents of the `List`
|
||||||
|
* @param alignment the number of bits padded between the `List` size and the `List` contents (on successful)
|
||||||
|
* @param limit the number of elements in the `List`
|
||||||
|
* @tparam A the type of the `List` contents
|
||||||
|
* @see ListCodec.scala
|
||||||
|
*/
|
||||||
|
private class AlignedListCodec[A](countCodec : Codec[Long], valueCodec: Codec[A], alignment : Int, limit: Option[Long] = None) extends Codec[List[A]] {
|
||||||
|
/**
|
||||||
|
* Convert a `List` of elements into a byte-aligned `BitVector`.<br>
|
||||||
|
* <br>
|
||||||
|
* Bit padding after the encoded size of the `List` is only added if the `alignment` value is greater than zero and the initial encoding process was successful.
|
||||||
|
* The padding is rather heavy-handed and a completely different `BitVector` is returned if successful.
|
||||||
|
* Performance hits for this complexity are not expected to be significant.
|
||||||
|
* @param list the `List` to be encoded
|
||||||
|
* @return the `BitVector` encoding, if successful
|
||||||
|
*/
|
||||||
|
override def encode(list : List[A]) : Attempt[BitVector] = {
|
||||||
|
val solve : Attempt[BitVector] = Encoder.encodeSeq(valueCodec)(list)
|
||||||
|
if(alignment > 0) {
|
||||||
|
solve match {
|
||||||
|
case Attempt.Successful(vector) =>
|
||||||
|
val countCodecSize : Long = countCodec.sizeBound.lowerBound
|
||||||
|
return Attempt.successful(vector.take(countCodecSize) ++ BitVector.fill(alignment)(false) ++ vector.drop(countCodecSize))
|
||||||
|
case _ =>
|
||||||
|
return Attempt.failure(Err("failed to create a list"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
solve
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a byte-aligned `BitVector` into a `List` of elements.
|
||||||
|
* @param buffer the encoded bits in the `List`, preceded by the alignment bits
|
||||||
|
* @return the decoded `List`
|
||||||
|
*/
|
||||||
|
def decode(buffer: BitVector) = {
|
||||||
|
val lim = Option( if(limit.isDefined) limit.get.asInstanceOf[Int] else 0 ) //TODO potentially unsafe size conversion
|
||||||
|
Decoder.decodeCollect[List, A](valueCodec, lim)(buffer.drop(alignment))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the encoded `List`.<br>
|
||||||
|
* <br>
|
||||||
|
* Unchanged from original.
|
||||||
|
* @return the size as calculated by the size of each element for each element
|
||||||
|
*/
|
||||||
|
def sizeBound = limit match {
|
||||||
|
case None => SizeBound.unknown
|
||||||
|
case Some(lim) => valueCodec.sizeBound * lim
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a `String` representation of this `List`.<br>
|
||||||
|
* <br>
|
||||||
|
* Unchanged from original.
|
||||||
|
* @return the `String` representation
|
||||||
|
*/
|
||||||
|
override def toString = s"list($valueCodec)"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
package net.psforever.packet.game
|
package net.psforever.packet.game
|
||||||
|
|
||||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
||||||
|
//import net.psforever.types.Vector3
|
||||||
import scodec.bits._
|
import scodec.bits._
|
||||||
import scodec.{Attempt, Codec, Err}
|
import scodec.{Attempt, Codec, Err}
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
import shapeless._
|
import shapeless._
|
||||||
|
|
||||||
import scala.annotation.switch
|
import scala.annotation.switch
|
||||||
import scala.util.Try
|
|
||||||
|
|
||||||
abstract class ConstructorData
|
abstract class ConstructorData
|
||||||
|
|
||||||
|
|
@ -31,6 +31,190 @@ object AmmoBoxData extends Marshallable[AmmoBoxData] {
|
||||||
).as[AmmoBoxData]
|
).as[AmmoBoxData]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case class WeaponData(ammo : InternalMold) extends ConstructorData
|
||||||
|
|
||||||
|
object WeaponData extends Marshallable[WeaponData] {
|
||||||
|
implicit val codec : Codec[WeaponData] = (
|
||||||
|
("code" | uint16L) ::
|
||||||
|
ignore(12) ::
|
||||||
|
uint4L ::
|
||||||
|
ignore(4) ::
|
||||||
|
uintL(12) ::
|
||||||
|
("data" | InternalMold.codec)
|
||||||
|
).exmap[WeaponData] (
|
||||||
|
{
|
||||||
|
case 0x88 :: _ :: 2 :: _ :: 0x2C0 :: ammo :: HNil =>
|
||||||
|
Attempt.successful(WeaponData(ammo))
|
||||||
|
case x :: _ :: y :: _ :: z :: _ :: HNil =>
|
||||||
|
Attempt.failure(Err("code wrong - looking for 136-2-704, found %d-%d-%d".format(x,y,z)))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
case WeaponData(ammo) =>
|
||||||
|
Attempt.successful(0x88 :: () :: 2 :: () :: 0x2C0 :: ammo :: HNil)
|
||||||
|
}
|
||||||
|
).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,
|
||||||
|
// healthMax : Int,
|
||||||
|
// health : Int,
|
||||||
|
// armor : Int,
|
||||||
|
// unk4 : Int, //1
|
||||||
|
// unk5 : Int, //7
|
||||||
|
// unk6 : Int, //7
|
||||||
|
// staminaMax : Int,
|
||||||
|
// stamina : Int,
|
||||||
|
// unk7 : Int, // 192
|
||||||
|
// unk8 : Int, //66
|
||||||
|
// unk9 : Int, //197
|
||||||
|
// unk10 : Int, //70
|
||||||
|
// unk11 : Int, //134
|
||||||
|
// unk12 : Int, //199
|
||||||
|
// firstTimeEvent_length : Long,
|
||||||
|
// firstEntry : String,
|
||||||
|
// firstTimEvent_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) ::
|
||||||
|
// ("healthMax" | uint16L) ::
|
||||||
|
// ("health" | uint16L) ::
|
||||||
|
// ignore(1) ::
|
||||||
|
// ("armor" | uint16L) ::
|
||||||
|
// ignore(1) ::
|
||||||
|
// ignore(8) ::
|
||||||
|
// ("unk4" | uint8L) ::
|
||||||
|
// ignore(8) ::
|
||||||
|
// ("unk5" | uint4L) ::
|
||||||
|
// ("unk6" | uintL(3)) ::
|
||||||
|
// ("staminaMax" | uint16L) ::
|
||||||
|
// ("stamina" | uint16L) ::
|
||||||
|
// ignore(148) ::
|
||||||
|
// ignore(4) ::
|
||||||
|
// ("unk7" | uint16L) ::
|
||||||
|
// ("unk8" | uint8L) ::
|
||||||
|
// ("unk9" | uint8L) ::
|
||||||
|
// ("unk10" | uint8L) ::
|
||||||
|
// ("unk11" | uint8L) ::
|
||||||
|
// ("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]
|
||||||
|
//}
|
||||||
|
|
||||||
|
case class InternalMold(objectClass : Int,
|
||||||
|
guid : PlanetSideGUID,
|
||||||
|
parentSlot : Int,
|
||||||
|
obj : Option[ConstructorData])
|
||||||
|
|
||||||
|
object InternalMold extends Marshallable[InternalMold] {
|
||||||
|
type objPattern = Int :: PlanetSideGUID :: Int :: Option[ConstructorData] :: HNil
|
||||||
|
|
||||||
|
implicit val codec : Codec[InternalMold] = (
|
||||||
|
ignore(1) :: //TODO determine what this bit does
|
||||||
|
("objectClass" | uintL(11)) ::
|
||||||
|
("guid" | PlanetSideGUID.codec) ::
|
||||||
|
("parentSlot" | PacketHelpers.encodedStringSize) ::
|
||||||
|
("data" | bits)
|
||||||
|
).exmap[objPattern] (
|
||||||
|
{
|
||||||
|
case _ :: cls :: guid :: slot :: data :: HNil =>
|
||||||
|
Attempt.successful(cls :: guid :: slot :: Mold.selectMold(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)
|
||||||
|
}
|
||||||
|
).exmap[objPattern] (
|
||||||
|
{
|
||||||
|
case cls :: guid :: slot :: None :: HNil =>
|
||||||
|
Attempt.failure(Err("no decoded constructor data"))
|
||||||
|
case cls :: guid :: slot :: mold :: HNil =>
|
||||||
|
Attempt.successful(cls :: guid :: slot :: mold :: HNil)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
case cls :: guid :: slot :: BitVector.empty :: HNil =>
|
||||||
|
Attempt.failure(Err("no encoded constructor data"))
|
||||||
|
case cls :: guid :: slot :: data :: HNil =>
|
||||||
|
Attempt.successful(cls :: guid :: slot :: data :: HNil)
|
||||||
|
}
|
||||||
|
).as[InternalMold]
|
||||||
|
}
|
||||||
|
|
||||||
case class Mold(objectClass : Int,
|
case class Mold(objectClass : Int,
|
||||||
data : BitVector) {
|
data : BitVector) {
|
||||||
private var obj : Option[ConstructorData] = Mold.selectMold(objectClass, data)
|
private var obj : Option[ConstructorData] = Mold.selectMold(objectClass, data)
|
||||||
|
|
@ -53,37 +237,45 @@ object Mold {
|
||||||
def apply(objectClass : Int, obj : ConstructorData) : Mold =
|
def apply(objectClass : Int, obj : ConstructorData) : Mold =
|
||||||
new Mold( objectClass, Mold.serialize(objectClass, obj) )
|
new Mold( objectClass, Mold.serialize(objectClass, obj) )
|
||||||
|
|
||||||
private def selectMold(objClass : Int, data : BitVector) : Option[ConstructorData] = {
|
def selectMold(objClass : Int, data : BitVector) : Option[ConstructorData] = {
|
||||||
var out : Option[ConstructorData] = None
|
var out : Option[ConstructorData] = None
|
||||||
if(!data.isEmpty) {
|
if(!data.isEmpty) {
|
||||||
(objClass : @switch) match {
|
(objClass : @switch) match {
|
||||||
case 0x1C =>
|
case 0x1C => //9mm
|
||||||
val opt = AmmoBoxData.codec.decode(data).toOption
|
val opt = AmmoBoxData.codec.decode(data).toOption
|
||||||
if(opt.isDefined) {
|
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)
|
out = Some(opt.get.value)
|
||||||
}
|
|
||||||
case _ =>
|
case _ =>
|
||||||
out = None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
private def serialize(objClass : Int, obj : ConstructorData) : BitVector = {
|
def serialize(objClass : Int, obj : ConstructorData) : BitVector = {
|
||||||
var out = BitVector.empty
|
var out = BitVector.empty
|
||||||
try {
|
try {
|
||||||
(objClass : @switch) match {
|
(objClass : @switch) match {
|
||||||
case 0x1C =>
|
case 0x1C => //9mm
|
||||||
val opt = AmmoBoxData.codec.encode(obj.asInstanceOf[AmmoBoxData]).toOption
|
val opt = AmmoBoxData.codec.encode(obj.asInstanceOf[AmmoBoxData]).toOption
|
||||||
if(opt.isDefined) {
|
if(opt.isDefined)
|
||||||
out = opt.get
|
out = opt.get
|
||||||
}
|
case 0x46 => //beamer
|
||||||
|
val opt = WeaponData.codec.encode(obj.asInstanceOf[WeaponData]).toOption
|
||||||
|
if(opt.isDefined)
|
||||||
|
out = opt.get
|
||||||
|
case _ =>
|
||||||
|
throw new ClassCastException("cannot find object code - "+objClass)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
case ex : ClassCastException => {
|
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
|
||||||
}
|
}
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue