package tf.bug.fancadescodec import scodec._ import scodec.bits.{BitVector, ByteVector} import scodec.codecs._ object Codecs { lazy val low: Codec[Unit] = constant(BitVector.low(1L)) lazy val high: Codec[Unit] = constant(BitVector.high(1L)) def optionC[A](b: Boolean, c: Codec[A]): Codec[Option[A]] = optional(provide(b), c) lazy val fancadeString: Codec[String] = variableSizeBytes(uint8L, utf8) lazy val cartridgeMagic: Codec[Unit] = constant(ByteVector(0x1B, 0x00)) lazy val entriesMagic: Codec[Unit] = constant(ByteVector(0x2C, 0x02)) lazy val cartridge: Codec[Cartridge] = ( cartridgeMagic ~> fancadeString :: fancadeString :: fancadeString :: (entriesMagic ~> vectorOfN(uint16L, entry)).hlist ).as[Cartridge] lazy val boundary: Codec[Boundary] = (uint16L :: uint16L :: uint16L).as[Boundary] lazy val position: Codec[Position] = (uint16L :: uint16L :: uint16L).as[Position] lazy val face: Codec[Vector[Int]] = fixedSizeBytes(8L * 8L * 8L, vector(uint8L)) lazy val faces: Codec[Faces] = (face :: face :: face :: face :: face :: face).as[Faces] lazy val obj: Codec[Obj] = uint16L.xmap(Obj(_), _.id) lazy val world: Codec[World] = boundary.flatPrepend { b => vectorOfN(provide(b.sizeLR * b.sizeDU * b.sizeNF), obj).hlist }.as[World] lazy val wires: Codec[Vector[Wire]] = vectorOfN(uint16L, wire) lazy val wire: Codec[Wire] = (position :: position :: position :: position.hlist).as[Wire] lazy val metadatas: Codec[Vector[Metadata]] = vectorOfN(uint16L, metadata) lazy val metadata: Codec[Metadata] = discriminated[Metadata].by(uint16L) .subcaseP(0x0100) { case bool: Metadata.Bool => bool } (metadataBool) .subcaseP(0x0201) { case pss: Metadata.PlaySoundSample => pss } (metadataPlaySoundSample) .subcaseP(0x0400) { case num: Metadata.Number => num } (metadataNumber) .subcaseP(0x0500) { case triple: Metadata.Triple => triple } (metadataTriple) .subcaseP(0x0600) { case text: Metadata.Text => text } (metadataText) .subcaseP(0x0700) { case terminal: Metadata.Terminal => terminal } (metadataTerminal) lazy val metadataBool: Codec[Metadata.Bool] = (position :: bool(8).hlist).as[Metadata.Bool] lazy val metadataPlaySoundSample: Codec[Metadata.PlaySoundSample] = (position :: sample.hlist).as[Metadata.PlaySoundSample] lazy val metadataNumber: Codec[Metadata.Number] = (position :: floatL.hlist).as[Metadata.Number] lazy val metadataTriple: Codec[Metadata.Triple] = (position :: floatL :: floatL :: floatL.hlist).as[Metadata.Triple] lazy val metadataText: Codec[Metadata.Text] = (position :: fancadeString.hlist).as[Metadata.Text] lazy val metadataTerminal: Codec[Metadata.Terminal] = (position :: fancadeString.hlist).as[Metadata.Terminal] lazy val sample: Codec[Metadata.Sample] = discriminated[Metadata.Sample].by(uint16L) .subcaseP(0) { case chirp @ Metadata.Sample.Chirp => chirp } (provide(Metadata.Sample.Chirp)) .subcaseP(1) { case scrape @ Metadata.Sample.Scrape => scrape } (provide(Metadata.Sample.Scrape)) .subcaseP(2) { case squeek @ Metadata.Sample.Squeek => squeek } (provide(Metadata.Sample.Squeek)) .subcaseP(3) { case engine @ Metadata.Sample.Engine => engine } (provide(Metadata.Sample.Engine)) .subcaseP(4) { case button @ Metadata.Sample.Button => button } (provide(Metadata.Sample.Button)) .subcaseP(5) { case ball @ Metadata.Sample.Ball => ball } (provide(Metadata.Sample.Ball)) .subcaseP(6) { case piano @ Metadata.Sample.Piano => piano } (provide(Metadata.Sample.Piano)) .subcaseP(7) { case marimba @ Metadata.Sample.Marimba => marimba } (provide(Metadata.Sample.Marimba)) .subcaseP(8) { case pad @ Metadata.Sample.Pad => pad } (provide(Metadata.Sample.Pad)) .subcaseP(9) { case beep @ Metadata.Sample.Beep => beep } (provide(Metadata.Sample.Beep)) .subcaseP(10) { case plop @ Metadata.Sample.Plop => plop } (provide(Metadata.Sample.Plop)) .subcaseP(11) { case flop @ Metadata.Sample.Flop => flop } (provide(Metadata.Sample.Flop)) .subcaseP(12) { case splash @ Metadata.Sample.Splash => splash } (provide(Metadata.Sample.Splash)) .subcaseP(13) { case boom @ Metadata.Sample.Boom => boom } (provide(Metadata.Sample.Boom)) .subcaseP(14) { case hit @ Metadata.Sample.Hit => hit } (provide(Metadata.Sample.Hit)) .subcaseP(15) { case clang @ Metadata.Sample.Clang => clang } (provide(Metadata.Sample.Clang)) .subcaseP(16) { case jump @ Metadata.Sample.Jump => jump } (provide(Metadata.Sample.Jump)) lazy val entry: Codec[Entry] = ( low ~ low ~ low ~ low ~ bool ~ bool ~ bool ~ bool ~ low ~ low ~ low ~ bool ~ high ~ low ~ low ~ low).consume { case (_ ~ _ ~ _ ~ _ ~ isFaces ~ isWorld ~ isMetadata ~ isWires ~ _ ~ _ ~ _ ~ isVisible ~ _ ~ _ ~ _ ~ _) => ( optionC(isVisible, uint8L) :: fancadeString :: optionC(isFaces, faces) :: optionC(isWorld, world) :: optionC(isMetadata, metadatas) :: optionC(isWires, wires).hlist ).as[Entry] } { case Entry(vFlags, _, f, wd, mt, wr) => (() ~ () ~ () ~ () ~ f.isDefined ~ wd.isDefined ~ mt.isDefined ~ wr.isDefined ~ () ~ () ~ () ~ vFlags.isDefined ~ () ~ () ~ () ~ ()) } lazy val encCartridge: Codec[Cartridge] = zlib(cartridge) }