packages feed

rattletrap 12.0.0 → 12.0.1

raw patch · 110 files changed

+3834/−3512 lines, 110 filesdep ~bytestringPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: bytestring

API changes (from Hackage documentation)

Files

LICENSE.markdown view
@@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Taylor Fausak+Copyright (c) 2023 Taylor Fausak  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal
README.markdown view
@@ -1,8 +1,8 @@ # [Rattletrap][] -[![Version badge][]][version]-[![Build badge][]][build]-[![Docker badge][]][docker]+[![Workflow](https://github.com/tfausak/rattletrap/actions/workflows/workflow.yaml/badge.svg)](https://github.com/tfausak/rattletrap/actions/workflows/workflow.yaml)+[![Hackage](https://img.shields.io/hackage/v/rattletrap)](https://hackage.haskell.org/package/rattletrap)+[![Stackage](https://www.stackage.org/package/rattletrap/badge/nightly?label=stackage)](https://www.stackage.org/package/rattletrap)  Rattletrap parses and generates [Rocket League][] replays. Parsing replays can be used to analyze data in order to collect high-level statistics like players@@ -21,10 +21,10 @@ using another tool like [Ball Chasing][].  The best way to get Rattletrap is by downloading [the latest release][] for-your platform. Rattletrap is also available as [a Docker image][docker].+your platform.  Rattletrap is written in [Haskell][]. To build Rattletrap from source, install-[Stack][]. Then run `stack --resolver nightly-2021-08-14 install rattletrap`.+[Stack][]. Then run `stack --resolver nightly-2023-02-12 install rattletrap`. If you'd like to use a program written in a different language, consider one of the following: @@ -56,7 +56,7 @@ ```  ```-rattletrap version 11.2.0+rattletrap version 12.0.0   -c           --compact         minify JSON output   -f           --fast            only encode or decode the header   -h           --help            show the help@@ -133,8 +133,6 @@ [version]: https://hackage.haskell.org/package/rattletrap [Build badge]: https://github.com/tfausak/rattletrap/workflows/ci/badge.svg [build]: https://github.com/tfausak/rattletrap/actions-[Docker badge]: https://img.shields.io/docker/v/taylorfausak/rattletrap?label=docker&logo=docker&logoColor=white-[docker]: https://hub.docker.com/r/taylorfausak/rattletrap [Rocket League]: https://www.rocketleague.com [2.23]: https://www.rocketleague.com/news/patch-notes-v2-23/ [Ball Chasing]: https://ballchasing.com
rattletrap.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.2  name: rattletrap-version: 12.0.0+version: 12.0.1 synopsis: Parse and generate Rocket League replays. description: Rattletrap parses and generates Rocket League replays. @@ -18,6 +18,7 @@  flag pedantic   default: False+  description: Enables @-Werror@, which turns warnings into errors.   manual: True  common library@@ -58,7 +59,7 @@     , aeson ^>= 2.0.3 || ^>= 2.1.0     , aeson-pretty ^>= 0.8.9     , array ^>= 0.5.4-    , bytestring >= 0.10 && < 0.12+    , bytestring >= 0.10.12 && < 0.12     , containers >= 0.6 && < 0.7     , filepath ^>= 1.4.2     , http-client ^>= 0.7.11@@ -212,7 +213,7 @@   hs-source-dirs: src/exe   main-is: Main.hs -test-suite test+test-suite rattletrap-test-suite   import: executable    build-depends: bytestring, filepath
src/lib/Rattletrap.hs view
@@ -1,11 +1,12 @@ module Rattletrap-  ( Rattletrap.Console.Main.main-  , Rattletrap.Console.Main.rattletrap-  , Rattletrap.Utility.Helper.decodeReplayFile-  , Rattletrap.Utility.Helper.encodeReplayJson-  , Rattletrap.Utility.Helper.decodeReplayJson-  , Rattletrap.Utility.Helper.encodeReplayFile-  ) where+  ( Rattletrap.Console.Main.main,+    Rattletrap.Console.Main.rattletrap,+    Rattletrap.Utility.Helper.decodeReplayFile,+    Rattletrap.Utility.Helper.encodeReplayJson,+    Rattletrap.Utility.Helper.decodeReplayJson,+    Rattletrap.Utility.Helper.encodeReplayFile,+  )+where  import qualified Rattletrap.Console.Main import qualified Rattletrap.Utility.Helper
src/lib/Rattletrap/BitBuilder.hs view
@@ -8,25 +8,25 @@ import qualified Data.Word as Word  data BitBuilder = BitBuilder-  { buffer :: Word.Word8-  , builder :: Builder.Builder-  , offset :: Int+  { buffer :: Word.Word8,+    builder :: Builder.Builder,+    offset :: Int   }  empty :: BitBuilder-empty = BitBuilder { buffer = 0x00, builder = mempty, offset = 0 }+empty = BitBuilder {buffer = 0x00, builder = mempty, offset = 0}  push :: Bool -> BitBuilder -> BitBuilder push b x =   let !newBuffer = if b then Bits.setBit (buffer x) (offset x) else buffer x-  in-    if offset x == 7-      then BitBuilder-        { buffer = 0x00-        , builder = builder x <> Builder.word8 newBuffer-        , offset = 0-        }-      else x { buffer = newBuffer, offset = offset x + 1 }+   in if offset x == 7+        then+          BitBuilder+            { buffer = 0x00,+              builder = builder x <> Builder.word8 newBuffer,+              offset = 0+            }+        else x {buffer = newBuffer, offset = offset x + 1}  toBuilder :: BitBuilder -> Builder.Builder toBuilder x =
src/lib/Rattletrap/BitGet.hs view
@@ -26,11 +26,10 @@   x <- byteString n   Get.embed f x -bits :: Bits.Bits a => Int -> BitGet a+bits :: (Bits.Bits a) => Int -> BitGet a bits n = do-  let-    f :: Bits.Bits a => Bool -> a -> a-    f bit x = let y = Bits.shiftL x 1 in if bit then Bits.setBit y 0 else y+  let f :: (Bits.Bits a) => Bool -> a -> a+      f bit x = let y = Bits.shiftL x 1 in if bit then Bits.setBit y 0 else y   xs <- Monad.replicateM n bool   pure $ foldr f Bits.zeroBits xs @@ -46,7 +45,7 @@ byteString :: Int -> BitGet ByteString.ByteString byteString n = fmap ByteString.pack . Monad.replicateM n $ bits 8 -throw :: Exception.Exception e => e -> BitGet a+throw :: (Exception.Exception e) => e -> BitGet a throw = Get.throw  label :: String -> BitGet a -> BitGet a
src/lib/Rattletrap/BitPut.hs view
@@ -22,7 +22,7 @@ fromBytePut :: BytePut.BytePut -> BitPut fromBytePut = byteString . BytePut.toByteString -bits :: Bits.Bits a => Int -> a -> BitPut+bits :: (Bits.Bits a) => Int -> a -> BitPut bits n x = foldMap (bool . Bits.testBit x) [0 .. n - 1]  bool :: Bool -> BitPut
src/lib/Rattletrap/BitString.hs view
@@ -4,20 +4,20 @@ import qualified Data.ByteString as ByteString  data BitString = BitString-  { byteString :: ByteString.ByteString-  , offset :: Int+  { byteString :: ByteString.ByteString,+    offset :: Int   }   deriving (Eq, Show)  fromByteString :: ByteString.ByteString -> BitString-fromByteString byteString = BitString { byteString, offset = 0 }+fromByteString byteString = BitString {byteString, offset = 0}  pop :: BitString -> Maybe (Bool, BitString) pop old = do   (word, byteString) <- ByteString.uncons $ byteString old-  let-    bit = Bits.testBit word $ offset old-    new = if offset old == 7-      then fromByteString byteString-      else old { offset = offset old + 1 }+  let bit = Bits.testBit word $ offset old+      new =+        if offset old == 7+          then fromByteString byteString+          else old {offset = offset old + 1}   pure (bit, new)
src/lib/Rattletrap/ByteGet.hs view
@@ -13,10 +13,10 @@  type ByteGet = Get.Get ByteString.ByteString Identity.Identity -run-  :: ByteGet a-  -> ByteString.ByteString-  -> Either ([String], Exception.SomeException) a+run ::+  ByteGet a ->+  ByteString.ByteString ->+  Either ([String], Exception.SomeException) a run g = fmap snd . Identity.runIdentity . Get.run g  byteString :: Int -> ByteGet ByteString.ByteString@@ -53,26 +53,26 @@ word32 :: ByteGet Word.Word32 word32 = do   x <- byteString 4-  pure-    $ Bits.shiftL (fromIntegral $ ByteString.index x 0) 0-    + Bits.shiftL (fromIntegral $ ByteString.index x 1) 8-    + Bits.shiftL (fromIntegral $ ByteString.index x 2) 16-    + Bits.shiftL (fromIntegral $ ByteString.index x 3) 24+  pure $+    Bits.shiftL (fromIntegral $ ByteString.index x 0) 0+      + Bits.shiftL (fromIntegral $ ByteString.index x 1) 8+      + Bits.shiftL (fromIntegral $ ByteString.index x 2) 16+      + Bits.shiftL (fromIntegral $ ByteString.index x 3) 24  word64 :: ByteGet Word.Word64 word64 = do   x <- byteString 8-  pure-    $ Bits.shiftL (fromIntegral $ ByteString.index x 0) 0-    + Bits.shiftL (fromIntegral $ ByteString.index x 1) 8-    + Bits.shiftL (fromIntegral $ ByteString.index x 2) 16-    + Bits.shiftL (fromIntegral $ ByteString.index x 3) 24-    + Bits.shiftL (fromIntegral $ ByteString.index x 4) 32-    + Bits.shiftL (fromIntegral $ ByteString.index x 5) 40-    + Bits.shiftL (fromIntegral $ ByteString.index x 6) 48-    + Bits.shiftL (fromIntegral $ ByteString.index x 7) 56+  pure $+    Bits.shiftL (fromIntegral $ ByteString.index x 0) 0+      + Bits.shiftL (fromIntegral $ ByteString.index x 1) 8+      + Bits.shiftL (fromIntegral $ ByteString.index x 2) 16+      + Bits.shiftL (fromIntegral $ ByteString.index x 3) 24+      + Bits.shiftL (fromIntegral $ ByteString.index x 4) 32+      + Bits.shiftL (fromIntegral $ ByteString.index x 5) 40+      + Bits.shiftL (fromIntegral $ ByteString.index x 6) 48+      + Bits.shiftL (fromIntegral $ ByteString.index x 7) 56 -throw :: Exception.Exception e => e -> ByteGet a+throw :: (Exception.Exception e) => e -> ByteGet a throw = Get.throw  embed :: ByteGet a -> ByteString.ByteString -> ByteGet a
src/lib/Rattletrap/Console/Config.hs view
@@ -5,53 +5,53 @@ import qualified System.FilePath as FilePath  data Config = Config-  { compact :: Bool-  , fast :: Bool-  , help :: Bool-  , input :: Maybe String-  , mode :: Maybe Mode.Mode-  , output :: Maybe String-  , schema :: Bool-  , skipCrc :: Bool-  , version :: Bool+  { compact :: Bool,+    fast :: Bool,+    help :: Bool,+    input :: Maybe String,+    mode :: Maybe Mode.Mode,+    output :: Maybe String,+    schema :: Bool,+    skipCrc :: Bool,+    version :: Bool   }   deriving (Eq, Show)  initial :: Config-initial = Config-  { compact = False-  , fast = False-  , help = False-  , input = Nothing-  , mode = Nothing-  , output = Nothing-  , schema = False-  , skipCrc = False-  , version = False-  }+initial =+  Config+    { compact = False,+      fast = False,+      help = False,+      input = Nothing,+      mode = Nothing,+      output = Nothing,+      schema = False,+      skipCrc = False,+      version = False+    }  applyFlag :: Config -> Flag.Flag -> Either String Config applyFlag config flag = case flag of-  Flag.Compact -> Right config { compact = True }-  Flag.Fast -> Right config { fast = True }-  Flag.Help -> Right config { help = True }-  Flag.Input x -> Right config { input = Just x }+  Flag.Compact -> Right config {compact = True}+  Flag.Fast -> Right config {fast = True}+  Flag.Help -> Right config {help = True}+  Flag.Input x -> Right config {input = Just x}   Flag.Mode x -> do     y <- Mode.fromString x-    Right config { mode = Just y }-  Flag.Output x -> Right config { output = Just x }-  Flag.Schema -> Right config { schema = True }-  Flag.SkipCrc -> Right config { skipCrc = True }-  Flag.Version -> Right config { version = True }+    Right config {mode = Just y}+  Flag.Output x -> Right config {output = Just x}+  Flag.Schema -> Right config {schema = True}+  Flag.SkipCrc -> Right config {skipCrc = True}+  Flag.Version -> Right config {version = True}  getMode :: Config -> Mode.Mode getMode config =-  let-    i = fmap FilePath.takeExtension $ input config-    o = fmap FilePath.takeExtension $ output config-  in case (i, o) of-    (Just ".json", _) -> Mode.Encode-    (Just ".replay", _) -> Mode.Decode-    (_, Just ".json") -> Mode.Decode-    (_, Just ".replay") -> Mode.Encode-    _ -> Mode.Decode+  let i = fmap FilePath.takeExtension $ input config+      o = fmap FilePath.takeExtension $ output config+   in case (i, o) of+        (Just ".json", _) -> Mode.Encode+        (Just ".replay", _) -> Mode.Decode+        (_, Just ".json") -> Mode.Decode+        (_, Just ".replay") -> Mode.Encode+        _ -> Mode.Decode
src/lib/Rattletrap/Console/Main.hs view
@@ -119,17 +119,20 @@   config <- getConfig arguments   if Config.help config     then helpMain name-    else if Config.version config-      then versionMain-      else if Config.schema config-        then schemaMain config-        else defaultMain name config+    else+      if Config.version config+        then versionMain+        else+          if Config.schema config+            then schemaMain config+            else defaultMain name config  helpMain :: String -> IO () helpMain name = do-  putStr $ Console.usageInfo-    (unwords [name, "version", Version.string])-    Option.all+  putStr $+    Console.usageInfo+      (unwords [name, "version", Version.string])+      Option.all  versionMain :: IO () versionMain = do@@ -144,13 +147,14 @@   let decode = getDecoder config   replay <- case decode input of     Left (ls, e) -> do-      IO.hPutStr IO.stderr $ unlines-        [ "ERROR: " <> Exception.displayException e-        , "-- Context: " <> List.intercalate ", " ls-        , "-- You are using Rattletrap version " <> Version.string-        , "-- " <> show config-        , "-- Please report this problem at https://github.com/tfausak/rattletrap/issues/new"-        ]+      IO.hPutStr IO.stderr $+        unlines+          [ "ERROR: " <> Exception.displayException e,+            "-- Context: " <> List.intercalate ", " ls,+            "-- You are using Rattletrap version " <> Version.string,+            "-- " <> show config,+            "-- Please report this problem at https://github.com/tfausak/rattletrap/issues/new"+          ]       Exit.exitFailure     Right x -> pure x   let encode = getEncoder config@@ -159,114 +163,114 @@ schema :: Json.Value schema =   let contentSchema = Content.schema $ List.schema Frame.schema-  in-    Json.object-      [ Json.pair "$schema" "http://json-schema.org/draft-07/schema"-      , Json.pair "$id" Replay.schemaUrl-      , Json.pair "$ref" "#/definitions/replay"-      , Json.pair "definitions" . Json.object $ fmap-        (\s -> Json.pair (Text.unpack $ Schema.name s) $ Schema.json s)-        [ Attribute.schema-        , Attribute.AppliedDamage.schema-        , Attribute.Boolean.schema-        , Attribute.Byte.schema-        , Attribute.CamSettings.schema-        , Attribute.ClubColors.schema-        , Attribute.CustomDemolish.schema-        , Attribute.DamageState.schema-        , Attribute.Demolish.schema-        , Attribute.Enum.schema-        , Attribute.Explosion.schema-        , Attribute.ExtendedExplosion.schema-        , Attribute.FlaggedByte.schema-        , Attribute.FlaggedInt.schema-        , Attribute.Float.schema-        , Attribute.GameMode.schema-        , Attribute.GameServer.schema-        , Attribute.Int.schema-        , Attribute.Int64.schema-        , Attribute.Loadout.schema-        , Attribute.LoadoutOnline.schema-        , Attribute.Loadouts.schema-        , Attribute.LoadoutsOnline.schema-        , Attribute.Location.schema-        , Attribute.MusicStinger.schema-        , Attribute.PartyLeader.schema-        , Attribute.Pickup.schema-        , Attribute.PickupInfo.schema-        , Attribute.PickupNew.schema-        , Attribute.PlayerHistoryKey.schema-        , Attribute.PrivateMatchSettings.schema-        , Attribute.Product.schema-        , Attribute.ProductValue.schema-        , Attribute.QWord.schema-        , Attribute.RepStatTitle.schema-        , Attribute.Reservation.schema-        , Attribute.RigidBodyState.schema-        , Attribute.Rotation.schema-        , Attribute.StatEvent.schema-        , Attribute.String.schema-        , Attribute.TeamPaint.schema-        , Attribute.Title.schema-        , Attribute.UniqueId.schema-        , Attribute.WeldedInfo.schema-        , AttributeMapping.schema-        , AttributeValue.schema-        , Cache.schema-        , ClassMapping.schema-        , CompressedWord.schema-        , CompressedWordVector.schema-        , contentSchema-        , Dictionary.schema Property.schema-        , F32.schema-        , Frame.schema-        , Header.schema-        , I32.schema-        , I64.schema-        , I8.schema-        , Initialization.schema-        , Int8Vector.schema-        , Keyframe.schema-        , List.schema Attribute.Product.schema-        , Mark.schema-        , Message.schema-        , Property.schema-        , Property.Array.schema Property.schema-        , Property.Byte.schema-        , PropertyValue.schema Property.schema-        , Quaternion.schema-        , RemoteId.schema-        , RemoteId.PlayStation.schema-        , RemoteId.PsyNet.schema-        , RemoteId.Switch.schema-        , Replay.schema (Section.schema Header.schema)-        . Section.schema-        $ contentSchema-        , Replication.Destroyed.schema-        , Replication.schema-        , Replication.Spawned.schema-        , Replication.Updated.schema-        , ReplicationValue.schema-        , Rotation.schema-        , Schema.boolean-        , Schema.integer-        , Schema.null-        , Schema.number-        , Schema.string-        , Section.schema contentSchema-        , Section.schema Header.schema-        , Str.schema-        , U32.schema-        , U64.schema-        , U8.schema-        , Vector.schema+   in Json.object+        [ Json.pair "$schema" "http://json-schema.org/draft-07/schema",+          Json.pair "$id" Replay.schemaUrl,+          Json.pair "$ref" "#/definitions/replay",+          Json.pair "definitions" . Json.object $+            fmap+              (\s -> Json.pair (Text.unpack $ Schema.name s) $ Schema.json s)+              [ Attribute.schema,+                Attribute.AppliedDamage.schema,+                Attribute.Boolean.schema,+                Attribute.Byte.schema,+                Attribute.CamSettings.schema,+                Attribute.ClubColors.schema,+                Attribute.CustomDemolish.schema,+                Attribute.DamageState.schema,+                Attribute.Demolish.schema,+                Attribute.Enum.schema,+                Attribute.Explosion.schema,+                Attribute.ExtendedExplosion.schema,+                Attribute.FlaggedByte.schema,+                Attribute.FlaggedInt.schema,+                Attribute.Float.schema,+                Attribute.GameMode.schema,+                Attribute.GameServer.schema,+                Attribute.Int.schema,+                Attribute.Int64.schema,+                Attribute.Loadout.schema,+                Attribute.LoadoutOnline.schema,+                Attribute.Loadouts.schema,+                Attribute.LoadoutsOnline.schema,+                Attribute.Location.schema,+                Attribute.MusicStinger.schema,+                Attribute.PartyLeader.schema,+                Attribute.Pickup.schema,+                Attribute.PickupInfo.schema,+                Attribute.PickupNew.schema,+                Attribute.PlayerHistoryKey.schema,+                Attribute.PrivateMatchSettings.schema,+                Attribute.Product.schema,+                Attribute.ProductValue.schema,+                Attribute.QWord.schema,+                Attribute.RepStatTitle.schema,+                Attribute.Reservation.schema,+                Attribute.RigidBodyState.schema,+                Attribute.Rotation.schema,+                Attribute.StatEvent.schema,+                Attribute.String.schema,+                Attribute.TeamPaint.schema,+                Attribute.Title.schema,+                Attribute.UniqueId.schema,+                Attribute.WeldedInfo.schema,+                AttributeMapping.schema,+                AttributeValue.schema,+                Cache.schema,+                ClassMapping.schema,+                CompressedWord.schema,+                CompressedWordVector.schema,+                contentSchema,+                Dictionary.schema Property.schema,+                F32.schema,+                Frame.schema,+                Header.schema,+                I32.schema,+                I64.schema,+                I8.schema,+                Initialization.schema,+                Int8Vector.schema,+                Keyframe.schema,+                List.schema Attribute.Product.schema,+                Mark.schema,+                Message.schema,+                Property.schema,+                Property.Array.schema Property.schema,+                Property.Byte.schema,+                PropertyValue.schema Property.schema,+                Quaternion.schema,+                RemoteId.schema,+                RemoteId.PlayStation.schema,+                RemoteId.PsyNet.schema,+                RemoteId.Switch.schema,+                Replay.schema (Section.schema Header.schema)+                  . Section.schema+                  $ contentSchema,+                Replication.Destroyed.schema,+                Replication.schema,+                Replication.Spawned.schema,+                Replication.Updated.schema,+                ReplicationValue.schema,+                Rotation.schema,+                Schema.boolean,+                Schema.integer,+                Schema.null,+                Schema.number,+                Schema.string,+                Section.schema contentSchema,+                Section.schema Header.schema,+                Str.schema,+                U32.schema,+                U64.schema,+                U8.schema,+                Vector.schema+              ]         ]-      ] -getDecoder-  :: Config.Config-  -> ByteString.ByteString-  -> Either ([String], Exception.SomeException) Replay.Replay+getDecoder ::+  Config.Config ->+  ByteString.ByteString ->+  Either ([String], Exception.SomeException) Replay.Replay getDecoder config = case Config.getMode config of   Mode.Decode ->     Rattletrap.decodeReplayFile (Config.fast config) (Config.skipCrc config)@@ -281,12 +285,13 @@ getInput name config = case Config.input config of   Nothing -> do     isTerminalDevice <- IO.hIsTerminalDevice IO.stdin-    Monad.when isTerminalDevice . IO.hPutStr IO.stderr $ unlines-      [ "-- You did not supply any input, so Rattletrap will read from STDIN."-      , "-- If that is unexpected, try running: "-      <> FilePath.combine "." name-      <> " --help"-      ]+    Monad.when isTerminalDevice . IO.hPutStr IO.stderr $+      unlines+        [ "-- You did not supply any input, so Rattletrap will read from STDIN.",+          "-- If that is unexpected, try running: "+            <> FilePath.combine "." name+            <> " --help"+        ]     ByteString.getContents   Just fileOrUrl -> case Client.parseUrlThrow fileOrUrl of     Nothing -> ByteString.readFile fileOrUrl@@ -299,18 +304,17 @@ putOutput =   maybe LazyByteString.putStr LazyByteString.writeFile . Config.output -encodeJson :: Json.ToJSON a => Config.Config -> a -> LazyByteString.ByteString+encodeJson :: (Json.ToJSON a) => Config.Config -> a -> LazyByteString.ByteString encodeJson = Bool.bool Json.encodePretty Json.encode . Config.compact  getConfig :: [String] -> IO Config.Config getConfig arguments = do-  let-    (flags, unexpectedArguments, unknownOptions, problems) =-      Console.getOpt' Console.Permute Option.all arguments+  let (flags, unexpectedArguments, unknownOptions, problems) =+        Console.getOpt' Console.Permute Option.all arguments   Monad.forM_ unexpectedArguments $ \x ->     IO.hPutStrLn IO.stderr $ "WARNING: unexpected argument `" <> x <> "'"-  Monad.forM_ unknownOptions-    $ \x -> IO.hPutStrLn IO.stderr $ "WARNING: unknown option `" <> x <> "'"+  Monad.forM_ unknownOptions $+    \x -> IO.hPutStrLn IO.stderr $ "WARNING: unknown option `" <> x <> "'"   Monad.forM_ problems $ \x -> IO.hPutStr IO.stderr $ "ERROR: " <> x   Monad.unless (null problems) Exit.exitFailure   either fail pure $ Monad.foldM Config.applyFlag Config.initial flags
src/lib/Rattletrap/Console/Option.hs view
@@ -9,42 +9,47 @@ all = [compact, fast, help, input, mode, output, schema, skipCrc, version]  compact :: Option-compact = Console.Option-  ['c']-  ["compact"]-  (Console.NoArg Flag.Compact)-  "minify JSON output"+compact =+  Console.Option+    ['c']+    ["compact"]+    (Console.NoArg Flag.Compact)+    "minify JSON output"  fast :: Option-fast = Console.Option-  ['f']-  ["fast"]-  (Console.NoArg Flag.Fast)-  "only encode or decode the header"+fast =+  Console.Option+    ['f']+    ["fast"]+    (Console.NoArg Flag.Fast)+    "only encode or decode the header"  help :: Option help = Console.Option ['h'] ["help"] (Console.NoArg Flag.Help) "show the help"  input :: Option-input = Console.Option-  ['i']-  ["input"]-  (Console.ReqArg Flag.Input "FILE|URL")-  "input file or URL"+input =+  Console.Option+    ['i']+    ["input"]+    (Console.ReqArg Flag.Input "FILE|URL")+    "input file or URL"  mode :: Option-mode = Console.Option-  ['m']-  ["mode"]-  (Console.ReqArg Flag.Mode "MODE")-  "decode or encode"+mode =+  Console.Option+    ['m']+    ["mode"]+    (Console.ReqArg Flag.Mode "MODE")+    "decode or encode"  output :: Option-output = Console.Option-  ['o']-  ["output"]-  (Console.ReqArg Flag.Output "FILE")-  "output file"+output =+  Console.Option+    ['o']+    ["output"]+    (Console.ReqArg Flag.Output "FILE")+    "output file"  schema :: Option schema =@@ -55,8 +60,9 @@   Console.Option [] ["skip-crc"] (Console.NoArg Flag.SkipCrc) "skip the CRC"  version :: Option-version = Console.Option-  ['v']-  ["version"]-  (Console.NoArg Flag.Version)-  "show the version"+version =+  Console.Option+    ['v']+    ["version"]+    (Console.NoArg Flag.Version)+    "show the version"
src/lib/Rattletrap/Data.hs view
@@ -8,445 +8,455 @@ import qualified Rattletrap.Type.AttributeType as AttributeType  parentClasses :: Map.Map Text.Text Text.Text-parentClasses = Map.fromList $ fmap-  (Bifunctor.bimap Text.pack Text.pack)-  [ ("Engine.Actor", "Core.Object")-  , ("Engine.GameReplicationInfo", "Engine.ReplicationInfo")-  , ("Engine.Info", "Engine.Actor")-  , ("Engine.Pawn", "Engine.Actor")-  , ("Engine.PlayerReplicationInfo", "Engine.ReplicationInfo")-  , ("Engine.ReplicationInfo", "Engine.Info")-  , ("Engine.TeamInfo", "Engine.ReplicationInfo")-  , ("ProjectX.GRI_X", "Engine.GameReplicationInfo")-  , ("ProjectX.Pawn_X", "Engine.Pawn")-  , ("ProjectX.PRI_X", "Engine.PlayerReplicationInfo")-  , ("TAGame.Ball_God_TA", "TAGame.Ball_TA")-  , ("TAGame.Ball_Haunted_TA", "TAGame.Ball_TA")-  , ("TAGame.Ball_TA", "TAGame.RBActor_TA")-  , ("TAGame.CameraSettingsActor_TA", "Engine.ReplicationInfo")-  , ("TAGame.Car_Season_TA", "TAGame.PRI_TA")-  , ("TAGame.Car_TA", "TAGame.Vehicle_TA")-  , ("TAGame.CarComponent_Boost_TA", "TAGame.CarComponent_TA")-  , ("TAGame.CarComponent_Dodge_TA", "TAGame.CarComponent_TA")-  , ("TAGame.CarComponent_DoubleJump_TA", "TAGame.CarComponent_TA")-  , ("TAGame.CarComponent_FlipCar_TA", "TAGame.CarComponent_TA")-  , ("TAGame.CarComponent_Jump_TA", "TAGame.CarComponent_TA")-  , ("TAGame.CarComponent_TA", "Engine.ReplicationInfo")-  , ("TAGame.CrowdActor_TA", "Engine.ReplicationInfo")-  , ("TAGame.CrowdManager_TA", "Engine.ReplicationInfo")-  , ("TAGame.GameEvent_Football_TA", "TAGame.GameEvent_Soccar_TA")-  , ("TAGame.GameEvent_GodBall_TA", "TAGame.GameEvent_Soccar_TA")-  , ("TAGame.GameEvent_Season_TA", "TAGame.GameEvent_Soccar_TA")-  , ("TAGame.GameEvent_Soccar_TA", "TAGame.GameEvent_Team_TA")-  , ("TAGame.GameEvent_SoccarPrivate_TA", "TAGame.GameEvent_Soccar_TA")-  , ("TAGame.GameEvent_SoccarSplitscreen_TA", "TAGame.GameEvent_SoccarPrivate_TA")-  , ("TAGame.GameEvent_TA", "Engine.ReplicationInfo")-  , ("TAGame.GameEvent_Team_TA", "TAGame.GameEvent_TA")-  , ("TAGame.GRI_TA", "ProjectX.GRI_X")-  , ("TAGame.HauntedBallTrapTrigger_TA", "Engine.Actor")-  , ("TAGame.InMapScoreboard_TA", "Engine.Actor")-  , ("TAGame.PRI_TA", "ProjectX.PRI_X")-  , ("TAGame.RBActor_TA", "ProjectX.Pawn_X")-  , ("TAGame.SpecialPickup_BallCarSpring_TA", "TAGame.SpecialPickup_Spring_TA")-  , ("TAGame.SpecialPickup_BallFreeze_TA", "TAGame.SpecialPickup_Targeted_TA")-  , ("TAGame.SpecialPickup_BallGravity_TA", "TAGame.SpecialPickup_TA")-  , ("TAGame.SpecialPickup_BallLasso_TA", "TAGame.SpecialPickup_GrapplingHook_TA")-  , ("TAGame.SpecialPickup_BallVelcro_TA", "TAGame.SpecialPickup_TA")-  , ("TAGame.SpecialPickup_Batarang_TA", "TAGame.SpecialPickup_BallLasso_TA")-  , ("TAGame.SpecialPickup_BoostOverride_TA", "TAGame.SpecialPickup_Targeted_TA")-  , ("TAGame.SpecialPickup_Football_TA", "TAGame.SpecialPickup_TA")-  , ("TAGame.SpecialPickup_GrapplingHook_TA", "TAGame.SpecialPickup_Targeted_TA")-  , ("TAGame.SpecialPickup_HauntedBallBeam_TA", "TAGame.SpecialPickup_TA")-  , ("TAGame.SpecialPickup_HitForce_TA", "TAGame.SpecialPickup_TA")-  , ("TAGame.SpecialPickup_Rugby_TA", "TAGame.SpecialPickup_TA")-  , ("TAGame.SpecialPickup_Spring_TA", "TAGame.SpecialPickup_Targeted_TA")-  , ("TAGame.SpecialPickup_Swapper_TA", "TAGame.SpecialPickup_Targeted_TA")-  , ("TAGame.SpecialPickup_TA", "TAGame.CarComponent_TA")-  , ("TAGame.SpecialPickup_Targeted_TA", "TAGame.SpecialPickup_TA")-  , ("TAGame.SpecialPickup_Tornado_TA", "TAGame.SpecialPickup_TA")-  , ("TAGame.Team_Soccar_TA", "TAGame.Team_TA")-  , ("TAGame.Team_TA", "Engine.TeamInfo")-  , ("TAGame.Vehicle_TA", "TAGame.RBActor_TA")-  , ("TAGame.VehiclePickup_Boost_TA", "TAGame.VehiclePickup_TA")-  , ("TAGame.VehiclePickup_TA", "Engine.ReplicationInfo")-  ]+parentClasses =+  Map.fromList $+    fmap+      (Bifunctor.bimap Text.pack Text.pack)+      [ ("Engine.Actor", "Core.Object"),+        ("Engine.GameReplicationInfo", "Engine.ReplicationInfo"),+        ("Engine.Info", "Engine.Actor"),+        ("Engine.Pawn", "Engine.Actor"),+        ("Engine.PlayerReplicationInfo", "Engine.ReplicationInfo"),+        ("Engine.ReplicationInfo", "Engine.Info"),+        ("Engine.TeamInfo", "Engine.ReplicationInfo"),+        ("ProjectX.GRI_X", "Engine.GameReplicationInfo"),+        ("ProjectX.Pawn_X", "Engine.Pawn"),+        ("ProjectX.PRI_X", "Engine.PlayerReplicationInfo"),+        ("TAGame.Ball_God_TA", "TAGame.Ball_TA"),+        ("TAGame.Ball_Haunted_TA", "TAGame.Ball_TA"),+        ("TAGame.Ball_TA", "TAGame.RBActor_TA"),+        ("TAGame.CameraSettingsActor_TA", "Engine.ReplicationInfo"),+        ("TAGame.Car_Season_TA", "TAGame.PRI_TA"),+        ("TAGame.Car_TA", "TAGame.Vehicle_TA"),+        ("TAGame.CarComponent_Boost_TA", "TAGame.CarComponent_TA"),+        ("TAGame.CarComponent_Dodge_TA", "TAGame.CarComponent_TA"),+        ("TAGame.CarComponent_DoubleJump_TA", "TAGame.CarComponent_TA"),+        ("TAGame.CarComponent_FlipCar_TA", "TAGame.CarComponent_TA"),+        ("TAGame.CarComponent_Jump_TA", "TAGame.CarComponent_TA"),+        ("TAGame.CarComponent_TA", "Engine.ReplicationInfo"),+        ("TAGame.CrowdActor_TA", "Engine.ReplicationInfo"),+        ("TAGame.CrowdManager_TA", "Engine.ReplicationInfo"),+        ("TAGame.GameEvent_Football_TA", "TAGame.GameEvent_Soccar_TA"),+        ("TAGame.GameEvent_GodBall_TA", "TAGame.GameEvent_Soccar_TA"),+        ("TAGame.GameEvent_Season_TA", "TAGame.GameEvent_Soccar_TA"),+        ("TAGame.GameEvent_Soccar_TA", "TAGame.GameEvent_Team_TA"),+        ("TAGame.GameEvent_SoccarPrivate_TA", "TAGame.GameEvent_Soccar_TA"),+        ("TAGame.GameEvent_SoccarSplitscreen_TA", "TAGame.GameEvent_SoccarPrivate_TA"),+        ("TAGame.GameEvent_TA", "Engine.ReplicationInfo"),+        ("TAGame.GameEvent_Team_TA", "TAGame.GameEvent_TA"),+        ("TAGame.GRI_TA", "ProjectX.GRI_X"),+        ("TAGame.HauntedBallTrapTrigger_TA", "Engine.Actor"),+        ("TAGame.InMapScoreboard_TA", "Engine.Actor"),+        ("TAGame.PRI_TA", "ProjectX.PRI_X"),+        ("TAGame.RBActor_TA", "ProjectX.Pawn_X"),+        ("TAGame.SpecialPickup_BallCarSpring_TA", "TAGame.SpecialPickup_Spring_TA"),+        ("TAGame.SpecialPickup_BallFreeze_TA", "TAGame.SpecialPickup_Targeted_TA"),+        ("TAGame.SpecialPickup_BallGravity_TA", "TAGame.SpecialPickup_TA"),+        ("TAGame.SpecialPickup_BallLasso_TA", "TAGame.SpecialPickup_GrapplingHook_TA"),+        ("TAGame.SpecialPickup_BallVelcro_TA", "TAGame.SpecialPickup_TA"),+        ("TAGame.SpecialPickup_Batarang_TA", "TAGame.SpecialPickup_BallLasso_TA"),+        ("TAGame.SpecialPickup_BoostOverride_TA", "TAGame.SpecialPickup_Targeted_TA"),+        ("TAGame.SpecialPickup_Football_TA", "TAGame.SpecialPickup_TA"),+        ("TAGame.SpecialPickup_GrapplingHook_TA", "TAGame.SpecialPickup_Targeted_TA"),+        ("TAGame.SpecialPickup_HauntedBallBeam_TA", "TAGame.SpecialPickup_TA"),+        ("TAGame.SpecialPickup_HitForce_TA", "TAGame.SpecialPickup_TA"),+        ("TAGame.SpecialPickup_Rugby_TA", "TAGame.SpecialPickup_TA"),+        ("TAGame.SpecialPickup_Spring_TA", "TAGame.SpecialPickup_Targeted_TA"),+        ("TAGame.SpecialPickup_Swapper_TA", "TAGame.SpecialPickup_Targeted_TA"),+        ("TAGame.SpecialPickup_TA", "TAGame.CarComponent_TA"),+        ("TAGame.SpecialPickup_Targeted_TA", "TAGame.SpecialPickup_TA"),+        ("TAGame.SpecialPickup_Tornado_TA", "TAGame.SpecialPickup_TA"),+        ("TAGame.Team_Soccar_TA", "TAGame.Team_TA"),+        ("TAGame.Team_TA", "Engine.TeamInfo"),+        ("TAGame.Vehicle_TA", "TAGame.RBActor_TA"),+        ("TAGame.VehiclePickup_Boost_TA", "TAGame.VehiclePickup_TA"),+        ("TAGame.VehiclePickup_TA", "Engine.ReplicationInfo")+      ]  classesWithLocation :: Set.Set Text.Text-classesWithLocation = Set.fromList $ fmap-  Text.pack-  [ "Archetypes.Ball.Ball_BasketBall_Mutator"-  , "Archetypes.Ball.Ball_Basketball"-  , "Archetypes.Ball.Ball_BasketBall"-  , "Archetypes.Ball.Ball_Breakout"-  , "Archetypes.Ball.Ball_Default"-  , "Archetypes.Ball.Ball_Puck"-  , "Archetypes.Ball.Ball_Trajectory"-  , "Archetypes.Ball.CubeBall"-  , "Archetypes.Car.Car_Default"-  , "Archetypes.GameEvent.GameEvent_Season:CarArchetype"-  , "Archetypes.SpecialPickups.SpecialPickup_Rugby"-  , "ProjectX.NetModeReplicator"-  , "TAGame.Ball_Breakout_TA"-  , "TAGame.Ball_God_TA"-  , "TAGame.Ball_Haunted_TA"-  , "TAGame.Ball_TA"-  , "TAGame.CameraSettingsActor_TA"-  , "TAGame.Cannon_TA"-  , "TAGame.Car_Season_TA"-  , "TAGame.Car_TA"-  , "TAGame.CarComponent_Boost_TA"-  , "TAGame.CarComponent_Dodge_TA"-  , "TAGame.CarComponent_DoubleJump_TA"-  , "TAGame.CarComponent_FlipCar_TA"-  , "TAGame.CarComponent_Jump_TA"-  , "TAGame.Default__CameraSettingsActor_TA"-  , "TAGame.Default__PRI_TA"-  , "TAGame.GameEvent_Football_TA"-  , "TAGame.GameEvent_GodBall_TA"-  , "TAGame.GameEvent_Season_TA"-  , "TAGame.GameEvent_Soccar_TA"-  , "TAGame.GameEvent_SoccarPrivate_TA"-  , "TAGame.GameEvent_SoccarSplitscreen_TA"-  , "TAGame.GameEvent_Tutorial_TA"-  , "TAGame.GRI_TA"-  , "TAGame.MaxTimeWarningData_TA"-  , "TAGame.PickupTimer_TA"-  , "TAGame.PRI_TA"-  , "TAGame.RumblePickups_TA"-  , "TAGame.SpecialPickup_BallCarSpring_TA"-  , "TAGame.SpecialPickup_BallFreeze_TA"-  , "TAGame.SpecialPickup_BallGravity_TA"-  , "TAGame.SpecialPickup_BallLasso_TA"-  , "TAGame.SpecialPickup_BallVelcro_TA"-  , "TAGame.SpecialPickup_Batarang_TA"-  , "TAGame.SpecialPickup_BoostOverride_TA"-  , "TAGame.SpecialPickup_Football_TA"-  , "TAGame.SpecialPickup_GrapplingHook_TA"-  , "TAGame.SpecialPickup_HauntedBallBeam_TA"-  , "TAGame.SpecialPickup_HitForce_TA"-  , "TAGame.SpecialPickup_Rugby_TA"-  , "TAGame.SpecialPickup_Swapper_TA"-  , "TAGame.SpecialPickup_Tornado_TA"-  , "TAGame.Team_Soccar_TA"-  , "TheWorld:PersistentLevel.BreakOutActor_Platform_TA"-  , "TheWorld:PersistentLevel.CrowdActor_TA"-  , "TheWorld:PersistentLevel.CrowdManager_TA"-  , "TheWorld:PersistentLevel.InMapScoreboard_TA"-  , "TheWorld:PersistentLevel.VehiclePickup_Boost_TA"-  ]+classesWithLocation =+  Set.fromList $+    fmap+      Text.pack+      [ "Archetypes.Ball.Ball_BasketBall_Mutator",+        "Archetypes.Ball.Ball_Basketball",+        "Archetypes.Ball.Ball_BasketBall",+        "Archetypes.Ball.Ball_Breakout",+        "Archetypes.Ball.Ball_Default",+        "Archetypes.Ball.Ball_Puck",+        "Archetypes.Ball.Ball_Trajectory",+        "Archetypes.Ball.CubeBall",+        "Archetypes.Car.Car_Default",+        "Archetypes.GameEvent.GameEvent_Season:CarArchetype",+        "Archetypes.SpecialPickups.SpecialPickup_Rugby",+        "ProjectX.NetModeReplicator",+        "TAGame.Ball_Breakout_TA",+        "TAGame.Ball_God_TA",+        "TAGame.Ball_Haunted_TA",+        "TAGame.Ball_TA",+        "TAGame.CameraSettingsActor_TA",+        "TAGame.Cannon_TA",+        "TAGame.Car_Season_TA",+        "TAGame.Car_TA",+        "TAGame.CarComponent_Boost_TA",+        "TAGame.CarComponent_Dodge_TA",+        "TAGame.CarComponent_DoubleJump_TA",+        "TAGame.CarComponent_FlipCar_TA",+        "TAGame.CarComponent_Jump_TA",+        "TAGame.Default__CameraSettingsActor_TA",+        "TAGame.Default__PRI_TA",+        "TAGame.GameEvent_Football_TA",+        "TAGame.GameEvent_GodBall_TA",+        "TAGame.GameEvent_Season_TA",+        "TAGame.GameEvent_Soccar_TA",+        "TAGame.GameEvent_SoccarPrivate_TA",+        "TAGame.GameEvent_SoccarSplitscreen_TA",+        "TAGame.GameEvent_Tutorial_TA",+        "TAGame.GRI_TA",+        "TAGame.MaxTimeWarningData_TA",+        "TAGame.PickupTimer_TA",+        "TAGame.PRI_TA",+        "TAGame.RumblePickups_TA",+        "TAGame.SpecialPickup_BallCarSpring_TA",+        "TAGame.SpecialPickup_BallFreeze_TA",+        "TAGame.SpecialPickup_BallGravity_TA",+        "TAGame.SpecialPickup_BallLasso_TA",+        "TAGame.SpecialPickup_BallVelcro_TA",+        "TAGame.SpecialPickup_Batarang_TA",+        "TAGame.SpecialPickup_BoostOverride_TA",+        "TAGame.SpecialPickup_Football_TA",+        "TAGame.SpecialPickup_GrapplingHook_TA",+        "TAGame.SpecialPickup_HauntedBallBeam_TA",+        "TAGame.SpecialPickup_HitForce_TA",+        "TAGame.SpecialPickup_Rugby_TA",+        "TAGame.SpecialPickup_Swapper_TA",+        "TAGame.SpecialPickup_Tornado_TA",+        "TAGame.Team_Soccar_TA",+        "TheWorld:PersistentLevel.BreakOutActor_Platform_TA",+        "TheWorld:PersistentLevel.CrowdActor_TA",+        "TheWorld:PersistentLevel.CrowdManager_TA",+        "TheWorld:PersistentLevel.InMapScoreboard_TA",+        "TheWorld:PersistentLevel.VehiclePickup_Boost_TA"+      ]  classesWithRotation :: Set.Set Text.Text-classesWithRotation = Set.fromList $ fmap-  Text.pack-  [ "Archetypes.Ball.Ball_BasketBall_Mutator"-  , "Archetypes.Ball.Ball_Basketball"-  , "Archetypes.Ball.Ball_BasketBall"-  , "Archetypes.Ball.Ball_Breakout"-  , "Archetypes.Ball.Ball_Default"-  , "Archetypes.Ball.Ball_Puck"-  , "Archetypes.Ball.Ball_Trajectory"-  , "Archetypes.Ball.CubeBall"-  , "Archetypes.Car.Car_Default"-  , "Archetypes.GameEvent.GameEvent_Season:CarArchetype"-  , "Archetypes.SpecialPickups.SpecialPickup_Rugby"-  , "TAGame.Ball_Breakout_TA"-  , "TAGame.Ball_God_TA"-  , "TAGame.Ball_Haunted_TA"-  , "TAGame.Ball_TA"-  , "TAGame.Car_Season_TA"-  , "TAGame.Car_TA"-  ]+classesWithRotation =+  Set.fromList $+    fmap+      Text.pack+      [ "Archetypes.Ball.Ball_BasketBall_Mutator",+        "Archetypes.Ball.Ball_Basketball",+        "Archetypes.Ball.Ball_BasketBall",+        "Archetypes.Ball.Ball_Breakout",+        "Archetypes.Ball.Ball_Default",+        "Archetypes.Ball.Ball_Puck",+        "Archetypes.Ball.Ball_Trajectory",+        "Archetypes.Ball.CubeBall",+        "Archetypes.Car.Car_Default",+        "Archetypes.GameEvent.GameEvent_Season:CarArchetype",+        "Archetypes.SpecialPickups.SpecialPickup_Rugby",+        "TAGame.Ball_Breakout_TA",+        "TAGame.Ball_God_TA",+        "TAGame.Ball_Haunted_TA",+        "TAGame.Ball_TA",+        "TAGame.Car_Season_TA",+        "TAGame.Car_TA"+      ]  objectClasses :: Map.Map Text.Text Text.Text-objectClasses = Map.fromList $ fmap-  (Bifunctor.bimap Text.pack Text.pack)-  [ ("Archetypes.Ball.Ball_Anniversary", "TAGame.Ball_TA")-  , ("Archetypes.Ball.Ball_BasketBall_Mutator", "TAGame.Ball_TA")-  , ("Archetypes.Ball.Ball_Basketball", "TAGame.Ball_TA")-  , ("Archetypes.Ball.Ball_BasketBall", "TAGame.Ball_TA")-  , ("Archetypes.Ball.Ball_Beachball", "TAGame.Ball_TA")-  , ("Archetypes.Ball.Ball_Breakout", "TAGame.Ball_Breakout_TA")-  , ("Archetypes.Ball.Ball_Default", "TAGame.Ball_TA")-  , ("Archetypes.Ball.Ball_Football", "TAGame.Ball_TA")-  , ("Archetypes.Ball.Ball_God", "TAGame.Ball_God_TA")-  , ("Archetypes.Ball.Ball_Haunted", "TAGame.Ball_Haunted_TA")-  , ("Archetypes.Ball.Ball_Puck", "TAGame.Ball_TA")-  , ("Archetypes.Ball.Ball_Training", "TAGame.Ball_TA")-  , ("Archetypes.Ball.Ball_Trajectory", "TAGame.Ball_TA")-  , ("Archetypes.Ball.CubeBall", "TAGame.Ball_TA")-  , ("Archetypes.Car.Car_Default", "TAGame.Car_TA")-  , ("Archetypes.Car.Car_PostGameLobby", "TAGame.Car_TA")-  , ("Archetypes.CarComponents.CarComponent_Boost", "TAGame.CarComponent_Boost_TA")-  , ("Archetypes.CarComponents.CarComponent_Dodge", "TAGame.CarComponent_Dodge_TA")-  , ("Archetypes.CarComponents.CarComponent_DoubleJump", "TAGame.CarComponent_DoubleJump_TA")-  , ("Archetypes.CarComponents.CarComponent_FlipCar", "TAGame.CarComponent_FlipCar_TA")-  , ("Archetypes.CarComponents.CarComponent_Jump", "TAGame.CarComponent_Jump_TA")-  , ("Archetypes.GameEvent.GameEvent_Basketball", "TAGame.GameEvent_Soccar_TA")-  , ("Archetypes.GameEvent.GameEvent_BasketballPrivate", "TAGame.GameEvent_SoccarPrivate_TA")-  , ("Archetypes.GameEvent.GameEvent_BasketballSplitscreen", "TAGame.GameEvent_SoccarSplitscreen_TA")-  , ("Archetypes.GameEvent.GameEvent_Breakout", "TAGame.GameEvent_Soccar_TA")-  , ("Archetypes.GameEvent.GameEvent_Hockey", "TAGame.GameEvent_Soccar_TA")-  , ("Archetypes.GameEvent.GameEvent_HockeyPrivate", "TAGame.GameEvent_SoccarPrivate_TA")-  , ("Archetypes.GameEvent.GameEvent_HockeySplitscreen", "TAGame.GameEvent_SoccarSplitscreen_TA")-  , ("Archetypes.GameEvent.GameEvent_Items", "TAGame.GameEvent_Soccar_TA")-  , ("Archetypes.GameEvent.GameEvent_Season:CarArchetype", "TAGame.Car_TA")-  , ("Archetypes.GameEvent.GameEvent_Season", "TAGame.GameEvent_Season_TA")-  , ("Archetypes.GameEvent.GameEvent_Soccar", "TAGame.GameEvent_Soccar_TA")-  , ("Archetypes.GameEvent.GameEvent_SoccarLan", "TAGame.GameEvent_Soccar_TA")-  , ("Archetypes.GameEvent.GameEvent_SoccarPrivate", "TAGame.GameEvent_SoccarPrivate_TA")-  , ("Archetypes.GameEvent.GameEvent_SoccarSplitscreen", "TAGame.GameEvent_SoccarSplitscreen_TA")-  , ("Archetypes.SpecialPickups.SpecialPickup_BallFreeze", "TAGame.SpecialPickup_BallFreeze_TA")-  , ("Archetypes.SpecialPickups.SpecialPickup_BallGrapplingHook", "TAGame.SpecialPickup_GrapplingHook_TA")-  , ("Archetypes.SpecialPickups.SpecialPickup_BallLasso", "TAGame.SpecialPickup_BallLasso_TA")-  , ("Archetypes.SpecialPickups.SpecialPickup_BallSpring", "TAGame.SpecialPickup_BallCarSpring_TA")-  , ("Archetypes.SpecialPickups.SpecialPickup_BallVelcro", "TAGame.SpecialPickup_BallVelcro_TA")-  , ("Archetypes.SpecialPickups.SpecialPickup_Batarang", "TAGame.SpecialPickup_Batarang_TA")-  , ("Archetypes.SpecialPickups.SpecialPickup_BoostOverride", "TAGame.SpecialPickup_BoostOverride_TA")-  , ("Archetypes.SpecialPickups.SpecialPickup_CarSpring", "TAGame.SpecialPickup_BallCarSpring_TA")-  , ("Archetypes.SpecialPickups.SpecialPickup_Football", "TAGame.SpecialPickup_Football_TA")-  , ("Archetypes.SpecialPickups.SpecialPickup_GravityWell", "TAGame.SpecialPickup_BallGravity_TA")-  , ("Archetypes.SpecialPickups.SpecialPickup_HauntedBallBeam", "TAGame.SpecialPickup_HauntedBallBeam_TA")-  , ("Archetypes.SpecialPickups.SpecialPickup_Rugby", "TAGame.SpecialPickup_Rugby_TA")-  , ("Archetypes.SpecialPickups.SpecialPickup_StrongHit", "TAGame.SpecialPickup_HitForce_TA")-  , ("Archetypes.SpecialPickups.SpecialPickup_Swapper", "TAGame.SpecialPickup_Swapper_TA")-  , ("Archetypes.SpecialPickups.SpecialPickup_Tornado", "TAGame.SpecialPickup_Tornado_TA")-  , ("Archetypes.Teams.Team0", "TAGame.Team_Soccar_TA")-  , ("Archetypes.Teams.Team1", "TAGame.Team_Soccar_TA")-  , ("Archetypes.Tutorial.Cannon", "TAGame.Cannon_TA")-  , ("GameInfo_Basketball.GameInfo.GameInfo_Basketball:GameReplicationInfoArchetype", "TAGame.GRI_TA")-  , ("GameInfo_Breakout.GameInfo.GameInfo_Breakout:GameReplicationInfoArchetype", "TAGame.GRI_TA")-  , ("GameInfo_FootBall.GameInfo.GameInfo_FootBall:Archetype", "TAGame.GameEvent_Football_TA")-  , ("GameInfo_FootBall.GameInfo.GameInfo_FootBall:GameReplicationInfoArchetype", "TAGame.GRI_TA")-  , ("gameinfo_godball.GameInfo.gameinfo_godball:Archetype", "TAGame.GameEvent_GodBall_TA")-  , ("GameInfo_GodBall.GameInfo.GameInfo_GodBall:Archetype", "TAGame.GameEvent_GodBall_TA")-  , ("gameinfo_godball.GameInfo.gameinfo_godball:GameReplicationInfoArchetype", "TAGame.GRI_TA")-  , ("GameInfo_GodBall.GameInfo.GameInfo_GodBall:GameReplicationInfoArchetype", "TAGame.GRI_TA")-  , ("Gameinfo_Hockey.GameInfo.Gameinfo_Hockey:GameReplicationInfoArchetype", "TAGame.GRI_TA")-  , ("GameInfo_Items.GameInfo.GameInfo_Items:GameReplicationInfoArchetype", "TAGame.GRI_TA")-  , ("GameInfo_Season.GameInfo.GameInfo_Season:GameReplicationInfoArchetype", "TAGame.GRI_TA")-  , ("GameInfo_Soccar.GameInfo.GameInfo_Soccar:GameReplicationInfoArchetype", "TAGame.GRI_TA")-  , ("GameInfo_Tutorial.GameEvent.GameEvent_Tutorial_Aerial", "TAGame.GameEvent_Tutorial_TA")-  , ("GameInfo_Tutorial.GameInfo.GameInfo_Tutorial:GameReplicationInfoArchetype", "TAGame.GRI_TA")-  , ("Haunted_TrainStation_P.TheWorld:PersistentLevel.HauntedBallTrapTrigger_TA_0", "TAGame.HauntedBallTrapTrigger_TA")-  , ("Haunted_TrainStation_P.TheWorld:PersistentLevel.HauntedBallTrapTrigger_TA_1", "TAGame.HauntedBallTrapTrigger_TA")-  , ("ProjectX.Default__NetModeReplicator_X", "ProjectX.NetModeReplicator")-  , ("TAGame.Default__CameraSettingsActor_TA", "TAGame.CameraSettingsActor_TA")-  , ("TAGame.Default__MaxTimeWarningData_TA", "TAGame.MaxTimeWarningData_TA")-  , ("TAGame.Default__PickupTimer_TA", "TAGame.PickupTimer_TA")-  , ("TAGame.Default__PRI_TA", "TAGame.PRI_TA")-  , ("TAGame.Default__RumblePickups_TA", "TAGame.RumblePickups_TA")-  , ("TheWorld:PersistentLevel.BreakOutActor_Platform_TA", "TAGame.BreakOutActor_Platform_TA")-  , ("TheWorld:PersistentLevel.CrowdActor_TA", "TAGame.CrowdActor_TA")-  , ("TheWorld:PersistentLevel.CrowdManager_TA", "TAGame.CrowdManager_TA")-  , ("TheWorld:PersistentLevel.InMapScoreboard_TA", "TAGame.InMapScoreboard_TA")-  , ("TheWorld:PersistentLevel.VehiclePickup_Boost_TA", "TAGame.VehiclePickup_Boost_TA")-  ]+objectClasses =+  Map.fromList $+    fmap+      (Bifunctor.bimap Text.pack Text.pack)+      [ ("Archetypes.Ball.Ball_Anniversary", "TAGame.Ball_TA"),+        ("Archetypes.Ball.Ball_BasketBall_Mutator", "TAGame.Ball_TA"),+        ("Archetypes.Ball.Ball_Basketball", "TAGame.Ball_TA"),+        ("Archetypes.Ball.Ball_BasketBall", "TAGame.Ball_TA"),+        ("Archetypes.Ball.Ball_Beachball", "TAGame.Ball_TA"),+        ("Archetypes.Ball.Ball_Breakout", "TAGame.Ball_Breakout_TA"),+        ("Archetypes.Ball.Ball_Default", "TAGame.Ball_TA"),+        ("Archetypes.Ball.Ball_Football", "TAGame.Ball_TA"),+        ("Archetypes.Ball.Ball_God", "TAGame.Ball_God_TA"),+        ("Archetypes.Ball.Ball_Haunted", "TAGame.Ball_Haunted_TA"),+        ("Archetypes.Ball.Ball_Puck", "TAGame.Ball_TA"),+        ("Archetypes.Ball.Ball_Training", "TAGame.Ball_TA"),+        ("Archetypes.Ball.Ball_Trajectory", "TAGame.Ball_TA"),+        ("Archetypes.Ball.CubeBall", "TAGame.Ball_TA"),+        ("Archetypes.Car.Car_Default", "TAGame.Car_TA"),+        ("Archetypes.Car.Car_PostGameLobby", "TAGame.Car_TA"),+        ("Archetypes.CarComponents.CarComponent_Boost", "TAGame.CarComponent_Boost_TA"),+        ("Archetypes.CarComponents.CarComponent_Dodge", "TAGame.CarComponent_Dodge_TA"),+        ("Archetypes.CarComponents.CarComponent_DoubleJump", "TAGame.CarComponent_DoubleJump_TA"),+        ("Archetypes.CarComponents.CarComponent_FlipCar", "TAGame.CarComponent_FlipCar_TA"),+        ("Archetypes.CarComponents.CarComponent_Jump", "TAGame.CarComponent_Jump_TA"),+        ("Archetypes.GameEvent.GameEvent_Basketball", "TAGame.GameEvent_Soccar_TA"),+        ("Archetypes.GameEvent.GameEvent_BasketballPrivate", "TAGame.GameEvent_SoccarPrivate_TA"),+        ("Archetypes.GameEvent.GameEvent_BasketballSplitscreen", "TAGame.GameEvent_SoccarSplitscreen_TA"),+        ("Archetypes.GameEvent.GameEvent_Breakout", "TAGame.GameEvent_Soccar_TA"),+        ("Archetypes.GameEvent.GameEvent_Hockey", "TAGame.GameEvent_Soccar_TA"),+        ("Archetypes.GameEvent.GameEvent_HockeyPrivate", "TAGame.GameEvent_SoccarPrivate_TA"),+        ("Archetypes.GameEvent.GameEvent_HockeySplitscreen", "TAGame.GameEvent_SoccarSplitscreen_TA"),+        ("Archetypes.GameEvent.GameEvent_Items", "TAGame.GameEvent_Soccar_TA"),+        ("Archetypes.GameEvent.GameEvent_Season:CarArchetype", "TAGame.Car_TA"),+        ("Archetypes.GameEvent.GameEvent_Season", "TAGame.GameEvent_Season_TA"),+        ("Archetypes.GameEvent.GameEvent_Soccar", "TAGame.GameEvent_Soccar_TA"),+        ("Archetypes.GameEvent.GameEvent_SoccarLan", "TAGame.GameEvent_Soccar_TA"),+        ("Archetypes.GameEvent.GameEvent_SoccarPrivate", "TAGame.GameEvent_SoccarPrivate_TA"),+        ("Archetypes.GameEvent.GameEvent_SoccarSplitscreen", "TAGame.GameEvent_SoccarSplitscreen_TA"),+        ("Archetypes.SpecialPickups.SpecialPickup_BallFreeze", "TAGame.SpecialPickup_BallFreeze_TA"),+        ("Archetypes.SpecialPickups.SpecialPickup_BallGrapplingHook", "TAGame.SpecialPickup_GrapplingHook_TA"),+        ("Archetypes.SpecialPickups.SpecialPickup_BallLasso", "TAGame.SpecialPickup_BallLasso_TA"),+        ("Archetypes.SpecialPickups.SpecialPickup_BallSpring", "TAGame.SpecialPickup_BallCarSpring_TA"),+        ("Archetypes.SpecialPickups.SpecialPickup_BallVelcro", "TAGame.SpecialPickup_BallVelcro_TA"),+        ("Archetypes.SpecialPickups.SpecialPickup_Batarang", "TAGame.SpecialPickup_Batarang_TA"),+        ("Archetypes.SpecialPickups.SpecialPickup_BoostOverride", "TAGame.SpecialPickup_BoostOverride_TA"),+        ("Archetypes.SpecialPickups.SpecialPickup_CarSpring", "TAGame.SpecialPickup_BallCarSpring_TA"),+        ("Archetypes.SpecialPickups.SpecialPickup_Football", "TAGame.SpecialPickup_Football_TA"),+        ("Archetypes.SpecialPickups.SpecialPickup_GravityWell", "TAGame.SpecialPickup_BallGravity_TA"),+        ("Archetypes.SpecialPickups.SpecialPickup_HauntedBallBeam", "TAGame.SpecialPickup_HauntedBallBeam_TA"),+        ("Archetypes.SpecialPickups.SpecialPickup_Rugby", "TAGame.SpecialPickup_Rugby_TA"),+        ("Archetypes.SpecialPickups.SpecialPickup_StrongHit", "TAGame.SpecialPickup_HitForce_TA"),+        ("Archetypes.SpecialPickups.SpecialPickup_Swapper", "TAGame.SpecialPickup_Swapper_TA"),+        ("Archetypes.SpecialPickups.SpecialPickup_Tornado", "TAGame.SpecialPickup_Tornado_TA"),+        ("Archetypes.Teams.Team0", "TAGame.Team_Soccar_TA"),+        ("Archetypes.Teams.Team1", "TAGame.Team_Soccar_TA"),+        ("Archetypes.Tutorial.Cannon", "TAGame.Cannon_TA"),+        ("GameInfo_Basketball.GameInfo.GameInfo_Basketball:GameReplicationInfoArchetype", "TAGame.GRI_TA"),+        ("GameInfo_Breakout.GameInfo.GameInfo_Breakout:GameReplicationInfoArchetype", "TAGame.GRI_TA"),+        ("GameInfo_FootBall.GameInfo.GameInfo_FootBall:Archetype", "TAGame.GameEvent_Football_TA"),+        ("GameInfo_FootBall.GameInfo.GameInfo_FootBall:GameReplicationInfoArchetype", "TAGame.GRI_TA"),+        ("gameinfo_godball.GameInfo.gameinfo_godball:Archetype", "TAGame.GameEvent_GodBall_TA"),+        ("GameInfo_GodBall.GameInfo.GameInfo_GodBall:Archetype", "TAGame.GameEvent_GodBall_TA"),+        ("gameinfo_godball.GameInfo.gameinfo_godball:GameReplicationInfoArchetype", "TAGame.GRI_TA"),+        ("GameInfo_GodBall.GameInfo.GameInfo_GodBall:GameReplicationInfoArchetype", "TAGame.GRI_TA"),+        ("Gameinfo_Hockey.GameInfo.Gameinfo_Hockey:GameReplicationInfoArchetype", "TAGame.GRI_TA"),+        ("GameInfo_Items.GameInfo.GameInfo_Items:GameReplicationInfoArchetype", "TAGame.GRI_TA"),+        ("GameInfo_Season.GameInfo.GameInfo_Season:GameReplicationInfoArchetype", "TAGame.GRI_TA"),+        ("GameInfo_Soccar.GameInfo.GameInfo_Soccar:GameReplicationInfoArchetype", "TAGame.GRI_TA"),+        ("GameInfo_Tutorial.GameEvent.GameEvent_Tutorial_Aerial", "TAGame.GameEvent_Tutorial_TA"),+        ("GameInfo_Tutorial.GameInfo.GameInfo_Tutorial:GameReplicationInfoArchetype", "TAGame.GRI_TA"),+        ("Haunted_TrainStation_P.TheWorld:PersistentLevel.HauntedBallTrapTrigger_TA_0", "TAGame.HauntedBallTrapTrigger_TA"),+        ("Haunted_TrainStation_P.TheWorld:PersistentLevel.HauntedBallTrapTrigger_TA_1", "TAGame.HauntedBallTrapTrigger_TA"),+        ("ProjectX.Default__NetModeReplicator_X", "ProjectX.NetModeReplicator"),+        ("TAGame.Default__CameraSettingsActor_TA", "TAGame.CameraSettingsActor_TA"),+        ("TAGame.Default__MaxTimeWarningData_TA", "TAGame.MaxTimeWarningData_TA"),+        ("TAGame.Default__PickupTimer_TA", "TAGame.PickupTimer_TA"),+        ("TAGame.Default__PRI_TA", "TAGame.PRI_TA"),+        ("TAGame.Default__RumblePickups_TA", "TAGame.RumblePickups_TA"),+        ("TheWorld:PersistentLevel.BreakOutActor_Platform_TA", "TAGame.BreakOutActor_Platform_TA"),+        ("TheWorld:PersistentLevel.CrowdActor_TA", "TAGame.CrowdActor_TA"),+        ("TheWorld:PersistentLevel.CrowdManager_TA", "TAGame.CrowdManager_TA"),+        ("TheWorld:PersistentLevel.InMapScoreboard_TA", "TAGame.InMapScoreboard_TA"),+        ("TheWorld:PersistentLevel.VehiclePickup_Boost_TA", "TAGame.VehiclePickup_Boost_TA")+      ]  attributeTypes :: Map.Map Text.Text AttributeType.AttributeType-attributeTypes = Map.fromList $ fmap-  (Bifunctor.first Text.pack)-  [ ("Engine.Actor:bBlockActors", AttributeType.Boolean)-  , ("Engine.Actor:bCollideActors", AttributeType.Boolean)-  , ("Engine.Actor:bHidden", AttributeType.Boolean)-  , ("Engine.Actor:bTearOff", AttributeType.Boolean)-  , ("Engine.Actor:DrawScale", AttributeType.Float)-  , ("Engine.Actor:RemoteRole", AttributeType.Enum)-  , ("Engine.Actor:Role", AttributeType.Enum)-  , ("Engine.Actor:Rotation", AttributeType.Rotation)-  , ("Engine.GameReplicationInfo:bMatchIsOver", AttributeType.Boolean)-  , ("Engine.GameReplicationInfo:GameClass", AttributeType.FlaggedInt)-  , ("Engine.GameReplicationInfo:ServerName", AttributeType.String)-  , ("Engine.Pawn:HealthMax", AttributeType.Int)-  , ("Engine.Pawn:PlayerReplicationInfo", AttributeType.FlaggedInt)-  , ("Engine.PlayerReplicationInfo:bBot", AttributeType.Boolean)-  , ("Engine.PlayerReplicationInfo:bIsSpectator", AttributeType.Boolean)-  , ("Engine.PlayerReplicationInfo:bReadyToPlay", AttributeType.Boolean)-  , ("Engine.PlayerReplicationInfo:bTimedOut", AttributeType.Boolean)-  , ("Engine.PlayerReplicationInfo:bWaitingPlayer", AttributeType.Boolean)-  , ("Engine.PlayerReplicationInfo:Ping", AttributeType.Byte)-  , ("Engine.PlayerReplicationInfo:PlayerID", AttributeType.Int)-  , ("Engine.PlayerReplicationInfo:PlayerName", AttributeType.String)-  , ("Engine.PlayerReplicationInfo:RemoteUserData", AttributeType.String)-  , ("Engine.PlayerReplicationInfo:Score", AttributeType.Int)-  , ("Engine.PlayerReplicationInfo:Team", AttributeType.FlaggedInt)-  , ("Engine.PlayerReplicationInfo:UniqueId", AttributeType.UniqueId)-  , ("Engine.ReplicatedActor_ORS:ReplicatedOwner", AttributeType.FlaggedInt)-  , ("Engine.TeamInfo:Score", AttributeType.Int)-  , ("ProjectX.GRI_X:bGameStarted", AttributeType.Boolean)-  , ("ProjectX.GRI_X:GameServerID", AttributeType.GameServer)-  , ("ProjectX.GRI_X:MatchGuid", AttributeType.String)-  , ("ProjectX.GRI_X:MatchGUID", AttributeType.String)-  , ("ProjectX.GRI_X:ReplicatedGameMutatorIndex", AttributeType.Int)-  , ("ProjectX.GRI_X:ReplicatedGamePlaylist", AttributeType.Int)-  , ("ProjectX.GRI_X:ReplicatedServerRegion", AttributeType.String)-  , ("ProjectX.GRI_X:Reservations", AttributeType.Reservation)-  , ("TAGame.Ball_Breakout_TA:AppliedDamage", AttributeType.AppliedDamage)-  , ("TAGame.Ball_Breakout_TA:DamageIndex", AttributeType.Int)-  , ("TAGame.Ball_Breakout_TA:LastTeamTouch", AttributeType.Byte)-  , ("TAGame.Ball_God_TA:TargetSpeed", AttributeType.Float)-  , ("TAGame.Ball_Haunted_TA:bIsBallBeamed", AttributeType.Boolean)-  , ("TAGame.Ball_Haunted_TA:DeactivatedGoalIndex", AttributeType.Byte)-  , ("TAGame.Ball_Haunted_TA:LastTeamTouch", AttributeType.Byte)-  , ("TAGame.Ball_Haunted_TA:ReplicatedBeamBrokenValue", AttributeType.Byte)-  , ("TAGame.Ball_Haunted_TA:TotalActiveBeams", AttributeType.Byte)-  , ("TAGame.Ball_TA:GameEvent", AttributeType.FlaggedInt)-  , ("TAGame.Ball_TA:HitTeamNum", AttributeType.Byte)-  , ("TAGame.Ball_TA:ReplicatedAddedCarBounceScale", AttributeType.Float)-  , ("TAGame.Ball_TA:ReplicatedBallMaxLinearSpeedScale", AttributeType.Float)-  , ("TAGame.Ball_TA:ReplicatedBallScale", AttributeType.Float)-  , ("TAGame.Ball_TA:ReplicatedExplosionData", AttributeType.Explosion)-  , ("TAGame.Ball_TA:ReplicatedExplosionDataExtended", AttributeType.ExtendedExplosion)-  , ("TAGame.Ball_TA:ReplicatedPhysMatOverride", AttributeType.FlaggedInt)-  , ("TAGame.Ball_TA:ReplicatedWorldBounceScale", AttributeType.Float)-  , ("TAGame.BreakOutActor_Platform_TA:DamageState", AttributeType.DamageState)-  , ("TAGame.CameraSettingsActor_TA:bMouseCameraToggleEnabled", AttributeType.Boolean)-  , ("TAGame.CameraSettingsActor_TA:bUsingBehindView", AttributeType.Boolean)-  , ("TAGame.CameraSettingsActor_TA:bUsingSecondaryCamera", AttributeType.Boolean)-  , ("TAGame.CameraSettingsActor_TA:bUsingSwivel", AttributeType.Boolean)-  , ("TAGame.CameraSettingsActor_TA:CameraPitch", AttributeType.Byte)-  , ("TAGame.CameraSettingsActor_TA:CameraYaw", AttributeType.Byte)-  , ("TAGame.CameraSettingsActor_TA:PRI", AttributeType.FlaggedInt)-  , ("TAGame.CameraSettingsActor_TA:ProfileSettings", AttributeType.CamSettings)-  , ("TAGame.Cannon_TA:FireCount", AttributeType.Byte)-  , ("TAGame.Cannon_TA:Pitch", AttributeType.Float)-  , ("TAGame.Car_TA:AddedBallForceMultiplier", AttributeType.Float)-  , ("TAGame.Car_TA:AddedCarForceMultiplier", AttributeType.Float)-  , ("TAGame.Car_TA:AttachedPickup", AttributeType.FlaggedInt)-  , ("TAGame.Car_TA:ClubColors", AttributeType.ClubColors)-  , ("TAGame.Car_TA:ReplicatedCarScale", AttributeType.Float)-  , ("TAGame.Car_TA:ReplicatedDemolish_CustomFX", AttributeType.CustomDemolish)-  , ("TAGame.Car_TA:ReplicatedDemolish", AttributeType.Demolish)-  , ("TAGame.Car_TA:ReplicatedDemolishGoalExplosion", AttributeType.CustomDemolish)-  , ("TAGame.Car_TA:RumblePickups", AttributeType.FlaggedInt)-  , ("TAGame.Car_TA:TeamPaint", AttributeType.TeamPaint)-  , ("TAGame.CarComponent_Boost_TA:bNoBoost", AttributeType.Boolean)-  , ("TAGame.CarComponent_Boost_TA:BoostModifier", AttributeType.Float)-  , ("TAGame.CarComponent_Boost_TA:bUnlimitedBoost", AttributeType.Boolean)-  , ("TAGame.CarComponent_Boost_TA:RechargeDelay", AttributeType.Float)-  , ("TAGame.CarComponent_Boost_TA:RechargeRate", AttributeType.Float)-  , ("TAGame.CarComponent_Boost_TA:ReplicatedBoostAmount", AttributeType.Byte)-  , ("TAGame.CarComponent_Boost_TA:UnlimitedBoostRefCount", AttributeType.Int)-  , ("TAGame.CarComponent_Dodge_TA:DodgeImpulse", AttributeType.Location)-  , ("TAGame.CarComponent_Dodge_TA:DodgeTorque", AttributeType.Location)-  , ("TAGame.CarComponent_DoubleJump_TA:DoubleJumpImpulse", AttributeType.Location)-  , ("TAGame.CarComponent_FlipCar_TA:bFlipRight", AttributeType.Boolean)-  , ("TAGame.CarComponent_FlipCar_TA:FlipCarTime", AttributeType.Float)-  , ("TAGame.CarComponent_TA:ReplicatedActive", AttributeType.Byte)-  , ("TAGame.CarComponent_TA:ReplicatedActivityTime", AttributeType.Float)-  , ("TAGame.CarComponent_TA:Vehicle", AttributeType.FlaggedInt)-  , ("TAGame.CrowdActor_TA:GameEvent", AttributeType.FlaggedInt)-  , ("TAGame.CrowdActor_TA:ModifiedNoise", AttributeType.Float)-  , ("TAGame.CrowdActor_TA:ReplicatedCountDownNumber", AttributeType.Int)-  , ("TAGame.CrowdActor_TA:ReplicatedOneShotSound", AttributeType.FlaggedInt)-  , ("TAGame.CrowdActor_TA:ReplicatedRoundCountDownNumber", AttributeType.Int)-  , ("TAGame.CrowdManager_TA:GameEvent", AttributeType.FlaggedInt)-  , ("TAGame.CrowdManager_TA:ReplicatedGlobalOneShotSound", AttributeType.FlaggedInt)-  , ("TAGame.GameEvent_Soccar_TA:bBallHasBeenHit", AttributeType.Boolean)-  , ("TAGame.GameEvent_Soccar_TA:bClubMatch", AttributeType.Boolean)-  , ("TAGame.GameEvent_Soccar_TA:bMatchEnded", AttributeType.Boolean)-  , ("TAGame.GameEvent_Soccar_TA:bNoContest", AttributeType.Boolean)-  , ("TAGame.GameEvent_Soccar_TA:bOverTime", AttributeType.Boolean)-  , ("TAGame.GameEvent_Soccar_TA:bUnlimitedTime", AttributeType.Boolean)-  , ("TAGame.GameEvent_Soccar_TA:GameTime", AttributeType.Int)-  , ("TAGame.GameEvent_Soccar_TA:GameWinner", AttributeType.FlaggedInt)-  , ("TAGame.GameEvent_Soccar_TA:MatchWinner", AttributeType.FlaggedInt)-  , ("TAGame.GameEvent_Soccar_TA:MaxScore", AttributeType.Int)-  , ("TAGame.GameEvent_Soccar_TA:MVP", AttributeType.FlaggedInt)-  , ("TAGame.GameEvent_Soccar_TA:ReplicatedMusicStinger", AttributeType.MusicStinger)-  , ("TAGame.GameEvent_Soccar_TA:ReplicatedScoredOnTeam", AttributeType.Byte)-  , ("TAGame.GameEvent_Soccar_TA:ReplicatedServerPerformanceState", AttributeType.Byte)-  , ("TAGame.GameEvent_Soccar_TA:ReplicatedStatEvent", AttributeType.StatEvent)-  , ("TAGame.GameEvent_Soccar_TA:RoundNum", AttributeType.Int)-  , ("TAGame.GameEvent_Soccar_TA:SecondsRemaining", AttributeType.Int)-  , ("TAGame.GameEvent_Soccar_TA:SeriesLength", AttributeType.Int)-  , ("TAGame.GameEvent_Soccar_TA:SubRulesArchetype", AttributeType.FlaggedInt)-  , ("TAGame.GameEvent_SoccarPrivate_TA:MatchSettings", AttributeType.PrivateMatchSettings)-  , ("TAGame.GameEvent_TA:bAllowReadyUp", AttributeType.Boolean)-  , ("TAGame.GameEvent_TA:bCanVoteToForfeit", AttributeType.Boolean)-  , ("TAGame.GameEvent_TA:bHasLeaveMatchPenalty", AttributeType.Boolean)-  , ("TAGame.GameEvent_TA:BotSkill", AttributeType.Int)-  , ("TAGame.GameEvent_TA:GameMode", AttributeType.GameMode)-  , ("TAGame.GameEvent_TA:MatchTypeClass", AttributeType.FlaggedInt)-  , ("TAGame.GameEvent_TA:ReplicatedGameStateTimeRemaining", AttributeType.Int)-  , ("TAGame.GameEvent_TA:ReplicatedRoundCountDownNumber", AttributeType.Int)-  , ("TAGame.GameEvent_TA:ReplicatedStateIndex", AttributeType.Byte)-  , ("TAGame.GameEvent_TA:ReplicatedStateName", AttributeType.Int)-  , ("TAGame.GameEvent_Team_TA:bForfeit", AttributeType.Boolean)-  , ("TAGame.GameEvent_Team_TA:MaxTeamSize", AttributeType.Int)-  , ("TAGame.GRI_TA:NewDedicatedServerIP", AttributeType.String)-  , ("TAGame.MaxTimeWarningData_TA:EndGameEpochTime", AttributeType.Int64)-  , ("TAGame.MaxTimeWarningData_TA:EndGameWarningEpochTime", AttributeType.Int64)-  , ("TAGame.PRI_TA:bIsDistracted", AttributeType.Boolean)-  , ("TAGame.PRI_TA:bIsInSplitScreen", AttributeType.Boolean)-  , ("TAGame.PRI_TA:bMatchMVP", AttributeType.Boolean)-  , ("TAGame.PRI_TA:bOnlineLoadoutSet", AttributeType.Boolean)-  , ("TAGame.PRI_TA:bOnlineLoadoutsSet", AttributeType.Boolean)-  , ("TAGame.PRI_TA:BotProductName", AttributeType.Int)-  , ("TAGame.PRI_TA:bReady", AttributeType.Boolean)-  , ("TAGame.PRI_TA:bUsingBehindView", AttributeType.Boolean)-  , ("TAGame.PRI_TA:bUsingItems", AttributeType.Boolean)-  , ("TAGame.PRI_TA:bUsingSecondaryCamera", AttributeType.Boolean)-  , ("TAGame.PRI_TA:CameraPitch", AttributeType.Byte)-  , ("TAGame.PRI_TA:CameraSettings", AttributeType.CamSettings)-  , ("TAGame.PRI_TA:CameraYaw", AttributeType.Byte)-  , ("TAGame.PRI_TA:ClientLoadout", AttributeType.Loadout)-  , ("TAGame.PRI_TA:ClientLoadoutOnline", AttributeType.LoadoutOnline)-  , ("TAGame.PRI_TA:ClientLoadouts", AttributeType.Loadouts)-  , ("TAGame.PRI_TA:ClientLoadoutsOnline", AttributeType.LoadoutsOnline)-  , ("TAGame.PRI_TA:ClubID", AttributeType.Int64)-  , ("TAGame.PRI_TA:CurrentVoiceRoom", AttributeType.String)-  , ("TAGame.PRI_TA:MatchAssists", AttributeType.Int)-  , ("TAGame.PRI_TA:MatchBreakoutDamage", AttributeType.Int)-  , ("TAGame.PRI_TA:MatchGoals", AttributeType.Int)-  , ("TAGame.PRI_TA:MatchSaves", AttributeType.Int)-  , ("TAGame.PRI_TA:MatchScore", AttributeType.Int)-  , ("TAGame.PRI_TA:MatchShots", AttributeType.Int)-  , ("TAGame.PRI_TA:MaxTimeTillItem", AttributeType.Int)-  , ("TAGame.PRI_TA:PartyLeader", AttributeType.PartyLeader)-  , ("TAGame.PRI_TA:PawnType", AttributeType.Byte)-  , ("TAGame.PRI_TA:PersistentCamera", AttributeType.FlaggedInt)-  , ("TAGame.PRI_TA:PlayerHistoryKey", AttributeType.PlayerHistoryKey)-  , ("TAGame.PRI_TA:PlayerHistoryValid", AttributeType.Boolean)-  , ("TAGame.PRI_TA:PrimaryTitle", AttributeType.Title)-  , ("TAGame.PRI_TA:ReplicatedGameEvent", AttributeType.FlaggedInt)-  , ("TAGame.PRI_TA:ReplicatedWorstNetQualityBeyondLatency", AttributeType.Byte)-  , ("TAGame.PRI_TA:RepStatTitles", AttributeType.RepStatTitle)-  , ("TAGame.PRI_TA:SecondaryTitle", AttributeType.Title)-  , ("TAGame.PRI_TA:SkillTier", AttributeType.FlaggedByte)-  , ("TAGame.PRI_TA:SpectatorShortcut", AttributeType.Int)-  , ("TAGame.PRI_TA:SteeringSensitivity", AttributeType.Float)-  , ("TAGame.PRI_TA:TimeTillItem", AttributeType.Int)-  , ("TAGame.PRI_TA:Title", AttributeType.Int)-  , ("TAGame.PRI_TA:TotalXP", AttributeType.Int)-  , ("TAGame.RBActor_TA:bFrozen", AttributeType.Boolean)-  , ("TAGame.RBActor_TA:bIgnoreSyncing", AttributeType.Boolean)-  , ("TAGame.RBActor_TA:bReplayActor", AttributeType.Boolean)-  , ("TAGame.RBActor_TA:ReplicatedRBState", AttributeType.RigidBodyState)-  , ("TAGame.RBActor_TA:WeldedInfo", AttributeType.WeldedInfo)-  , ("TAGame.RumblePickups_TA:AttachedPickup", AttributeType.FlaggedInt)-  , ("TAGame.RumblePickups_TA:ConcurrentItemCount", AttributeType.Int)-  , ("TAGame.RumblePickups_TA:PickupInfo", AttributeType.PickupInfo)-  , ("TAGame.SpecialPickup_BallFreeze_TA:RepOrigSpeed", AttributeType.Float)-  , ("TAGame.SpecialPickup_BallVelcro_TA:AttachTime", AttributeType.Float)-  , ("TAGame.SpecialPickup_BallVelcro_TA:bBroken", AttributeType.Boolean)-  , ("TAGame.SpecialPickup_BallVelcro_TA:bHit", AttributeType.Boolean)-  , ("TAGame.SpecialPickup_BallVelcro_TA:BreakTime", AttributeType.Float)-  , ("TAGame.SpecialPickup_Football_TA:WeldedBall", AttributeType.FlaggedInt)-  , ("TAGame.SpecialPickup_Rugby_TA:bBallWelded", AttributeType.Boolean)-  , ("TAGame.SpecialPickup_Targeted_TA:Targeted", AttributeType.FlaggedInt)-  , ("TAGame.Team_Soccar_TA:GameScore", AttributeType.Int)-  , ("TAGame.Team_TA:ClubColors", AttributeType.ClubColors)-  , ("TAGame.Team_TA:ClubID", AttributeType.Int64)-  , ("TAGame.Team_TA:CustomTeamName", AttributeType.String)-  , ("TAGame.Team_TA:Difficulty", AttributeType.Int)-  , ("TAGame.Team_TA:GameEvent", AttributeType.FlaggedInt)-  , ("TAGame.Team_TA:LogoData", AttributeType.FlaggedInt)-  , ("TAGame.Vehicle_TA:bDriving", AttributeType.Boolean)-  , ("TAGame.Vehicle_TA:bPodiumMode", AttributeType.Boolean)-  , ("TAGame.Vehicle_TA:bReplicatedHandbrake", AttributeType.Boolean)-  , ("TAGame.Vehicle_TA:ReplicatedSteer", AttributeType.Byte)-  , ("TAGame.Vehicle_TA:ReplicatedThrottle", AttributeType.Byte)-  , ("TAGame.VehiclePickup_TA:bNoPickup", AttributeType.Boolean)-  , ("TAGame.VehiclePickup_TA:NewReplicatedPickupData", AttributeType.PickupNew)-  , ("TAGame.VehiclePickup_TA:ReplicatedPickupData", AttributeType.Pickup)-  ]+attributeTypes =+  Map.fromList $+    fmap+      (Bifunctor.first Text.pack)+      [ ("Engine.Actor:bBlockActors", AttributeType.Boolean),+        ("Engine.Actor:bCollideActors", AttributeType.Boolean),+        ("Engine.Actor:bHidden", AttributeType.Boolean),+        ("Engine.Actor:bTearOff", AttributeType.Boolean),+        ("Engine.Actor:DrawScale", AttributeType.Float),+        ("Engine.Actor:RemoteRole", AttributeType.Enum),+        ("Engine.Actor:Role", AttributeType.Enum),+        ("Engine.Actor:Rotation", AttributeType.Rotation),+        ("Engine.GameReplicationInfo:bMatchIsOver", AttributeType.Boolean),+        ("Engine.GameReplicationInfo:GameClass", AttributeType.FlaggedInt),+        ("Engine.GameReplicationInfo:ServerName", AttributeType.String),+        ("Engine.Pawn:HealthMax", AttributeType.Int),+        ("Engine.Pawn:PlayerReplicationInfo", AttributeType.FlaggedInt),+        ("Engine.PlayerReplicationInfo:bBot", AttributeType.Boolean),+        ("Engine.PlayerReplicationInfo:bIsSpectator", AttributeType.Boolean),+        ("Engine.PlayerReplicationInfo:bReadyToPlay", AttributeType.Boolean),+        ("Engine.PlayerReplicationInfo:bTimedOut", AttributeType.Boolean),+        ("Engine.PlayerReplicationInfo:bWaitingPlayer", AttributeType.Boolean),+        ("Engine.PlayerReplicationInfo:Ping", AttributeType.Byte),+        ("Engine.PlayerReplicationInfo:PlayerID", AttributeType.Int),+        ("Engine.PlayerReplicationInfo:PlayerName", AttributeType.String),+        ("Engine.PlayerReplicationInfo:RemoteUserData", AttributeType.String),+        ("Engine.PlayerReplicationInfo:Score", AttributeType.Int),+        ("Engine.PlayerReplicationInfo:Team", AttributeType.FlaggedInt),+        ("Engine.PlayerReplicationInfo:UniqueId", AttributeType.UniqueId),+        ("Engine.ReplicatedActor_ORS:ReplicatedOwner", AttributeType.FlaggedInt),+        ("Engine.TeamInfo:Score", AttributeType.Int),+        ("ProjectX.GRI_X:bGameStarted", AttributeType.Boolean),+        ("ProjectX.GRI_X:GameServerID", AttributeType.GameServer),+        ("ProjectX.GRI_X:MatchGuid", AttributeType.String),+        ("ProjectX.GRI_X:MatchGUID", AttributeType.String),+        ("ProjectX.GRI_X:ReplicatedGameMutatorIndex", AttributeType.Int),+        ("ProjectX.GRI_X:ReplicatedGamePlaylist", AttributeType.Int),+        ("ProjectX.GRI_X:ReplicatedServerRegion", AttributeType.String),+        ("ProjectX.GRI_X:Reservations", AttributeType.Reservation),+        ("TAGame.Ball_Breakout_TA:AppliedDamage", AttributeType.AppliedDamage),+        ("TAGame.Ball_Breakout_TA:DamageIndex", AttributeType.Int),+        ("TAGame.Ball_Breakout_TA:LastTeamTouch", AttributeType.Byte),+        ("TAGame.Ball_God_TA:TargetSpeed", AttributeType.Float),+        ("TAGame.Ball_Haunted_TA:bIsBallBeamed", AttributeType.Boolean),+        ("TAGame.Ball_Haunted_TA:DeactivatedGoalIndex", AttributeType.Byte),+        ("TAGame.Ball_Haunted_TA:LastTeamTouch", AttributeType.Byte),+        ("TAGame.Ball_Haunted_TA:ReplicatedBeamBrokenValue", AttributeType.Byte),+        ("TAGame.Ball_Haunted_TA:TotalActiveBeams", AttributeType.Byte),+        ("TAGame.Ball_TA:GameEvent", AttributeType.FlaggedInt),+        ("TAGame.Ball_TA:HitTeamNum", AttributeType.Byte),+        ("TAGame.Ball_TA:ReplicatedAddedCarBounceScale", AttributeType.Float),+        ("TAGame.Ball_TA:ReplicatedBallMaxLinearSpeedScale", AttributeType.Float),+        ("TAGame.Ball_TA:ReplicatedBallScale", AttributeType.Float),+        ("TAGame.Ball_TA:ReplicatedExplosionData", AttributeType.Explosion),+        ("TAGame.Ball_TA:ReplicatedExplosionDataExtended", AttributeType.ExtendedExplosion),+        ("TAGame.Ball_TA:ReplicatedPhysMatOverride", AttributeType.FlaggedInt),+        ("TAGame.Ball_TA:ReplicatedWorldBounceScale", AttributeType.Float),+        ("TAGame.BreakOutActor_Platform_TA:DamageState", AttributeType.DamageState),+        ("TAGame.CameraSettingsActor_TA:bMouseCameraToggleEnabled", AttributeType.Boolean),+        ("TAGame.CameraSettingsActor_TA:bUsingBehindView", AttributeType.Boolean),+        ("TAGame.CameraSettingsActor_TA:bUsingSecondaryCamera", AttributeType.Boolean),+        ("TAGame.CameraSettingsActor_TA:bUsingSwivel", AttributeType.Boolean),+        ("TAGame.CameraSettingsActor_TA:CameraPitch", AttributeType.Byte),+        ("TAGame.CameraSettingsActor_TA:CameraYaw", AttributeType.Byte),+        ("TAGame.CameraSettingsActor_TA:PRI", AttributeType.FlaggedInt),+        ("TAGame.CameraSettingsActor_TA:ProfileSettings", AttributeType.CamSettings),+        ("TAGame.Cannon_TA:FireCount", AttributeType.Byte),+        ("TAGame.Cannon_TA:Pitch", AttributeType.Float),+        ("TAGame.Car_TA:AddedBallForceMultiplier", AttributeType.Float),+        ("TAGame.Car_TA:AddedCarForceMultiplier", AttributeType.Float),+        ("TAGame.Car_TA:AttachedPickup", AttributeType.FlaggedInt),+        ("TAGame.Car_TA:ClubColors", AttributeType.ClubColors),+        ("TAGame.Car_TA:ReplicatedCarScale", AttributeType.Float),+        ("TAGame.Car_TA:ReplicatedDemolish_CustomFX", AttributeType.CustomDemolish),+        ("TAGame.Car_TA:ReplicatedDemolish", AttributeType.Demolish),+        ("TAGame.Car_TA:ReplicatedDemolishGoalExplosion", AttributeType.CustomDemolish),+        ("TAGame.Car_TA:RumblePickups", AttributeType.FlaggedInt),+        ("TAGame.Car_TA:TeamPaint", AttributeType.TeamPaint),+        ("TAGame.CarComponent_Boost_TA:bNoBoost", AttributeType.Boolean),+        ("TAGame.CarComponent_Boost_TA:BoostModifier", AttributeType.Float),+        ("TAGame.CarComponent_Boost_TA:bUnlimitedBoost", AttributeType.Boolean),+        ("TAGame.CarComponent_Boost_TA:RechargeDelay", AttributeType.Float),+        ("TAGame.CarComponent_Boost_TA:RechargeRate", AttributeType.Float),+        ("TAGame.CarComponent_Boost_TA:ReplicatedBoostAmount", AttributeType.Byte),+        ("TAGame.CarComponent_Boost_TA:UnlimitedBoostRefCount", AttributeType.Int),+        ("TAGame.CarComponent_Dodge_TA:DodgeImpulse", AttributeType.Location),+        ("TAGame.CarComponent_Dodge_TA:DodgeTorque", AttributeType.Location),+        ("TAGame.CarComponent_DoubleJump_TA:DoubleJumpImpulse", AttributeType.Location),+        ("TAGame.CarComponent_FlipCar_TA:bFlipRight", AttributeType.Boolean),+        ("TAGame.CarComponent_FlipCar_TA:FlipCarTime", AttributeType.Float),+        ("TAGame.CarComponent_TA:ReplicatedActive", AttributeType.Byte),+        ("TAGame.CarComponent_TA:ReplicatedActivityTime", AttributeType.Float),+        ("TAGame.CarComponent_TA:Vehicle", AttributeType.FlaggedInt),+        ("TAGame.CrowdActor_TA:GameEvent", AttributeType.FlaggedInt),+        ("TAGame.CrowdActor_TA:ModifiedNoise", AttributeType.Float),+        ("TAGame.CrowdActor_TA:ReplicatedCountDownNumber", AttributeType.Int),+        ("TAGame.CrowdActor_TA:ReplicatedOneShotSound", AttributeType.FlaggedInt),+        ("TAGame.CrowdActor_TA:ReplicatedRoundCountDownNumber", AttributeType.Int),+        ("TAGame.CrowdManager_TA:GameEvent", AttributeType.FlaggedInt),+        ("TAGame.CrowdManager_TA:ReplicatedGlobalOneShotSound", AttributeType.FlaggedInt),+        ("TAGame.GameEvent_Soccar_TA:bBallHasBeenHit", AttributeType.Boolean),+        ("TAGame.GameEvent_Soccar_TA:bClubMatch", AttributeType.Boolean),+        ("TAGame.GameEvent_Soccar_TA:bMatchEnded", AttributeType.Boolean),+        ("TAGame.GameEvent_Soccar_TA:bNoContest", AttributeType.Boolean),+        ("TAGame.GameEvent_Soccar_TA:bOverTime", AttributeType.Boolean),+        ("TAGame.GameEvent_Soccar_TA:bUnlimitedTime", AttributeType.Boolean),+        ("TAGame.GameEvent_Soccar_TA:GameTime", AttributeType.Int),+        ("TAGame.GameEvent_Soccar_TA:GameWinner", AttributeType.FlaggedInt),+        ("TAGame.GameEvent_Soccar_TA:MatchWinner", AttributeType.FlaggedInt),+        ("TAGame.GameEvent_Soccar_TA:MaxScore", AttributeType.Int),+        ("TAGame.GameEvent_Soccar_TA:MVP", AttributeType.FlaggedInt),+        ("TAGame.GameEvent_Soccar_TA:ReplicatedMusicStinger", AttributeType.MusicStinger),+        ("TAGame.GameEvent_Soccar_TA:ReplicatedScoredOnTeam", AttributeType.Byte),+        ("TAGame.GameEvent_Soccar_TA:ReplicatedServerPerformanceState", AttributeType.Byte),+        ("TAGame.GameEvent_Soccar_TA:ReplicatedStatEvent", AttributeType.StatEvent),+        ("TAGame.GameEvent_Soccar_TA:RoundNum", AttributeType.Int),+        ("TAGame.GameEvent_Soccar_TA:SecondsRemaining", AttributeType.Int),+        ("TAGame.GameEvent_Soccar_TA:SeriesLength", AttributeType.Int),+        ("TAGame.GameEvent_Soccar_TA:SubRulesArchetype", AttributeType.FlaggedInt),+        ("TAGame.GameEvent_SoccarPrivate_TA:MatchSettings", AttributeType.PrivateMatchSettings),+        ("TAGame.GameEvent_TA:bAllowReadyUp", AttributeType.Boolean),+        ("TAGame.GameEvent_TA:bCanVoteToForfeit", AttributeType.Boolean),+        ("TAGame.GameEvent_TA:bHasLeaveMatchPenalty", AttributeType.Boolean),+        ("TAGame.GameEvent_TA:BotSkill", AttributeType.Int),+        ("TAGame.GameEvent_TA:GameMode", AttributeType.GameMode),+        ("TAGame.GameEvent_TA:MatchTypeClass", AttributeType.FlaggedInt),+        ("TAGame.GameEvent_TA:ReplicatedGameStateTimeRemaining", AttributeType.Int),+        ("TAGame.GameEvent_TA:ReplicatedRoundCountDownNumber", AttributeType.Int),+        ("TAGame.GameEvent_TA:ReplicatedStateIndex", AttributeType.Byte),+        ("TAGame.GameEvent_TA:ReplicatedStateName", AttributeType.Int),+        ("TAGame.GameEvent_Team_TA:bForfeit", AttributeType.Boolean),+        ("TAGame.GameEvent_Team_TA:MaxTeamSize", AttributeType.Int),+        ("TAGame.GRI_TA:NewDedicatedServerIP", AttributeType.String),+        ("TAGame.MaxTimeWarningData_TA:EndGameEpochTime", AttributeType.Int64),+        ("TAGame.MaxTimeWarningData_TA:EndGameWarningEpochTime", AttributeType.Int64),+        ("TAGame.PRI_TA:bIsDistracted", AttributeType.Boolean),+        ("TAGame.PRI_TA:bIsInSplitScreen", AttributeType.Boolean),+        ("TAGame.PRI_TA:bMatchMVP", AttributeType.Boolean),+        ("TAGame.PRI_TA:bOnlineLoadoutSet", AttributeType.Boolean),+        ("TAGame.PRI_TA:bOnlineLoadoutsSet", AttributeType.Boolean),+        ("TAGame.PRI_TA:BotProductName", AttributeType.Int),+        ("TAGame.PRI_TA:bReady", AttributeType.Boolean),+        ("TAGame.PRI_TA:bUsingBehindView", AttributeType.Boolean),+        ("TAGame.PRI_TA:bUsingItems", AttributeType.Boolean),+        ("TAGame.PRI_TA:bUsingSecondaryCamera", AttributeType.Boolean),+        ("TAGame.PRI_TA:CameraPitch", AttributeType.Byte),+        ("TAGame.PRI_TA:CameraSettings", AttributeType.CamSettings),+        ("TAGame.PRI_TA:CameraYaw", AttributeType.Byte),+        ("TAGame.PRI_TA:ClientLoadout", AttributeType.Loadout),+        ("TAGame.PRI_TA:ClientLoadoutOnline", AttributeType.LoadoutOnline),+        ("TAGame.PRI_TA:ClientLoadouts", AttributeType.Loadouts),+        ("TAGame.PRI_TA:ClientLoadoutsOnline", AttributeType.LoadoutsOnline),+        ("TAGame.PRI_TA:ClubID", AttributeType.Int64),+        ("TAGame.PRI_TA:CurrentVoiceRoom", AttributeType.String),+        ("TAGame.PRI_TA:MatchAssists", AttributeType.Int),+        ("TAGame.PRI_TA:MatchBreakoutDamage", AttributeType.Int),+        ("TAGame.PRI_TA:MatchGoals", AttributeType.Int),+        ("TAGame.PRI_TA:MatchSaves", AttributeType.Int),+        ("TAGame.PRI_TA:MatchScore", AttributeType.Int),+        ("TAGame.PRI_TA:MatchShots", AttributeType.Int),+        ("TAGame.PRI_TA:MaxTimeTillItem", AttributeType.Int),+        ("TAGame.PRI_TA:PartyLeader", AttributeType.PartyLeader),+        ("TAGame.PRI_TA:PawnType", AttributeType.Byte),+        ("TAGame.PRI_TA:PersistentCamera", AttributeType.FlaggedInt),+        ("TAGame.PRI_TA:PlayerHistoryKey", AttributeType.PlayerHistoryKey),+        ("TAGame.PRI_TA:PlayerHistoryValid", AttributeType.Boolean),+        ("TAGame.PRI_TA:PrimaryTitle", AttributeType.Title),+        ("TAGame.PRI_TA:ReplicatedGameEvent", AttributeType.FlaggedInt),+        ("TAGame.PRI_TA:ReplicatedWorstNetQualityBeyondLatency", AttributeType.Byte),+        ("TAGame.PRI_TA:RepStatTitles", AttributeType.RepStatTitle),+        ("TAGame.PRI_TA:SecondaryTitle", AttributeType.Title),+        ("TAGame.PRI_TA:SkillTier", AttributeType.FlaggedByte),+        ("TAGame.PRI_TA:SpectatorShortcut", AttributeType.Int),+        ("TAGame.PRI_TA:SteeringSensitivity", AttributeType.Float),+        ("TAGame.PRI_TA:TimeTillItem", AttributeType.Int),+        ("TAGame.PRI_TA:Title", AttributeType.Int),+        ("TAGame.PRI_TA:TotalXP", AttributeType.Int),+        ("TAGame.RBActor_TA:bFrozen", AttributeType.Boolean),+        ("TAGame.RBActor_TA:bIgnoreSyncing", AttributeType.Boolean),+        ("TAGame.RBActor_TA:bReplayActor", AttributeType.Boolean),+        ("TAGame.RBActor_TA:ReplicatedRBState", AttributeType.RigidBodyState),+        ("TAGame.RBActor_TA:WeldedInfo", AttributeType.WeldedInfo),+        ("TAGame.RumblePickups_TA:AttachedPickup", AttributeType.FlaggedInt),+        ("TAGame.RumblePickups_TA:ConcurrentItemCount", AttributeType.Int),+        ("TAGame.RumblePickups_TA:PickupInfo", AttributeType.PickupInfo),+        ("TAGame.SpecialPickup_BallFreeze_TA:RepOrigSpeed", AttributeType.Float),+        ("TAGame.SpecialPickup_BallVelcro_TA:AttachTime", AttributeType.Float),+        ("TAGame.SpecialPickup_BallVelcro_TA:bBroken", AttributeType.Boolean),+        ("TAGame.SpecialPickup_BallVelcro_TA:bHit", AttributeType.Boolean),+        ("TAGame.SpecialPickup_BallVelcro_TA:BreakTime", AttributeType.Float),+        ("TAGame.SpecialPickup_Football_TA:WeldedBall", AttributeType.FlaggedInt),+        ("TAGame.SpecialPickup_Rugby_TA:bBallWelded", AttributeType.Boolean),+        ("TAGame.SpecialPickup_Targeted_TA:Targeted", AttributeType.FlaggedInt),+        ("TAGame.Team_Soccar_TA:GameScore", AttributeType.Int),+        ("TAGame.Team_TA:ClubColors", AttributeType.ClubColors),+        ("TAGame.Team_TA:ClubID", AttributeType.Int64),+        ("TAGame.Team_TA:CustomTeamName", AttributeType.String),+        ("TAGame.Team_TA:Difficulty", AttributeType.Int),+        ("TAGame.Team_TA:GameEvent", AttributeType.FlaggedInt),+        ("TAGame.Team_TA:LogoData", AttributeType.FlaggedInt),+        ("TAGame.Vehicle_TA:bDriving", AttributeType.Boolean),+        ("TAGame.Vehicle_TA:bPodiumMode", AttributeType.Boolean),+        ("TAGame.Vehicle_TA:bReplicatedHandbrake", AttributeType.Boolean),+        ("TAGame.Vehicle_TA:ReplicatedSteer", AttributeType.Byte),+        ("TAGame.Vehicle_TA:ReplicatedThrottle", AttributeType.Byte),+        ("TAGame.VehiclePickup_TA:bNoPickup", AttributeType.Boolean),+        ("TAGame.VehiclePickup_TA:NewReplicatedPickupData", AttributeType.PickupNew),+        ("TAGame.VehiclePickup_TA:ReplicatedPickupData", AttributeType.Pickup)+      ]
src/lib/Rattletrap/Get.hs view
@@ -6,12 +6,12 @@ import qualified Rattletrap.Exception.Empty as Empty import qualified Rattletrap.Exception.Fail as Fail -newtype Get s m a = Get (s -> m (Either ([String], Exception.SomeException)  (s, a)))+newtype Get s m a = Get (s -> m (Either ([String], Exception.SomeException) (s, a))) -instance Functor m => Functor (Get s m) where+instance (Functor m) => Functor (Get s m) where   fmap f g = Get $ fmap (fmap (fmap f)) . run g -instance Monad m => Applicative (Get s m) where+instance (Monad m) => Applicative (Get s m) where   pure x = Get $ \s -> pure $ Right (s, x)    gf <*> gx = Get $ \s1 -> do@@ -20,17 +20,17 @@       Left e -> pure $ Left e       Right (s2, f) -> run (fmap f gx) s2 -instance Monad m => Monad (Get s m) where+instance (Monad m) => Monad (Get s m) where   g >>= f = Get $ \s1 -> do     r <- run g s1     case r of       Left e -> pure $ Left e       Right (s2, x) -> run (f x) s2 -instance Monad m => MonadFail (Get s m) where+instance (Monad m) => MonadFail (Get s m) where   fail = throw . Fail.Fail -instance Monad m => Applicative.Alternative (Get s m) where+instance (Monad m) => Applicative.Alternative (Get s m) where   empty = throw Empty.Empty    gx <|> gy = Get $ \s -> do@@ -42,27 +42,27 @@ run :: Get s m a -> s -> m (Either ([String], Exception.SomeException) (s, a)) run (Get f) = f -get :: Applicative m => Get s m s+get :: (Applicative m) => Get s m s get = Get $ \s -> pure $ Right (s, s) -put :: Applicative m => s -> Get s m ()+put :: (Applicative m) => s -> Get s m () put s = Get $ \_ -> pure $ Right (s, ()) -lift :: Functor m => m a -> Get s m a+lift :: (Functor m) => m a -> Get s m a lift m = Get $ \s -> fmap (\x -> Right (s, x)) m  throw :: (Exception.Exception e, Applicative m) => e -> Get s m a throw = Get . const . pure . Left . (,) [] . Exception.toException -embed :: Monad m => Get s m a -> s -> Get t m a+embed :: (Monad m) => Get s m a -> s -> Get t m a embed g s = do   r <- lift $ run g s   case r of     Left (ls, e) -> labels ls $ throw e     Right (_, x) -> pure x -labels :: Functor m => [String] -> Get s m a -> Get s m a+labels :: (Functor m) => [String] -> Get s m a -> Get s m a labels ls g = Get $ fmap (Bifunctor.first $ Bifunctor.first (ls <>)) . run g -label :: Functor m => String -> Get s m a -> Get s m a+label :: (Functor m) => String -> Get s m a -> Get s m a label = labels . pure
src/lib/Rattletrap/Schema.hs view
@@ -4,48 +4,53 @@ import qualified Rattletrap.Utility.Json as Json  data Schema = Schema-  { name :: Text.Text-  , json :: Json.Value+  { name :: Text.Text,+    json :: Json.Value   }   deriving (Eq, Show)  named :: String -> Json.Value -> Schema-named n j = Schema { name = Text.pack n, json = j }+named n j = Schema {name = Text.pack n, json = j}  ref :: Schema -> Json.Value ref s = Json.object [Json.pair "$ref" $ Text.pack "#/definitions/" <> name s]  object :: [((Json.Key, Json.Value), Bool)] -> Json.Value-object xs = Json.object-  [ Json.pair "type" "object"-  , Json.pair "properties" . Json.object $ fmap-    ((\(k, v) -> Json.pair (Json.keyToString k) v) . fst)-    xs-  , Json.pair "required" . fmap (fst . fst) $ filter snd xs-  ]+object xs =+  Json.object+    [ Json.pair "type" "object",+      Json.pair "properties" . Json.object $+        fmap+          ((\(k, v) -> Json.pair (Json.keyToString k) v) . fst)+          xs,+      Json.pair "required" . fmap (fst . fst) $ filter snd xs+    ]  maybe :: Schema -> Schema-maybe s = Schema-  { name = Text.pack "maybe-" <> name s-  , json = oneOf [ref s, json Rattletrap.Schema.null]-  }+maybe s =+  Schema+    { name = Text.pack "maybe-" <> name s,+      json = oneOf [ref s, json Rattletrap.Schema.null]+    }  oneOf :: [Json.Value] -> Json.Value oneOf xs = Json.object [Json.pair "oneOf" xs]  tuple :: [Json.Value] -> Json.Value-tuple xs = Json.object-  [ Json.pair "type" "array"-  , Json.pair "items" xs-  , Json.pair "minItems" $ length xs-  , Json.pair "maxItems" $ length xs-  ]+tuple xs =+  Json.object+    [ Json.pair "type" "array",+      Json.pair "items" xs,+      Json.pair "minItems" $ length xs,+      Json.pair "maxItems" $ length xs+    ]  array :: Schema -> Schema-array s = Schema-  { name = Text.pack "array-" <> name s-  , json = Json.object [Json.pair "type" "array", Json.pair "items" $ ref s]-  }+array s =+  Schema+    { name = Text.pack "array-" <> name s,+      json = Json.object [Json.pair "type" "array", Json.pair "items" $ ref s]+    }  boolean :: Schema boolean = named "boolean" $ Json.object [Json.pair "type" "boolean"]
src/lib/Rattletrap/Type/Attribute.hs view
@@ -2,7 +2,6 @@  import qualified Control.Exception as Exception import qualified Data.Map as Map-import Prelude hiding (id) import qualified Rattletrap.BitGet as BitGet import qualified Rattletrap.BitPut as BitPut import qualified Rattletrap.Exception.MissingAttributeLimit as MissingAttributeLimit@@ -16,13 +15,14 @@ import qualified Rattletrap.Type.U32 as U32 import qualified Rattletrap.Type.Version as Version import qualified Rattletrap.Utility.Json as Json+import Prelude hiding (id)  data Attribute = Attribute-  { id :: CompressedWord.CompressedWord-  , name :: Str.Str-  -- ^ Read-only! Changing an attribute's name requires editing the class-  -- attribute map.-  , value :: AttributeValue.AttributeValue+  { id :: CompressedWord.CompressedWord,+    -- | Read-only! Changing an attribute's name requires editing the class+    -- attribute map.+    name :: Str.Str,+    value :: AttributeValue.AttributeValue   }   deriving (Eq, Show) @@ -31,72 +31,80 @@     id <- Json.required object "id"     name <- Json.required object "name"     value <- Json.required object "value"-    pure Attribute { id, name, value }+    pure Attribute {id, name, value}  instance Json.ToJSON Attribute where-  toJSON x = Json.object-    [ Json.pair "id" $ id x-    , Json.pair "name" $ name x-    , Json.pair "value" $ value x-    ]+  toJSON x =+    Json.object+      [ Json.pair "id" $ id x,+        Json.pair "name" $ name x,+        Json.pair "value" $ value x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute" $ Schema.object-  [ (Json.pair "id" $ Schema.ref CompressedWord.schema, True)-  , (Json.pair "name" $ Schema.ref Str.schema, True)-  , (Json.pair "value" $ Schema.ref AttributeValue.schema, True)-  ]+schema =+  Schema.named "attribute" $+    Schema.object+      [ (Json.pair "id" $ Schema.ref CompressedWord.schema, True),+        (Json.pair "name" $ Schema.ref Str.schema, True),+        (Json.pair "value" $ Schema.ref AttributeValue.schema, True)+      ]  bitPut :: Attribute -> BitPut.BitPut bitPut attribute =   CompressedWord.bitPut (Rattletrap.Type.Attribute.id attribute)     <> AttributeValue.bitPut (value attribute) -bitGet-  :: Version.Version-  -> Maybe Str.Str-  -> ClassAttributeMap.ClassAttributeMap-  -> Map.Map CompressedWord.CompressedWord U32.U32-  -> CompressedWord.CompressedWord-  -> BitGet.BitGet Attribute+bitGet ::+  Version.Version ->+  Maybe Str.Str ->+  ClassAttributeMap.ClassAttributeMap ->+  Map.Map CompressedWord.CompressedWord U32.U32 ->+  CompressedWord.CompressedWord ->+  BitGet.BitGet Attribute bitGet version buildVersion classes actors actor =   BitGet.label "Attribute" $ do     attributes <- lookupAttributeMap classes actors actor     limit <- lookupAttributeIdLimit attributes actor     id <- BitGet.label "id" $ CompressedWord.bitGet limit     name <- lookupAttributeName classes attributes id-    value <- BitGet.label "value" $ AttributeValue.bitGet-      version-      buildVersion-      (ClassAttributeMap.objectMap classes)-      name-    pure Attribute { id, name, value }+    value <-+      BitGet.label "value" $+        AttributeValue.bitGet+          version+          buildVersion+          (ClassAttributeMap.objectMap classes)+          name+    pure Attribute {id, name, value} -lookupAttributeMap-  :: ClassAttributeMap.ClassAttributeMap-  -> Map.Map CompressedWord.CompressedWord U32.U32-  -> CompressedWord.CompressedWord-  -> BitGet.BitGet (Map.Map U32.U32 U32.U32)-lookupAttributeMap classes actors actor = fromMaybe-  (UnknownActor.UnknownActor $ CompressedWord.value actor)-  (ClassAttributeMap.getAttributeMap classes actors actor)+lookupAttributeMap ::+  ClassAttributeMap.ClassAttributeMap ->+  Map.Map CompressedWord.CompressedWord U32.U32 ->+  CompressedWord.CompressedWord ->+  BitGet.BitGet (Map.Map U32.U32 U32.U32)+lookupAttributeMap classes actors actor =+  fromMaybe+    (UnknownActor.UnknownActor $ CompressedWord.value actor)+    (ClassAttributeMap.getAttributeMap classes actors actor) -lookupAttributeIdLimit-  :: Map.Map U32.U32 U32.U32-  -> CompressedWord.CompressedWord-  -> BitGet.BitGet Word-lookupAttributeIdLimit attributes actor = fromMaybe-  (MissingAttributeLimit.MissingAttributeLimit $ CompressedWord.value actor)-  (ClassAttributeMap.getAttributeIdLimit attributes)+lookupAttributeIdLimit ::+  Map.Map U32.U32 U32.U32 ->+  CompressedWord.CompressedWord ->+  BitGet.BitGet Word+lookupAttributeIdLimit attributes actor =+  fromMaybe+    (MissingAttributeLimit.MissingAttributeLimit $ CompressedWord.value actor)+    (ClassAttributeMap.getAttributeIdLimit attributes) -lookupAttributeName-  :: ClassAttributeMap.ClassAttributeMap-  -> Map.Map U32.U32 U32.U32-  -> CompressedWord.CompressedWord-  -> BitGet.BitGet Str.Str-lookupAttributeName classes attributes attribute = fromMaybe-  (MissingAttributeName.MissingAttributeName $ CompressedWord.value attribute)-  (ClassAttributeMap.getAttributeName classes attributes attribute)+lookupAttributeName ::+  ClassAttributeMap.ClassAttributeMap ->+  Map.Map U32.U32 U32.U32 ->+  CompressedWord.CompressedWord ->+  BitGet.BitGet Str.Str+lookupAttributeName classes attributes attribute =+  fromMaybe+    (MissingAttributeName.MissingAttributeName $ CompressedWord.value attribute)+    (ClassAttributeMap.getAttributeName classes attributes attribute) -fromMaybe :: Exception.Exception e => e -> Maybe a -> BitGet.BitGet a+fromMaybe :: (Exception.Exception e) => e -> Maybe a -> BitGet.BitGet a fromMaybe message = maybe (BitGet.throw message) pure
src/lib/Rattletrap/Type/Attribute/AppliedDamage.hs view
@@ -10,10 +10,10 @@ import qualified Rattletrap.Utility.Json as Json  data AppliedDamage = AppliedDamage-  { unknown1 :: U8.U8-  , location :: Vector.Vector-  , unknown3 :: I32.I32-  , unknown4 :: I32.I32+  { unknown1 :: U8.U8,+    location :: Vector.Vector,+    unknown3 :: I32.I32,+    unknown4 :: I32.I32   }   deriving (Eq, Show) @@ -23,23 +23,26 @@     location <- Json.required object "location"     unknown3 <- Json.required object "unknown3"     unknown4 <- Json.required object "unknown4"-    pure AppliedDamage { unknown1, location, unknown3, unknown4 }+    pure AppliedDamage {unknown1, location, unknown3, unknown4}  instance Json.ToJSON AppliedDamage where-  toJSON x = Json.object-    [ Json.pair "unknown1" $ unknown1 x-    , Json.pair "location" $ location x-    , Json.pair "unknown3" $ unknown3 x-    , Json.pair "unknown4" $ unknown4 x-    ]+  toJSON x =+    Json.object+      [ Json.pair "unknown1" $ unknown1 x,+        Json.pair "location" $ location x,+        Json.pair "unknown3" $ unknown3 x,+        Json.pair "unknown4" $ unknown4 x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-applied-damage" $ Schema.object-  [ (Json.pair "unknown1" $ Schema.ref U8.schema, True)-  , (Json.pair "location" $ Schema.ref Vector.schema, True)-  , (Json.pair "unknown3" $ Schema.ref I32.schema, True)-  , (Json.pair "unknown4" $ Schema.ref I32.schema, True)-  ]+schema =+  Schema.named "attribute-applied-damage" $+    Schema.object+      [ (Json.pair "unknown1" $ Schema.ref U8.schema, True),+        (Json.pair "location" $ Schema.ref Vector.schema, True),+        (Json.pair "unknown3" $ Schema.ref I32.schema, True),+        (Json.pair "unknown4" $ Schema.ref I32.schema, True)+      ]  bitPut :: AppliedDamage -> BitPut.BitPut bitPut appliedDamageAttribute =@@ -54,4 +57,4 @@   location <- BitGet.label "location" $ Vector.bitGet version   unknown3 <- BitGet.label "unknown3" I32.bitGet   unknown4 <- BitGet.label "unknown4" I32.bitGet-  pure AppliedDamage { unknown1, location, unknown3, unknown4 }+  pure AppliedDamage {unknown1, location, unknown3, unknown4}
src/lib/Rattletrap/Type/Attribute/Boolean.hs view
@@ -7,7 +7,8 @@  newtype Boolean = Boolean   { value :: Bool-  } deriving (Eq, Show)+  }+  deriving (Eq, Show)  instance Json.FromJSON Boolean where   parseJSON = fmap Boolean . Json.parseJSON@@ -24,4 +25,4 @@ bitGet :: BitGet.BitGet Boolean bitGet = BitGet.label "Boolean" $ do   value <- BitGet.label "value" BitGet.bool-  pure Boolean { value }+  pure Boolean {value}
src/lib/Rattletrap/Type/Attribute/Byte.hs view
@@ -8,7 +8,8 @@  newtype Byte = Byte   { value :: U8.U8-  } deriving (Eq, Show)+  }+  deriving (Eq, Show)  instance Json.FromJSON Byte where   parseJSON = fmap Byte . Json.parseJSON@@ -25,4 +26,4 @@ bitGet :: BitGet.BitGet Byte bitGet = BitGet.label "Byte" $ do   value <- BitGet.label "value" U8.bitGet-  pure Byte { value }+  pure Byte {value}
src/lib/Rattletrap/Type/Attribute/CamSettings.hs view
@@ -9,13 +9,13 @@ import qualified Rattletrap.Utility.Monad as Monad  data CamSettings = CamSettings-  { fov :: F32.F32-  , height :: F32.F32-  , angle :: F32.F32-  , distance :: F32.F32-  , stiffness :: F32.F32-  , swivelSpeed :: F32.F32-  , transitionSpeed :: Maybe F32.F32+  { fov :: F32.F32,+    height :: F32.F32,+    angle :: F32.F32,+    distance :: F32.F32,+    stiffness :: F32.F32,+    swivelSpeed :: F32.F32,+    transitionSpeed :: Maybe F32.F32   }   deriving (Eq, Show) @@ -28,39 +28,43 @@     stiffness <- Json.required object "stiffness"     swivelSpeed <- Json.required object "swivel_speed"     transitionSpeed <- Json.optional object "transition_speed"-    pure CamSettings-      { fov-      , height-      , angle-      , distance-      , stiffness-      , swivelSpeed-      , transitionSpeed-      }+    pure+      CamSettings+        { fov,+          height,+          angle,+          distance,+          stiffness,+          swivelSpeed,+          transitionSpeed+        }  instance Json.ToJSON CamSettings where-  toJSON x = Json.object-    [ Json.pair "fov" $ fov x-    , Json.pair "height" $ height x-    , Json.pair "angle" $ angle x-    , Json.pair "distance" $ distance x-    , Json.pair "stiffness" $ stiffness x-    , Json.pair "swivel_speed" $ swivelSpeed x-    , Json.pair "transition_speed" $ transitionSpeed x-    ]+  toJSON x =+    Json.object+      [ Json.pair "fov" $ fov x,+        Json.pair "height" $ height x,+        Json.pair "angle" $ angle x,+        Json.pair "distance" $ distance x,+        Json.pair "stiffness" $ stiffness x,+        Json.pair "swivel_speed" $ swivelSpeed x,+        Json.pair "transition_speed" $ transitionSpeed x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-cam-settings" $ Schema.object-  [ (Json.pair "fov" $ Schema.ref F32.schema, True)-  , (Json.pair "height" $ Schema.ref F32.schema, True)-  , (Json.pair "angle" $ Schema.ref F32.schema, True)-  , (Json.pair "distance" $ Schema.ref F32.schema, True)-  , (Json.pair "stiffness" $ Schema.ref F32.schema, True)-  , (Json.pair "swivel_speed" $ Schema.ref F32.schema, True)-  , ( Json.pair "transition_speed" . Schema.json $ Schema.maybe F32.schema-    , False-    )-  ]+schema =+  Schema.named "attribute-cam-settings" $+    Schema.object+      [ (Json.pair "fov" $ Schema.ref F32.schema, True),+        (Json.pair "height" $ Schema.ref F32.schema, True),+        (Json.pair "angle" $ Schema.ref F32.schema, True),+        (Json.pair "distance" $ Schema.ref F32.schema, True),+        (Json.pair "stiffness" $ Schema.ref F32.schema, True),+        (Json.pair "swivel_speed" $ Schema.ref F32.schema, True),+        ( Json.pair "transition_speed" . Schema.json $ Schema.maybe F32.schema,+          False+        )+      ]  bitPut :: CamSettings -> BitPut.BitPut bitPut camSettingsAttribute =@@ -80,14 +84,16 @@   distance <- BitGet.label "distance" F32.bitGet   stiffness <- BitGet.label "stiffness" F32.bitGet   swivelSpeed <- BitGet.label "swivelSpeed" F32.bitGet-  transitionSpeed <- BitGet.label "transitionSpeed"-    $ Monad.whenMaybe (Version.atLeast 868 20 0 version) F32.bitGet-  pure CamSettings-    { fov-    , height-    , angle-    , distance-    , stiffness-    , swivelSpeed-    , transitionSpeed-    }+  transitionSpeed <-+    BitGet.label "transitionSpeed" $+      Monad.whenMaybe (Version.atLeast 868 20 0 version) F32.bitGet+  pure+    CamSettings+      { fov,+        height,+        angle,+        distance,+        stiffness,+        swivelSpeed,+        transitionSpeed+      }
src/lib/Rattletrap/Type/Attribute/ClubColors.hs view
@@ -7,10 +7,10 @@ import qualified Rattletrap.Utility.Json as Json  data ClubColors = ClubColors-  { blueFlag :: Bool-  , blueColor :: U8.U8-  , orangeFlag :: Bool-  , orangeColor :: U8.U8+  { blueFlag :: Bool,+    blueColor :: U8.U8,+    orangeFlag :: Bool,+    orangeColor :: U8.U8   }   deriving (Eq, Show) @@ -20,23 +20,26 @@     blueColor <- Json.required object "blue_color"     orangeFlag <- Json.required object "orange_flag"     orangeColor <- Json.required object "orange_color"-    pure ClubColors { blueFlag, blueColor, orangeFlag, orangeColor }+    pure ClubColors {blueFlag, blueColor, orangeFlag, orangeColor}  instance Json.ToJSON ClubColors where-  toJSON x = Json.object-    [ Json.pair "blue_flag" $ blueFlag x-    , Json.pair "blue_color" $ blueColor x-    , Json.pair "orange_flag" $ orangeFlag x-    , Json.pair "orange_color" $ orangeColor x-    ]+  toJSON x =+    Json.object+      [ Json.pair "blue_flag" $ blueFlag x,+        Json.pair "blue_color" $ blueColor x,+        Json.pair "orange_flag" $ orangeFlag x,+        Json.pair "orange_color" $ orangeColor x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-club-colors" $ Schema.object-  [ (Json.pair "blue_flag" $ Schema.ref Schema.boolean, True)-  , (Json.pair "blue_color" $ Schema.ref U8.schema, True)-  , (Json.pair "orange_flag" $ Schema.ref Schema.boolean, True)-  , (Json.pair "orange_color" $ Schema.ref U8.schema, True)-  ]+schema =+  Schema.named "attribute-club-colors" $+    Schema.object+      [ (Json.pair "blue_flag" $ Schema.ref Schema.boolean, True),+        (Json.pair "blue_color" $ Schema.ref U8.schema, True),+        (Json.pair "orange_flag" $ Schema.ref Schema.boolean, True),+        (Json.pair "orange_color" $ Schema.ref U8.schema, True)+      ]  bitPut :: ClubColors -> BitPut.BitPut bitPut clubColorsAttribute =@@ -51,4 +54,4 @@   blueColor <- BitGet.label "blueColor" U8.bitGet   orangeFlag <- BitGet.label "orangeFlag" BitGet.bool   orangeColor <- BitGet.label "orangeColor" U8.bitGet-  pure ClubColors { blueFlag, blueColor, orangeFlag, orangeColor }+  pure ClubColors {blueFlag, blueColor, orangeFlag, orangeColor}
src/lib/Rattletrap/Type/Attribute/CustomDemolish.hs view
@@ -1,6 +1,5 @@ module Rattletrap.Type.Attribute.CustomDemolish where -import Prelude hiding (id) import qualified Rattletrap.BitGet as BitGet import qualified Rattletrap.BitPut as BitPut import qualified Rattletrap.Schema as Schema@@ -8,11 +7,12 @@ import qualified Rattletrap.Type.I32 as I32 import qualified Rattletrap.Type.Version as Version import qualified Rattletrap.Utility.Json as Json+import Prelude hiding (id)  data CustomDemolish = CustomDemolish-  { flag :: Bool-  , id :: I32.I32-  , demolish :: Demolish.Demolish+  { flag :: Bool,+    id :: I32.I32,+    demolish :: Demolish.Demolish   }   deriving (Eq, Show) @@ -21,21 +21,24 @@     flag <- Json.required object "flag"     id <- Json.required object "id"     demolish <- Json.required object "demolish"-    pure CustomDemolish { flag, id, demolish }+    pure CustomDemolish {flag, id, demolish}  instance Json.ToJSON CustomDemolish where-  toJSON x = Json.object-    [ Json.pair "flag" $ flag x-    , Json.pair "id" $ id x-    , Json.pair "demolish" $ demolish x-    ]+  toJSON x =+    Json.object+      [ Json.pair "flag" $ flag x,+        Json.pair "id" $ id x,+        Json.pair "demolish" $ demolish x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-custom-demolish" $ Schema.object-  [ (Json.pair "flag" $ Schema.ref Schema.boolean, True)-  , (Json.pair "id" $ Schema.ref I32.schema, True)-  , (Json.pair "demolish" $ Schema.ref Demolish.schema, True)-  ]+schema =+  Schema.named "attribute-custom-demolish" $+    Schema.object+      [ (Json.pair "flag" $ Schema.ref Schema.boolean, True),+        (Json.pair "id" $ Schema.ref I32.schema, True),+        (Json.pair "demolish" $ Schema.ref Demolish.schema, True)+      ]  bitPut :: CustomDemolish -> BitPut.BitPut bitPut x =@@ -48,8 +51,9 @@   flag <- BitGet.label "flag" BitGet.bool   id <- BitGet.label "id" I32.bitGet   demolish <- BitGet.label "demolish" $ Demolish.bitGet version-  pure CustomDemolish-    { flag-    , Rattletrap.Type.Attribute.CustomDemolish.id-    , demolish-    }+  pure+    CustomDemolish+      { flag,+        Rattletrap.Type.Attribute.CustomDemolish.id,+        demolish+      }
src/lib/Rattletrap/Type/Attribute/DamageState.hs view
@@ -10,12 +10,12 @@ import qualified Rattletrap.Utility.Json as Json  data DamageState = DamageState-  { unknown1 :: U8.U8-  , unknown2 :: Bool-  , unknown3 :: I32.I32-  , unknown4 :: Vector.Vector-  , unknown5 :: Bool-  , unknown6 :: Bool+  { unknown1 :: U8.U8,+    unknown2 :: Bool,+    unknown3 :: I32.I32,+    unknown4 :: Vector.Vector,+    unknown5 :: Bool,+    unknown6 :: Bool   }   deriving (Eq, Show) @@ -27,34 +27,38 @@     unknown4 <- Json.required object "unknown4"     unknown5 <- Json.required object "unknown5"     unknown6 <- Json.required object "unknown6"-    pure DamageState-      { unknown1-      , unknown2-      , unknown3-      , unknown4-      , unknown5-      , unknown6-      }+    pure+      DamageState+        { unknown1,+          unknown2,+          unknown3,+          unknown4,+          unknown5,+          unknown6+        }  instance Json.ToJSON DamageState where-  toJSON x = Json.object-    [ Json.pair "unknown1" $ unknown1 x-    , Json.pair "unknown2" $ unknown2 x-    , Json.pair "unknown3" $ unknown3 x-    , Json.pair "unknown4" $ unknown4 x-    , Json.pair "unknown5" $ unknown5 x-    , Json.pair "unknown6" $ unknown6 x-    ]+  toJSON x =+    Json.object+      [ Json.pair "unknown1" $ unknown1 x,+        Json.pair "unknown2" $ unknown2 x,+        Json.pair "unknown3" $ unknown3 x,+        Json.pair "unknown4" $ unknown4 x,+        Json.pair "unknown5" $ unknown5 x,+        Json.pair "unknown6" $ unknown6 x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-damage-state" $ Schema.object-  [ (Json.pair "unknown1" $ Schema.ref U8.schema, True)-  , (Json.pair "unknown2" $ Schema.ref Schema.boolean, True)-  , (Json.pair "unknown3" $ Schema.ref I32.schema, True)-  , (Json.pair "unknown4" $ Schema.ref Vector.schema, True)-  , (Json.pair "unknown5" $ Schema.ref Schema.boolean, True)-  , (Json.pair "unknown6" $ Schema.ref Schema.boolean, True)-  ]+schema =+  Schema.named "attribute-damage-state" $+    Schema.object+      [ (Json.pair "unknown1" $ Schema.ref U8.schema, True),+        (Json.pair "unknown2" $ Schema.ref Schema.boolean, True),+        (Json.pair "unknown3" $ Schema.ref I32.schema, True),+        (Json.pair "unknown4" $ Schema.ref Vector.schema, True),+        (Json.pair "unknown5" $ Schema.ref Schema.boolean, True),+        (Json.pair "unknown6" $ Schema.ref Schema.boolean, True)+      ]  bitPut :: DamageState -> BitPut.BitPut bitPut damageStateAttribute =@@ -73,11 +77,12 @@   unknown4 <- BitGet.label "unknown4" $ Vector.bitGet version   unknown5 <- BitGet.label "unknown5" BitGet.bool   unknown6 <- BitGet.label "unknown6" BitGet.bool-  pure DamageState-    { unknown1-    , unknown2-    , unknown3-    , unknown4-    , unknown5-    , unknown6-    }+  pure+    DamageState+      { unknown1,+        unknown2,+        unknown3,+        unknown4,+        unknown5,+        unknown6+      }
src/lib/Rattletrap/Type/Attribute/Demolish.hs view
@@ -9,12 +9,12 @@ import qualified Rattletrap.Utility.Json as Json  data Demolish = Demolish-  { attackerFlag :: Bool-  , attackerActorId :: U32.U32-  , victimFlag :: Bool-  , victimActorId :: U32.U32-  , attackerVelocity :: Vector.Vector-  , victimVelocity :: Vector.Vector+  { attackerFlag :: Bool,+    attackerActorId :: U32.U32,+    victimFlag :: Bool,+    victimActorId :: U32.U32,+    attackerVelocity :: Vector.Vector,+    victimVelocity :: Vector.Vector   }   deriving (Eq, Show) @@ -26,34 +26,38 @@     victimActorId <- Json.required object "victim_actor_id"     attackerVelocity <- Json.required object "attacker_velocity"     victimVelocity <- Json.required object "victim_velocity"-    pure Demolish-      { attackerFlag-      , attackerActorId-      , victimFlag-      , victimActorId-      , attackerVelocity-      , victimVelocity-      }+    pure+      Demolish+        { attackerFlag,+          attackerActorId,+          victimFlag,+          victimActorId,+          attackerVelocity,+          victimVelocity+        }  instance Json.ToJSON Demolish where-  toJSON x = Json.object-    [ Json.pair "attacker_flag" $ attackerFlag x-    , Json.pair "attacker_actor_id" $ attackerActorId x-    , Json.pair "victim_flag" $ victimFlag x-    , Json.pair "victim_actor_id" $ victimActorId x-    , Json.pair "attacker_velocity" $ attackerVelocity x-    , Json.pair "victim_velocity" $ victimVelocity x-    ]+  toJSON x =+    Json.object+      [ Json.pair "attacker_flag" $ attackerFlag x,+        Json.pair "attacker_actor_id" $ attackerActorId x,+        Json.pair "victim_flag" $ victimFlag x,+        Json.pair "victim_actor_id" $ victimActorId x,+        Json.pair "attacker_velocity" $ attackerVelocity x,+        Json.pair "victim_velocity" $ victimVelocity x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-demolish" $ Schema.object-  [ (Json.pair "attacker_flag" $ Schema.ref Schema.boolean, True)-  , (Json.pair "attacker_actor_id" $ Schema.ref U32.schema, True)-  , (Json.pair "victim_flag" $ Schema.ref Schema.boolean, True)-  , (Json.pair "victim_actor_id" $ Schema.ref U32.schema, True)-  , (Json.pair "attacker_velocity" $ Schema.ref Vector.schema, True)-  , (Json.pair "victim_velocity" $ Schema.ref Vector.schema, True)-  ]+schema =+  Schema.named "attribute-demolish" $+    Schema.object+      [ (Json.pair "attacker_flag" $ Schema.ref Schema.boolean, True),+        (Json.pair "attacker_actor_id" $ Schema.ref U32.schema, True),+        (Json.pair "victim_flag" $ Schema.ref Schema.boolean, True),+        (Json.pair "victim_actor_id" $ Schema.ref U32.schema, True),+        (Json.pair "attacker_velocity" $ Schema.ref Vector.schema, True),+        (Json.pair "victim_velocity" $ Schema.ref Vector.schema, True)+      ]  bitPut :: Demolish -> BitPut.BitPut bitPut demolishAttribute =@@ -72,11 +76,12 @@   victimActorId <- BitGet.label "victimActorId" U32.bitGet   attackerVelocity <- BitGet.label "attackerVelocity" $ Vector.bitGet version   victimVelocity <- BitGet.label "victimVelocity" $ Vector.bitGet version-  pure Demolish-    { attackerFlag-    , attackerActorId-    , victimFlag-    , victimActorId-    , attackerVelocity-    , victimVelocity-    }+  pure+    Demolish+      { attackerFlag,+        attackerActorId,+        victimFlag,+        victimActorId,+        attackerVelocity,+        victimVelocity+      }
src/lib/Rattletrap/Type/Attribute/Enum.hs view
@@ -1,15 +1,16 @@ module Rattletrap.Type.Attribute.Enum where  import qualified Data.Word as Word-import Prelude hiding (Enum) import qualified Rattletrap.BitGet as BitGet import qualified Rattletrap.BitPut as BitPut import qualified Rattletrap.Schema as Schema import qualified Rattletrap.Utility.Json as Json+import Prelude hiding (Enum)  newtype Enum = Enum   { value :: Word.Word16-  } deriving (Eq, Show)+  }+  deriving (Eq, Show)  instance Json.FromJSON Enum where   parseJSON = fmap Enum . Json.parseJSON@@ -26,4 +27,4 @@ bitGet :: BitGet.BitGet Enum bitGet = BitGet.label "Enum" $ do   value <- BitGet.label "value" $ BitGet.bits 11-  pure Enum { value }+  pure Enum {value}
src/lib/Rattletrap/Type/Attribute/Explosion.hs view
@@ -9,9 +9,9 @@ import qualified Rattletrap.Utility.Json as Json  data Explosion = Explosion-  { flag :: Bool-  , actorId :: I32.I32-  , location :: Vector.Vector+  { flag :: Bool,+    actorId :: I32.I32,+    location :: Vector.Vector   }   deriving (Eq, Show) @@ -20,21 +20,24 @@     flag <- Json.required object "flag"     actorId <- Json.required object "actor_id"     location <- Json.required object "location"-    pure Explosion { flag, actorId, location }+    pure Explosion {flag, actorId, location}  instance Json.ToJSON Explosion where-  toJSON x = Json.object-    [ Json.pair "flag" $ flag x-    , Json.pair "actor_id" $ actorId x-    , Json.pair "location" $ location x-    ]+  toJSON x =+    Json.object+      [ Json.pair "flag" $ flag x,+        Json.pair "actor_id" $ actorId x,+        Json.pair "location" $ location x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-explosion" $ Schema.object-  [ (Json.pair "flag" $ Schema.ref Schema.boolean, True)-  , (Json.pair "actor_id" $ Schema.ref I32.schema, True)-  , (Json.pair "location" $ Schema.ref Vector.schema, True)-  ]+schema =+  Schema.named "attribute-explosion" $+    Schema.object+      [ (Json.pair "flag" $ Schema.ref Schema.boolean, True),+        (Json.pair "actor_id" $ Schema.ref I32.schema, True),+        (Json.pair "location" $ Schema.ref Vector.schema, True)+      ]  bitPut :: Explosion -> BitPut.BitPut bitPut explosionAttribute =@@ -47,4 +50,4 @@   flag <- BitGet.label "flag" BitGet.bool   actorId <- BitGet.label "actorId" I32.bitGet   location <- BitGet.label "location" $ Vector.bitGet version-  pure Explosion { flag, actorId, location }+  pure Explosion {flag, actorId, location}
src/lib/Rattletrap/Type/Attribute/ExtendedExplosion.hs view
@@ -9,8 +9,8 @@ import qualified Rattletrap.Utility.Json as Json  data ExtendedExplosion = ExtendedExplosion-  { explosion :: Explosion.Explosion-  , unknown :: FlaggedInt.FlaggedInt+  { explosion :: Explosion.Explosion,+    unknown :: FlaggedInt.FlaggedInt   }   deriving (Eq, Show) @@ -18,17 +18,20 @@   parseJSON = Json.withObject "ExtendedExplosion" $ \object -> do     explosion <- Json.required object "explosion"     unknown <- Json.required object "unknown"-    pure ExtendedExplosion { explosion, unknown }+    pure ExtendedExplosion {explosion, unknown}  instance Json.ToJSON ExtendedExplosion where-  toJSON x = Json.object-    [Json.pair "explosion" $ explosion x, Json.pair "unknown" $ unknown x]+  toJSON x =+    Json.object+      [Json.pair "explosion" $ explosion x, Json.pair "unknown" $ unknown x]  schema :: Schema.Schema-schema = Schema.named "attribute-extended-explosion" $ Schema.object-  [ (Json.pair "explosion" $ Schema.ref Explosion.schema, True)-  , (Json.pair "unknown" $ Schema.ref FlaggedInt.schema, True)-  ]+schema =+  Schema.named "attribute-extended-explosion" $+    Schema.object+      [ (Json.pair "explosion" $ Schema.ref Explosion.schema, True),+        (Json.pair "unknown" $ Schema.ref FlaggedInt.schema, True)+      ]  bitPut :: ExtendedExplosion -> BitPut.BitPut bitPut x = Explosion.bitPut (explosion x) <> FlaggedInt.bitPut (unknown x)@@ -37,4 +40,4 @@ bitGet version = BitGet.label "ExtendedExplosion" $ do   explosion <- BitGet.label "explosion" $ Explosion.bitGet version   unknown <- BitGet.label "unknown" FlaggedInt.bitGet-  pure ExtendedExplosion { explosion, unknown }+  pure ExtendedExplosion {explosion, unknown}
src/lib/Rattletrap/Type/Attribute/FlaggedByte.hs view
@@ -7,8 +7,8 @@ import qualified Rattletrap.Utility.Json as Json  data FlaggedByte = FlaggedByte-  { flag :: Bool-  , byte :: U8.U8+  { flag :: Bool,+    byte :: U8.U8   }   deriving (Eq, Show) @@ -16,24 +16,27 @@   parseJSON = Json.withObject "FlaggedByte" $ \object -> do     flag <- Json.required object "flag"     byte <- Json.required object "byte"-    pure FlaggedByte { flag, byte }+    pure FlaggedByte {flag, byte}  instance Json.ToJSON FlaggedByte where   toJSON x =     Json.object [Json.pair "flag" $ flag x, Json.pair "byte" $ byte x]  schema :: Schema.Schema-schema = Schema.named "attribute-flagged-byte" $ Schema.object-  [ (Json.pair "flag" $ Schema.ref Schema.boolean, True)-  , (Json.pair "byte" $ Schema.ref U8.schema, True)-  ]+schema =+  Schema.named "attribute-flagged-byte" $+    Schema.object+      [ (Json.pair "flag" $ Schema.ref Schema.boolean, True),+        (Json.pair "byte" $ Schema.ref U8.schema, True)+      ]  bitPut :: FlaggedByte -> BitPut.BitPut-bitPut flaggedByteAttribute = BitPut.bool (flag flaggedByteAttribute)-  <> U8.bitPut (byte flaggedByteAttribute)+bitPut flaggedByteAttribute =+  BitPut.bool (flag flaggedByteAttribute)+    <> U8.bitPut (byte flaggedByteAttribute)  bitGet :: BitGet.BitGet FlaggedByte bitGet = BitGet.label "FlaggedByte" $ do   flag <- BitGet.label "flag" BitGet.bool   byte <- BitGet.label "byte" U8.bitGet-  pure FlaggedByte { flag, byte }+  pure FlaggedByte {flag, byte}
src/lib/Rattletrap/Type/Attribute/FlaggedInt.hs view
@@ -7,8 +7,8 @@ import qualified Rattletrap.Utility.Json as Json  data FlaggedInt = FlaggedInt-  { flag :: Bool-  , int :: I32.I32+  { flag :: Bool,+    int :: I32.I32   }   deriving (Eq, Show) @@ -16,23 +16,26 @@   parseJSON = Json.withObject "FlaggedInt" $ \object -> do     flag <- Json.required object "flag"     int <- Json.required object "int"-    pure FlaggedInt { flag, int }+    pure FlaggedInt {flag, int}  instance Json.ToJSON FlaggedInt where   toJSON x = Json.object [Json.pair "flag" $ flag x, Json.pair "int" $ int x]  schema :: Schema.Schema-schema = Schema.named "attribute-flagged-int" $ Schema.object-  [ (Json.pair "flag" $ Schema.ref Schema.boolean, True)-  , (Json.pair "int" $ Schema.ref I32.schema, True)-  ]+schema =+  Schema.named "attribute-flagged-int" $+    Schema.object+      [ (Json.pair "flag" $ Schema.ref Schema.boolean, True),+        (Json.pair "int" $ Schema.ref I32.schema, True)+      ]  bitPut :: FlaggedInt -> BitPut.BitPut-bitPut flaggedIntAttribute = BitPut.bool (flag flaggedIntAttribute)-  <> I32.bitPut (int flaggedIntAttribute)+bitPut flaggedIntAttribute =+  BitPut.bool (flag flaggedIntAttribute)+    <> I32.bitPut (int flaggedIntAttribute)  bitGet :: BitGet.BitGet FlaggedInt bitGet = BitGet.label "FlaggedInt" $ do   flag <- BitGet.label "flag" BitGet.bool   int <- BitGet.label "int" I32.bitGet-  pure FlaggedInt { flag, int }+  pure FlaggedInt {flag, int}
src/lib/Rattletrap/Type/Attribute/Float.hs view
@@ -1,15 +1,16 @@ module Rattletrap.Type.Attribute.Float where -import Prelude hiding (Float) import qualified Rattletrap.BitGet as BitGet import qualified Rattletrap.BitPut as BitPut import qualified Rattletrap.Schema as Schema import qualified Rattletrap.Type.F32 as F32 import qualified Rattletrap.Utility.Json as Json+import Prelude hiding (Float)  newtype Float = Float   { value :: F32.F32-  } deriving (Eq, Show)+  }+  deriving (Eq, Show)  instance Json.FromJSON Float where   parseJSON = fmap Float . Json.parseJSON@@ -26,4 +27,4 @@ bitGet :: BitGet.BitGet Float bitGet = BitGet.label "Float" $ do   value <- BitGet.label "value" F32.bitGet-  pure Float { value }+  pure Float {value}
src/lib/Rattletrap/Type/Attribute/GameMode.hs view
@@ -8,12 +8,12 @@ import qualified Rattletrap.Utility.Json as Json  data GameMode = GameMode-  { numBits :: Int-  -- ^ This field is guaranteed to be small. In other words, it won't overflow.-  -- It's stored as a regular 'Int' rather than something more precise like an-  -- 'Int8' because it just gets passed to functions that expect 'Int's.-  -- There's no reason to do a bunch of conversions.-  , word :: Word.Word8+  { -- | This field is guaranteed to be small. In other words, it won't overflow.+    -- It's stored as a regular 'Int' rather than something more precise like an+    -- 'Int8' because it just gets passed to functions that expect 'Int's.+    -- There's no reason to do a bunch of conversions.+    numBits :: Int,+    word :: Word.Word8   }   deriving (Eq, Show) @@ -21,17 +21,19 @@   parseJSON = Json.withObject "GameMode" $ \object -> do     numBits <- Json.required object "num_bits"     word <- Json.required object "word"-    pure GameMode { numBits, word }+    pure GameMode {numBits, word}  instance Json.ToJSON GameMode where   toJSON x =     Json.object [Json.pair "num_bits" $ numBits x, Json.pair "word" $ word x]  schema :: Schema.Schema-schema = Schema.named "attribute-game-mode" $ Schema.object-  [ (Json.pair "num_bits" $ Schema.ref Schema.integer, True)-  , (Json.pair "word" $ Schema.ref Schema.integer, True)-  ]+schema =+  Schema.named "attribute-game-mode" $+    Schema.object+      [ (Json.pair "num_bits" $ Schema.ref Schema.integer, True),+        (Json.pair "word" $ Schema.ref Schema.integer, True)+      ]  bitPut :: GameMode -> BitPut.BitPut bitPut gameModeAttribute = do@@ -41,4 +43,4 @@ bitGet version = BitGet.label "GameMode" $ do   let numBits = if Version.atLeast 868 12 0 version then 8 else 2 :: Int   word <- BitGet.label "word" $ BitGet.bits numBits-  pure GameMode { numBits, word }+  pure GameMode {numBits, word}
src/lib/Rattletrap/Type/Attribute/GameServer.hs view
@@ -14,8 +14,9 @@   deriving (Eq, Show)  instance Json.FromJSON GameServer where-  parseJSON = Json.withObject "GameServer" $ \x -> Foldable.asum-    [fmap Old $ Json.required x "old", fmap New $ Json.required x "new"]+  parseJSON = Json.withObject "GameServer" $ \x ->+    Foldable.asum+      [fmap Old $ Json.required x "old", fmap New $ Json.required x "new"]  instance Json.ToJSON GameServer where   toJSON x = case x of@@ -23,9 +24,11 @@     New y -> Json.object [Json.pair "new" $ Json.toJSON y]  schema :: Schema.Schema-schema = Schema.named "attribute-game-server" . Schema.oneOf $ fmap-  (\(k, v) -> Schema.object [(Json.pair k v, True)])-  [("old", Schema.ref QWord.schema), ("new", Schema.ref Str.schema)]+schema =+  Schema.named "attribute-game-server" . Schema.oneOf $+    fmap+      (\(k, v) -> Schema.object [(Json.pair k v, True)])+      [("old", Schema.ref QWord.schema), ("new", Schema.ref Str.schema)]  bitPut :: GameServer -> BitPut.BitPut bitPut x = case x of@@ -34,7 +37,7 @@  bitGet :: Maybe Str.Str -> BitGet.BitGet GameServer bitGet buildVersion =-  BitGet.label "GameServer"-    $ if buildVersion >= Just (Str.fromString "221120.42953.406184")-        then BitGet.label "New" $ fmap New Str.bitGet-        else BitGet.label "Old" $ fmap Old QWord.bitGet+  BitGet.label "GameServer" $+    if buildVersion >= Just (Str.fromString "221120.42953.406184")+      then BitGet.label "New" $ fmap New Str.bitGet+      else BitGet.label "Old" $ fmap Old QWord.bitGet
src/lib/Rattletrap/Type/Attribute/Int.hs view
@@ -1,15 +1,16 @@ module Rattletrap.Type.Attribute.Int where -import Prelude hiding (Int) import qualified Rattletrap.BitGet as BitGet import qualified Rattletrap.BitPut as BitPut import qualified Rattletrap.Schema as Schema import qualified Rattletrap.Type.I32 as I32 import qualified Rattletrap.Utility.Json as Json+import Prelude hiding (Int)  newtype Int = Int   { value :: I32.I32-  } deriving (Eq, Show)+  }+  deriving (Eq, Show)  instance Json.FromJSON Int where   parseJSON = fmap Int . Json.parseJSON@@ -26,4 +27,4 @@ bitGet :: BitGet.BitGet Int bitGet = BitGet.label "Int" $ do   value <- BitGet.label "value" I32.bitGet-  pure Int { value }+  pure Int {value}
src/lib/Rattletrap/Type/Attribute/Int64.hs view
@@ -8,7 +8,8 @@  newtype Int64 = Int64   { value :: I64.I64-  } deriving (Eq, Show)+  }+  deriving (Eq, Show)  instance Json.FromJSON Int64 where   parseJSON = fmap Int64 . Json.parseJSON@@ -25,4 +26,4 @@ bitGet :: BitGet.BitGet Int64 bitGet = BitGet.label "Int64" $ do   value <- BitGet.label "value" I64.bitGet-  pure Int64 { value }+  pure Int64 {value}
src/lib/Rattletrap/Type/Attribute/Loadout.hs view
@@ -9,24 +9,24 @@ import qualified Rattletrap.Utility.Monad as Monad  data Loadout = Loadout-  { version :: U8.U8-  , body :: U32.U32-  , decal :: U32.U32-  , wheels :: U32.U32-  , rocketTrail :: U32.U32-  -- ^ Now known as "rocket boost".-  , antenna :: U32.U32-  , topper :: U32.U32-  , unknown1 :: U32.U32-  , unknown2 :: Maybe U32.U32-  , engineAudio :: Maybe U32.U32-  , trail :: Maybe U32.U32-  , goalExplosion :: Maybe U32.U32-  , banner :: Maybe U32.U32-  , unknown3 :: Maybe U32.U32-  , unknown4 :: Maybe U32.U32-  , unknown5 :: Maybe U32.U32-  , unknown6 :: Maybe U32.U32+  { version :: U8.U8,+    body :: U32.U32,+    decal :: U32.U32,+    wheels :: U32.U32,+    -- | Now known as "rocket boost".+    rocketTrail :: U32.U32,+    antenna :: U32.U32,+    topper :: U32.U32,+    unknown1 :: U32.U32,+    unknown2 :: Maybe U32.U32,+    engineAudio :: Maybe U32.U32,+    trail :: Maybe U32.U32,+    goalExplosion :: Maybe U32.U32,+    banner :: Maybe U32.U32,+    unknown3 :: Maybe U32.U32,+    unknown4 :: Maybe U32.U32,+    unknown5 :: Maybe U32.U32,+    unknown6 :: Maybe U32.U32   }   deriving (Eq, Show) @@ -49,67 +49,71 @@     unknown4 <- Json.optional object "unknown4"     unknown5 <- Json.optional object "unknown5"     unknown6 <- Json.optional object "unknown6"-    pure Loadout-      { version-      , body-      , decal-      , wheels-      , rocketTrail-      , antenna-      , topper-      , unknown1-      , unknown2-      , engineAudio-      , trail-      , goalExplosion-      , banner-      , unknown3-      , unknown4-      , unknown5-      , unknown6-      }+    pure+      Loadout+        { version,+          body,+          decal,+          wheels,+          rocketTrail,+          antenna,+          topper,+          unknown1,+          unknown2,+          engineAudio,+          trail,+          goalExplosion,+          banner,+          unknown3,+          unknown4,+          unknown5,+          unknown6+        }  instance Json.ToJSON Loadout where-  toJSON x = Json.object-    [ Json.pair "version" $ version x-    , Json.pair "body" $ body x-    , Json.pair "decal" $ decal x-    , Json.pair "wheels" $ wheels x-    , Json.pair "rocket_trail" $ rocketTrail x-    , Json.pair "antenna" $ antenna x-    , Json.pair "topper" $ topper x-    , Json.pair "unknown1" $ unknown1 x-    , Json.pair "unknown2" $ unknown2 x-    , Json.pair "engine_audio" $ engineAudio x-    , Json.pair "trail" $ trail x-    , Json.pair "goal_explosion" $ goalExplosion x-    , Json.pair "banner" $ banner x-    , Json.pair "unknown3" $ unknown3 x-    , Json.pair "unknown4" $ unknown4 x-    , Json.pair "unknown5" $ unknown5 x-    , Json.pair "unknown6" $ unknown6 x-    ]+  toJSON x =+    Json.object+      [ Json.pair "version" $ version x,+        Json.pair "body" $ body x,+        Json.pair "decal" $ decal x,+        Json.pair "wheels" $ wheels x,+        Json.pair "rocket_trail" $ rocketTrail x,+        Json.pair "antenna" $ antenna x,+        Json.pair "topper" $ topper x,+        Json.pair "unknown1" $ unknown1 x,+        Json.pair "unknown2" $ unknown2 x,+        Json.pair "engine_audio" $ engineAudio x,+        Json.pair "trail" $ trail x,+        Json.pair "goal_explosion" $ goalExplosion x,+        Json.pair "banner" $ banner x,+        Json.pair "unknown3" $ unknown3 x,+        Json.pair "unknown4" $ unknown4 x,+        Json.pair "unknown5" $ unknown5 x,+        Json.pair "unknown6" $ unknown6 x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-loadout" $ Schema.object-  [ (Json.pair "version" $ Schema.ref U8.schema, True)-  , (Json.pair "body" $ Schema.ref U32.schema, True)-  , (Json.pair "decal" $ Schema.ref U32.schema, True)-  , (Json.pair "wheels" $ Schema.ref U32.schema, True)-  , (Json.pair "rocket_trail" $ Schema.ref U32.schema, True)-  , (Json.pair "antenna" $ Schema.ref U32.schema, True)-  , (Json.pair "topper" $ Schema.ref U32.schema, True)-  , (Json.pair "unknown1" $ Schema.ref U32.schema, True)-  , (Json.pair "unknown2" . Schema.json $ Schema.maybe U32.schema, False)-  , (Json.pair "engine_audio" . Schema.json $ Schema.maybe U32.schema, False)-  , (Json.pair "trail" . Schema.json $ Schema.maybe U32.schema, False)-  , (Json.pair "goal_explosion" . Schema.json $ Schema.maybe U32.schema, False)-  , (Json.pair "banner" . Schema.json $ Schema.maybe U32.schema, False)-  , (Json.pair "unknown3" . Schema.json $ Schema.maybe U32.schema, False)-  , (Json.pair "unknown4" . Schema.json $ Schema.maybe U32.schema, False)-  , (Json.pair "unknown5" . Schema.json $ Schema.maybe U32.schema, False)-  , (Json.pair "unknown6" . Schema.json $ Schema.maybe U32.schema, False)-  ]+schema =+  Schema.named "attribute-loadout" $+    Schema.object+      [ (Json.pair "version" $ Schema.ref U8.schema, True),+        (Json.pair "body" $ Schema.ref U32.schema, True),+        (Json.pair "decal" $ Schema.ref U32.schema, True),+        (Json.pair "wheels" $ Schema.ref U32.schema, True),+        (Json.pair "rocket_trail" $ Schema.ref U32.schema, True),+        (Json.pair "antenna" $ Schema.ref U32.schema, True),+        (Json.pair "topper" $ Schema.ref U32.schema, True),+        (Json.pair "unknown1" $ Schema.ref U32.schema, True),+        (Json.pair "unknown2" . Schema.json $ Schema.maybe U32.schema, False),+        (Json.pair "engine_audio" . Schema.json $ Schema.maybe U32.schema, False),+        (Json.pair "trail" . Schema.json $ Schema.maybe U32.schema, False),+        (Json.pair "goal_explosion" . Schema.json $ Schema.maybe U32.schema, False),+        (Json.pair "banner" . Schema.json $ Schema.maybe U32.schema, False),+        (Json.pair "unknown3" . Schema.json $ Schema.maybe U32.schema, False),+        (Json.pair "unknown4" . Schema.json $ Schema.maybe U32.schema, False),+        (Json.pair "unknown5" . Schema.json $ Schema.maybe U32.schema, False),+        (Json.pair "unknown6" . Schema.json $ Schema.maybe U32.schema, False)+      ]  bitPut :: Loadout -> BitPut.BitPut bitPut loadoutAttribute =@@ -141,40 +145,50 @@   antenna <- BitGet.label "antenna" U32.bitGet   topper <- BitGet.label "topper" U32.bitGet   unknown1 <- BitGet.label "unknown1" U32.bitGet-  unknown2 <- BitGet.label "unknown2"-    $ Monad.whenMaybe (U8.toWord8 version >= 11) U32.bitGet-  engineAudio <- BitGet.label "engineAudio"-    $ Monad.whenMaybe (U8.toWord8 version >= 16) U32.bitGet-  trail <- BitGet.label "trail"-    $ Monad.whenMaybe (U8.toWord8 version >= 16) U32.bitGet-  goalExplosion <- BitGet.label "goalExplosion"-    $ Monad.whenMaybe (U8.toWord8 version >= 16) U32.bitGet-  banner <- BitGet.label "banner"-    $ Monad.whenMaybe (U8.toWord8 version >= 17) U32.bitGet-  unknown3 <- BitGet.label "unknown3"-    $ Monad.whenMaybe (U8.toWord8 version >= 19) U32.bitGet-  unknown4 <- BitGet.label "unknown4"-    $ Monad.whenMaybe (U8.toWord8 version >= 22) U32.bitGet-  unknown5 <- BitGet.label "unknown5"-    $ Monad.whenMaybe (U8.toWord8 version >= 22) U32.bitGet-  unknown6 <- BitGet.label "unknown6"-    $ Monad.whenMaybe (U8.toWord8 version >= 22) U32.bitGet-  pure Loadout-    { version-    , body-    , decal-    , wheels-    , rocketTrail-    , antenna-    , topper-    , unknown1-    , unknown2-    , engineAudio-    , trail-    , goalExplosion-    , banner-    , unknown3-    , unknown4-    , unknown5-    , unknown6-    }+  unknown2 <-+    BitGet.label "unknown2" $+      Monad.whenMaybe (U8.toWord8 version >= 11) U32.bitGet+  engineAudio <-+    BitGet.label "engineAudio" $+      Monad.whenMaybe (U8.toWord8 version >= 16) U32.bitGet+  trail <-+    BitGet.label "trail" $+      Monad.whenMaybe (U8.toWord8 version >= 16) U32.bitGet+  goalExplosion <-+    BitGet.label "goalExplosion" $+      Monad.whenMaybe (U8.toWord8 version >= 16) U32.bitGet+  banner <-+    BitGet.label "banner" $+      Monad.whenMaybe (U8.toWord8 version >= 17) U32.bitGet+  unknown3 <-+    BitGet.label "unknown3" $+      Monad.whenMaybe (U8.toWord8 version >= 19) U32.bitGet+  unknown4 <-+    BitGet.label "unknown4" $+      Monad.whenMaybe (U8.toWord8 version >= 22) U32.bitGet+  unknown5 <-+    BitGet.label "unknown5" $+      Monad.whenMaybe (U8.toWord8 version >= 22) U32.bitGet+  unknown6 <-+    BitGet.label "unknown6" $+      Monad.whenMaybe (U8.toWord8 version >= 22) U32.bitGet+  pure+    Loadout+      { version,+        body,+        decal,+        wheels,+        rocketTrail,+        antenna,+        topper,+        unknown1,+        unknown2,+        engineAudio,+        trail,+        goalExplosion,+        banner,+        unknown3,+        unknown4,+        unknown5,+        unknown6+      }
src/lib/Rattletrap/Type/Attribute/LoadoutOnline.hs view
@@ -14,7 +14,8 @@  newtype LoadoutOnline = LoadoutOnline   { value :: List.List (List.List Product.Product)-  } deriving (Eq, Show)+  }+  deriving (Eq, Show)  instance Json.FromJSON LoadoutOnline where   parseJSON = fmap LoadoutOnline . Json.parseJSON@@ -32,16 +33,15 @@ bitPut :: LoadoutOnline -> BitPut.BitPut bitPut loadoutAttribute =   let attributes = List.toList $ value loadoutAttribute-  in-    (U8.bitPut . U8.fromWord8 . fromIntegral $ length attributes)-      <> foldMap Product.putProductAttributes attributes+   in (U8.bitPut . U8.fromWord8 . fromIntegral $ length attributes)+        <> foldMap Product.putProductAttributes attributes -bitGet-  :: Version.Version -> Map.Map U32.U32 Str.Str -> BitGet.BitGet LoadoutOnline+bitGet ::+  Version.Version -> Map.Map U32.U32 Str.Str -> BitGet.BitGet LoadoutOnline bitGet version objectMap = BitGet.label "LoadoutOnline" $ do   size <- BitGet.label "size" U8.bitGet   value <-     BitGet.label "value"-    . List.replicateM (fromIntegral $ U8.toWord8 size)-    $ Product.decodeProductAttributesBits version objectMap-  pure LoadoutOnline { value }+      . List.replicateM (fromIntegral $ U8.toWord8 size)+      $ Product.decodeProductAttributesBits version objectMap+  pure LoadoutOnline {value}
src/lib/Rattletrap/Type/Attribute/Loadouts.hs view
@@ -7,8 +7,8 @@ import qualified Rattletrap.Utility.Json as Json  data Loadouts = Loadouts-  { blue :: Loadout.Loadout-  , orange :: Loadout.Loadout+  { blue :: Loadout.Loadout,+    orange :: Loadout.Loadout   }   deriving (Eq, Show) @@ -16,24 +16,27 @@   parseJSON = Json.withObject "Loadouts" $ \object -> do     blue <- Json.required object "blue"     orange <- Json.required object "orange"-    pure Loadouts { blue, orange }+    pure Loadouts {blue, orange}  instance Json.ToJSON Loadouts where   toJSON x =     Json.object [Json.pair "blue" $ blue x, Json.pair "orange" $ orange x]  schema :: Schema.Schema-schema = Schema.named "attribute-loadouts" $ Schema.object-  [ (Json.pair "blue" $ Schema.ref Loadout.schema, True)-  , (Json.pair "orange" $ Schema.ref Loadout.schema, True)-  ]+schema =+  Schema.named "attribute-loadouts" $+    Schema.object+      [ (Json.pair "blue" $ Schema.ref Loadout.schema, True),+        (Json.pair "orange" $ Schema.ref Loadout.schema, True)+      ]  bitPut :: Loadouts -> BitPut.BitPut-bitPut loadoutsAttribute = Loadout.bitPut (blue loadoutsAttribute)-  <> Loadout.bitPut (orange loadoutsAttribute)+bitPut loadoutsAttribute =+  Loadout.bitPut (blue loadoutsAttribute)+    <> Loadout.bitPut (orange loadoutsAttribute)  bitGet :: BitGet.BitGet Loadouts bitGet = BitGet.label "Loadouts" $ do   blue <- BitGet.label "blue" Loadout.bitGet   orange <- BitGet.label "orange" Loadout.bitGet-  pure Loadouts { blue, orange }+  pure Loadouts {blue, orange}
src/lib/Rattletrap/Type/Attribute/LoadoutsOnline.hs view
@@ -11,10 +11,10 @@ import qualified Rattletrap.Utility.Json as Json  data LoadoutsOnline = LoadoutsOnline-  { blue :: LoadoutOnline.LoadoutOnline-  , orange :: LoadoutOnline.LoadoutOnline-  , unknown1 :: Bool-  , unknown2 :: Bool+  { blue :: LoadoutOnline.LoadoutOnline,+    orange :: LoadoutOnline.LoadoutOnline,+    unknown1 :: Bool,+    unknown2 :: Bool   }   deriving (Eq, Show) @@ -24,23 +24,26 @@     orange <- Json.required object "orange"     unknown1 <- Json.required object "unknown1"     unknown2 <- Json.required object "unknown2"-    pure LoadoutsOnline { blue, orange, unknown1, unknown2 }+    pure LoadoutsOnline {blue, orange, unknown1, unknown2}  instance Json.ToJSON LoadoutsOnline where-  toJSON x = Json.object-    [ Json.pair "blue" $ blue x-    , Json.pair "orange" $ orange x-    , Json.pair "unknown1" $ unknown1 x-    , Json.pair "unknown2" $ unknown2 x-    ]+  toJSON x =+    Json.object+      [ Json.pair "blue" $ blue x,+        Json.pair "orange" $ orange x,+        Json.pair "unknown1" $ unknown1 x,+        Json.pair "unknown2" $ unknown2 x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-loadouts-online" $ Schema.object-  [ (Json.pair "blue" $ Schema.ref LoadoutOnline.schema, True)-  , (Json.pair "orange" $ Schema.ref LoadoutOnline.schema, True)-  , (Json.pair "unknown1" $ Schema.ref Schema.boolean, True)-  , (Json.pair "unknown2" $ Schema.ref Schema.boolean, True)-  ]+schema =+  Schema.named "attribute-loadouts-online" $+    Schema.object+      [ (Json.pair "blue" $ Schema.ref LoadoutOnline.schema, True),+        (Json.pair "orange" $ Schema.ref LoadoutOnline.schema, True),+        (Json.pair "unknown1" $ Schema.ref Schema.boolean, True),+        (Json.pair "unknown2" $ Schema.ref Schema.boolean, True)+      ]  bitPut :: LoadoutsOnline -> BitPut.BitPut bitPut loadoutsOnlineAttribute =@@ -49,11 +52,11 @@     <> BitPut.bool (unknown1 loadoutsOnlineAttribute)     <> BitPut.bool (unknown2 loadoutsOnlineAttribute) -bitGet-  :: Version.Version -> Map.Map U32.U32 Str.Str -> BitGet.BitGet LoadoutsOnline+bitGet ::+  Version.Version -> Map.Map U32.U32 Str.Str -> BitGet.BitGet LoadoutsOnline bitGet version objectMap = BitGet.label "LoadoutsOnline" $ do   blue <- BitGet.label "blue" $ LoadoutOnline.bitGet version objectMap   orange <- BitGet.label "orange" $ LoadoutOnline.bitGet version objectMap   unknown1 <- BitGet.label "unknown1" BitGet.bool   unknown2 <- BitGet.label "unknown2" BitGet.bool-  pure LoadoutsOnline { blue, orange, unknown1, unknown2 }+  pure LoadoutsOnline {blue, orange, unknown1, unknown2}
src/lib/Rattletrap/Type/Attribute/Location.hs view
@@ -9,7 +9,8 @@  newtype Location = Location   { value :: Vector.Vector-  } deriving (Eq, Show)+  }+  deriving (Eq, Show)  instance Json.FromJSON Location where   parseJSON = fmap Location . Json.parseJSON@@ -26,4 +27,4 @@ bitGet :: Version.Version -> BitGet.BitGet Location bitGet version = BitGet.label "Location" $ do   value <- BitGet.label "value" $ Vector.bitGet version-  pure Location { value }+  pure Location {value}
src/lib/Rattletrap/Type/Attribute/MusicStinger.hs view
@@ -8,9 +8,9 @@ import qualified Rattletrap.Utility.Json as Json  data MusicStinger = MusicStinger-  { flag :: Bool-  , cue :: U32.U32-  , trigger :: U8.U8+  { flag :: Bool,+    cue :: U32.U32,+    trigger :: U8.U8   }   deriving (Eq, Show) @@ -19,21 +19,24 @@     flag <- Json.required object "flag"     cue <- Json.required object "cue"     trigger <- Json.required object "trigger"-    pure MusicStinger { flag, cue, trigger }+    pure MusicStinger {flag, cue, trigger}  instance Json.ToJSON MusicStinger where-  toJSON x = Json.object-    [ Json.pair "flag" $ flag x-    , Json.pair "cue" $ cue x-    , Json.pair "trigger" $ trigger x-    ]+  toJSON x =+    Json.object+      [ Json.pair "flag" $ flag x,+        Json.pair "cue" $ cue x,+        Json.pair "trigger" $ trigger x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-music-stinger" $ Schema.object-  [ (Json.pair "flag" $ Schema.ref Schema.boolean, True)-  , (Json.pair "cue" $ Schema.ref U32.schema, True)-  , (Json.pair "trigger" $ Schema.ref U8.schema, True)-  ]+schema =+  Schema.named "attribute-music-stinger" $+    Schema.object+      [ (Json.pair "flag" $ Schema.ref Schema.boolean, True),+        (Json.pair "cue" $ Schema.ref U32.schema, True),+        (Json.pair "trigger" $ Schema.ref U8.schema, True)+      ]  bitPut :: MusicStinger -> BitPut.BitPut bitPut musicStingerAttribute =@@ -46,4 +49,4 @@   flag <- BitGet.label "flag" BitGet.bool   cue <- BitGet.label "cue" U32.bitGet   trigger <- BitGet.label "trigger" U8.bitGet-  pure MusicStinger { flag, cue, trigger }+  pure MusicStinger {flag, cue, trigger}
src/lib/Rattletrap/Type/Attribute/PartyLeader.hs view
@@ -9,9 +9,9 @@ import qualified Rattletrap.Utility.Json as Json  data PartyLeader = PartyLeader-  { systemId :: U8.U8-  , remoteId :: Maybe RemoteId.RemoteId-  , localId :: Maybe U8.U8+  { systemId :: U8.U8,+    remoteId :: Maybe RemoteId.RemoteId,+    localId :: Maybe U8.U8   }   deriving (Eq, Show) @@ -19,44 +19,52 @@   parseJSON = Json.withObject "PartyLeader" $ \object -> do     systemId <- Json.required object "system_id"     maybeId <- Json.optional object "id"-    pure PartyLeader-      { systemId-      , remoteId = fmap fst maybeId-      , localId = fmap snd maybeId-      }+    pure+      PartyLeader+        { systemId,+          remoteId = fmap fst maybeId,+          localId = fmap snd maybeId+        }  instance Json.ToJSON PartyLeader where-  toJSON x = Json.object-    [ Json.pair "system_id" $ systemId x-    , Json.pair "id" $ case (remoteId x, localId x) of-      (Just r, Just l) -> Just (r, l)-      _ -> Nothing-    ]+  toJSON x =+    Json.object+      [ Json.pair "system_id" $ systemId x,+        Json.pair "id" $ case (remoteId x, localId x) of+          (Just r, Just l) -> Just (r, l)+          _ -> Nothing+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-party-leader" $ Schema.object-  [ (Json.pair "system_id" $ Schema.ref U8.schema, True)-  , ( Json.pair "id" $ Schema.oneOf-      [ Schema.tuple [Schema.ref RemoteId.schema, Schema.ref U8.schema]-      , Schema.ref Schema.null+schema =+  Schema.named "attribute-party-leader" $+    Schema.object+      [ (Json.pair "system_id" $ Schema.ref U8.schema, True),+        ( Json.pair "id" $+            Schema.oneOf+              [ Schema.tuple [Schema.ref RemoteId.schema, Schema.ref U8.schema],+                Schema.ref Schema.null+              ],+          False+        )       ]-    , False-    )-  ]  bitPut :: PartyLeader -> BitPut.BitPut bitPut x =-  U8.bitPut (systemId x) <> foldMap RemoteId.bitPut (remoteId x) <> foldMap-    U8.bitPut-    (localId x)+  U8.bitPut (systemId x)+    <> foldMap RemoteId.bitPut (remoteId x)+    <> foldMap+      U8.bitPut+      (localId x)  bitGet :: Version.Version -> BitGet.BitGet PartyLeader bitGet version = BitGet.label "PartyLeader" $ do   systemId <- BitGet.label "systemId" U8.bitGet-  (remoteId, localId) <- if systemId == U8.fromWord8 0-    then pure (Nothing, Nothing)-    else do-      remoteId <- BitGet.label "remoteId" $ RemoteId.bitGet version systemId-      localId <- BitGet.label "localId" U8.bitGet-      pure (Just remoteId, Just localId)-  pure PartyLeader { systemId, remoteId, localId }+  (remoteId, localId) <-+    if systemId == U8.fromWord8 0+      then pure (Nothing, Nothing)+      else do+        remoteId <- BitGet.label "remoteId" $ RemoteId.bitGet version systemId+        localId <- BitGet.label "localId" U8.bitGet+        pure (Just remoteId, Just localId)+  pure PartyLeader {systemId, remoteId, localId}
src/lib/Rattletrap/Type/Attribute/Pickup.hs view
@@ -8,8 +8,8 @@ import qualified Rattletrap.Utility.Monad as Monad  data Pickup = Pickup-  { instigatorId :: Maybe U32.U32-  , pickedUp :: Bool+  { instigatorId :: Maybe U32.U32,+    pickedUp :: Bool   }   deriving (Eq, Show) @@ -17,32 +17,36 @@   parseJSON = Json.withObject "Pickup" $ \object -> do     instigatorId <- Json.optional object "instigator_id"     pickedUp <- Json.required object "picked_up"-    pure Pickup { instigatorId, pickedUp }+    pure Pickup {instigatorId, pickedUp}  instance Json.ToJSON Pickup where-  toJSON x = Json.object-    [ Json.pair "instigator_id" $ instigatorId x-    , Json.pair "picked_up" $ pickedUp x-    ]+  toJSON x =+    Json.object+      [ Json.pair "instigator_id" $ instigatorId x,+        Json.pair "picked_up" $ pickedUp x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-pickup" $ Schema.object-  [ (Json.pair "instigator_id" . Schema.json $ Schema.maybe U32.schema, False)-  , (Json.pair "picked_up" $ Schema.ref Schema.boolean, True)-  ]+schema =+  Schema.named "attribute-pickup" $+    Schema.object+      [ (Json.pair "instigator_id" . Schema.json $ Schema.maybe U32.schema, False),+        (Json.pair "picked_up" $ Schema.ref Schema.boolean, True)+      ]  bitPut :: Pickup -> BitPut.BitPut bitPut x =   maybe-      (BitPut.bool False)-      (\y -> BitPut.bool True <> U32.bitPut y)-      (instigatorId x)+    (BitPut.bool False)+    (\y -> BitPut.bool True <> U32.bitPut y)+    (instigatorId x)     <> BitPut.bool (pickedUp x)  bitGet :: BitGet.BitGet Pickup bitGet = BitGet.label "Pickup" $ do   instigator <- BitGet.label "instigator" BitGet.bool-  instigatorId <- BitGet.label "instigatorId"-    $ Monad.whenMaybe instigator U32.bitGet+  instigatorId <-+    BitGet.label "instigatorId" $+      Monad.whenMaybe instigator U32.bitGet   pickedUp <- BitGet.label "pickedUp" BitGet.bool-  pure Pickup { instigatorId, pickedUp }+  pure Pickup {instigatorId, pickedUp}
src/lib/Rattletrap/Type/Attribute/PickupInfo.hs view
@@ -8,13 +8,13 @@ import qualified Rattletrap.Utility.Json as Json  data PickupInfo = PickupInfo-  { unknown1 :: Bool-  , unknown2 :: Bool-  , unknown3 :: U32.U32-  , unknown4 :: I32.I32-  , unknown5 :: I32.I32-  , unknown6 :: Bool-  , unknown7 :: Bool+  { unknown1 :: Bool,+    unknown2 :: Bool,+    unknown3 :: U32.U32,+    unknown4 :: I32.I32,+    unknown5 :: I32.I32,+    unknown6 :: Bool,+    unknown7 :: Bool   }   deriving (Eq, Show) @@ -27,37 +27,41 @@     unknown5 <- Json.required object "unknown5"     unknown6 <- Json.required object "unknown6"     unknown7 <- Json.required object "unknown7"-    pure PickupInfo-      { unknown1-      , unknown2-      , unknown3-      , unknown4-      , unknown5-      , unknown6-      , unknown7-      }+    pure+      PickupInfo+        { unknown1,+          unknown2,+          unknown3,+          unknown4,+          unknown5,+          unknown6,+          unknown7+        }  instance Json.ToJSON PickupInfo where-  toJSON x = Json.object-    [ Json.pair "unknown1" $ unknown1 x-    , Json.pair "unknown2" $ unknown2 x-    , Json.pair "unknown3" $ unknown3 x-    , Json.pair "unknown4" $ unknown4 x-    , Json.pair "unknown5" $ unknown5 x-    , Json.pair "unknown6" $ unknown6 x-    , Json.pair "unknown7" $ unknown7 x-    ]+  toJSON x =+    Json.object+      [ Json.pair "unknown1" $ unknown1 x,+        Json.pair "unknown2" $ unknown2 x,+        Json.pair "unknown3" $ unknown3 x,+        Json.pair "unknown4" $ unknown4 x,+        Json.pair "unknown5" $ unknown5 x,+        Json.pair "unknown6" $ unknown6 x,+        Json.pair "unknown7" $ unknown7 x+      ]  schema :: Schema.Schema-schema = Schema.named "pickup-info" $ Schema.object-  [ (Json.pair "unknown1" $ Schema.ref Schema.boolean, True)-  , (Json.pair "unknown2" $ Schema.ref Schema.boolean, True)-  , (Json.pair "unknown3" $ Schema.ref U32.schema, True)-  , (Json.pair "unknown4" $ Schema.ref I32.schema, True)-  , (Json.pair "unknown5" $ Schema.ref I32.schema, True)-  , (Json.pair "unknown6" $ Schema.ref Schema.boolean, True)-  , (Json.pair "unknown7" $ Schema.ref Schema.boolean, True)-  ]+schema =+  Schema.named "pickup-info" $+    Schema.object+      [ (Json.pair "unknown1" $ Schema.ref Schema.boolean, True),+        (Json.pair "unknown2" $ Schema.ref Schema.boolean, True),+        (Json.pair "unknown3" $ Schema.ref U32.schema, True),+        (Json.pair "unknown4" $ Schema.ref I32.schema, True),+        (Json.pair "unknown5" $ Schema.ref I32.schema, True),+        (Json.pair "unknown6" $ Schema.ref Schema.boolean, True),+        (Json.pair "unknown7" $ Schema.ref Schema.boolean, True)+      ]  bitPut :: PickupInfo -> BitPut.BitPut bitPut x =@@ -78,12 +82,13 @@   unknown5 <- BitGet.label "unknown5" I32.bitGet   unknown6 <- BitGet.label "unknown6" BitGet.bool   unknown7 <- BitGet.label "unknown7" BitGet.bool-  pure PickupInfo-    { unknown1-    , unknown2-    , unknown3-    , unknown4-    , unknown5-    , unknown6-    , unknown7-    }+  pure+    PickupInfo+      { unknown1,+        unknown2,+        unknown3,+        unknown4,+        unknown5,+        unknown6,+        unknown7+      }
src/lib/Rattletrap/Type/Attribute/PickupNew.hs view
@@ -9,8 +9,8 @@ import qualified Rattletrap.Utility.Monad as Monad  data PickupNew = PickupNew-  { instigatorId :: Maybe U32.U32-  , pickedUp :: U8.U8+  { instigatorId :: Maybe U32.U32,+    pickedUp :: U8.U8   }   deriving (Eq, Show) @@ -18,32 +18,36 @@   parseJSON = Json.withObject "PickupNew" $ \object -> do     instigatorId <- Json.optional object "instigator_id"     pickedUp <- Json.required object "picked_up"-    pure PickupNew { instigatorId, pickedUp }+    pure PickupNew {instigatorId, pickedUp}  instance Json.ToJSON PickupNew where-  toJSON x = Json.object-    [ Json.pair "instigator_id" $ instigatorId x-    , Json.pair "picked_up" $ pickedUp x-    ]+  toJSON x =+    Json.object+      [ Json.pair "instigator_id" $ instigatorId x,+        Json.pair "picked_up" $ pickedUp x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-pickup-new" $ Schema.object-  [ (Json.pair "instigator_id" . Schema.json $ Schema.maybe U32.schema, False)-  , (Json.pair "picked_up" $ Schema.ref U8.schema, True)-  ]+schema =+  Schema.named "attribute-pickup-new" $+    Schema.object+      [ (Json.pair "instigator_id" . Schema.json $ Schema.maybe U32.schema, False),+        (Json.pair "picked_up" $ Schema.ref U8.schema, True)+      ]  bitPut :: PickupNew -> BitPut.BitPut bitPut x =   maybe-      (BitPut.bool False)-      (\y -> BitPut.bool True <> U32.bitPut y)-      (instigatorId x)+    (BitPut.bool False)+    (\y -> BitPut.bool True <> U32.bitPut y)+    (instigatorId x)     <> U8.bitPut (pickedUp x)  bitGet :: BitGet.BitGet PickupNew bitGet = BitGet.label "PickupNew" $ do   instigator <- BitGet.label "instigator" BitGet.bool-  instigatorId <- BitGet.label "instigatorId"-    $ Monad.whenMaybe instigator U32.bitGet+  instigatorId <-+    BitGet.label "instigatorId" $+      Monad.whenMaybe instigator U32.bitGet   pickedUp <- BitGet.label "pickedUp" U8.bitGet-  pure PickupNew { instigatorId, pickedUp }+  pure PickupNew {instigatorId, pickedUp}
src/lib/Rattletrap/Type/Attribute/PlayerHistoryKey.hs view
@@ -8,7 +8,8 @@  newtype PlayerHistoryKey = PlayerHistoryKey   { unknown :: Word.Word16-  } deriving (Eq, Show)+  }+  deriving (Eq, Show)  instance Json.FromJSON PlayerHistoryKey where   parseJSON = fmap PlayerHistoryKey . Json.parseJSON@@ -26,4 +27,4 @@ bitGet :: BitGet.BitGet PlayerHistoryKey bitGet = BitGet.label "PlayerHistoryKey" $ do   unknown <- BitGet.label "unknown" $ BitGet.bits 14-  pure PlayerHistoryKey { unknown }+  pure PlayerHistoryKey {unknown}
src/lib/Rattletrap/Type/Attribute/PrivateMatchSettings.hs view
@@ -8,12 +8,12 @@ import qualified Rattletrap.Utility.Json as Json  data PrivateMatchSettings = PrivateMatchSettings-  { mutators :: Str.Str-  , joinableBy :: U32.U32-  , maxPlayers :: U32.U32-  , gameName :: Str.Str-  , password :: Str.Str-  , flag :: Bool+  { mutators :: Str.Str,+    joinableBy :: U32.U32,+    maxPlayers :: U32.U32,+    gameName :: Str.Str,+    password :: Str.Str,+    flag :: Bool   }   deriving (Eq, Show) @@ -25,34 +25,38 @@     gameName <- Json.required object "game_name"     password <- Json.required object "password"     flag <- Json.required object "flag"-    pure PrivateMatchSettings-      { mutators-      , joinableBy-      , maxPlayers-      , gameName-      , password-      , flag-      }+    pure+      PrivateMatchSettings+        { mutators,+          joinableBy,+          maxPlayers,+          gameName,+          password,+          flag+        }  instance Json.ToJSON PrivateMatchSettings where-  toJSON x = Json.object-    [ Json.pair "mutators" $ mutators x-    , Json.pair "joinable_by" $ joinableBy x-    , Json.pair "max_players" $ maxPlayers x-    , Json.pair "game_name" $ gameName x-    , Json.pair "password" $ password x-    , Json.pair "flag" $ flag x-    ]+  toJSON x =+    Json.object+      [ Json.pair "mutators" $ mutators x,+        Json.pair "joinable_by" $ joinableBy x,+        Json.pair "max_players" $ maxPlayers x,+        Json.pair "game_name" $ gameName x,+        Json.pair "password" $ password x,+        Json.pair "flag" $ flag x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-private-match-settings" $ Schema.object-  [ (Json.pair "mutators" $ Schema.ref Str.schema, True)-  , (Json.pair "joinable_by" $ Schema.ref U32.schema, True)-  , (Json.pair "max_players" $ Schema.ref U32.schema, True)-  , (Json.pair "game_name" $ Schema.ref Str.schema, True)-  , (Json.pair "password" $ Schema.ref Str.schema, True)-  , (Json.pair "flag" $ Schema.ref Schema.boolean, True)-  ]+schema =+  Schema.named "attribute-private-match-settings" $+    Schema.object+      [ (Json.pair "mutators" $ Schema.ref Str.schema, True),+        (Json.pair "joinable_by" $ Schema.ref U32.schema, True),+        (Json.pair "max_players" $ Schema.ref U32.schema, True),+        (Json.pair "game_name" $ Schema.ref Str.schema, True),+        (Json.pair "password" $ Schema.ref Str.schema, True),+        (Json.pair "flag" $ Schema.ref Schema.boolean, True)+      ]  bitPut :: PrivateMatchSettings -> BitPut.BitPut bitPut privateMatchSettingsAttribute =@@ -71,11 +75,12 @@   gameName <- BitGet.label "gameName" Str.bitGet   password <- BitGet.label "password" Str.bitGet   flag <- BitGet.label "flag" BitGet.bool-  pure PrivateMatchSettings-    { mutators-    , joinableBy-    , maxPlayers-    , gameName-    , password-    , flag-    }+  pure+    PrivateMatchSettings+      { mutators,+        joinableBy,+        maxPlayers,+        gameName,+        password,+        flag+      }
src/lib/Rattletrap/Type/Attribute/Product.hs view
@@ -13,11 +13,11 @@ import qualified Rattletrap.Utility.Json as Json  data Product = Product-  { unknown :: Bool-  , objectId :: U32.U32-  , objectName :: Maybe Str.Str-  -- ^ read-only-  , value :: ProductValue.ProductValue+  { unknown :: Bool,+    objectId :: U32.U32,+    -- | read-only+    objectName :: Maybe Str.Str,+    value :: ProductValue.ProductValue   }   deriving (Eq, Show) @@ -27,28 +27,31 @@     objectId <- Json.required object "object_id"     objectName <- Json.optional object "object_name"     value <- Json.required object "value"-    pure Product { unknown, objectId, objectName, value }+    pure Product {unknown, objectId, objectName, value}  instance Json.ToJSON Product where-  toJSON x = Json.object-    [ Json.pair "unknown" $ unknown x-    , Json.pair "object_id" $ objectId x-    , Json.pair "object_name" $ objectName x-    , Json.pair "value" $ value x-    ]+  toJSON x =+    Json.object+      [ Json.pair "unknown" $ unknown x,+        Json.pair "object_id" $ objectId x,+        Json.pair "object_name" $ objectName x,+        Json.pair "value" $ value x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-product" $ Schema.object-  [ (Json.pair "unknown" $ Schema.ref Schema.boolean, True)-  , (Json.pair "object_id" $ Schema.ref U32.schema, True)-  , (Json.pair "object_name" . Schema.json $ Schema.maybe Str.schema, False)-  , (Json.pair "value" $ Schema.ref ProductValue.schema, True)-  ]+schema =+  Schema.named "attribute-product" $+    Schema.object+      [ (Json.pair "unknown" $ Schema.ref Schema.boolean, True),+        (Json.pair "object_id" $ Schema.ref U32.schema, True),+        (Json.pair "object_name" . Schema.json $ Schema.maybe Str.schema, False),+        (Json.pair "value" $ Schema.ref ProductValue.schema, True)+      ]  putProductAttributes :: List.List Product -> BitPut.BitPut putProductAttributes attributes =   let v = List.toList attributes-  in (U8.bitPut . U8.fromWord8 . fromIntegral $ length v) <> foldMap bitPut v+   in (U8.bitPut . U8.fromWord8 . fromIntegral $ length v) <> foldMap bitPut v  bitPut :: Product -> BitPut.BitPut bitPut attribute =@@ -56,10 +59,10 @@     <> U32.bitPut (objectId attribute)     <> ProductValue.bitPut (value attribute) -decodeProductAttributesBits-  :: Version.Version-  -> Map.Map U32.U32 Str.Str-  -> BitGet.BitGet (List.List Product)+decodeProductAttributesBits ::+  Version.Version ->+  Map.Map U32.U32 Str.Str ->+  BitGet.BitGet (List.List Product) decodeProductAttributesBits version objectMap = do   size <- U8.bitGet   List.replicateM (fromIntegral $ U8.toWord8 size) $ bitGet version objectMap@@ -69,6 +72,7 @@   unknown <- BitGet.label "unknown" BitGet.bool   objectId <- BitGet.label "objectId" U32.bitGet   let objectName = Map.lookup objectId objectMap-  value <- BitGet.label "value"-    $ ProductValue.bitGet version objectId objectName-  pure Product { unknown, objectId, objectName, value }+  value <-+    BitGet.label "value" $+      ProductValue.bitGet version objectId objectName+  pure Product {unknown, objectId, objectName, value}
src/lib/Rattletrap/Type/Attribute/ProductValue.hs view
@@ -26,16 +26,17 @@   deriving (Eq, Show)  instance Json.FromJSON ProductValue where-  parseJSON = Json.withObject "ProductValue" $ \object -> Foldable.asum-    [ fmap PaintedOld $ Json.required object "painted_old"-    , fmap PaintedNew $ Json.required object "painted_new"-    , fmap TeamEditionOld $ Json.required object "team_edition_old"-    , fmap TeamEditionNew $ Json.required object "team_edition_new"-    , fmap SpecialEdition $ Json.required object "special_edition"-    , fmap UserColorOld $ Json.required object "user_color_old"-    , fmap UserColorNew $ Json.required object "user_color_new"-    , fmap TitleId $ Json.required object "title_id"-    ]+  parseJSON = Json.withObject "ProductValue" $ \object ->+    Foldable.asum+      [ fmap PaintedOld $ Json.required object "painted_old",+        fmap PaintedNew $ Json.required object "painted_new",+        fmap TeamEditionOld $ Json.required object "team_edition_old",+        fmap TeamEditionNew $ Json.required object "team_edition_new",+        fmap SpecialEdition $ Json.required object "special_edition",+        fmap UserColorOld $ Json.required object "user_color_old",+        fmap UserColorNew $ Json.required object "user_color_new",+        fmap TitleId $ Json.required object "title_id"+      ]  instance Json.ToJSON ProductValue where   toJSON x = case x of@@ -49,17 +50,19 @@     TitleId y -> Json.object [Json.pair "title_id" y]  schema :: Schema.Schema-schema = Schema.named "attribute-product-value" . Schema.oneOf $ fmap-  (\(k, v) -> Schema.object [(Json.pair k v, True)])-  [ ("painted_old", Schema.ref CompressedWord.schema)-  , ("painted_new", Schema.ref Schema.integer)-  , ("team_edition_old", Schema.ref CompressedWord.schema)-  , ("team_edition_new", Schema.ref Schema.integer)-  , ("special_edition", Schema.ref Schema.integer)-  , ("user_color_old", Schema.json $ Schema.maybe Schema.integer)-  , ("user_color_new", Schema.ref U32.schema)-  , ("title_id", Schema.ref Str.schema)-  ]+schema =+  Schema.named "attribute-product-value" . Schema.oneOf $+    fmap+      (\(k, v) -> Schema.object [(Json.pair k v, True)])+      [ ("painted_old", Schema.ref CompressedWord.schema),+        ("painted_new", Schema.ref Schema.integer),+        ("team_edition_old", Schema.ref CompressedWord.schema),+        ("team_edition_new", Schema.ref Schema.integer),+        ("special_edition", Schema.ref Schema.integer),+        ("user_color_old", Schema.json $ Schema.maybe Schema.integer),+        ("user_color_new", Schema.ref U32.schema),+        ("title_id", Schema.ref Str.schema)+      ]  bitPut :: ProductValue -> BitPut.BitPut bitPut val = case val of@@ -74,8 +77,8 @@   UserColorNew x -> U32.bitPut x   TitleId x -> Str.bitPut x -bitGet-  :: Version.Version -> U32.U32 -> Maybe Str.Str -> BitGet.BitGet ProductValue+bitGet ::+  Version.Version -> U32.U32 -> Maybe Str.Str -> BitGet.BitGet ProductValue bitGet version objectId maybeObjectName =   BitGet.label "ProductValue" $ case fmap Str.toString maybeObjectName of     Just "TAGame.ProductAttribute_Painted_TA" -> decodePainted version@@ -85,31 +88,36 @@     Just "TAGame.ProductAttribute_UserColor_TA" -> decodeColor version     Just x -> BitGet.throw $ UnknownProduct.UnknownProduct x     Nothing ->-      BitGet.throw . MissingProductName.MissingProductName $ U32.toWord32-        objectId+      BitGet.throw . MissingProductName.MissingProductName $+        U32.toWord32+          objectId  decodeSpecialEdition :: BitGet.BitGet ProductValue decodeSpecialEdition =   BitGet.label "SpecialEdition" . fmap SpecialEdition $ BitGet.bits 31  decodePainted :: Version.Version -> BitGet.BitGet ProductValue-decodePainted version = BitGet.label "Painted" $ if hasNewPainted version-  then fmap PaintedNew $ BitGet.bits 31-  else fmap PaintedOld $ CompressedWord.bitGet 13+decodePainted version =+  BitGet.label "Painted" $+    if hasNewPainted version+      then fmap PaintedNew $ BitGet.bits 31+      else fmap PaintedOld $ CompressedWord.bitGet 13  decodeTeamEdition :: Version.Version -> BitGet.BitGet ProductValue decodeTeamEdition version =-  BitGet.label "TeamEdition" $ if hasNewPainted version-    then fmap TeamEditionNew $ BitGet.bits 31-    else fmap TeamEditionOld $ CompressedWord.bitGet 13+  BitGet.label "TeamEdition" $+    if hasNewPainted version+      then fmap TeamEditionNew $ BitGet.bits 31+      else fmap TeamEditionOld $ CompressedWord.bitGet 13  decodeColor :: Version.Version -> BitGet.BitGet ProductValue decodeColor version =-  BitGet.label "UserColor" $ if Version.atLeast 868 23 8 version-    then fmap UserColorNew U32.bitGet-    else do-      hasValue <- BitGet.bool-      fmap UserColorOld $ Monad.whenMaybe hasValue (BitGet.bits 31)+  BitGet.label "UserColor" $+    if Version.atLeast 868 23 8 version+      then fmap UserColorNew U32.bitGet+      else do+        hasValue <- BitGet.bool+        fmap UserColorOld $ Monad.whenMaybe hasValue (BitGet.bits 31)  hasNewPainted :: Version.Version -> Bool hasNewPainted = Version.atLeast 868 18 0
src/lib/Rattletrap/Type/Attribute/QWord.hs view
@@ -8,7 +8,8 @@  newtype QWord = QWord   { value :: U64.U64-  } deriving (Eq, Show)+  }+  deriving (Eq, Show)  instance Json.FromJSON QWord where   parseJSON = fmap QWord . Json.parseJSON@@ -25,4 +26,4 @@ bitGet :: BitGet.BitGet QWord bitGet = BitGet.label "QWord" $ do   value <- BitGet.label "value" U64.bitGet-  pure QWord { value }+  pure QWord {value}
src/lib/Rattletrap/Type/Attribute/RepStatTitle.hs view
@@ -9,10 +9,10 @@ import qualified Rattletrap.Utility.Json as Json  data RepStatTitle = RepStatTitle-  { unknown :: Bool-  , name :: Str.Str-  , target :: FlaggedInt.FlaggedInt-  , value :: U32.U32+  { unknown :: Bool,+    name :: Str.Str,+    target :: FlaggedInt.FlaggedInt,+    value :: U32.U32   }   deriving (Eq, Show) @@ -22,23 +22,26 @@     name <- Json.required object "name"     target <- Json.required object "target"     value <- Json.required object "value"-    pure RepStatTitle { unknown, name, target, value }+    pure RepStatTitle {unknown, name, target, value}  instance Json.ToJSON RepStatTitle where-  toJSON x = Json.object-    [ Json.pair "unknown" $ unknown x-    , Json.pair "name" $ name x-    , Json.pair "target" $ target x-    , Json.pair "value" $ value x-    ]+  toJSON x =+    Json.object+      [ Json.pair "unknown" $ unknown x,+        Json.pair "name" $ name x,+        Json.pair "target" $ target x,+        Json.pair "value" $ value x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-rep-stat-title" $ Schema.object-  [ (Json.pair "unknown" $ Schema.ref Schema.boolean, True)-  , (Json.pair "name" $ Schema.ref Str.schema, True)-  , (Json.pair "target" $ Schema.ref FlaggedInt.schema, True)-  , (Json.pair "value" $ Schema.ref U32.schema, True)-  ]+schema =+  Schema.named "attribute-rep-stat-title" $+    Schema.object+      [ (Json.pair "unknown" $ Schema.ref Schema.boolean, True),+        (Json.pair "name" $ Schema.ref Str.schema, True),+        (Json.pair "target" $ Schema.ref FlaggedInt.schema, True),+        (Json.pair "value" $ Schema.ref U32.schema, True)+      ]  bitPut :: RepStatTitle -> BitPut.BitPut bitPut x =@@ -53,4 +56,4 @@   name <- BitGet.label "name" Str.bitGet   target <- BitGet.label "target" FlaggedInt.bitGet   value <- BitGet.label "value" U32.bitGet-  pure RepStatTitle { unknown, name, target, value }+  pure RepStatTitle {unknown, name, target, value}
src/lib/Rattletrap/Type/Attribute/Reservation.hs view
@@ -13,12 +13,12 @@ import qualified Rattletrap.Utility.Monad as Monad  data Reservation = Reservation-  { number :: CompressedWord.CompressedWord-  , uniqueId :: UniqueId.UniqueId-  , name :: Maybe Str.Str-  , unknown1 :: Bool-  , unknown2 :: Bool-  , unknown3 :: Maybe Word.Word8+  { number :: CompressedWord.CompressedWord,+    uniqueId :: UniqueId.UniqueId,+    name :: Maybe Str.Str,+    unknown1 :: Bool,+    unknown2 :: Bool,+    unknown3 :: Maybe Word.Word8   }   deriving (Eq, Show) @@ -30,27 +30,30 @@     unknown1 <- Json.required object "unknown1"     unknown2 <- Json.required object "unknown2"     unknown3 <- Json.optional object "unknown3"-    pure Reservation { number, uniqueId, name, unknown1, unknown2, unknown3 }+    pure Reservation {number, uniqueId, name, unknown1, unknown2, unknown3}  instance Json.ToJSON Reservation where-  toJSON x = Json.object-    [ Json.pair "number" $ number x-    , Json.pair "unique_id" $ uniqueId x-    , Json.pair "name" $ name x-    , Json.pair "unknown1" $ unknown1 x-    , Json.pair "unknown2" $ unknown2 x-    , Json.pair "unknown3" $ unknown3 x-    ]+  toJSON x =+    Json.object+      [ Json.pair "number" $ number x,+        Json.pair "unique_id" $ uniqueId x,+        Json.pair "name" $ name x,+        Json.pair "unknown1" $ unknown1 x,+        Json.pair "unknown2" $ unknown2 x,+        Json.pair "unknown3" $ unknown3 x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-reservation" $ Schema.object-  [ (Json.pair "number" $ Schema.ref CompressedWord.schema, True)-  , (Json.pair "unique_id" $ Schema.ref UniqueId.schema, True)-  , (Json.pair "name" . Schema.json $ Schema.maybe Str.schema, False)-  , (Json.pair "unknown1" $ Schema.ref Schema.boolean, True)-  , (Json.pair "unknown2" $ Schema.ref Schema.boolean, True)-  , (Json.pair "unknown3" . Schema.json $ Schema.maybe Schema.integer, False)-  ]+schema =+  Schema.named "attribute-reservation" $+    Schema.object+      [ (Json.pair "number" $ Schema.ref CompressedWord.schema, True),+        (Json.pair "unique_id" $ Schema.ref UniqueId.schema, True),+        (Json.pair "name" . Schema.json $ Schema.maybe Str.schema, False),+        (Json.pair "unknown1" $ Schema.ref Schema.boolean, True),+        (Json.pair "unknown2" $ Schema.ref Schema.boolean, True),+        (Json.pair "unknown3" . Schema.json $ Schema.maybe Schema.integer, False)+      ]  bitPut :: Reservation -> BitPut.BitPut bitPut reservationAttribute =@@ -65,13 +68,15 @@ bitGet version = BitGet.label "Reservation" $ do   number <- BitGet.label "number" $ CompressedWord.bitGet 7   uniqueId <- BitGet.label "uniqueId" $ UniqueId.bitGet version-  name <- BitGet.label "name" $ Monad.whenMaybe-    (UniqueId.systemId uniqueId /= U8.fromWord8 0)-    Str.bitGet+  name <-+    BitGet.label "name" $+      Monad.whenMaybe+        (UniqueId.systemId uniqueId /= U8.fromWord8 0)+        Str.bitGet   unknown1 <- BitGet.label "unknown1" BitGet.bool   unknown2 <- BitGet.label "unknown2" BitGet.bool   unknown3 <-     BitGet.label "unknown3"-    . Monad.whenMaybe (Version.atLeast 868 12 0 version)-    $ BitGet.bits 6-  pure Reservation { number, uniqueId, name, unknown1, unknown2, unknown3 }+      . Monad.whenMaybe (Version.atLeast 868 12 0 version)+      $ BitGet.bits 6+  pure Reservation {number, uniqueId, name, unknown1, unknown2, unknown3}
src/lib/Rattletrap/Type/Attribute/RigidBodyState.hs view
@@ -10,11 +10,11 @@ import qualified Rattletrap.Utility.Monad as Monad  data RigidBodyState = RigidBodyState-  { sleeping :: Bool-  , location :: Vector.Vector-  , rotation :: Rotation.Rotation-  , linearVelocity :: Maybe Vector.Vector-  , angularVelocity :: Maybe Vector.Vector+  { sleeping :: Bool,+    location :: Vector.Vector,+    rotation :: Rotation.Rotation,+    linearVelocity :: Maybe Vector.Vector,+    angularVelocity :: Maybe Vector.Vector   }   deriving (Eq, Show) @@ -25,35 +25,39 @@     rotation <- Json.required object "rotation"     linearVelocity <- Json.optional object "linear_velocity"     angularVelocity <- Json.optional object "angular_velocity"-    pure RigidBodyState-      { sleeping-      , location-      , rotation-      , linearVelocity-      , angularVelocity-      }+    pure+      RigidBodyState+        { sleeping,+          location,+          rotation,+          linearVelocity,+          angularVelocity+        }  instance Json.ToJSON RigidBodyState where-  toJSON x = Json.object-    [ Json.pair "sleeping" $ sleeping x-    , Json.pair "location" $ location x-    , Json.pair "rotation" $ rotation x-    , Json.pair "linear_velocity" $ linearVelocity x-    , Json.pair "angular_velocity" $ angularVelocity x-    ]+  toJSON x =+    Json.object+      [ Json.pair "sleeping" $ sleeping x,+        Json.pair "location" $ location x,+        Json.pair "rotation" $ rotation x,+        Json.pair "linear_velocity" $ linearVelocity x,+        Json.pair "angular_velocity" $ angularVelocity x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-rigid-body-state" $ Schema.object-  [ (Json.pair "sleeping" $ Schema.ref Schema.boolean, True)-  , (Json.pair "location" $ Schema.ref Vector.schema, True)-  , (Json.pair "rotation" $ Schema.ref Rotation.schema, True)-  , ( Json.pair "linear_velocity" . Schema.json $ Schema.maybe Vector.schema-    , False-    )-  , ( Json.pair "angular_velocity" . Schema.json $ Schema.maybe Vector.schema-    , False-    )-  ]+schema =+  Schema.named "attribute-rigid-body-state" $+    Schema.object+      [ (Json.pair "sleeping" $ Schema.ref Schema.boolean, True),+        (Json.pair "location" $ Schema.ref Vector.schema, True),+        (Json.pair "rotation" $ Schema.ref Rotation.schema, True),+        ( Json.pair "linear_velocity" . Schema.json $ Schema.maybe Vector.schema,+          False+        ),+        ( Json.pair "angular_velocity" . Schema.json $ Schema.maybe Vector.schema,+          False+        )+      ]  bitPut :: RigidBodyState -> BitPut.BitPut bitPut rigidBodyStateAttribute =@@ -68,14 +72,17 @@   sleeping <- BitGet.label "sleeping" BitGet.bool   location <- BitGet.label "location" $ Vector.bitGet version   rotation <- BitGet.label "rotation" $ Rotation.bitGet version-  linearVelocity <- BitGet.label "linearVelocity"-    $ Monad.whenMaybe (not sleeping) (Vector.bitGet version)-  angularVelocity <- BitGet.label "angularVelocity"-    $ Monad.whenMaybe (not sleeping) (Vector.bitGet version)-  pure RigidBodyState-    { sleeping-    , location-    , rotation-    , linearVelocity-    , angularVelocity-    }+  linearVelocity <-+    BitGet.label "linearVelocity" $+      Monad.whenMaybe (not sleeping) (Vector.bitGet version)+  angularVelocity <-+    BitGet.label "angularVelocity" $+      Monad.whenMaybe (not sleeping) (Vector.bitGet version)+  pure+    RigidBodyState+      { sleeping,+        location,+        rotation,+        linearVelocity,+        angularVelocity+      }
src/lib/Rattletrap/Type/Attribute/Rotation.hs view
@@ -8,7 +8,8 @@  newtype Rotation = Rotation   { value :: Int8Vector.Int8Vector-  } deriving (Eq, Show)+  }+  deriving (Eq, Show)  instance Json.FromJSON Rotation where   parseJSON = fmap Rotation . Json.parseJSON@@ -25,4 +26,4 @@ bitGet :: BitGet.BitGet Rotation bitGet = BitGet.label "Rotation" $ do   value <- BitGet.label "value" Int8Vector.bitGet-  pure Rotation { value }+  pure Rotation {value}
src/lib/Rattletrap/Type/Attribute/StatEvent.hs view
@@ -7,8 +7,8 @@ import qualified Rattletrap.Utility.Json as Json  data StatEvent = StatEvent-  { unknown :: Bool-  , objectId :: I32.I32+  { unknown :: Bool,+    objectId :: I32.I32   }   deriving (Eq, Show) @@ -16,24 +16,28 @@   parseJSON = Json.withObject "StatEvent" $ \object -> do     unknown <- Json.required object "unknown"     objectId <- Json.required object "object_id"-    pure StatEvent { unknown, objectId }+    pure StatEvent {unknown, objectId}  instance Json.ToJSON StatEvent where-  toJSON x = Json.object-    [Json.pair "unknown" $ unknown x, Json.pair "object_id" $ objectId x]+  toJSON x =+    Json.object+      [Json.pair "unknown" $ unknown x, Json.pair "object_id" $ objectId x]  schema :: Schema.Schema-schema = Schema.named "attribute-stat-event" $ Schema.object-  [ (Json.pair "unknown" $ Schema.ref Schema.boolean, True)-  , (Json.pair "object_id" $ Schema.ref I32.schema, True)-  ]+schema =+  Schema.named "attribute-stat-event" $+    Schema.object+      [ (Json.pair "unknown" $ Schema.ref Schema.boolean, True),+        (Json.pair "object_id" $ Schema.ref I32.schema, True)+      ]  bitPut :: StatEvent -> BitPut.BitPut-bitPut statEventAttribute = BitPut.bool (unknown statEventAttribute)-  <> I32.bitPut (objectId statEventAttribute)+bitPut statEventAttribute =+  BitPut.bool (unknown statEventAttribute)+    <> I32.bitPut (objectId statEventAttribute)  bitGet :: BitGet.BitGet StatEvent bitGet = BitGet.label "StatEvent" $ do   unknown <- BitGet.label "unknown" BitGet.bool   objectId <- BitGet.label "objectId" I32.bitGet-  pure StatEvent { unknown, objectId }+  pure StatEvent {unknown, objectId}
src/lib/Rattletrap/Type/Attribute/String.hs view
@@ -1,15 +1,16 @@ module Rattletrap.Type.Attribute.String where -import Prelude hiding (String) import qualified Rattletrap.BitGet as BitGet import qualified Rattletrap.BitPut as BitPut import qualified Rattletrap.Schema as Schema import qualified Rattletrap.Type.Str as Str import qualified Rattletrap.Utility.Json as Json+import Prelude hiding (String)  newtype String = String   { value :: Str.Str-  } deriving (Eq, Show)+  }+  deriving (Eq, Show)  instance Json.FromJSON String where   parseJSON = fmap String . Json.parseJSON@@ -26,4 +27,4 @@ bitGet :: BitGet.BitGet String bitGet = BitGet.label "String" $ do   value <- BitGet.label "value" Str.bitGet-  pure String { value }+  pure String {value}
src/lib/Rattletrap/Type/Attribute/TeamPaint.hs view
@@ -8,11 +8,11 @@ import qualified Rattletrap.Utility.Json as Json  data TeamPaint = TeamPaint-  { team :: U8.U8-  , primaryColor :: U8.U8-  , accentColor :: U8.U8-  , primaryFinish :: U32.U32-  , accentFinish :: U32.U32+  { team :: U8.U8,+    primaryColor :: U8.U8,+    accentColor :: U8.U8,+    primaryFinish :: U32.U32,+    accentFinish :: U32.U32   }   deriving (Eq, Show) @@ -23,31 +23,35 @@     accentColor <- Json.required object "accent_color"     primaryFinish <- Json.required object "primary_finish"     accentFinish <- Json.required object "accent_finish"-    pure TeamPaint-      { team-      , primaryColor-      , accentColor-      , primaryFinish-      , accentFinish-      }+    pure+      TeamPaint+        { team,+          primaryColor,+          accentColor,+          primaryFinish,+          accentFinish+        }  instance Json.ToJSON TeamPaint where-  toJSON x = Json.object-    [ Json.pair "team" $ team x-    , Json.pair "primary_color" $ primaryColor x-    , Json.pair "accent_color" $ accentColor x-    , Json.pair "primary_finish" $ primaryFinish x-    , Json.pair "accent_finish" $ accentFinish x-    ]+  toJSON x =+    Json.object+      [ Json.pair "team" $ team x,+        Json.pair "primary_color" $ primaryColor x,+        Json.pair "accent_color" $ accentColor x,+        Json.pair "primary_finish" $ primaryFinish x,+        Json.pair "accent_finish" $ accentFinish x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-team-paint" $ Schema.object-  [ (Json.pair "team" $ Schema.ref U8.schema, True)-  , (Json.pair "primary_color" $ Schema.ref U8.schema, True)-  , (Json.pair "accent_color" $ Schema.ref U8.schema, True)-  , (Json.pair "primary_finish" $ Schema.ref U32.schema, True)-  , (Json.pair "accent_finish" $ Schema.ref U32.schema, True)-  ]+schema =+  Schema.named "attribute-team-paint" $+    Schema.object+      [ (Json.pair "team" $ Schema.ref U8.schema, True),+        (Json.pair "primary_color" $ Schema.ref U8.schema, True),+        (Json.pair "accent_color" $ Schema.ref U8.schema, True),+        (Json.pair "primary_finish" $ Schema.ref U32.schema, True),+        (Json.pair "accent_finish" $ Schema.ref U32.schema, True)+      ]  bitPut :: TeamPaint -> BitPut.BitPut bitPut teamPaintAttribute =@@ -64,10 +68,11 @@   accentColor <- BitGet.label "accentColor" U8.bitGet   primaryFinish <- BitGet.label "primaryFinish" U32.bitGet   accentFinish <- BitGet.label "accentFinish" U32.bitGet-  pure TeamPaint-    { team-    , primaryColor-    , accentColor-    , primaryFinish-    , accentFinish-    }+  pure+    TeamPaint+      { team,+        primaryColor,+        accentColor,+        primaryFinish,+        accentFinish+      }
src/lib/Rattletrap/Type/Attribute/Title.hs view
@@ -7,14 +7,14 @@ import qualified Rattletrap.Utility.Json as Json  data Title = Title-  { unknown1 :: Bool-  , unknown2 :: Bool-  , unknown3 :: U32.U32-  , unknown4 :: U32.U32-  , unknown5 :: U32.U32-  , unknown6 :: U32.U32-  , unknown7 :: U32.U32-  , unknown8 :: Bool+  { unknown1 :: Bool,+    unknown2 :: Bool,+    unknown3 :: U32.U32,+    unknown4 :: U32.U32,+    unknown5 :: U32.U32,+    unknown6 :: U32.U32,+    unknown7 :: U32.U32,+    unknown8 :: Bool   }   deriving (Eq, Show) @@ -28,40 +28,44 @@     unknown6 <- Json.required object "unknown6"     unknown7 <- Json.required object "unknown7"     unknown8 <- Json.required object "unknown8"-    pure Title-      { unknown1-      , unknown2-      , unknown3-      , unknown4-      , unknown5-      , unknown6-      , unknown7-      , unknown8-      }+    pure+      Title+        { unknown1,+          unknown2,+          unknown3,+          unknown4,+          unknown5,+          unknown6,+          unknown7,+          unknown8+        }  instance Json.ToJSON Title where-  toJSON x = Json.object-    [ Json.pair "unknown1" $ unknown1 x-    , Json.pair "unknown2" $ unknown2 x-    , Json.pair "unknown3" $ unknown3 x-    , Json.pair "unknown4" $ unknown4 x-    , Json.pair "unknown5" $ unknown5 x-    , Json.pair "unknown6" $ unknown6 x-    , Json.pair "unknown7" $ unknown7 x-    , Json.pair "unknown8" $ unknown8 x-    ]+  toJSON x =+    Json.object+      [ Json.pair "unknown1" $ unknown1 x,+        Json.pair "unknown2" $ unknown2 x,+        Json.pair "unknown3" $ unknown3 x,+        Json.pair "unknown4" $ unknown4 x,+        Json.pair "unknown5" $ unknown5 x,+        Json.pair "unknown6" $ unknown6 x,+        Json.pair "unknown7" $ unknown7 x,+        Json.pair "unknown8" $ unknown8 x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-title" $ Schema.object-  [ (Json.pair "unknown1" $ Schema.ref Schema.boolean, True)-  , (Json.pair "unknown2" $ Schema.ref Schema.boolean, True)-  , (Json.pair "unknown3" $ Schema.ref U32.schema, True)-  , (Json.pair "unknown4" $ Schema.ref U32.schema, True)-  , (Json.pair "unknown5" $ Schema.ref U32.schema, True)-  , (Json.pair "unknown6" $ Schema.ref U32.schema, True)-  , (Json.pair "unknown7" $ Schema.ref U32.schema, True)-  , (Json.pair "unknown8" $ Schema.ref Schema.boolean, True)-  ]+schema =+  Schema.named "attribute-title" $+    Schema.object+      [ (Json.pair "unknown1" $ Schema.ref Schema.boolean, True),+        (Json.pair "unknown2" $ Schema.ref Schema.boolean, True),+        (Json.pair "unknown3" $ Schema.ref U32.schema, True),+        (Json.pair "unknown4" $ Schema.ref U32.schema, True),+        (Json.pair "unknown5" $ Schema.ref U32.schema, True),+        (Json.pair "unknown6" $ Schema.ref U32.schema, True),+        (Json.pair "unknown7" $ Schema.ref U32.schema, True),+        (Json.pair "unknown8" $ Schema.ref Schema.boolean, True)+      ]  bitPut :: Title -> BitPut.BitPut bitPut titleAttribute =@@ -84,13 +88,14 @@   unknown6 <- BitGet.label "unknown6" U32.bitGet   unknown7 <- BitGet.label "unknown7" U32.bitGet   unknown8 <- BitGet.label "unknown8" BitGet.bool-  pure Title-    { unknown1-    , unknown2-    , unknown3-    , unknown4-    , unknown5-    , unknown6-    , unknown7-    , unknown8-    }+  pure+    Title+      { unknown1,+        unknown2,+        unknown3,+        unknown4,+        unknown5,+        unknown6,+        unknown7,+        unknown8+      }
src/lib/Rattletrap/Type/Attribute/UniqueId.hs view
@@ -9,9 +9,9 @@ import qualified Rattletrap.Utility.Json as Json  data UniqueId = UniqueId-  { systemId :: U8.U8-  , remoteId :: RemoteId.RemoteId-  , localId :: U8.U8+  { systemId :: U8.U8,+    remoteId :: RemoteId.RemoteId,+    localId :: U8.U8   }   deriving (Eq, Show) @@ -20,21 +20,24 @@     systemId <- Json.required object "system_id"     remoteId <- Json.required object "remote_id"     localId <- Json.required object "local_id"-    pure UniqueId { systemId, remoteId, localId }+    pure UniqueId {systemId, remoteId, localId}  instance Json.ToJSON UniqueId where-  toJSON x = Json.object-    [ Json.pair "system_id" $ systemId x-    , Json.pair "remote_id" $ remoteId x-    , Json.pair "local_id" $ localId x-    ]+  toJSON x =+    Json.object+      [ Json.pair "system_id" $ systemId x,+        Json.pair "remote_id" $ remoteId x,+        Json.pair "local_id" $ localId x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-unique-id" $ Schema.object-  [ (Json.pair "system_id" $ Schema.ref U8.schema, True)-  , (Json.pair "remote_id" $ Schema.ref RemoteId.schema, True)-  , (Json.pair "local_id" $ Schema.ref U8.schema, True)-  ]+schema =+  Schema.named "attribute-unique-id" $+    Schema.object+      [ (Json.pair "system_id" $ Schema.ref U8.schema, True),+        (Json.pair "remote_id" $ Schema.ref RemoteId.schema, True),+        (Json.pair "local_id" $ Schema.ref U8.schema, True)+      ]  bitPut :: UniqueId -> BitPut.BitPut bitPut uniqueIdAttribute =@@ -47,4 +50,4 @@   systemId <- BitGet.label "systemId" U8.bitGet   remoteId <- BitGet.label "remoteId" $ RemoteId.bitGet version systemId   localId <- BitGet.label "localId" U8.bitGet-  pure UniqueId { systemId, remoteId, localId }+  pure UniqueId {systemId, remoteId, localId}
src/lib/Rattletrap/Type/Attribute/WeldedInfo.hs view
@@ -11,11 +11,11 @@ import qualified Rattletrap.Utility.Json as Json  data WeldedInfo = WeldedInfo-  { active :: Bool-  , actorId :: I32.I32-  , offset :: Vector.Vector-  , mass :: F32.F32-  , rotation :: Int8Vector.Int8Vector+  { active :: Bool,+    actorId :: I32.I32,+    offset :: Vector.Vector,+    mass :: F32.F32,+    rotation :: Int8Vector.Int8Vector   }   deriving (Eq, Show) @@ -26,25 +26,28 @@     offset <- Json.required object "offset"     mass <- Json.required object "mass"     rotation <- Json.required object "rotation"-    pure WeldedInfo { active, actorId, offset, mass, rotation }+    pure WeldedInfo {active, actorId, offset, mass, rotation}  instance Json.ToJSON WeldedInfo where-  toJSON x = Json.object-    [ Json.pair "active" $ active x-    , Json.pair "actor_id" $ actorId x-    , Json.pair "offset" $ offset x-    , Json.pair "mass" $ mass x-    , Json.pair "rotation" $ rotation x-    ]+  toJSON x =+    Json.object+      [ Json.pair "active" $ active x,+        Json.pair "actor_id" $ actorId x,+        Json.pair "offset" $ offset x,+        Json.pair "mass" $ mass x,+        Json.pair "rotation" $ rotation x+      ]  schema :: Schema.Schema-schema = Schema.named "attribute-welded-info" $ Schema.object-  [ (Json.pair "active" $ Schema.ref Schema.boolean, True)-  , (Json.pair "actor_id" $ Schema.ref I32.schema, True)-  , (Json.pair "offset" $ Schema.ref Vector.schema, True)-  , (Json.pair "mass" $ Schema.ref F32.schema, True)-  , (Json.pair "rotation" $ Schema.ref Int8Vector.schema, True)-  ]+schema =+  Schema.named "attribute-welded-info" $+    Schema.object+      [ (Json.pair "active" $ Schema.ref Schema.boolean, True),+        (Json.pair "actor_id" $ Schema.ref I32.schema, True),+        (Json.pair "offset" $ Schema.ref Vector.schema, True),+        (Json.pair "mass" $ Schema.ref F32.schema, True),+        (Json.pair "rotation" $ Schema.ref Int8Vector.schema, True)+      ]  bitPut :: WeldedInfo -> BitPut.BitPut bitPut weldedInfoAttribute =@@ -61,4 +64,4 @@   offset <- BitGet.label "offset" $ Vector.bitGet version   mass <- BitGet.label "mass" F32.bitGet   rotation <- BitGet.label "rotation" Int8Vector.bitGet-  pure WeldedInfo { active, actorId, offset, mass, rotation }+  pure WeldedInfo {active, actorId, offset, mass, rotation}
src/lib/Rattletrap/Type/AttributeMapping.hs view
@@ -7,8 +7,8 @@ import qualified Rattletrap.Utility.Json as Json  data AttributeMapping = AttributeMapping-  { objectId :: U32.U32-  , streamId :: U32.U32+  { objectId :: U32.U32,+    streamId :: U32.U32   }   deriving (Eq, Show) @@ -16,17 +16,20 @@   parseJSON = Json.withObject "AttributeMapping" $ \object -> do     objectId <- Json.required object "object_id"     streamId <- Json.required object "stream_id"-    pure AttributeMapping { objectId, streamId }+    pure AttributeMapping {objectId, streamId}  instance Json.ToJSON AttributeMapping where-  toJSON x = Json.object-    [Json.pair "object_id" $ objectId x, Json.pair "stream_id" $ streamId x]+  toJSON x =+    Json.object+      [Json.pair "object_id" $ objectId x, Json.pair "stream_id" $ streamId x]  schema :: Schema.Schema-schema = Schema.named "attributeMapping" $ Schema.object-  [ (Json.pair "object_id" $ Schema.ref U32.schema, True)-  , (Json.pair "stream_id" $ Schema.ref U32.schema, True)-  ]+schema =+  Schema.named "attributeMapping" $+    Schema.object+      [ (Json.pair "object_id" $ Schema.ref U32.schema, True),+        (Json.pair "stream_id" $ Schema.ref U32.schema, True)+      ]  bytePut :: AttributeMapping -> BytePut.BytePut bytePut x = U32.bytePut (objectId x) <> U32.bytePut (streamId x)@@ -35,4 +38,4 @@ byteGet = ByteGet.label "AttributeMapping" $ do   objectId <- ByteGet.label "objectId" U32.byteGet   streamId <- ByteGet.label "streamId" U32.byteGet-  pure AttributeMapping { objectId, streamId }+  pure AttributeMapping {objectId, streamId}
src/lib/Rattletrap/Type/AttributeValue.hs view
@@ -99,49 +99,50 @@   deriving (Eq, Show)  instance Json.FromJSON AttributeValue where-  parseJSON = Json.withObject "AttributeValue" $ \object -> Foldable.asum-    [ fmap AppliedDamage $ Json.required object "applied_damage"-    , fmap Boolean $ Json.required object "boolean"-    , fmap Byte $ Json.required object "byte"-    , fmap CamSettings $ Json.required object "cam_settings"-    , fmap ClubColors $ Json.required object "club_colors"-    , fmap CustomDemolish $ Json.required object "custom_demolish"-    , fmap DamageState $ Json.required object "damage_state"-    , fmap Demolish $ Json.required object "demolish"-    , fmap Enum $ Json.required object "enum"-    , fmap Explosion $ Json.required object "explosion"-    , fmap ExtendedExplosion $ Json.required object "extended_explosion"-    , fmap FlaggedByte $ Json.required object "flagged_byte"-    , fmap FlaggedInt $ Json.required object "flagged_int"-    , fmap Float $ Json.required object "float"-    , fmap GameMode $ Json.required object "game_mode"-    , fmap GameServer $ Json.required object "game_server"-    , fmap Int $ Json.required object "int"-    , fmap Int64 $ Json.required object "int64"-    , fmap Loadout $ Json.required object "loadout"-    , fmap LoadoutOnline $ Json.required object "loadout_online"-    , fmap Loadouts $ Json.required object "loadouts"-    , fmap LoadoutsOnline $ Json.required object "loadouts_online"-    , fmap Location $ Json.required object "location"-    , fmap MusicStinger $ Json.required object "music_stinger"-    , fmap PartyLeader $ Json.required object "party_leader"-    , fmap Pickup $ Json.required object "pickup"-    , fmap PickupInfo $ Json.required object "pickup_info"-    , fmap PickupNew $ Json.required object "pickup_new"-    , fmap PlayerHistoryKey $ Json.required object "player_history_key"-    , fmap PrivateMatchSettings $ Json.required object "private_match_settings"-    , fmap QWord $ Json.required object "q_word"-    , fmap RepStatTitle $ Json.required object "rep_stat_title"-    , fmap Reservation $ Json.required object "reservation"-    , fmap RigidBodyState $ Json.required object "rigid_body_state"-    , fmap Rotation $ Json.required object "rotation"-    , fmap StatEvent $ Json.required object "stat_event"-    , fmap String $ Json.required object "string"-    , fmap TeamPaint $ Json.required object "team_paint"-    , fmap Title $ Json.required object "title"-    , fmap UniqueId $ Json.required object "unique_id"-    , fmap WeldedInfo $ Json.required object "welded_info"-    ]+  parseJSON = Json.withObject "AttributeValue" $ \object ->+    Foldable.asum+      [ fmap AppliedDamage $ Json.required object "applied_damage",+        fmap Boolean $ Json.required object "boolean",+        fmap Byte $ Json.required object "byte",+        fmap CamSettings $ Json.required object "cam_settings",+        fmap ClubColors $ Json.required object "club_colors",+        fmap CustomDemolish $ Json.required object "custom_demolish",+        fmap DamageState $ Json.required object "damage_state",+        fmap Demolish $ Json.required object "demolish",+        fmap Enum $ Json.required object "enum",+        fmap Explosion $ Json.required object "explosion",+        fmap ExtendedExplosion $ Json.required object "extended_explosion",+        fmap FlaggedByte $ Json.required object "flagged_byte",+        fmap FlaggedInt $ Json.required object "flagged_int",+        fmap Float $ Json.required object "float",+        fmap GameMode $ Json.required object "game_mode",+        fmap GameServer $ Json.required object "game_server",+        fmap Int $ Json.required object "int",+        fmap Int64 $ Json.required object "int64",+        fmap Loadout $ Json.required object "loadout",+        fmap LoadoutOnline $ Json.required object "loadout_online",+        fmap Loadouts $ Json.required object "loadouts",+        fmap LoadoutsOnline $ Json.required object "loadouts_online",+        fmap Location $ Json.required object "location",+        fmap MusicStinger $ Json.required object "music_stinger",+        fmap PartyLeader $ Json.required object "party_leader",+        fmap Pickup $ Json.required object "pickup",+        fmap PickupInfo $ Json.required object "pickup_info",+        fmap PickupNew $ Json.required object "pickup_new",+        fmap PlayerHistoryKey $ Json.required object "player_history_key",+        fmap PrivateMatchSettings $ Json.required object "private_match_settings",+        fmap QWord $ Json.required object "q_word",+        fmap RepStatTitle $ Json.required object "rep_stat_title",+        fmap Reservation $ Json.required object "reservation",+        fmap RigidBodyState $ Json.required object "rigid_body_state",+        fmap Rotation $ Json.required object "rotation",+        fmap StatEvent $ Json.required object "stat_event",+        fmap String $ Json.required object "string",+        fmap TeamPaint $ Json.required object "team_paint",+        fmap Title $ Json.required object "title",+        fmap UniqueId $ Json.required object "unique_id",+        fmap WeldedInfo $ Json.required object "welded_info"+      ]  instance Json.ToJSON AttributeValue where   toJSON x = case x of@@ -189,50 +190,52 @@     WeldedInfo y -> Json.object [Json.pair "welded_info" y]  schema :: Schema.Schema-schema = Schema.named "attribute-value" . Schema.oneOf $ fmap-  (\(k, v) -> Schema.object [(Json.pair k $ Schema.ref v, True)])-  [ ("applied_damage", AppliedDamage.schema)-  , ("boolean", Boolean.schema)-  , ("byte", Byte.schema)-  , ("cam_settings", CamSettings.schema)-  , ("club_colors", ClubColors.schema)-  , ("custom_demolish", CustomDemolish.schema)-  , ("damage_state", DamageState.schema)-  , ("demolish", Demolish.schema)-  , ("enum", Enum.schema)-  , ("explosion", Explosion.schema)-  , ("extended_explosion", ExtendedExplosion.schema)-  , ("flagged_byte", FlaggedByte.schema)-  , ("flagged_int", FlaggedInt.schema)-  , ("float", Float.schema)-  , ("game_mode", GameMode.schema)-  , ("game_server", GameServer.schema)-  , ("int", Int.schema)-  , ("int64", Int64.schema)-  , ("loadout_online", LoadoutOnline.schema)-  , ("loadout", Loadout.schema)-  , ("loadouts_online", LoadoutsOnline.schema)-  , ("loadouts", Loadouts.schema)-  , ("location", Location.schema)-  , ("music_stinger", MusicStinger.schema)-  , ("party_leader", PartyLeader.schema)-  , ("pickup_info", PickupInfo.schema)-  , ("pickup_new", PickupNew.schema)-  , ("pickup", Pickup.schema)-  , ("player_history_key", PlayerHistoryKey.schema)-  , ("private_match_settings", PrivateMatchSettings.schema)-  , ("q_word", QWord.schema)-  , ("rep_stat_title", RepStatTitle.schema)-  , ("reservation", Reservation.schema)-  , ("rigid_body_state", RigidBodyState.schema)-  , ("rotation", Rotation.schema)-  , ("stat_event", StatEvent.schema)-  , ("string", String.schema)-  , ("team_paint", TeamPaint.schema)-  , ("title", Title.schema)-  , ("unique_id", UniqueId.schema)-  , ("welded_info", WeldedInfo.schema)-  ]+schema =+  Schema.named "attribute-value" . Schema.oneOf $+    fmap+      (\(k, v) -> Schema.object [(Json.pair k $ Schema.ref v, True)])+      [ ("applied_damage", AppliedDamage.schema),+        ("boolean", Boolean.schema),+        ("byte", Byte.schema),+        ("cam_settings", CamSettings.schema),+        ("club_colors", ClubColors.schema),+        ("custom_demolish", CustomDemolish.schema),+        ("damage_state", DamageState.schema),+        ("demolish", Demolish.schema),+        ("enum", Enum.schema),+        ("explosion", Explosion.schema),+        ("extended_explosion", ExtendedExplosion.schema),+        ("flagged_byte", FlaggedByte.schema),+        ("flagged_int", FlaggedInt.schema),+        ("float", Float.schema),+        ("game_mode", GameMode.schema),+        ("game_server", GameServer.schema),+        ("int", Int.schema),+        ("int64", Int64.schema),+        ("loadout_online", LoadoutOnline.schema),+        ("loadout", Loadout.schema),+        ("loadouts_online", LoadoutsOnline.schema),+        ("loadouts", Loadouts.schema),+        ("location", Location.schema),+        ("music_stinger", MusicStinger.schema),+        ("party_leader", PartyLeader.schema),+        ("pickup_info", PickupInfo.schema),+        ("pickup_new", PickupNew.schema),+        ("pickup", Pickup.schema),+        ("player_history_key", PlayerHistoryKey.schema),+        ("private_match_settings", PrivateMatchSettings.schema),+        ("q_word", QWord.schema),+        ("rep_stat_title", RepStatTitle.schema),+        ("reservation", Reservation.schema),+        ("rigid_body_state", RigidBodyState.schema),+        ("rotation", Rotation.schema),+        ("stat_event", StatEvent.schema),+        ("string", String.schema),+        ("team_paint", TeamPaint.schema),+        ("title", Title.schema),+        ("unique_id", UniqueId.schema),+        ("welded_info", WeldedInfo.schema)+      ]  bitPut :: AttributeValue -> BitPut.BitPut bitPut value = case value of@@ -278,12 +281,12 @@   UniqueId x -> UniqueId.bitPut x   WeldedInfo x -> WeldedInfo.bitPut x -bitGet-  :: Version.Version-  -> Maybe Str.Str-  -> Map.Map U32.U32 Str.Str-  -> Str.Str-  -> BitGet.BitGet AttributeValue+bitGet ::+  Version.Version ->+  Maybe Str.Str ->+  Map.Map U32.U32 Str.Str ->+  Str.Str ->+  BitGet.BitGet AttributeValue bitGet version buildVersion objectMap name =   BitGet.label "AttributeValue" $ do     constructor <- case Map.lookup (Str.toText name) Data.attributeTypes of
src/lib/Rattletrap/Type/Cache.hs view
@@ -9,10 +9,10 @@ import qualified Rattletrap.Utility.Json as Json  data Cache = Cache-  { classId :: U32.U32-  , parentCacheId :: U32.U32-  , cacheId :: U32.U32-  , attributeMappings :: List.List AttributeMapping.AttributeMapping+  { classId :: U32.U32,+    parentCacheId :: U32.U32,+    cacheId :: U32.U32,+    attributeMappings :: List.List AttributeMapping.AttributeMapping   }   deriving (Eq, Show) @@ -22,26 +22,30 @@     parentCacheId <- Json.required object "parent_cache_id"     cacheId <- Json.required object "cache_id"     attributeMappings <- Json.required object "attribute_mappings"-    pure Cache { classId, parentCacheId, cacheId, attributeMappings }+    pure Cache {classId, parentCacheId, cacheId, attributeMappings}  instance Json.ToJSON Cache where-  toJSON x = Json.object-    [ Json.pair "class_id" $ classId x-    , Json.pair "parent_cache_id" $ parentCacheId x-    , Json.pair "cache_id" $ cacheId x-    , Json.pair "attribute_mappings" $ attributeMappings x-    ]+  toJSON x =+    Json.object+      [ Json.pair "class_id" $ classId x,+        Json.pair "parent_cache_id" $ parentCacheId x,+        Json.pair "cache_id" $ cacheId x,+        Json.pair "attribute_mappings" $ attributeMappings x+      ]  schema :: Schema.Schema-schema = Schema.named "cache" $ Schema.object-  [ (Json.pair "class_id" $ Schema.ref U32.schema, True)-  , (Json.pair "parent_cache_id" $ Schema.ref U32.schema, True)-  , (Json.pair "cache_id" $ Schema.ref U32.schema, True)-  , ( Json.pair "attribute_mappings" . Schema.json $ List.schema-      AttributeMapping.schema-    , True-    )-  ]+schema =+  Schema.named "cache" $+    Schema.object+      [ (Json.pair "class_id" $ Schema.ref U32.schema, True),+        (Json.pair "parent_cache_id" $ Schema.ref U32.schema, True),+        (Json.pair "cache_id" $ Schema.ref U32.schema, True),+        ( Json.pair "attribute_mappings" . Schema.json $+            List.schema+              AttributeMapping.schema,+          True+        )+      ]  bytePut :: Cache -> BytePut.BytePut bytePut x =@@ -55,6 +59,7 @@   classId <- ByteGet.label "classId" U32.byteGet   parentCacheId <- ByteGet.label "parentCacheId" U32.byteGet   cacheId <- ByteGet.label "cacheId" U32.byteGet-  attributeMappings <- ByteGet.label "attributeMappings"-    $ List.byteGet AttributeMapping.byteGet-  pure Cache { classId, parentCacheId, cacheId, attributeMappings }+  attributeMappings <-+    ByteGet.label "attributeMappings" $+      List.byteGet AttributeMapping.byteGet+  pure Cache {classId, parentCacheId, cacheId, attributeMappings}
src/lib/Rattletrap/Type/ClassAttributeMap.hs view
@@ -22,14 +22,14 @@ -- to each class are not fixed either. Converting the raw data into a usable -- structure is tedious; see 'make'. data ClassAttributeMap = ClassAttributeMap-  { objectMap :: Map.Map U32.U32 Str.Str-  -- ^ A map from object IDs to their names.-  , objectClassMap :: Map.Map U32.U32 U32.U32-  -- ^ A map from object IDs to their class IDs.-  , value :: Map.Map U32.U32 (Map.Map U32.U32 U32.U32)-  -- ^ A map from class IDs to a map from attribute stream IDs to attribute-  -- IDs.-  , nameMap :: IntMap.IntMap Str.Str+  { -- | A map from object IDs to their names.+    objectMap :: Map.Map U32.U32 Str.Str,+    -- | A map from object IDs to their class IDs.+    objectClassMap :: Map.Map U32.U32 U32.U32,+    -- | A map from class IDs to a map from attribute stream IDs to attribute+    -- IDs.+    value :: Map.Map U32.U32 (Map.Map U32.U32 U32.U32),+    nameMap :: IntMap.IntMap Str.Str   }   deriving (Eq, Show) @@ -38,54 +38,55 @@ bimap :: (Ord l, Ord r) => [(l, r)] -> Bimap l r bimap xs = (Map.fromList xs, Map.fromList (fmap Tuple.swap xs)) -lookupL :: Ord l => l -> Bimap l r -> Maybe r+lookupL :: (Ord l) => l -> Bimap l r -> Maybe r lookupL k = Map.lookup k . fst -lookupR :: Ord r => r -> Bimap l r -> Maybe l+lookupR :: (Ord r) => r -> Bimap l r -> Maybe l lookupR k = Map.lookup k . snd  -- | Makes a 'ClassAttributeMap' given the necessary fields from the -- 'Rattletrap.Content.Content'.-make-  :: List.List Str.Str-  -- ^ From 'Rattletrap.Content.objects'.-  -> List.List ClassMapping.ClassMapping-  -- ^ From 'Rattletrap.Content.classMappings'.-  -> List.List Cache.Cache-  -- ^ From 'Rattletrap.Content.caches'.-  -> List.List Str.Str-  -- ^ From 'Rattletrap.Content.names'.-  -> ClassAttributeMap+make ::+  -- | From 'Rattletrap.Content.objects'.+  List.List Str.Str ->+  -- | From 'Rattletrap.Content.classMappings'.+  List.List ClassMapping.ClassMapping ->+  -- | From 'Rattletrap.Content.caches'.+  List.List Cache.Cache ->+  -- | From 'Rattletrap.Content.names'.+  List.List Str.Str ->+  ClassAttributeMap make objects classMappings caches names =-  let-    objectMap_ = makeObjectMap objects-    classMap = makeClassMap classMappings-    objectClassMap_ = makeObjectClassMap objectMap_ classMap-    classCache = makeClassCache classMap caches-    attributeMap = makeAttributeMap caches-    classIds = fmap (\(_, classId, _, _) -> classId) classCache-    parentMap = makeParentMap classCache-    value_ = Map.fromList-      (fmap-        (\classId ->-          let-            ownAttributes =-              Maybe.fromMaybe Map.empty (Map.lookup classId attributeMap)-            parentsAttributes = case Map.lookup classId parentMap of-              Nothing -> []-              Just parentClassIds -> fmap-                (\parentClassId -> Maybe.fromMaybe-                  Map.empty-                  (Map.lookup parentClassId attributeMap)-                )-                parentClassIds-            attributes = ownAttributes : parentsAttributes-          in (classId, Map.fromList (concatMap Map.toList attributes))-        )-        classIds-      )-    nameMap_ = makeNameMap names-  in ClassAttributeMap objectMap_ objectClassMap_ value_ nameMap_+  let objectMap_ = makeObjectMap objects+      classMap = makeClassMap classMappings+      objectClassMap_ = makeObjectClassMap objectMap_ classMap+      classCache = makeClassCache classMap caches+      attributeMap = makeAttributeMap caches+      classIds = fmap (\(_, classId, _, _) -> classId) classCache+      parentMap = makeParentMap classCache+      value_ =+        Map.fromList+          ( fmap+              ( \classId ->+                  let ownAttributes =+                        Maybe.fromMaybe Map.empty (Map.lookup classId attributeMap)+                      parentsAttributes = case Map.lookup classId parentMap of+                        Nothing -> []+                        Just parentClassIds ->+                          fmap+                            ( \parentClassId ->+                                Maybe.fromMaybe+                                  Map.empty+                                  (Map.lookup parentClassId attributeMap)+                            )+                            parentClassIds+                      attributes = ownAttributes : parentsAttributes+                   in (classId, Map.fromList (concatMap Map.toList attributes))+              )+              classIds+          )+      nameMap_ = makeNameMap names+   in ClassAttributeMap objectMap_ objectClassMap_ value_ nameMap_  makeNameMap :: List.List Str.Str -> IntMap.IntMap Str.Str makeNameMap names =@@ -95,99 +96,101 @@ getName nameMap_ nameIndex =   IntMap.lookup (fromIntegral (U32.toWord32 nameIndex)) nameMap_ -makeObjectClassMap-  :: Map.Map U32.U32 Str.Str-  -> Bimap U32.U32 Str.Str-  -> Map.Map U32.U32 U32.U32+makeObjectClassMap ::+  Map.Map U32.U32 Str.Str ->+  Bimap U32.U32 Str.Str ->+  Map.Map U32.U32 U32.U32 makeObjectClassMap objectMap_ classMap = do   let objectIds = Map.keys objectMap_   let classIds = fmap (getClassId objectMap_ classMap) objectIds   let rawPairs = zip objectIds classIds-  let-    pairs = Maybe.mapMaybe-      (\(objectId, maybeClassId) -> case maybeClassId of-        Nothing -> Nothing-        Just classId -> Just (objectId, classId)-      )-      rawPairs+  let pairs =+        Maybe.mapMaybe+          ( \(objectId, maybeClassId) -> case maybeClassId of+              Nothing -> Nothing+              Just classId -> Just (objectId, classId)+          )+          rawPairs   Map.fromList pairs -getClassId-  :: Map.Map U32.U32 Str.Str-  -> Bimap U32.U32 Str.Str-  -> U32.U32-  -> Maybe U32.U32+getClassId ::+  Map.Map U32.U32 Str.Str ->+  Bimap U32.U32 Str.Str ->+  U32.U32 ->+  Maybe U32.U32 getClassId objectMap_ classMap objectId = do   objectName <- getObjectName objectMap_ objectId   className <- getClassName objectName   lookupR className classMap -makeClassCache-  :: Bimap U32.U32 Str.Str-  -> List.List Cache.Cache-  -> [(Maybe Str.Str, U32.U32, U32.U32, U32.U32)]-makeClassCache classMap caches = fmap-  (\cache ->-    let classId = Cache.classId cache-    in-      ( lookupL classId classMap-      , classId-      , Cache.cacheId cache-      , Cache.parentCacheId cache-      )-  )-  (List.toList caches)+makeClassCache ::+  Bimap U32.U32 Str.Str ->+  List.List Cache.Cache ->+  [(Maybe Str.Str, U32.U32, U32.U32, U32.U32)]+makeClassCache classMap caches =+  fmap+    ( \cache ->+        let classId = Cache.classId cache+         in ( lookupL classId classMap,+              classId,+              Cache.cacheId cache,+              Cache.parentCacheId cache+            )+    )+    (List.toList caches)  makeClassMap :: List.List ClassMapping.ClassMapping -> Bimap U32.U32 Str.Str-makeClassMap classMappings = bimap-  (fmap-    (\classMapping ->-      (ClassMapping.streamId classMapping, ClassMapping.name classMapping)+makeClassMap classMappings =+  bimap+    ( fmap+        ( \classMapping ->+            (ClassMapping.streamId classMapping, ClassMapping.name classMapping)+        )+        (List.toList classMappings)     )-    (List.toList classMappings)-  ) -makeAttributeMap-  :: List.List Cache.Cache -> Map.Map U32.U32 (Map.Map U32.U32 U32.U32)-makeAttributeMap caches = Map.fromList-  (fmap-    (\cache ->-      ( Cache.classId cache-      , Map.fromList-        (fmap-          (\attributeMapping ->-            ( AttributeMapping.streamId attributeMapping-            , AttributeMapping.objectId attributeMapping+makeAttributeMap ::+  List.List Cache.Cache -> Map.Map U32.U32 (Map.Map U32.U32 U32.U32)+makeAttributeMap caches =+  Map.fromList+    ( fmap+        ( \cache ->+            ( Cache.classId cache,+              Map.fromList+                ( fmap+                    ( \attributeMapping ->+                        ( AttributeMapping.streamId attributeMapping,+                          AttributeMapping.objectId attributeMapping+                        )+                    )+                    (List.toList (Cache.attributeMappings cache))+                )             )-          )-          (List.toList (Cache.attributeMappings cache))         )-      )+        (List.toList caches)     )-    (List.toList caches)-  ) -makeShallowParentMap-  :: [(Maybe Str.Str, U32.U32, U32.U32, U32.U32)] -> Map.Map U32.U32 U32.U32-makeShallowParentMap classCache = Map.fromList-  (Maybe.mapMaybe-    (\xs -> case xs of-      [] -> Nothing-      (maybeClassName, classId, _, parentCacheId) : rest -> do-        parentClassId <- getParentClass maybeClassName parentCacheId rest-        pure (classId, parentClassId)+makeShallowParentMap ::+  [(Maybe Str.Str, U32.U32, U32.U32, U32.U32)] -> Map.Map U32.U32 U32.U32+makeShallowParentMap classCache =+  Map.fromList+    ( Maybe.mapMaybe+        ( \xs -> case xs of+            [] -> Nothing+            (maybeClassName, classId, _, parentCacheId) : rest -> do+              parentClassId <- getParentClass maybeClassName parentCacheId rest+              pure (classId, parentClassId)+        )+        (List.tails (reverse classCache))     )-    (List.tails (reverse classCache))-  ) -makeParentMap-  :: [(Maybe Str.Str, U32.U32, U32.U32, U32.U32)] -> Map.Map U32.U32 [U32.U32]+makeParentMap ::+  [(Maybe Str.Str, U32.U32, U32.U32, U32.U32)] -> Map.Map U32.U32 [U32.U32] makeParentMap classCache =   let shallowParentMap = makeShallowParentMap classCache-  in-    Map.mapWithKey-      (\classId _ -> getParentClasses shallowParentMap classId)-      shallowParentMap+   in Map.mapWithKey+        (\classId _ -> getParentClasses shallowParentMap classId)+        shallowParentMap  getParentClasses :: Map.Map U32.U32 U32.U32 -> U32.U32 -> [U32.U32] getParentClasses shallowParentMap classId =@@ -196,51 +199,54 @@     Just parentClassId ->       parentClassId : getParentClasses shallowParentMap parentClassId -getParentClass-  :: Maybe Str.Str-  -> U32.U32-  -> [(Maybe Str.Str, U32.U32, U32.U32, U32.U32)]-  -> Maybe U32.U32+getParentClass ::+  Maybe Str.Str ->+  U32.U32 ->+  [(Maybe Str.Str, U32.U32, U32.U32, U32.U32)] ->+  Maybe U32.U32 getParentClass maybeClassName parentCacheId xs = case maybeClassName of   Nothing -> getParentClassById parentCacheId xs   Just className -> getParentClassByName className parentCacheId xs -getParentClassById-  :: U32.U32 -> [(Maybe Str.Str, U32.U32, U32.U32, U32.U32)] -> Maybe U32.U32+getParentClassById ::+  U32.U32 -> [(Maybe Str.Str, U32.U32, U32.U32, U32.U32)] -> Maybe U32.U32 getParentClassById parentCacheId xs =   case dropWhile (\(_, _, cacheId, _) -> cacheId /= parentCacheId) xs of-    [] -> if parentCacheId == U32.fromWord32 0-      then Nothing-      else getParentClassById-        (U32.fromWord32 (U32.toWord32 parentCacheId - 1))-        xs+    [] ->+      if parentCacheId == U32.fromWord32 0+        then Nothing+        else+          getParentClassById+            (U32.fromWord32 (U32.toWord32 parentCacheId - 1))+            xs     (_, parentClassId, _, _) : _ -> Just parentClassId -getParentClassByName-  :: Str.Str-  -> U32.U32-  -> [(Maybe Str.Str, U32.U32, U32.U32, U32.U32)]-  -> Maybe U32.U32+getParentClassByName ::+  Str.Str ->+  U32.U32 ->+  [(Maybe Str.Str, U32.U32, U32.U32, U32.U32)] ->+  Maybe U32.U32 getParentClassByName className parentCacheId xs =   case Map.lookup (Str.toText className) Data.parentClasses of     Nothing -> getParentClassById parentCacheId xs-    Just parentClassName -> Maybe.maybe-      (getParentClassById parentCacheId xs)-      Just-      (Maybe.listToMaybe-        (fmap-          (\(_, parentClassId, _, _) -> parentClassId)-          (filter-            (\(_, _, cacheId, _) -> cacheId <= parentCacheId)-            (filter-              (\(maybeClassName, _, _, _) ->-                fmap Str.toText maybeClassName == Just parentClassName-              )-              xs+    Just parentClassName ->+      Maybe.maybe+        (getParentClassById parentCacheId xs)+        Just+        ( Maybe.listToMaybe+            ( fmap+                (\(_, parentClassId, _, _) -> parentClassId)+                ( filter+                    (\(_, _, cacheId, _) -> cacheId <= parentCacheId)+                    ( filter+                        ( \(maybeClassName, _, _, _) ->+                            fmap Str.toText maybeClassName == Just parentClassName+                        )+                        xs+                    )+                )             )-          )         )-      )  makeObjectMap :: List.List Str.Str -> Map.Map U32.U32 Str.Str makeObjectMap objects =@@ -250,30 +256,35 @@ getObjectName objectMap_ objectId = Map.lookup objectId objectMap_  getClassName :: Str.Str -> Maybe Str.Str-getClassName rawObjectName = fmap Str.fromText $ Map.lookup-  (Str.toText $ normalizeObjectName rawObjectName)-  Data.objectClasses+getClassName rawObjectName =+  fmap Str.fromText $+    Map.lookup+      (Str.toText $ normalizeObjectName rawObjectName)+      Data.objectClasses  normalizeObjectName :: Str.Str -> Str.Str normalizeObjectName objectName =-  let-    name = Str.toText objectName-    crowdActor = Text.pack "TheWorld:PersistentLevel.CrowdActor_TA"-    crowdManager = Text.pack "TheWorld:PersistentLevel.CrowdManager_TA"-    boostPickup = Text.pack "TheWorld:PersistentLevel.VehiclePickup_Boost_TA"-    mapScoreboard = Text.pack "TheWorld:PersistentLevel.InMapScoreboard_TA"-    breakout = Text.pack "TheWorld:PersistentLevel.BreakOutActor_Platform_TA"-  in if Text.isInfixOf crowdActor name-    then Str.fromText crowdActor-    else if Text.isInfixOf crowdManager name-      then Str.fromText crowdManager-      else if Text.isInfixOf boostPickup name-        then Str.fromText boostPickup-        else if Text.isInfixOf mapScoreboard name-          then Str.fromText mapScoreboard-          else if Text.isInfixOf breakout name-            then Str.fromText breakout-            else objectName+  let name = Str.toText objectName+      crowdActor = Text.pack "TheWorld:PersistentLevel.CrowdActor_TA"+      crowdManager = Text.pack "TheWorld:PersistentLevel.CrowdManager_TA"+      boostPickup = Text.pack "TheWorld:PersistentLevel.VehiclePickup_Boost_TA"+      mapScoreboard = Text.pack "TheWorld:PersistentLevel.InMapScoreboard_TA"+      breakout = Text.pack "TheWorld:PersistentLevel.BreakOutActor_Platform_TA"+   in if Text.isInfixOf crowdActor name+        then Str.fromText crowdActor+        else+          if Text.isInfixOf crowdManager name+            then Str.fromText crowdManager+            else+              if Text.isInfixOf boostPickup name+                then Str.fromText boostPickup+                else+                  if Text.isInfixOf mapScoreboard name+                    then Str.fromText mapScoreboard+                    else+                      if Text.isInfixOf breakout name+                        then Str.fromText breakout+                        else objectName  classHasLocation :: Str.Str -> Bool classHasLocation className =@@ -288,22 +299,22 @@   ((streamId, _), _) <- Map.maxViewWithKey attributeMap   pure (fromIntegral (U32.toWord32 streamId)) -getAttributeName-  :: ClassAttributeMap-  -> Map.Map U32.U32 U32.U32-  -> CompressedWord.CompressedWord-  -> Maybe Str.Str+getAttributeName ::+  ClassAttributeMap ->+  Map.Map U32.U32 U32.U32 ->+  CompressedWord.CompressedWord ->+  Maybe Str.Str getAttributeName classAttributeMap attributeMap streamId = do   let key = U32.fromWord32 (fromIntegral (CompressedWord.value streamId))   attributeId <- Map.lookup key attributeMap   let objectMap_ = objectMap classAttributeMap   Map.lookup attributeId objectMap_ -getAttributeMap-  :: ClassAttributeMap-  -> Map.Map CompressedWord.CompressedWord U32.U32-  -> CompressedWord.CompressedWord-  -> Maybe (Map.Map U32.U32 U32.U32)+getAttributeMap ::+  ClassAttributeMap ->+  Map.Map CompressedWord.CompressedWord U32.U32 ->+  CompressedWord.CompressedWord ->+  Maybe (Map.Map U32.U32 U32.U32) getAttributeMap classAttributeMap actorMap actorId = do   objectId <- Map.lookup actorId actorMap   let objectClassMap_ = objectClassMap classAttributeMap
src/lib/Rattletrap/Type/ClassMapping.hs view
@@ -8,8 +8,8 @@ import qualified Rattletrap.Utility.Json as Json  data ClassMapping = ClassMapping-  { name :: Str.Str-  , streamId :: U32.U32+  { name :: Str.Str,+    streamId :: U32.U32   }   deriving (Eq, Show) @@ -17,17 +17,19 @@   parseJSON = Json.withObject "ClassMapping" $ \object -> do     name <- Json.required object "name"     streamId <- Json.required object "stream_id"-    pure ClassMapping { name, streamId }+    pure ClassMapping {name, streamId}  instance Json.ToJSON ClassMapping where   toJSON x =     Json.object [Json.pair "name" $ name x, Json.pair "stream_id" $ streamId x]  schema :: Schema.Schema-schema = Schema.named "classMapping" $ Schema.object-  [ (Json.pair "name" $ Schema.ref Str.schema, True)-  , (Json.pair "stream_id" $ Schema.ref U32.schema, True)-  ]+schema =+  Schema.named "classMapping" $+    Schema.object+      [ (Json.pair "name" $ Schema.ref Str.schema, True),+        (Json.pair "stream_id" $ Schema.ref U32.schema, True)+      ]  bytePut :: ClassMapping -> BytePut.BytePut bytePut x = Str.bytePut (name x) <> U32.bytePut (streamId x)@@ -36,4 +38,4 @@ byteGet = ByteGet.label "ClassMapping" $ do   name <- ByteGet.label "name" Str.byteGet   streamId <- ByteGet.label "streamId" U32.byteGet-  pure ClassMapping { name, streamId }+  pure ClassMapping {name, streamId}
src/lib/Rattletrap/Type/CompressedWord.hs view
@@ -9,8 +9,8 @@ -- | Although there's no guarantee that these values will not overflow, it's -- exceptionally unlikely. Most 'CompressedWord's are very small. data CompressedWord = CompressedWord-  { limit :: Word-  , value :: Word+  { limit :: Word,+    value :: Word   }   deriving (Eq, Ord, Show) @@ -18,25 +18,26 @@   parseJSON = Json.withObject "CompressedWord" $ \object -> do     limit <- Json.required object "limit"     value <- Json.required object "value"-    pure CompressedWord { limit, value }+    pure CompressedWord {limit, value}  instance Json.ToJSON CompressedWord where   toJSON x =     Json.object [Json.pair "limit" $ limit x, Json.pair "value" $ value x]  schema :: Schema.Schema-schema = Schema.named "compressedWord" $ Schema.object-  [ (Json.pair "limit" $ Json.object [Json.pair "type" "integer"], True)-  , (Json.pair "value" $ Json.object [Json.pair "type" "integer"], True)-  ]+schema =+  Schema.named "compressedWord" $+    Schema.object+      [ (Json.pair "limit" $ Json.object [Json.pair "type" "integer"], True),+        (Json.pair "value" $ Json.object [Json.pair "type" "integer"], True)+      ]  bitPut :: CompressedWord -> BitPut.BitPut bitPut compressedWord =-  let-    limit_ = limit compressedWord-    value_ = value compressedWord-    maxBits = getMaxBits limit_-  in putCompressedWordStep limit_ value_ maxBits 0 0+  let limit_ = limit compressedWord+      value_ = value compressedWord+      maxBits = getMaxBits limit_+   in putCompressedWordStep limit_ value_ maxBits 0 0  putCompressedWordStep :: Word -> Word -> Int -> Int -> Word -> BitPut.BitPut putCompressedWordStep limit_ value_ maxBits position soFar =@@ -46,44 +47,43 @@       if maxBits > 1 && position == maxBits - 1 && soFar + x > limit_         then mempty         else-          let-            bit = Bits.testBit value_ position-            delta = if bit then x else 0-          in BitPut.bool bit <> putCompressedWordStep-            limit_-            value_-            maxBits-            (position + 1)-            (soFar + delta)+          let bit = Bits.testBit value_ position+              delta = if bit then x else 0+           in BitPut.bool bit+                <> putCompressedWordStep+                  limit_+                  value_+                  maxBits+                  (position + 1)+                  (soFar + delta)     else mempty  getMaxBits :: Word -> Int getMaxBits x =-  let-    n :: Int-    n = max 1 (ceiling (logBase (2 :: Double) (fromIntegral (max 1 x))))-  in if x < 1024 && x == 2 ^ n then n + 1 else n+  let n :: Int+      n = max 1 (ceiling (logBase (2 :: Double) (fromIntegral (max 1 x))))+   in if x < 1024 && x == 2 ^ n then n + 1 else n  bitGet :: Word -> BitGet.BitGet CompressedWord bitGet = bitGetNew  bitGetNew :: Word -> BitGet.BitGet CompressedWord bitGetNew limit = do-  value <- if limit < 1-    then pure 0-    else do-      let-        numBits =-          max (0 :: Int)-            . subtract 1-            . ceiling-            . logBase (2 :: Double)-            $ fromIntegral limit-      partial <- BitGet.bits numBits-      let next = partial + Bits.shiftL 1 numBits-      if next > limit-        then pure partial-        else do-          x <- BitGet.bool-          pure $ if x then next else partial-  pure CompressedWord { limit, value }+  value <-+    if limit < 1+      then pure 0+      else do+        let numBits =+              max (0 :: Int)+                . subtract 1+                . ceiling+                . logBase (2 :: Double)+                $ fromIntegral limit+        partial <- BitGet.bits numBits+        let next = partial + Bits.shiftL 1 numBits+        if next > limit+          then pure partial+          else do+            x <- BitGet.bool+            pure $ if x then next else partial+  pure CompressedWord {limit, value}
src/lib/Rattletrap/Type/CompressedWordVector.hs view
@@ -7,9 +7,9 @@ import qualified Rattletrap.Utility.Json as Json  data CompressedWordVector = CompressedWordVector-  { x :: CompressedWord.CompressedWord-  , y :: CompressedWord.CompressedWord-  , z :: CompressedWord.CompressedWord+  { x :: CompressedWord.CompressedWord,+    y :: CompressedWord.CompressedWord,+    z :: CompressedWord.CompressedWord   }   deriving (Eq, Show) @@ -18,18 +18,20 @@     x <- Json.required object "x"     y <- Json.required object "y"     z <- Json.required object "z"-    pure CompressedWordVector { x, y, z }+    pure CompressedWordVector {x, y, z}  instance Json.ToJSON CompressedWordVector where   toJSON a =     Json.object [Json.pair "x" $ x a, Json.pair "y" $ y a, Json.pair "z" $ z a]  schema :: Schema.Schema-schema = Schema.named "compressed-word-vector" $ Schema.object-  [ (Json.pair "x" $ Schema.ref CompressedWord.schema, True)-  , (Json.pair "y" $ Schema.ref CompressedWord.schema, True)-  , (Json.pair "z" $ Schema.ref CompressedWord.schema, True)-  ]+schema =+  Schema.named "compressed-word-vector" $+    Schema.object+      [ (Json.pair "x" $ Schema.ref CompressedWord.schema, True),+        (Json.pair "y" $ Schema.ref CompressedWord.schema, True),+        (Json.pair "z" $ Schema.ref CompressedWord.schema, True)+      ]  bitPut :: CompressedWordVector -> BitPut.BitPut bitPut compressedWordVector =@@ -42,7 +44,7 @@   x <- CompressedWord.bitGet limit   y <- CompressedWord.bitGet limit   z <- CompressedWord.bitGet limit-  pure CompressedWordVector { x, y, z }+  pure CompressedWordVector {x, y, z}  limit :: Word limit = 65536
src/lib/Rattletrap/Type/Content.hs view
@@ -27,41 +27,41 @@  -- | Contains low-level game data about a 'Rattletrap.Replay.Replay'. data ContentWith frames = Content-  { levels :: List.List Str.Str-  -- ^ This typically only has one element, like @stadium_oob_audio_map@.-  , keyframes :: List.List Keyframe.Keyframe-  -- ^ A list of which frames are key frames. Although they aren't necessary-  -- for replay, key frames are frames that replicate every actor. They-  -- typically happen once every 10 seconds.-  , streamSize :: U32.U32-  -- ^ The size of the stream in bytes. This is only really necessary because-  -- the stream has some arbitrary amount of padding at the end.-  , frames :: frames-  -- ^ The actual game data. This is where all the interesting information is.-  , messages :: List.List Message.Message-  -- ^ Debugging messages. In newer replays, this is always empty.-  , marks :: List.List Mark.Mark-  -- ^ Tick marks shown on the scrubber when watching a replay.-  , packages :: List.List Str.Str-  -- ^ A list of @.upk@ files to load, like-  -- @..\\..\\TAGame\\CookedPCConsole\\Stadium_P.upk@.-  , objects :: List.List Str.Str-  -- ^ Objects in the stream. Used for the-  -- 'Rattletrap.Type.ClassAttributeMap.ClassAttributeMap'.-  , names :: List.List Str.Str-  -- ^ It's not clear what these are used for. This list is usually not empty,-  -- but appears unused otherwise.-  , classMappings :: List.List ClassMapping.ClassMapping-  -- ^ A mapping between classes and their ID in the stream. Used for the-  -- 'Rattletrap.Type.ClassAttributeMap.ClassAttributeMap'.-  , caches :: List.List Cache.Cache-  -- ^ A list of classes along with their parent classes and attributes. Used-  -- for the 'Rattletrap.Type.ClassAttributeMap.ClassAttributeMap'.-  , unknown :: [Word.Word8]+  { -- | This typically only has one element, like @stadium_oob_audio_map@.+    levels :: List.List Str.Str,+    -- | A list of which frames are key frames. Although they aren't necessary+    -- for replay, key frames are frames that replicate every actor. They+    -- typically happen once every 10 seconds.+    keyframes :: List.List Keyframe.Keyframe,+    -- | The size of the stream in bytes. This is only really necessary because+    -- the stream has some arbitrary amount of padding at the end.+    streamSize :: U32.U32,+    -- | The actual game data. This is where all the interesting information is.+    frames :: frames,+    -- | Debugging messages. In newer replays, this is always empty.+    messages :: List.List Message.Message,+    -- | Tick marks shown on the scrubber when watching a replay.+    marks :: List.List Mark.Mark,+    -- | A list of @.upk@ files to load, like+    -- @..\\..\\TAGame\\CookedPCConsole\\Stadium_P.upk@.+    packages :: List.List Str.Str,+    -- | Objects in the stream. Used for the+    -- 'Rattletrap.Type.ClassAttributeMap.ClassAttributeMap'.+    objects :: List.List Str.Str,+    -- | It's not clear what these are used for. This list is usually not empty,+    -- but appears unused otherwise.+    names :: List.List Str.Str,+    -- | A mapping between classes and their ID in the stream. Used for the+    -- 'Rattletrap.Type.ClassAttributeMap.ClassAttributeMap'.+    classMappings :: List.List ClassMapping.ClassMapping,+    -- | A list of classes along with their parent classes and attributes. Used+    -- for the 'Rattletrap.Type.ClassAttributeMap.ClassAttributeMap'.+    caches :: List.List Cache.Cache,+    unknown :: [Word.Word8]   }   deriving (Eq, Show) -instance Json.FromJSON frames => Json.FromJSON (ContentWith frames) where+instance (Json.FromJSON frames) => Json.FromJSON (ContentWith frames) where   parseJSON = Json.withObject "Content" $ \object -> do     levels <- Json.required object "levels"     keyframes <- Json.required object "key_frames"@@ -75,71 +75,77 @@     classMappings <- Json.required object "class_mappings"     caches <- Json.required object "caches"     unknown <- Json.required object "unknown"-    pure Content-      { levels-      , keyframes-      , streamSize-      , frames-      , messages-      , marks-      , packages-      , objects-      , names-      , classMappings-      , caches-      , unknown-      }+    pure+      Content+        { levels,+          keyframes,+          streamSize,+          frames,+          messages,+          marks,+          packages,+          objects,+          names,+          classMappings,+          caches,+          unknown+        } -instance Json.ToJSON frames => Json.ToJSON (ContentWith frames) where-  toJSON x = Json.object-    [ Json.pair "levels" $ levels x-    , Json.pair "key_frames" $ keyframes x-    , Json.pair "stream_size" $ streamSize x-    , Json.pair "frames" $ frames x-    , Json.pair "messages" $ messages x-    , Json.pair "marks" $ marks x-    , Json.pair "packages" $ packages x-    , Json.pair "objects" $ objects x-    , Json.pair "names" $ names x-    , Json.pair "class_mappings" $ classMappings x-    , Json.pair "caches" $ caches x-    , Json.pair "unknown" $ unknown x-    ]+instance (Json.ToJSON frames) => Json.ToJSON (ContentWith frames) where+  toJSON x =+    Json.object+      [ Json.pair "levels" $ levels x,+        Json.pair "key_frames" $ keyframes x,+        Json.pair "stream_size" $ streamSize x,+        Json.pair "frames" $ frames x,+        Json.pair "messages" $ messages x,+        Json.pair "marks" $ marks x,+        Json.pair "packages" $ packages x,+        Json.pair "objects" $ objects x,+        Json.pair "names" $ names x,+        Json.pair "class_mappings" $ classMappings x,+        Json.pair "caches" $ caches x,+        Json.pair "unknown" $ unknown x+      ]  schema :: Schema.Schema -> Schema.Schema-schema s = Schema.named "content" $ Schema.object-  [ (Json.pair "levels" . Schema.json $ List.schema Str.schema, True)-  , (Json.pair "key_frames" . Schema.json $ List.schema Keyframe.schema, True)-  , (Json.pair "stream_size" $ Schema.ref U32.schema, True)-  , (Json.pair "frames" $ Schema.json s, True)-  , (Json.pair "messages" . Schema.json $ List.schema Message.schema, True)-  , (Json.pair "marks" . Schema.json $ List.schema Mark.schema, True)-  , (Json.pair "packages" . Schema.json $ List.schema Str.schema, True)-  , (Json.pair "objects" . Schema.json $ List.schema Str.schema, True)-  , (Json.pair "names" . Schema.json $ List.schema Str.schema, True)-  , ( Json.pair "class_mappings" . Schema.json $ List.schema-      ClassMapping.schema-    , True-    )-  , (Json.pair "caches" . Schema.json $ List.schema Cache.schema, True)-  , (Json.pair "unknown" . Schema.json $ Schema.array U8.schema, True)-  ]+schema s =+  Schema.named "content" $+    Schema.object+      [ (Json.pair "levels" . Schema.json $ List.schema Str.schema, True),+        (Json.pair "key_frames" . Schema.json $ List.schema Keyframe.schema, True),+        (Json.pair "stream_size" $ Schema.ref U32.schema, True),+        (Json.pair "frames" $ Schema.json s, True),+        (Json.pair "messages" . Schema.json $ List.schema Message.schema, True),+        (Json.pair "marks" . Schema.json $ List.schema Mark.schema, True),+        (Json.pair "packages" . Schema.json $ List.schema Str.schema, True),+        (Json.pair "objects" . Schema.json $ List.schema Str.schema, True),+        (Json.pair "names" . Schema.json $ List.schema Str.schema, True),+        ( Json.pair "class_mappings" . Schema.json $+            List.schema+              ClassMapping.schema,+          True+        ),+        (Json.pair "caches" . Schema.json $ List.schema Cache.schema, True),+        (Json.pair "unknown" . Schema.json $ Schema.array U8.schema, True)+      ]  empty :: Content-empty = Content-  { levels = List.empty-  , keyframes = List.empty-  , streamSize = U32.fromWord32 0-  , frames = List.empty-  , messages = List.empty-  , marks = List.empty-  , packages = List.empty-  , objects = List.empty-  , names = List.empty-  , classMappings = List.empty-  , caches = List.empty-  , unknown = []-  }+empty =+  Content+    { levels = List.empty,+      keyframes = List.empty,+      streamSize = U32.fromWord32 0,+      frames = List.empty,+      messages = List.empty,+      marks = List.empty,+      packages = List.empty,+      objects = List.empty,+      names = List.empty,+      classMappings = List.empty,+      caches = List.empty,+      unknown = []+    }  bytePut :: Content -> BytePut.BytePut bytePut x =@@ -157,80 +163,85 @@  putFrames :: Content -> BytePut.BytePut putFrames x =-  let-    stream =-      BytePut.toByteString . BitPut.toBytePut . Frame.putFrames $ frames x-    -- This is a little strange. When parsing a binary replay, the stream size-    -- is given before the stream itself. When generating the JSON, the stream-    -- size is included. That allows a bit-for-bit identical binary replay to-    -- be generated from the JSON. However if you modify the JSON before-    -- converting it back into binary, the stream size might be different.-    ---    -- If it was possible to know how much padding the stream required without-    -- carrying it along as extra data on the side, this logic could go away.-    -- Unforunately that isn't currently known. See this issue for details:-    -- <https://github.com/tfausak/rattletrap/issues/171>.-    expectedStreamSize = streamSize x-    actualStreamSize =-      U32.fromWord32 . fromIntegral $ ByteString.length stream-    streamSize_ = U32.fromWord32-      $ max (U32.toWord32 expectedStreamSize) (U32.toWord32 actualStreamSize)-  in U32.bytePut streamSize_-    <> BytePut.byteString (Bytes.padBytes (U32.toWord32 streamSize_) stream)+  let stream =+        BytePut.toByteString . BitPut.toBytePut . Frame.putFrames $ frames x+      -- This is a little strange. When parsing a binary replay, the stream size+      -- is given before the stream itself. When generating the JSON, the stream+      -- size is included. That allows a bit-for-bit identical binary replay to+      -- be generated from the JSON. However if you modify the JSON before+      -- converting it back into binary, the stream size might be different.+      --+      -- If it was possible to know how much padding the stream required without+      -- carrying it along as extra data on the side, this logic could go away.+      -- Unforunately that isn't currently known. See this issue for details:+      -- <https://github.com/tfausak/rattletrap/issues/171>.+      expectedStreamSize = streamSize x+      actualStreamSize =+        U32.fromWord32 . fromIntegral $ ByteString.length stream+      streamSize_ =+        U32.fromWord32 $+          max (U32.toWord32 expectedStreamSize) (U32.toWord32 actualStreamSize)+   in U32.bytePut streamSize_+        <> BytePut.byteString (Bytes.padBytes (U32.toWord32 streamSize_) stream) -byteGet-  :: Maybe Str.Str-  -> Version.Version-  -- ^ Version numbers, usually from 'Rattletrap.Header.getVersion'.-  -> Int-  -- ^ The number of frames in the stream, usually from+byteGet ::+  Maybe Str.Str ->+  -- | Version numbers, usually from 'Rattletrap.Header.getVersion'.+  Version.Version ->+  -- | The number of frames in the stream, usually from   -- 'Rattletrap.Header.getNumFrames'.-  -> Word-  -- ^ The maximum number of channels in the stream, usually from+  Int ->+  -- | The maximum number of channels in the stream, usually from   -- 'Rattletrap.Header.getMaxChannels'.-  -> Maybe Str.Str-  -- ^ 'Rattletrap.Header.getBuildVersion'-  -> ByteGet.ByteGet Content+  Word ->+  -- | 'Rattletrap.Header.getBuildVersion'+  Maybe Str.Str ->+  ByteGet.ByteGet Content byteGet matchType version numFrames maxChannels buildVersion =   ByteGet.label "Content" $ do     levels <- ByteGet.label "levels" $ List.byteGet Str.byteGet     keyframes <- ByteGet.label "keyframes" $ List.byteGet Keyframe.byteGet     streamSize <- ByteGet.label "streamSize" U32.byteGet     stream <--      ByteGet.label "stream" . ByteGet.byteString . fromIntegral $ U32.toWord32-        streamSize+      ByteGet.label "stream" . ByteGet.byteString . fromIntegral $+        U32.toWord32+          streamSize     messages <- ByteGet.label "messages" $ List.byteGet Message.byteGet     marks <- ByteGet.label "marks" $ List.byteGet Mark.byteGet     packages <- ByteGet.label "packages" $ List.byteGet Str.byteGet     objects <- ByteGet.label "objects" $ List.byteGet Str.byteGet     names <- ByteGet.label "names" $ List.byteGet Str.byteGet-    classMappings <- ByteGet.label "classMappings"-      $ List.byteGet ClassMapping.byteGet+    classMappings <-+      ByteGet.label "classMappings" $+        List.byteGet ClassMapping.byteGet     caches <- ByteGet.label "caches" $ List.byteGet Cache.byteGet-    let-      classAttributeMap =-        ClassAttributeMap.make objects classMappings caches names-      getFrames = BitGet.toByteGet $ Frame.decodeFramesBits-        matchType-        version-        buildVersion-        numFrames-        maxChannels-        classAttributeMap+    let classAttributeMap =+          ClassAttributeMap.make objects classMappings caches names+        getFrames =+          BitGet.toByteGet $+            Frame.decodeFramesBits+              matchType+              version+              buildVersion+              numFrames+              maxChannels+              classAttributeMap     frames <- ByteGet.label "frames" $ ByteGet.embed getFrames stream-    unknown <- ByteGet.label "unknown"-      $ fmap LazyByteString.unpack ByteGet.remaining-    pure Content-      { levels-      , keyframes-      , streamSize-      , frames-      , messages-      , marks-      , packages-      , objects-      , names-      , classMappings-      , caches-      , unknown-      }+    unknown <-+      ByteGet.label "unknown" $+        fmap LazyByteString.unpack ByteGet.remaining+    pure+      Content+        { levels,+          keyframes,+          streamSize,+          frames,+          messages,+          marks,+          packages,+          objects,+          names,+          classMappings,+          caches,+          unknown+        }
src/lib/Rattletrap/Type/Dictionary.hs view
@@ -11,55 +11,57 @@ import qualified Rattletrap.Utility.Json as Json  data Dictionary a = Dictionary-  { elements :: List.List (Str.Str, a)-  , lastKey :: Str.Str+  { elements :: List.List (Str.Str, a),+    lastKey :: Str.Str   }   deriving (Eq, Show) -instance Json.FromJSON a => Json.FromJSON (Dictionary a) where+instance (Json.FromJSON a) => Json.FromJSON (Dictionary a) where   parseJSON = Json.withObject "Dictionary" $ \o -> do     keys <- Json.required o "keys"     lastKey_ <- Json.required o "last_key"     value <- Json.required o "value"-    let-      build-        :: MonadFail m-        => Map.Map Text.Text a-        -> Int-        -> [(Int, (Str.Str, a))]-        -> [Text.Text]-        -> m (List.List (Str.Str, a))-      build m i xs ks = case ks of-        [] -> pure . List.fromList . reverse $ fmap snd xs-        k : t -> case Map.lookup k m of-          Nothing -> fail $ "missing required key " <> show k-          Just v -> build m (i + 1) ((i, (Str.fromText k, v)) : xs) t+    let build ::+          (MonadFail m) =>+          Map.Map Text.Text a ->+          Int ->+          [(Int, (Str.Str, a))] ->+          [Text.Text] ->+          m (List.List (Str.Str, a))+        build m i xs ks = case ks of+          [] -> pure . List.fromList . reverse $ fmap snd xs+          k : t -> case Map.lookup k m of+            Nothing -> fail $ "missing required key " <> show k+            Just v -> build m (i + 1) ((i, (Str.fromText k, v)) : xs) t     elements_ <- build value 0 [] keys-    pure Dictionary { elements = elements_, lastKey = lastKey_ }+    pure Dictionary {elements = elements_, lastKey = lastKey_} -instance Json.ToJSON a => Json.ToJSON (Dictionary a) where-  toJSON x = Json.object-    [ Json.pair "keys" . fmap fst . List.toList $ elements x-    , Json.pair "last_key" $ lastKey x-    , Json.pair "value"-    . Map.fromList-    . fmap (Bifunctor.first Str.toText)-    . List.toList-    $ elements x-    ]+instance (Json.ToJSON a) => Json.ToJSON (Dictionary a) where+  toJSON x =+    Json.object+      [ Json.pair "keys" . fmap fst . List.toList $ elements x,+        Json.pair "last_key" $ lastKey x,+        Json.pair "value"+          . Map.fromList+          . fmap (Bifunctor.first Str.toText)+          . List.toList+          $ elements x+      ]  schema :: Schema.Schema -> Schema.Schema schema s =-  Schema.named ("dictionary-" <> Text.unpack (Schema.name s)) $ Schema.object-    [ (Json.pair "keys" . Schema.json $ Schema.array Str.schema, True)-    , (Json.pair "last_key" $ Schema.ref Str.schema, True)-    , ( Json.pair "value" $ Json.object-        [ Json.pair "type" "object"-        , Json.pair "additionalProperties" $ Schema.ref s-        ]-      , True-      )-    ]+  Schema.named ("dictionary-" <> Text.unpack (Schema.name s)) $+    Schema.object+      [ (Json.pair "keys" . Schema.json $ Schema.array Str.schema, True),+        (Json.pair "last_key" $ Schema.ref Str.schema, True),+        ( Json.pair "value" $+            Json.object+              [ Json.pair "type" "object",+                Json.pair "additionalProperties" $ Schema.ref s+              ],+          True+        )+      ]  lookup :: Str.Str -> Dictionary a -> Maybe a lookup k = Prelude.lookup k . List.toList . elements@@ -72,18 +74,20 @@ byteGet :: ByteGet.ByteGet a -> ByteGet.ByteGet (Dictionary a) byteGet = ByteGet.label "Dictionary" . byteGetWith 0 [] -byteGetWith-  :: Int-  -> [(Int, (Str.Str, a))]-  -> ByteGet.ByteGet a-  -> ByteGet.ByteGet (Dictionary a)+byteGetWith ::+  Int ->+  [(Int, (Str.Str, a))] ->+  ByteGet.ByteGet a ->+  ByteGet.ByteGet (Dictionary a) byteGetWith i xs f = do   k <- ByteGet.label ("key (" <> show i <> ")") Str.byteGet   if isNone k-    then pure Dictionary-      { elements = List.fromList . reverse $ fmap snd xs-      , lastKey = k-      }+    then+      pure+        Dictionary+          { elements = List.fromList . reverse $ fmap snd xs,+            lastKey = k+          }     else do       v <- ByteGet.label ("value (" <> Str.toString k <> ")") f       byteGetWith (i + 1) ((i, (k, v)) : xs) f
src/lib/Rattletrap/Type/Frame.hs view
@@ -15,12 +15,12 @@ import qualified Rattletrap.Utility.Json as Json  data Frame = Frame-  { time :: F32.F32-  -- ^ Time in seconds since the beginning of the match.-  , delta :: F32.F32-  -- ^ Time in seconds since the last frame. Usually about 0.03 since there-  -- are 30 frames per second.-  , replications :: List.List Replication.Replication+  { -- | Time in seconds since the beginning of the match.+    time :: F32.F32,+    -- | Time in seconds since the last frame. Usually about 0.03 since there+    -- are 30 frames per second.+    delta :: F32.F32,+    replications :: List.List Replication.Replication   }   deriving (Eq, Show) @@ -29,23 +29,26 @@     time <- Json.required object "time"     delta <- Json.required object "delta"     replications <- Json.required object "replications"-    pure Frame { time, delta, replications }+    pure Frame {time, delta, replications}  instance Json.ToJSON Frame where-  toJSON x = Json.object-    [ Json.pair "time" $ time x-    , Json.pair "delta" $ delta x-    , Json.pair "replications" $ replications x-    ]+  toJSON x =+    Json.object+      [ Json.pair "time" $ time x,+        Json.pair "delta" $ delta x,+        Json.pair "replications" $ replications x+      ]  schema :: Schema.Schema-schema = Schema.named "frame" $ Schema.object-  [ (Json.pair "time" $ Schema.ref F32.schema, True)-  , (Json.pair "delta" $ Schema.ref F32.schema, True)-  , ( Json.pair "replications" . Schema.json $ List.schema Replication.schema-    , True-    )-  ]+schema =+  Schema.named "frame" $+    Schema.object+      [ (Json.pair "time" $ Schema.ref F32.schema, True),+        (Json.pair "delta" $ Schema.ref F32.schema, True),+        ( Json.pair "replications" . Schema.json $ List.schema Replication.schema,+          True+        )+      ]  putFrames :: List.List Frame -> BitPut.BitPut putFrames = foldMap bitPut . List.toList@@ -56,80 +59,82 @@     <> F32.bitPut (delta frame)     <> Replication.putReplications (replications frame) -decodeFramesBits-  :: Maybe Str.Str-  -> Version.Version-  -> Maybe Str.Str-  -> Int-  -> Word-  -> ClassAttributeMap.ClassAttributeMap-  -> BitGet.BitGet (List.List Frame)+decodeFramesBits ::+  Maybe Str.Str ->+  Version.Version ->+  Maybe Str.Str ->+  Int ->+  Word ->+  ClassAttributeMap.ClassAttributeMap ->+  BitGet.BitGet (List.List Frame) decodeFramesBits matchType version buildVersion count limit classes =-  fmap snd $ decodeFramesBitsWith-    matchType-    version-    buildVersion-    count-    limit-    classes-    Map.empty-    0-    []+  fmap snd $+    decodeFramesBitsWith+      matchType+      version+      buildVersion+      count+      limit+      classes+      Map.empty+      0+      [] -decodeFramesBitsWith-  :: Maybe Str.Str-  -> Version.Version-  -> Maybe Str.Str-  -> Int-  -> Word-  -> ClassAttributeMap.ClassAttributeMap-  -> Map.Map CompressedWord.CompressedWord U32.U32-  -> Int-  -> [Frame]-  -> BitGet.BitGet-       ( Map.Map-           CompressedWord.CompressedWord-           U32.U32-       , List.List Frame-       )-decodeFramesBitsWith matchType version buildVersion count limit classes actorMap index frames-  = if index >= count+decodeFramesBitsWith ::+  Maybe Str.Str ->+  Version.Version ->+  Maybe Str.Str ->+  Int ->+  Word ->+  ClassAttributeMap.ClassAttributeMap ->+  Map.Map CompressedWord.CompressedWord U32.U32 ->+  Int ->+  [Frame] ->+  BitGet.BitGet+    ( Map.Map+        CompressedWord.CompressedWord+        U32.U32,+      List.List Frame+    )+decodeFramesBitsWith matchType version buildVersion count limit classes actorMap index frames =+  if index >= count     then pure (actorMap, List.fromList $ reverse frames)     else do       (newActorMap, frame) <--        BitGet.label ("element (" <> show index <> ")")-          $ bitGet matchType version buildVersion limit classes actorMap+        BitGet.label ("element (" <> show index <> ")") $+          bitGet matchType version buildVersion limit classes actorMap       decodeFramesBitsWith-          matchType-          version-          buildVersion-          count-          limit-          classes-          newActorMap-          (index + 1)+        matchType+        version+        buildVersion+        count+        limit+        classes+        newActorMap+        (index + 1)         $ frame-        : frames+          : frames -bitGet-  :: Maybe Str.Str-  -> Version.Version-  -> Maybe Str.Str-  -> Word-  -> ClassAttributeMap.ClassAttributeMap-  -> Map.Map CompressedWord.CompressedWord U32.U32-  -> BitGet.BitGet-       (Map.Map CompressedWord.CompressedWord U32.U32, Frame)+bitGet ::+  Maybe Str.Str ->+  Version.Version ->+  Maybe Str.Str ->+  Word ->+  ClassAttributeMap.ClassAttributeMap ->+  Map.Map CompressedWord.CompressedWord U32.U32 ->+  BitGet.BitGet+    (Map.Map CompressedWord.CompressedWord U32.U32, Frame) bitGet matchType version buildVersion limit classes actorMap =   BitGet.label "Frame" $ do     time <- BitGet.label "time" F32.bitGet     delta <- BitGet.label "delta" F32.bitGet     (newActorMap, replications) <--      BitGet.label "replications" $ Replication.decodeReplicationsBits-        matchType-        version-        buildVersion-        limit-        classes-        actorMap-    pure (newActorMap, Frame { time, delta, replications })+      BitGet.label "replications" $+        Replication.decodeReplicationsBits+          matchType+          version+          buildVersion+          limit+          classes+          actorMap+    pure (newActorMap, Frame {time, delta, replications})
src/lib/Rattletrap/Type/Header.hs view
@@ -12,44 +12,44 @@  -- | Contains high-level metadata about a 'Rattletrap.Replay.Replay'. data Header = Header-  { version :: Version.Version-  , label :: Str.Str-  -- ^ Always @TAGame.Replay_Soccar_TA@.-  , properties :: Dictionary.Dictionary Property.Property-  -- ^ These properties determine how a replay will look in the list of-  -- replays in-game. One element is required for the replay to show up:-  ---  -- - MapName: This is a 'Rattletrap.PropertyValue.NameProperty' with a-  --   case-insensitive map identifier, like @Stadium_P@.-  ---  -- There are many other properties that affect how the replay looks in the-  -- list of replays.-  ---  -- - Date: A 'Rattletrap.PropertyValue.StrProperty' with the format-  --   @YYYY-mm-dd:HH-MM@. Dates are not validated, but the month must be-  --   between 1 and 12 to show up. The hour is shown modulo 12 with AM or PM.-  -- - MatchType: A 'Rattletrap.PropertyValue.NameProperty'. If this is not-  --   one of the expected values, nothing will be shown next to the replay's-  --   map. The expected values are: @Online@, @Offline@, @Private@, and-  --   @Season@.-  -- - NumFrames: This 'Rattletrap.PropertyValue.IntProperty' is used to-  --   calculate the length of the match. There are 30 frames per second,-  --   a typical 5-minute match has about 9,000 frames.-  -- - PrimaryPlayerTeam: This is an 'Rattletrap.PropertyValue.IntProperty'.-  --   It is either 0 (blue) or 1 (orange). Any other value is ignored. If-  --   this would be 0, you don't have to set it at all.-  -- - ReplayName: An optional 'Rattletrap.PropertyValue.StrProperty' with a-  --   user-supplied name for the replay.-  -- - Team0Score: The blue team's score as an-  --   'Rattletrap.PropertyValue.IntProperty'. Can be omitted if the score is-  --   0.-  -- - Team1Score: The orange team's score as an-  --   'Rattletrap.PropertyValue.IntProperty'. Can also be omitted if the-  --   score is 0.-  -- - TeamSize: An 'Rattletrap.PropertyValue.IntProperty' with the number of-  --   players per team. This value is not validated, so you can put absurd-  --   values like 99. To get an "unfair" team size like 1v4, you must set the-  --   bUnfairBots 'Rattletrap.PropertyValue.BoolProperty' to @True@.+  { version :: Version.Version,+    -- | Always @TAGame.Replay_Soccar_TA@.+    label :: Str.Str,+    -- | These properties determine how a replay will look in the list of+    -- replays in-game. One element is required for the replay to show up:+    --+    -- - MapName: This is a 'Rattletrap.PropertyValue.NameProperty' with a+    --   case-insensitive map identifier, like @Stadium_P@.+    --+    -- There are many other properties that affect how the replay looks in the+    -- list of replays.+    --+    -- - Date: A 'Rattletrap.PropertyValue.StrProperty' with the format+    --   @YYYY-mm-dd:HH-MM@. Dates are not validated, but the month must be+    --   between 1 and 12 to show up. The hour is shown modulo 12 with AM or PM.+    -- - MatchType: A 'Rattletrap.PropertyValue.NameProperty'. If this is not+    --   one of the expected values, nothing will be shown next to the replay's+    --   map. The expected values are: @Online@, @Offline@, @Private@, and+    --   @Season@.+    -- - NumFrames: This 'Rattletrap.PropertyValue.IntProperty' is used to+    --   calculate the length of the match. There are 30 frames per second,+    --   a typical 5-minute match has about 9,000 frames.+    -- - PrimaryPlayerTeam: This is an 'Rattletrap.PropertyValue.IntProperty'.+    --   It is either 0 (blue) or 1 (orange). Any other value is ignored. If+    --   this would be 0, you don't have to set it at all.+    -- - ReplayName: An optional 'Rattletrap.PropertyValue.StrProperty' with a+    --   user-supplied name for the replay.+    -- - Team0Score: The blue team's score as an+    --   'Rattletrap.PropertyValue.IntProperty'. Can be omitted if the score is+    --   0.+    -- - Team1Score: The orange team's score as an+    --   'Rattletrap.PropertyValue.IntProperty'. Can also be omitted if the+    --   score is 0.+    -- - TeamSize: An 'Rattletrap.PropertyValue.IntProperty' with the number of+    --   players per team. This value is not validated, so you can put absurd+    --   values like 99. To get an "unfair" team size like 1v4, you must set the+    --   bUnfairBots 'Rattletrap.PropertyValue.BoolProperty' to @True@.+    properties :: Dictionary.Dictionary Property.Property   }   deriving (Eq, Show) @@ -60,46 +60,54 @@     patch <- Json.optional object "patch_version"     label <- Json.required object "label"     properties <- Json.required object "properties"-    pure Header-      { version = Version.Version-        { Version.major-        , Version.minor-        , Version.patch+    pure+      Header+        { version =+            Version.Version+              { Version.major,+                Version.minor,+                Version.patch+              },+          label,+          properties         }-      , label-      , properties-      }  instance Json.ToJSON Header where-  toJSON x = Json.object-    [ Json.pair "engine_version" . Version.major $ version x-    , Json.pair "licensee_version" . Version.minor $ version x-    , Json.pair "patch_version" . Version.patch $ version x-    , Json.pair "label" $ label x-    , Json.pair "properties" $ properties x-    ]+  toJSON x =+    Json.object+      [ Json.pair "engine_version" . Version.major $ version x,+        Json.pair "licensee_version" . Version.minor $ version x,+        Json.pair "patch_version" . Version.patch $ version x,+        Json.pair "label" $ label x,+        Json.pair "properties" $ properties x+      ]  schema :: Schema.Schema-schema = Schema.named "header" $ Schema.object-  [ (Json.pair "engine_version" $ Schema.ref U32.schema, True)-  , (Json.pair "licensee_version" $ Schema.ref U32.schema, True)-  , (Json.pair "patch_version" . Schema.json $ Schema.maybe U32.schema, False)-  , (Json.pair "label" $ Schema.ref Str.schema, True)-  , ( Json.pair "properties" . Schema.json $ Dictionary.schema Property.schema-    , True-    )-  ]+schema =+  Schema.named "header" $+    Schema.object+      [ (Json.pair "engine_version" $ Schema.ref U32.schema, True),+        (Json.pair "licensee_version" $ Schema.ref U32.schema, True),+        (Json.pair "patch_version" . Schema.json $ Schema.maybe U32.schema, False),+        (Json.pair "label" $ Schema.ref Str.schema, True),+        ( Json.pair "properties" . Schema.json $ Dictionary.schema Property.schema,+          True+        )+      ]  bytePut :: Header -> BytePut.BytePut bytePut x =-  Version.bytePut (version x) <> Str.bytePut (label x) <> Dictionary.bytePut-    Property.bytePut-    (properties x)+  Version.bytePut (version x)+    <> Str.bytePut (label x)+    <> Dictionary.bytePut+      Property.bytePut+      (properties x)  byteGet :: ByteGet.ByteGet Header byteGet = ByteGet.label "Header" $ do   version <- ByteGet.label "version" Version.byteGet   label <- ByteGet.label "label" Str.byteGet-  properties <- ByteGet.label "properties"-    $ Dictionary.byteGet Property.byteGet-  pure Header { version, label, properties }+  properties <-+    ByteGet.label "properties" $+      Dictionary.byteGet Property.byteGet+  pure Header {version, label, properties}
src/lib/Rattletrap/Type/I32.hs view
@@ -19,11 +19,13 @@   toJSON = Json.toJSON . toInt32  schema :: Schema.Schema-schema = Schema.named "i32" $ Json.object-  [ Json.pair "type" "integer"-  , Json.pair "minimum" (minBound :: Int.Int32)-  , Json.pair "maximum" (maxBound :: Int.Int32)-  ]+schema =+  Schema.named "i32" $+    Json.object+      [ Json.pair "type" "integer",+        Json.pair "minimum" (minBound :: Int.Int32),+        Json.pair "maximum" (maxBound :: Int.Int32)+      ]  fromInt32 :: Int.Int32 -> I32 fromInt32 = I32
src/lib/Rattletrap/Type/I64.hs view
@@ -16,17 +16,18 @@  instance Json.FromJSON I64 where   parseJSON =-    Json.withText "I64"-      $ either fail (pure . fromInt64)-      . Read.readEither-      . Text.unpack+    Json.withText "I64" $+      either fail (pure . fromInt64)+        . Read.readEither+        . Text.unpack  instance Json.ToJSON I64 where   toJSON = Json.toJSON . show . toInt64  schema :: Schema.Schema-schema = Schema.named "i64"-  $ Json.object [Json.pair "type" "string", Json.pair "pattern" "^-?[0-9]+$"]+schema =+  Schema.named "i64" $+    Json.object [Json.pair "type" "string", Json.pair "pattern" "^-?[0-9]+$"]  fromInt64 :: Int.Int64 -> I64 fromInt64 = I64
src/lib/Rattletrap/Type/I8.hs view
@@ -19,11 +19,13 @@   toJSON = Json.toJSON . toInt8  schema :: Schema.Schema-schema = Schema.named "i8" $ Json.object-  [ Json.pair "type" "integer"-  , Json.pair "minimum" (minBound :: Int.Int8)-  , Json.pair "maximum" (maxBound :: Int.Int8)-  ]+schema =+  Schema.named "i8" $+    Json.object+      [ Json.pair "type" "integer",+        Json.pair "minimum" (minBound :: Int.Int8),+        Json.pair "maximum" (maxBound :: Int.Int8)+      ]  fromInt8 :: Int.Int8 -> I8 fromInt8 = I8
src/lib/Rattletrap/Type/Initialization.hs view
@@ -10,12 +10,12 @@ import qualified Rattletrap.Utility.Monad as Monad  data Initialization = Initialization-  { location :: Maybe Vector.Vector-  -- ^ Not every class has an initial location. See-  -- 'Rattletrap.Data.classesWithLocation'.-  , rotation :: Maybe Int8Vector.Int8Vector-  -- ^ Only classes with location can have rotation, but not every one does.-  -- See 'Rattletrap.Data.classesWithRotation'.+  { -- | Not every class has an initial location. See+    -- 'Rattletrap.Data.classesWithLocation'.+    location :: Maybe Vector.Vector,+    -- | Only classes with location can have rotation, but not every one does.+    -- See 'Rattletrap.Data.classesWithRotation'.+    rotation :: Maybe Int8Vector.Int8Vector   }   deriving (Eq, Show) @@ -23,19 +23,22 @@   parseJSON = Json.withObject "Initialization" $ \object -> do     location <- Json.optional object "location"     rotation <- Json.optional object "rotation"-    pure Initialization { location, rotation }+    pure Initialization {location, rotation}  instance Json.ToJSON Initialization where-  toJSON x = Json.object-    [Json.pair "location" $ location x, Json.pair "rotation" $ rotation x]+  toJSON x =+    Json.object+      [Json.pair "location" $ location x, Json.pair "rotation" $ rotation x]  schema :: Schema.Schema-schema = Schema.named "initialization" $ Schema.object-  [ (Json.pair "location" . Schema.json $ Schema.maybe Vector.schema, False)-  , ( Json.pair "rotation" . Schema.json $ Schema.maybe Int8Vector.schema-    , False-    )-  ]+schema =+  Schema.named "initialization" $+    Schema.object+      [ (Json.pair "location" . Schema.json $ Schema.maybe Vector.schema, False),+        ( Json.pair "rotation" . Schema.json $ Schema.maybe Int8Vector.schema,+          False+        )+      ]  bitPut :: Initialization -> BitPut.BitPut bitPut initialization =@@ -44,8 +47,10 @@  bitGet :: Version.Version -> Bool -> Bool -> BitGet.BitGet Initialization bitGet version hasLocation hasRotation = BitGet.label "Initialization" $ do-  location <- BitGet.label "location"-    $ Monad.whenMaybe hasLocation (Vector.bitGet version)-  rotation <- BitGet.label "rotation"-    $ Monad.whenMaybe hasRotation Int8Vector.bitGet-  pure Initialization { location, rotation }+  location <-+    BitGet.label "location" $+      Monad.whenMaybe hasLocation (Vector.bitGet version)+  rotation <-+    BitGet.label "rotation" $+      Monad.whenMaybe hasRotation Int8Vector.bitGet+  pure Initialization {location, rotation}
src/lib/Rattletrap/Type/Int8Vector.hs view
@@ -8,9 +8,9 @@ import qualified Rattletrap.Utility.Monad as Monad  data Int8Vector = Int8Vector-  { x :: Maybe I8.I8-  , y :: Maybe I8.I8-  , z :: Maybe I8.I8+  { x :: Maybe I8.I8,+    y :: Maybe I8.I8,+    z :: Maybe I8.I8   }   deriving (Eq, Show) @@ -19,18 +19,20 @@     x <- Json.optional object "x"     y <- Json.optional object "y"     z <- Json.optional object "z"-    pure Int8Vector { x, y, z }+    pure Int8Vector {x, y, z}  instance Json.ToJSON Int8Vector where   toJSON a =     Json.object [Json.pair "x" $ x a, Json.pair "y" $ y a, Json.pair "z" $ z a]  schema :: Schema.Schema-schema = Schema.named "int8Vector" $ Schema.object-  [ (Json.pair "x" . Schema.json $ Schema.maybe I8.schema, False)-  , (Json.pair "y" . Schema.json $ Schema.maybe I8.schema, False)-  , (Json.pair "z" . Schema.json $ Schema.maybe I8.schema, False)-  ]+schema =+  Schema.named "int8Vector" $+    Schema.object+      [ (Json.pair "x" . Schema.json $ Schema.maybe I8.schema, False),+        (Json.pair "y" . Schema.json $ Schema.maybe I8.schema, False),+        (Json.pair "z" . Schema.json $ Schema.maybe I8.schema, False)+      ]  bitPut :: Int8Vector -> BitPut.BitPut bitPut int8Vector =@@ -48,7 +50,7 @@   x <- BitGet.label "x" decodeFieldBits   y <- BitGet.label "y" decodeFieldBits   z <- BitGet.label "z" decodeFieldBits-  pure Int8Vector { x, y, z }+  pure Int8Vector {x, y, z}  decodeFieldBits :: BitGet.BitGet (Maybe I8.I8) decodeFieldBits = do
src/lib/Rattletrap/Type/Keyframe.hs view
@@ -8,12 +8,12 @@ import qualified Rattletrap.Utility.Json as Json  data Keyframe = Keyframe-  { time :: F32.F32-  -- ^ When this key frame occurs, in seconds.-  , frame :: U32.U32-  -- ^ The frame number of this key frame, starting from 0.-  , position :: U32.U32-  -- ^ The bit position of this key frame in the stream.+  { -- | When this key frame occurs, in seconds.+    time :: F32.F32,+    -- | The frame number of this key frame, starting from 0.+    frame :: U32.U32,+    -- | The bit position of this key frame in the stream.+    position :: U32.U32   }   deriving (Eq, Show) @@ -22,21 +22,24 @@     time <- Json.required object "time"     frame <- Json.required object "frame"     position <- Json.required object "position"-    pure Keyframe { time, frame, position }+    pure Keyframe {time, frame, position}  instance Json.ToJSON Keyframe where-  toJSON x = Json.object-    [ Json.pair "time" $ time x-    , Json.pair "frame" $ frame x-    , Json.pair "position" $ position x-    ]+  toJSON x =+    Json.object+      [ Json.pair "time" $ time x,+        Json.pair "frame" $ frame x,+        Json.pair "position" $ position x+      ]  schema :: Schema.Schema-schema = Schema.named "keyframe" $ Schema.object-  [ (Json.pair "time" $ Schema.ref F32.schema, True)-  , (Json.pair "frame" $ Schema.ref U32.schema, True)-  , (Json.pair "position" $ Schema.ref U32.schema, True)-  ]+schema =+  Schema.named "keyframe" $+    Schema.object+      [ (Json.pair "time" $ Schema.ref F32.schema, True),+        (Json.pair "frame" $ Schema.ref U32.schema, True),+        (Json.pair "position" $ Schema.ref U32.schema, True)+      ]  bytePut :: Keyframe -> BytePut.BytePut bytePut x =@@ -47,4 +50,4 @@   time <- ByteGet.label "time" F32.byteGet   frame <- ByteGet.label "frame" U32.byteGet   position <- ByteGet.label "position" U32.byteGet-  pure Keyframe { time, frame, position }+  pure Keyframe {time, frame, position}
src/lib/Rattletrap/Type/List.hs view
@@ -11,10 +11,10 @@   = List [a]   deriving (Eq, Show) -instance Json.FromJSON a => Json.FromJSON (List a) where+instance (Json.FromJSON a) => Json.FromJSON (List a) where   parseJSON = fmap fromList . Json.parseJSON -instance Json.ToJSON a => Json.ToJSON (List a) where+instance (Json.ToJSON a) => Json.ToJSON (List a) where   toJSON = Json.toJSON . toList  schema :: Schema.Schema -> Schema.Schema@@ -32,24 +32,24 @@ bytePut :: (a -> BytePut.BytePut) -> List a -> BytePut.BytePut bytePut f x =   let v = toList x-  in (U32.bytePut . U32.fromWord32 . fromIntegral $ length v) <> foldMap f v+   in (U32.bytePut . U32.fromWord32 . fromIntegral $ length v) <> foldMap f v  byteGet :: ByteGet.ByteGet a -> ByteGet.ByteGet (List a) byteGet f = ByteGet.label "List" $ do   size <- ByteGet.label "size" U32.byteGet-  generateM (fromIntegral $ U32.toWord32 size)-    $ \i -> ByteGet.label ("element (" <> show i <> ")") f+  generateM (fromIntegral $ U32.toWord32 size) $+    \i -> ByteGet.label ("element (" <> show i <> ")") f -generateM :: Monad m => Int -> (Int -> m a) -> m (List a)+generateM :: (Monad m) => Int -> (Int -> m a) -> m (List a) generateM n f = fmap fromList $ mapM f [0 .. n - 1] -replicateM :: Monad m => Int -> m a -> m (List a)+replicateM :: (Monad m) => Int -> m a -> m (List a) replicateM n = fmap fromList . Monad.replicateM n -untilM :: Monad m => m (Maybe a) -> m (List a)+untilM :: (Monad m) => m (Maybe a) -> m (List a) untilM f = untilMWith f 0 [] -untilMWith :: Monad m => m (Maybe a) -> Int -> [(Int, a)] -> m (List a)+untilMWith :: (Monad m) => m (Maybe a) -> Int -> [(Int, a)] -> m (List a) untilMWith f i xs = do   m <- f   case m of
src/lib/Rattletrap/Type/Mark.hs view
@@ -8,10 +8,10 @@ import qualified Rattletrap.Utility.Json as Json  data Mark = Mark-  { value :: Str.Str-  -- ^ Which type of mark this is, like @Team0Goal@.-  , frame :: U32.U32-  -- ^ Which frame this mark belongs to, starting from 0.+  { -- | Which type of mark this is, like @Team0Goal@.+    value :: Str.Str,+    -- | Which frame this mark belongs to, starting from 0.+    frame :: U32.U32   }   deriving (Eq, Show) @@ -19,17 +19,19 @@   parseJSON = Json.withObject "Mark" $ \object -> do     value <- Json.required object "value"     frame <- Json.required object "frame"-    pure Mark { value, frame }+    pure Mark {value, frame}  instance Json.ToJSON Mark where   toJSON x =     Json.object [Json.pair "value" $ value x, Json.pair "frame" $ frame x]  schema :: Schema.Schema-schema = Schema.named "mark" $ Schema.object-  [ (Json.pair "value" $ Schema.ref Str.schema, True)-  , (Json.pair "frame" $ Schema.ref U32.schema, True)-  ]+schema =+  Schema.named "mark" $+    Schema.object+      [ (Json.pair "value" $ Schema.ref Str.schema, True),+        (Json.pair "frame" $ Schema.ref U32.schema, True)+      ]  bytePut :: Mark -> BytePut.BytePut bytePut x = Str.bytePut (value x) <> U32.bytePut (frame x)@@ -38,4 +40,4 @@ byteGet = ByteGet.label "Mark" $ do   value <- ByteGet.label "value" Str.byteGet   frame <- ByteGet.label "frame" U32.byteGet-  pure Mark { value, frame }+  pure Mark {value, frame}
src/lib/Rattletrap/Type/Message.hs view
@@ -8,12 +8,12 @@ import qualified Rattletrap.Utility.Json as Json  data Message = Message-  { frame :: U32.U32-  -- ^ Which frame this message belongs to, starting from 0.-  , name :: Str.Str-  -- ^ The primary player's name.-  , value :: Str.Str-  -- ^ The content of the message.+  { -- | Which frame this message belongs to, starting from 0.+    frame :: U32.U32,+    -- | The primary player's name.+    name :: Str.Str,+    -- | The content of the message.+    value :: Str.Str   }   deriving (Eq, Show) @@ -22,21 +22,24 @@     frame <- Json.required object "frame"     name <- Json.required object "name"     value <- Json.required object "value"-    pure Message { frame, name, value }+    pure Message {frame, name, value}  instance Json.ToJSON Message where-  toJSON x = Json.object-    [ Json.pair "frame" $ frame x-    , Json.pair "name" $ name x-    , Json.pair "value" $ value x-    ]+  toJSON x =+    Json.object+      [ Json.pair "frame" $ frame x,+        Json.pair "name" $ name x,+        Json.pair "value" $ value x+      ]  schema :: Schema.Schema-schema = Schema.named "message" $ Schema.object-  [ (Json.pair "frame" $ Schema.ref U32.schema, True)-  , (Json.pair "name" $ Schema.ref Str.schema, True)-  , (Json.pair "value" $ Schema.ref Str.schema, True)-  ]+schema =+  Schema.named "message" $+    Schema.object+      [ (Json.pair "frame" $ Schema.ref U32.schema, True),+        (Json.pair "name" $ Schema.ref Str.schema, True),+        (Json.pair "value" $ Schema.ref Str.schema, True)+      ]  bytePut :: Message -> BytePut.BytePut bytePut x =@@ -47,4 +50,4 @@   frame <- ByteGet.label "frame" U32.byteGet   name <- ByteGet.label "name" Str.byteGet   value <- ByteGet.label "value" Str.byteGet-  pure Message { frame, name, value }+  pure Message {frame, name, value}
src/lib/Rattletrap/Type/Property.hs view
@@ -9,10 +9,10 @@ import qualified Rattletrap.Utility.Json as Json  data Property = Property-  { kind :: Str.Str-  , size :: U64.U64-  -- ^ Not used.-  , value :: PropertyValue.PropertyValue Property+  { kind :: Str.Str,+    -- | Not used.+    size :: U64.U64,+    value :: PropertyValue.PropertyValue Property   }   deriving (Eq, Show) @@ -21,31 +21,36 @@     kind <- Json.required object "kind"     size <- Json.required object "size"     value <- Json.required object "value"-    pure Property { kind, size, value }+    pure Property {kind, size, value}  instance Json.ToJSON Property where-  toJSON x = Json.object-    [ Json.pair "kind" $ kind x-    , Json.pair "size" $ size x-    , Json.pair "value" $ value x-    ]+  toJSON x =+    Json.object+      [ Json.pair "kind" $ kind x,+        Json.pair "size" $ size x,+        Json.pair "value" $ value x+      ]  schema :: Schema.Schema-schema = Schema.named "property" $ Schema.object-  [ (Json.pair "kind" $ Schema.ref Str.schema, True)-  , (Json.pair "size" $ Schema.ref U64.schema, True)-  , (Json.pair "value" . Schema.ref $ PropertyValue.schema schema, True)-  ]+schema =+  Schema.named "property" $+    Schema.object+      [ (Json.pair "kind" $ Schema.ref Str.schema, True),+        (Json.pair "size" $ Schema.ref U64.schema, True),+        (Json.pair "value" . Schema.ref $ PropertyValue.schema schema, True)+      ]  bytePut :: Property -> BytePut.BytePut bytePut x =-  Str.bytePut (kind x) <> U64.bytePut (size x) <> PropertyValue.bytePut-    bytePut-    (value x)+  Str.bytePut (kind x)+    <> U64.bytePut (size x)+    <> PropertyValue.bytePut+      bytePut+      (value x)  byteGet :: ByteGet.ByteGet Property byteGet = ByteGet.label "Property" $ do   kind <- ByteGet.label "kind" Str.byteGet   size <- ByteGet.label "size" U64.byteGet   value <- ByteGet.label "value" $ PropertyValue.byteGet byteGet kind-  pure Property { kind, size, value }+  pure Property {kind, size, value}
src/lib/Rattletrap/Type/Property/Array.hs view
@@ -17,16 +17,17 @@ toList :: Array a -> List.List (Dictionary.Dictionary a) toList (Array x) = x -instance Json.FromJSON a => Json.FromJSON (Array a) where+instance (Json.FromJSON a) => Json.FromJSON (Array a) where   parseJSON = fmap fromList . Json.parseJSON -instance Json.ToJSON a => Json.ToJSON (Array a) where+instance (Json.ToJSON a) => Json.ToJSON (Array a) where   toJSON = Json.toJSON . toList  schema :: Schema.Schema -> Schema.Schema schema s =-  Schema.named "property-array" . Schema.json . List.schema $ Dictionary.schema-    s+  Schema.named "property-array" . Schema.json . List.schema $+    Dictionary.schema+      s  bytePut :: (a -> BytePut.BytePut) -> Array a -> BytePut.BytePut bytePut f = List.bytePut (Dictionary.bytePut f) . toList
src/lib/Rattletrap/Type/Property/Bool.hs view
@@ -1,11 +1,11 @@ module Rattletrap.Type.Property.Bool where -import Prelude hiding (Bool) import qualified Rattletrap.ByteGet as ByteGet import qualified Rattletrap.BytePut as BytePut import qualified Rattletrap.Schema as Schema import qualified Rattletrap.Type.U8 as U8 import qualified Rattletrap.Utility.Json as Json+import Prelude hiding (Bool)  newtype Bool   = Bool U8.U8
src/lib/Rattletrap/Type/Property/Byte.hs view
@@ -8,22 +8,24 @@ import qualified Rattletrap.Utility.Monad as Monad  data Byte = Byte-  { key :: Str.Str-  , value :: Maybe Str.Str+  { key :: Str.Str,+    value :: Maybe Str.Str   }   deriving (Eq, Show)  instance Json.FromJSON Byte where   parseJSON json = do     (key, value) <- Json.parseJSON json-    pure Byte { key, value }+    pure Byte {key, value}  instance Json.ToJSON Byte where   toJSON byte = Json.toJSON (key byte, value byte)  schema :: Schema.Schema-schema = Schema.named "property-byte" $ Schema.tuple-  [Schema.ref Str.schema, Schema.json $ Schema.maybe Str.schema]+schema =+  Schema.named "property-byte" $+    Schema.tuple+      [Schema.ref Str.schema, Schema.json $ Schema.maybe Str.schema]  bytePut :: Byte -> BytePut.BytePut bytePut byte = Str.bytePut (key byte) <> foldMap Str.bytePut (value byte)@@ -31,9 +33,9 @@ byteGet :: ByteGet.ByteGet Byte byteGet = ByteGet.label "Byte" $ do   key <- ByteGet.label "key" Str.byteGet-  let-    isSteam = key == Str.fromString "OnlinePlatform_Steam"-    isPlayStation = key == Str.fromString "OnlinePlatform_PS4"-  value <- ByteGet.label "value"-    $ Monad.whenMaybe (not $ isSteam || isPlayStation) Str.byteGet-  pure Byte { key, value }+  let isSteam = key == Str.fromString "OnlinePlatform_Steam"+      isPlayStation = key == Str.fromString "OnlinePlatform_PS4"+  value <-+    ByteGet.label "value" $+      Monad.whenMaybe (not $ isSteam || isPlayStation) Str.byteGet+  pure Byte {key, value}
src/lib/Rattletrap/Type/Property/Float.hs view
@@ -1,11 +1,11 @@ module Rattletrap.Type.Property.Float where -import Prelude hiding (Float) import qualified Rattletrap.ByteGet as ByteGet import qualified Rattletrap.BytePut as BytePut import qualified Rattletrap.Schema as Schema import qualified Rattletrap.Type.F32 as F32 import qualified Rattletrap.Utility.Json as Json+import Prelude hiding (Float)  newtype Float   = Float F32.F32
src/lib/Rattletrap/Type/Property/Int.hs view
@@ -1,11 +1,11 @@ module Rattletrap.Type.Property.Int where -import Prelude hiding (Int) import qualified Rattletrap.ByteGet as ByteGet import qualified Rattletrap.BytePut as BytePut import qualified Rattletrap.Schema as Schema import qualified Rattletrap.Type.I32 as I32 import qualified Rattletrap.Utility.Json as Json+import Prelude hiding (Int)  newtype Int   = Int I32.I32
src/lib/Rattletrap/Type/PropertyValue.hs view
@@ -17,33 +17,34 @@ import qualified Rattletrap.Utility.Json as Json  data PropertyValue a-  = Array (Property.Array.Array a)-  -- ^ Yes, a list of dictionaries. No, it doesn't make sense. These usually-  -- only have one element.+  = -- | Yes, a list of dictionaries. No, it doesn't make sense. These usually+    -- only have one element.+    Array (Property.Array.Array a)   | Bool Property.Bool.Bool-  | Byte Property.Byte.Byte-  -- ^ This is a strange name for essentially a key-value pair.+  | -- | This is a strange name for essentially a key-value pair.+    Byte Property.Byte.Byte   | Float Property.Float.Float   | Int Property.Int.Int-  | Name Property.Name.Name-  -- ^ It's unclear how exactly this is different than a 'StrProperty'.+  | -- | It's unclear how exactly this is different than a 'StrProperty'.+    Name Property.Name.Name   | QWord Property.QWord.QWord   | Str Property.Str.Str   deriving (Eq, Show) -instance Json.FromJSON a => Json.FromJSON (PropertyValue a) where-  parseJSON = Json.withObject "PropertyValue" $ \object -> Foldable.asum-    [ fmap Array $ Json.required object "array"-    , fmap Bool $ Json.required object "bool"-    , fmap Byte $ Json.required object "byte"-    , fmap Float $ Json.required object "float"-    , fmap Int $ Json.required object "int"-    , fmap Name $ Json.required object "name"-    , fmap QWord $ Json.required object "q_word"-    , fmap Str $ Json.required object "str"-    ]+instance (Json.FromJSON a) => Json.FromJSON (PropertyValue a) where+  parseJSON = Json.withObject "PropertyValue" $ \object ->+    Foldable.asum+      [ fmap Array $ Json.required object "array",+        fmap Bool $ Json.required object "bool",+        fmap Byte $ Json.required object "byte",+        fmap Float $ Json.required object "float",+        fmap Int $ Json.required object "int",+        fmap Name $ Json.required object "name",+        fmap QWord $ Json.required object "q_word",+        fmap Str $ Json.required object "str"+      ] -instance Json.ToJSON a => Json.ToJSON (PropertyValue a) where+instance (Json.ToJSON a) => Json.ToJSON (PropertyValue a) where   toJSON x = case x of     Array y -> Json.object [Json.pair "array" y]     Bool y -> Json.object [Json.pair "bool" y]@@ -55,17 +56,19 @@     Str y -> Json.object [Json.pair "str" y]  schema :: Schema.Schema -> Schema.Schema-schema s = Schema.named "property-value" . Schema.oneOf $ fmap-  (\(k, v) -> Schema.object [(Json.pair k v, True)])-  [ ("array", Schema.ref $ Property.Array.schema s)-  , ("bool", Schema.ref Property.Bool.schema)-  , ("byte", Schema.ref Property.Byte.schema)-  , ("float", Schema.ref Property.Float.schema)-  , ("int", Schema.ref Property.Int.schema)-  , ("name", Schema.ref Property.Name.schema)-  , ("q_word", Schema.ref Property.QWord.schema)-  , ("str", Schema.ref Property.Str.schema)-  ]+schema s =+  Schema.named "property-value" . Schema.oneOf $+    fmap+      (\(k, v) -> Schema.object [(Json.pair k v, True)])+      [ ("array", Schema.ref $ Property.Array.schema s),+        ("bool", Schema.ref Property.Bool.schema),+        ("byte", Schema.ref Property.Byte.schema),+        ("float", Schema.ref Property.Float.schema),+        ("int", Schema.ref Property.Int.schema),+        ("name", Schema.ref Property.Name.schema),+        ("q_word", Schema.ref Property.QWord.schema),+        ("str", Schema.ref Property.Str.schema)+      ]  bytePut :: (a -> BytePut.BytePut) -> PropertyValue a -> BytePut.BytePut bytePut putProperty value = case value of
src/lib/Rattletrap/Type/Quaternion.hs view
@@ -11,10 +11,10 @@ import qualified Rattletrap.Utility.Json as Json  data Quaternion = Quaternion-  { x :: Double-  , y :: Double-  , z :: Double-  , w :: Double+  { x :: Double,+    y :: Double,+    z :: Double,+    w :: Double   }   deriving (Eq, Show) @@ -24,23 +24,26 @@     y <- Json.required object "y"     z <- Json.required object "z"     w <- Json.required object "w"-    pure Quaternion { x, y, z, w }+    pure Quaternion {x, y, z, w}  instance Json.ToJSON Quaternion where-  toJSON a = Json.object-    [ Json.pair "x" $ x a-    , Json.pair "y" $ y a-    , Json.pair "z" $ z a-    , Json.pair "w" $ w a-    ]+  toJSON a =+    Json.object+      [ Json.pair "x" $ x a,+        Json.pair "y" $ y a,+        Json.pair "z" $ z a,+        Json.pair "w" $ w a+      ]  schema :: Schema.Schema-schema = Schema.named "quaternion" $ Schema.object-  [ (Json.pair "x" $ Schema.ref Schema.number, True)-  , (Json.pair "y" $ Schema.ref Schema.number, True)-  , (Json.pair "z" $ Schema.ref Schema.number, True)-  , (Json.pair "w" $ Schema.ref Schema.number, True)-  ]+schema =+  Schema.named "quaternion" $+    Schema.object+      [ (Json.pair "x" $ Schema.ref Schema.number, True),+        (Json.pair "y" $ Schema.ref Schema.number, True),+        (Json.pair "z" $ Schema.ref Schema.number, True),+        (Json.pair "w" $ Schema.ref Schema.number, True)+      ]  data Component   = X@@ -52,12 +55,11 @@ toQuaternion :: Component -> Double -> Double -> Double -> Quaternion toQuaternion component a b c =   let d = toPart a b c-  in-    case component of-      X -> Quaternion d a b c-      Y -> Quaternion a d b c-      Z -> Quaternion a b d c-      W -> Quaternion a b c d+   in case component of+        X -> Quaternion d a b c+        Y -> Quaternion a d b c+        Z -> Quaternion a b d c+        W -> Quaternion a b c d  toPart :: Double -> Double -> Double -> Double toPart a b c = sqrt (1 - (a * a) - (b * b) - (c * c))@@ -82,23 +84,23 @@  maxComponent :: Quaternion -> Component maxComponent quaternion =-  let-    x_ = x quaternion-    y_ = y quaternion-    z_ = z quaternion-    w_ = w quaternion-    parts = [(x_, X), (y_, Y), (z_, Z), (w_, W)]-    biggestPart = maximumOn fst parts-    roundTrip = decompressPart . compressPart-    computedPart = Maybe.fromMaybe-      biggestPart-      (List.find (\(value, _) -> value /= roundTrip value) parts)-  in snd-    (if (biggestPart == computedPart)-        || (abs (fst biggestPart - fst computedPart) > 0.00001)-      then biggestPart-      else computedPart-    )+  let x_ = x quaternion+      y_ = y quaternion+      z_ = z quaternion+      w_ = w quaternion+      parts = [(x_, X), (y_, Y), (z_, Z), (w_, W)]+      biggestPart = maximumOn fst parts+      roundTrip = decompressPart . compressPart+      computedPart =+        Maybe.fromMaybe+          biggestPart+          (List.find (\(value, _) -> value /= roundTrip value) parts)+   in snd+        ( if (biggestPart == computedPart)+            || (abs (fst biggestPart - fst computedPart) > 0.00001)+            then biggestPart+            else computedPart+        )  maximumOn :: (Foldable t, Ord b) => (a -> b) -> t a -> a maximumOn f = List.maximumBy (Ord.comparing f)@@ -118,24 +120,24 @@ bitPut :: Quaternion -> BitPut.BitPut bitPut q =   let c = maxComponent q-  in-    putComponent c <> case c of-      X -> putParts (y q) (z q) (w q)-      Y -> putParts (x q) (z q) (w q)-      Z -> putParts (x q) (y q) (w q)-      W -> putParts (x q) (y q) (z q)+   in putComponent c <> case c of+        X -> putParts (y q) (z q) (w q)+        Y -> putParts (x q) (z q) (w q)+        Z -> putParts (x q) (y q) (w q)+        W -> putParts (x q) (y q) (z q)  putComponent :: Component -> BitPut.BitPut-putComponent component = CompressedWord.bitPut-  (CompressedWord.CompressedWord-    3-    (case component of-      X -> 0-      Y -> 1-      Z -> 2-      W -> 3+putComponent component =+  CompressedWord.bitPut+    ( CompressedWord.CompressedWord+        3+        ( case component of+            X -> 0+            Y -> 1+            Z -> 2+            W -> 3+        )     )-  )  putParts :: Double -> Double -> Double -> BitPut.BitPut putParts a b c = putPart a <> putPart b <> putPart c
src/lib/Rattletrap/Type/RemoteId.hs view
@@ -21,8 +21,8 @@   = PlayStation PlayStation.PlayStation   | PsyNet PsyNet.PsyNet   | QQ QQ.QQ-  | Splitscreen Splitscreen.Splitscreen-  -- ^ Really only 24 bits.+  | -- | Really only 24 bits.+    Splitscreen Splitscreen.Splitscreen   | Steam Steam.Steam   | Switch Switch.Switch   | Xbox Xbox.Xbox@@ -30,16 +30,17 @@   deriving (Eq, Show)  instance Json.FromJSON RemoteId where-  parseJSON = Json.withObject "RemoteId" $ \object -> Foldable.asum-    [ fmap PlayStation $ Json.required object "play_station"-    , fmap PsyNet $ Json.required object "psy_net"-    , fmap QQ $ Json.required object "qq"-    , fmap Splitscreen $ Json.required object "splitscreen"-    , fmap Steam $ Json.required object "steam"-    , fmap Switch $ Json.required object "switch"-    , fmap Xbox $ Json.required object "xbox"-    , fmap Epic $ Json.required object "epic"-    ]+  parseJSON = Json.withObject "RemoteId" $ \object ->+    Foldable.asum+      [ fmap PlayStation $ Json.required object "play_station",+        fmap PsyNet $ Json.required object "psy_net",+        fmap QQ $ Json.required object "qq",+        fmap Splitscreen $ Json.required object "splitscreen",+        fmap Steam $ Json.required object "steam",+        fmap Switch $ Json.required object "switch",+        fmap Xbox $ Json.required object "xbox",+        fmap Epic $ Json.required object "epic"+      ]  instance Json.ToJSON RemoteId where   toJSON x = case x of@@ -53,17 +54,19 @@     Epic y -> Json.object [Json.pair "epic" y]  schema :: Schema.Schema-schema = Schema.named "remote-id" . Schema.oneOf $ fmap-  (\(k, v) -> Schema.object [(Json.pair k v, True)])-  [ ("play_station", Schema.ref PlayStation.schema)-  , ("psy_net", Schema.ref PsyNet.schema)-  , ("qq", Schema.ref QQ.schema)-  , ("splitscreen", Schema.ref Splitscreen.schema)-  , ("steam", Schema.ref Steam.schema)-  , ("switch", Schema.ref Switch.schema)-  , ("xbox", Schema.ref Xbox.schema)-  , ("epic", Schema.ref Epic.schema)-  ]+schema =+  Schema.named "remote-id" . Schema.oneOf $+    fmap+      (\(k, v) -> Schema.object [(Json.pair k v, True)])+      [ ("play_station", Schema.ref PlayStation.schema),+        ("psy_net", Schema.ref PsyNet.schema),+        ("qq", Schema.ref QQ.schema),+        ("splitscreen", Schema.ref Splitscreen.schema),+        ("steam", Schema.ref Steam.schema),+        ("switch", Schema.ref Switch.schema),+        ("xbox", Schema.ref Xbox.schema),+        ("epic", Schema.ref Epic.schema)+      ]  bitPut :: RemoteId -> BitPut.BitPut bitPut remoteId = case remoteId of
src/lib/Rattletrap/Type/RemoteId/PlayStation.hs view
@@ -12,39 +12,41 @@ import qualified Rattletrap.Utility.Json as Json  data PlayStation = PlayStation-  { name :: Text.Text-  , code :: [Word.Word8]+  { name :: Text.Text,+    code :: [Word.Word8]   }   deriving (Eq, Show)  instance Json.FromJSON PlayStation where   parseJSON json = do     (name, code) <- Json.parseJSON json-    pure PlayStation { name, code }+    pure PlayStation {name, code}  instance Json.ToJSON PlayStation where   toJSON x = Json.toJSON (name x, code x)  schema :: Schema.Schema-schema = Schema.named "remote-id-play-station" $ Schema.tuple-  [Schema.ref Schema.string, Schema.json $ Schema.array Schema.number]+schema =+  Schema.named "remote-id-play-station" $+    Schema.tuple+      [Schema.ref Schema.string, Schema.json $ Schema.array Schema.number]  bitPut :: PlayStation -> BitPut.BitPut bitPut x =-  let-    nameBytes = Bytes.padBytes (16 :: Int) . Bytes.encodeLatin1 $ name x-    codeBytes = ByteString.pack $ code x-  in BitPut.byteString nameBytes <> BitPut.byteString codeBytes+  let nameBytes = Bytes.padBytes (16 :: Int) . Bytes.encodeLatin1 $ name x+      codeBytes = ByteString.pack $ code x+   in BitPut.byteString nameBytes <> BitPut.byteString codeBytes  bitGet :: Version.Version -> BitGet.BitGet PlayStation bitGet version = BitGet.label "PlayStation" $ do   name <- BitGet.label "name" getCode   code <- BitGet.label "code" $ getName version-  pure PlayStation { name, code }+  pure PlayStation {name, code}  getCode :: BitGet.BitGet Text.Text-getCode = fmap (Text.dropWhileEnd (== '\x00') . Text.decodeLatin1)-  $ BitGet.byteString 16+getCode =+  fmap (Text.dropWhileEnd (== '\x00') . Text.decodeLatin1) $+    BitGet.byteString 16  getName :: Version.Version -> BitGet.BitGet [Word.Word8] getName version =
src/lib/Rattletrap/Type/RemoteId/PsyNet.hs view
@@ -15,11 +15,10 @@  instance Json.FromJSON PsyNet where   parseJSON = Json.withObject "PsyNet" $ \object -> do-    let-      new = fmap New $ Json.required object "Left"-      old = do-        (a, b, c, d) <- Json.required object "Right"-        pure $ Old a b c d+    let new = fmap New $ Json.required object "Left"+        old = do+          (a, b, c, d) <- Json.required object "Right"+          pure $ Old a b c d     new Applicative.<|> old  instance Json.ToJSON PsyNet where@@ -28,14 +27,16 @@     Old a b c d -> Json.object [Json.pair "Right" (a, b, c, d)]  schema :: Schema.Schema-schema = Schema.named "remote-id-psy-net" $ Schema.oneOf-  [ Schema.object [(Json.pair "Left" $ Schema.ref U64.schema, True)]-  , Schema.object-    [ ( Json.pair "Right" . Schema.tuple . replicate 4 $ Schema.ref U64.schema-      , True-      )-    ]-  ]+schema =+  Schema.named "remote-id-psy-net" $+    Schema.oneOf+      [ Schema.object [(Json.pair "Left" $ Schema.ref U64.schema, True)],+        Schema.object+          [ ( Json.pair "Right" . Schema.tuple . replicate 4 $ Schema.ref U64.schema,+              True+            )+          ]+      ]  bitPut :: PsyNet -> BitPut.BitPut bitPut x = case x of@@ -43,11 +44,13 @@   Old a b c d -> U64.bitPut a <> U64.bitPut b <> U64.bitPut c <> U64.bitPut d  bitGet :: Version.Version -> BitGet.BitGet PsyNet-bitGet version = BitGet.label "PsyNet" $ if Version.atLeast 868 24 10 version-  then BitGet.label "New" $ fmap New U64.bitGet-  else BitGet.label "Old" $ do-    a <- U64.bitGet-    b <- U64.bitGet-    c <- U64.bitGet-    d <- U64.bitGet-    pure $ Old a b c d+bitGet version =+  BitGet.label "PsyNet" $+    if Version.atLeast 868 24 10 version+      then BitGet.label "New" $ fmap New U64.bitGet+      else BitGet.label "Old" $ do+        a <- U64.bitGet+        b <- U64.bitGet+        c <- U64.bitGet+        d <- U64.bitGet+        pure $ Old a b c d
src/lib/Rattletrap/Type/RemoteId/Switch.hs view
@@ -7,25 +7,26 @@ import qualified Rattletrap.Utility.Json as Json  data Switch = Switch-  { a :: U64.U64-  , b :: U64.U64-  , c :: U64.U64-  , d :: U64.U64+  { a :: U64.U64,+    b :: U64.U64,+    c :: U64.U64,+    d :: U64.U64   }   deriving (Eq, Show)  instance Json.FromJSON Switch where   parseJSON json = do     (a, b, c, d) <- Json.parseJSON json-    pure Switch { a, b, c, d }+    pure Switch {a, b, c, d}  instance Json.ToJSON Switch where   toJSON x = Json.toJSON (a x, b x, c x, d x)  schema :: Schema.Schema schema =-  Schema.named "remote-id-switch" . Schema.tuple . replicate 4 $ Schema.ref-    U64.schema+  Schema.named "remote-id-switch" . Schema.tuple . replicate 4 $+    Schema.ref+      U64.schema  bitPut :: Switch -> BitPut.BitPut bitPut x =@@ -37,4 +38,4 @@   b <- U64.bitGet   c <- U64.bitGet   d <- U64.bitGet-  pure Switch { a, b, c, d }+  pure Switch {a, b, c, d}
src/lib/Rattletrap/Type/Replay.hs view
@@ -18,17 +18,17 @@ import qualified Rattletrap.Utility.Json as Json import qualified Rattletrap.Version as Version -type Replay-  = ReplayWith-      (Section.Section Header.Header)-      (Section.Section Content.Content)+type Replay =+  ReplayWith+    (Section.Section Header.Header)+    (Section.Section Content.Content)  -- | A Rocket League replay. data ReplayWith header content = Replay-  { header :: header-  -- ^ This has most of the high-level metadata.-  , content :: content-  -- ^ This has most of the low-level game data.+  { -- | This has most of the high-level metadata.+    header :: header,+    -- | This has most of the low-level game data.+    content :: content   }   deriving (Eq, Show) @@ -36,33 +36,38 @@   parseJSON = Json.withObject "Replay" $ \object -> do     header <- Json.required object "header"     content <- Json.required object "content"-    pure Replay { header, content }+    pure Replay {header, content}  instance (Json.ToJSON h, Json.ToJSON c) => Json.ToJSON (ReplayWith h c) where-  toJSON x = Json.object-    [ Json.pair "$schema" schemaUrl-    , Json.pair "header" $ header x-    , Json.pair "content" $ content x-    ]+  toJSON x =+    Json.object+      [ Json.pair "$schema" schemaUrl,+        Json.pair "header" $ header x,+        Json.pair "content" $ content x+      ]  schema :: Schema.Schema -> Schema.Schema -> Schema.Schema-schema h c = Schema.named "replay" $ Schema.object-  [ (Json.pair "header" $ Schema.ref h, True)-  , (Json.pair "content" $ Schema.ref c, True)-  ]+schema h c =+  Schema.named "replay" $+    Schema.object+      [ (Json.pair "header" $ Schema.ref h, True),+        (Json.pair "content" $ Schema.ref c, True)+      ]  schemaUrl :: String-schemaUrl = mconcat-  [ "https://github.com/tfausak/rattletrap/releases/download/"-  , Version.string-  , "/rattletrap-"-  , Version.string-  , "-schema.json"-  ]+schemaUrl =+  mconcat+    [ "https://github.com/tfausak/rattletrap/releases/download/",+      Version.string,+      "/rattletrap-",+      Version.string,+      "-schema.json"+    ]  bytePut :: Replay -> BytePut.BytePut-bytePut x = Section.bytePut Header.bytePut (header x)-  <> Section.bytePut Content.bytePut (content x)+bytePut x =+  Section.bytePut Header.bytePut (header x)+    <> Section.bytePut Content.bytePut (content x)  byteGet :: Bool -> Bool -> ByteGet.ByteGet Replay byteGet fast skip = ByteGet.label "Replay" $ do@@ -70,28 +75,31 @@     section <-       Section.byteGet skip $ ByteGet.byteString . fromIntegral . U32.toWord32     body <- ByteGet.embed Header.byteGet $ Section.body section-    pure section { Section.body }+    pure section {Section.body}   content <- ByteGet.label "content" $ do     section <-       Section.byteGet skip $ ByteGet.byteString . fromIntegral . U32.toWord32-    body <- if fast-      then pure Content.empty-      else ByteGet.embed (getContent $ Section.body header)-        $ Section.body section-    pure section { Section.body }-  pure Replay { header, content }+    body <-+      if fast+        then pure Content.empty+        else+          ByteGet.embed (getContent $ Section.body header) $+            Section.body section+    pure section {Section.body}+  pure Replay {header, content}  getContent :: Header.Header -> ByteGet.ByteGet Content.Content-getContent h = Content.byteGet-  (getMatchType h)-  (Header.version h)-  (getNumFrames h)-  (getMaxChannels h)-  (getBuildVersion h)+getContent h =+  Content.byteGet+    (getMatchType h)+    (Header.version h)+    (getNumFrames h)+    (getMaxChannels h)+    (getBuildVersion h)  getMatchType :: Header.Header -> Maybe Str.Str getMatchType header = do-  Property.Property { Property.value } <-+  Property.Property {Property.value} <-     Dictionary.lookup (Str.fromString "MatchType") $ Header.properties header   case value of     PropertyValue.Name x -> Just $ Property.Name.toStr x@@ -99,31 +107,28 @@  getNumFrames :: Header.Header -> Int getNumFrames header_ =-  case-      Dictionary.lookup-        (Str.fromString "NumFrames")-        (Header.properties header_)-    of-      Just (Property.Property _ _ (PropertyValue.Int numFrames)) ->-        fromIntegral (I32.toInt32 (Property.Int.toI32 numFrames))-      _ -> 0+  case Dictionary.lookup+    (Str.fromString "NumFrames")+    (Header.properties header_) of+    Just (Property.Property _ _ (PropertyValue.Int numFrames)) ->+      fromIntegral (I32.toInt32 (Property.Int.toI32 numFrames))+    _ -> 0  getMaxChannels :: Header.Header -> Word getMaxChannels header_ =-  subtract 1-    $ case-        Dictionary.lookup-          (Str.fromString "MaxChannels")-          (Header.properties header_)-      of-        Just (Property.Property _ _ (PropertyValue.Int maxChannels)) ->-          fromIntegral (I32.toInt32 (Property.Int.toI32 maxChannels))-        _ -> 1023+  subtract 1 $+    case Dictionary.lookup+      (Str.fromString "MaxChannels")+      (Header.properties header_) of+      Just (Property.Property _ _ (PropertyValue.Int maxChannels)) ->+        fromIntegral (I32.toInt32 (Property.Int.toI32 maxChannels))+      _ -> 1023  getBuildVersion :: Header.Header -> Maybe Str.Str getBuildVersion header = do-  property <- Dictionary.lookup (Str.fromString "BuildVersion")-    $ Header.properties header+  property <-+    Dictionary.lookup (Str.fromString "BuildVersion") $+      Header.properties header   case Property.value property of     PropertyValue.Str x -> Just $ Property.Str.toStr x     _ -> Nothing
src/lib/Rattletrap/Type/Replication.hs view
@@ -14,8 +14,8 @@ import qualified Rattletrap.Utility.Json as Json  data Replication = Replication-  { actorId :: CompressedWord.CompressedWord-  , value :: ReplicationValue.ReplicationValue+  { actorId :: CompressedWord.CompressedWord,+    value :: ReplicationValue.ReplicationValue   }   deriving (Eq, Show) @@ -23,17 +23,19 @@   parseJSON = Json.withObject "Replication" $ \object -> do     actorId <- Json.required object "actor_id"     value <- Json.required object "value"-    pure Replication { actorId, value }+    pure Replication {actorId, value}  instance Json.ToJSON Replication where   toJSON x =     Json.object [Json.pair "actor_id" $ actorId x, Json.pair "value" $ value x]  schema :: Schema.Schema-schema = Schema.named "replication" $ Schema.object-  [ (Json.pair "actor_id" $ Schema.ref CompressedWord.schema, True)-  , (Json.pair "value" $ Schema.ref ReplicationValue.schema, True)-  ]+schema =+  Schema.named "replication" $+    Schema.object+      [ (Json.pair "actor_id" $ Schema.ref CompressedWord.schema, True),+        (Json.pair "value" $ Schema.ref ReplicationValue.schema, True)+      ]  putReplications :: List.List Replication -> BitPut.BitPut putReplications xs =@@ -41,20 +43,21 @@     <> BitPut.bool False  bitPut :: Replication -> BitPut.BitPut-bitPut replication = CompressedWord.bitPut (actorId replication)-  <> ReplicationValue.bitPut (value replication)+bitPut replication =+  CompressedWord.bitPut (actorId replication)+    <> ReplicationValue.bitPut (value replication) -decodeReplicationsBits-  :: Maybe Str.Str-  -> Version.Version-  -> Maybe Str.Str-  -> Word-  -> ClassAttributeMap.ClassAttributeMap-  -> Map.Map CompressedWord.CompressedWord U32.U32-  -> BitGet.BitGet-       ( Map.Map CompressedWord.CompressedWord U32.U32-       , List.List Replication-       )+decodeReplicationsBits ::+  Maybe Str.Str ->+  Version.Version ->+  Maybe Str.Str ->+  Word ->+  ClassAttributeMap.ClassAttributeMap ->+  Map.Map CompressedWord.CompressedWord U32.U32 ->+  BitGet.BitGet+    ( Map.Map CompressedWord.CompressedWord U32.U32,+      List.List Replication+    ) decodeReplicationsBits matchType version buildVersion limit classes actorMap =   decodeReplicationsBitsWith     matchType@@ -66,58 +69,60 @@     0     [] -decodeReplicationsBitsWith-  :: Maybe Str.Str-  -> Version.Version-  -> Maybe Str.Str-  -> Word-  -> ClassAttributeMap.ClassAttributeMap-  -> Map.Map CompressedWord.CompressedWord U32.U32-  -> Int-  -> [Replication]-  -> BitGet.BitGet-       ( Map.Map CompressedWord.CompressedWord U32.U32-       , List.List Replication-       )-decodeReplicationsBitsWith matchType version buildVersion limit classes actorMap index replications-  = do+decodeReplicationsBitsWith ::+  Maybe Str.Str ->+  Version.Version ->+  Maybe Str.Str ->+  Word ->+  ClassAttributeMap.ClassAttributeMap ->+  Map.Map CompressedWord.CompressedWord U32.U32 ->+  Int ->+  [Replication] ->+  BitGet.BitGet+    ( Map.Map CompressedWord.CompressedWord U32.U32,+      List.List Replication+    )+decodeReplicationsBitsWith matchType version buildVersion limit classes actorMap index replications =+  do     hasReplication <- BitGet.bool     if hasReplication       then do         (newActorMap, replication) <--          BitGet.label ("element (" <> show index <> ")")-            $ bitGet matchType version buildVersion limit classes actorMap+          BitGet.label ("element (" <> show index <> ")") $+            bitGet matchType version buildVersion limit classes actorMap         decodeReplicationsBitsWith-            matchType-            version-            buildVersion-            limit-            classes-            newActorMap-            (index + 1)+          matchType+          version+          buildVersion+          limit+          classes+          newActorMap+          (index + 1)           $ replication-          : replications+            : replications       else pure (actorMap, List.fromList $ reverse replications) -bitGet-  :: Maybe Str.Str-  -> Version.Version-  -> Maybe Str.Str-  -> Word-  -> ClassAttributeMap.ClassAttributeMap-  -> Map.Map CompressedWord.CompressedWord U32.U32-  -> BitGet.BitGet-       ( Map.Map CompressedWord.CompressedWord U32.U32-       , Replication-       )+bitGet ::+  Maybe Str.Str ->+  Version.Version ->+  Maybe Str.Str ->+  Word ->+  ClassAttributeMap.ClassAttributeMap ->+  Map.Map CompressedWord.CompressedWord U32.U32 ->+  BitGet.BitGet+    ( Map.Map CompressedWord.CompressedWord U32.U32,+      Replication+    ) bitGet matchType version buildVersion limit classes actorMap =   BitGet.label "Replication" $ do     actorId <- BitGet.label "actorId" $ CompressedWord.bitGet limit-    (newActorMap, value) <- BitGet.label "value" $ ReplicationValue.bitGet-      matchType-      version-      buildVersion-      classes-      actorId-      actorMap-    pure (newActorMap, Replication { actorId, value })+    (newActorMap, value) <-+      BitGet.label "value" $+        ReplicationValue.bitGet+          matchType+          version+          buildVersion+          classes+          actorId+          actorMap+    pure (newActorMap, Replication {actorId, value})
src/lib/Rattletrap/Type/Replication/Spawned.hs view
@@ -17,20 +17,20 @@ import qualified Rattletrap.Utility.Monad as Monad  data Spawned = Spawned-  { flag :: Bool-  -- ^ Unclear what this is.-  , nameIndex :: Maybe U32.U32-  , name :: Maybe Str.Str-  -- ^ Read-only! Changing a replication's name requires editing the-  -- 'nameIndex' and maybe the class attribute map.-  , objectId :: U32.U32-  , objectName :: Str.Str-  -- ^ Read-only! Changing a replication's object requires editing the class-  -- attribute map.-  , className :: Str.Str-  -- ^ Read-only! Changing a replication's class requires editing the class-  -- attribute map.-  , initialization :: Initialization.Initialization+  { -- | Unclear what this is.+    flag :: Bool,+    nameIndex :: Maybe U32.U32,+    -- | Read-only! Changing a replication's name requires editing the+    -- 'nameIndex' and maybe the class attribute map.+    name :: Maybe Str.Str,+    objectId :: U32.U32,+    -- | Read-only! Changing a replication's object requires editing the class+    -- attribute map.+    objectName :: Str.Str,+    -- | Read-only! Changing a replication's class requires editing the class+    -- attribute map.+    className :: Str.Str,+    initialization :: Initialization.Initialization   }   deriving (Eq, Show) @@ -43,37 +43,41 @@     objectName <- Json.required object "object_name"     className <- Json.required object "class_name"     initialization <- Json.required object "initialization"-    pure Spawned-      { flag-      , nameIndex-      , name-      , objectId-      , objectName-      , className-      , initialization-      }+    pure+      Spawned+        { flag,+          nameIndex,+          name,+          objectId,+          objectName,+          className,+          initialization+        }  instance Json.ToJSON Spawned where-  toJSON x = Json.object-    [ Json.pair "flag" $ flag x-    , Json.pair "name_index" $ nameIndex x-    , Json.pair "name" $ name x-    , Json.pair "object_id" $ objectId x-    , Json.pair "object_name" $ objectName x-    , Json.pair "class_name" $ className x-    , Json.pair "initialization" $ initialization x-    ]+  toJSON x =+    Json.object+      [ Json.pair "flag" $ flag x,+        Json.pair "name_index" $ nameIndex x,+        Json.pair "name" $ name x,+        Json.pair "object_id" $ objectId x,+        Json.pair "object_name" $ objectName x,+        Json.pair "class_name" $ className x,+        Json.pair "initialization" $ initialization x+      ]  schema :: Schema.Schema-schema = Schema.named "replication-spawned" $ Schema.object-  [ (Json.pair "flag" $ Schema.ref Schema.boolean, True)-  , (Json.pair "name_index" . Schema.json $ Schema.maybe U32.schema, False)-  , (Json.pair "name" . Schema.json $ Schema.maybe Str.schema, False)-  , (Json.pair "object_id" $ Schema.ref U32.schema, True)-  , (Json.pair "object_name" $ Schema.ref Str.schema, True)-  , (Json.pair "class_name" $ Schema.ref Str.schema, True)-  , (Json.pair "initialization" $ Schema.ref Initialization.schema, True)-  ]+schema =+  Schema.named "replication-spawned" $+    Schema.object+      [ (Json.pair "flag" $ Schema.ref Schema.boolean, True),+        (Json.pair "name_index" . Schema.json $ Schema.maybe U32.schema, False),+        (Json.pair "name" . Schema.json $ Schema.maybe Str.schema, False),+        (Json.pair "object_id" $ Schema.ref U32.schema, True),+        (Json.pair "object_name" $ Schema.ref Str.schema, True),+        (Json.pair "class_name" $ Schema.ref Str.schema, True),+        (Json.pair "initialization" $ Schema.ref Initialization.schema, True)+      ]  bitPut :: Spawned -> BitPut.BitPut bitPut spawnedReplication =@@ -82,78 +86,79 @@     <> U32.bitPut (objectId spawnedReplication)     <> Initialization.bitPut (initialization spawnedReplication) -bitGet-  :: Maybe Str.Str-  -> Version.Version-  -> ClassAttributeMap.ClassAttributeMap-  -> CompressedWord.CompressedWord-  -> Map.Map CompressedWord.CompressedWord U32.U32-  -> BitGet.BitGet-       (Map.Map CompressedWord.CompressedWord U32.U32, Spawned)+bitGet ::+  Maybe Str.Str ->+  Version.Version ->+  ClassAttributeMap.ClassAttributeMap ->+  CompressedWord.CompressedWord ->+  Map.Map CompressedWord.CompressedWord U32.U32 ->+  BitGet.BitGet+    (Map.Map CompressedWord.CompressedWord U32.U32, Spawned) bitGet matchType version classAttributeMap actorId actorMap =   BitGet.label "Spawned" $ do     flag <- BitGet.label "flag" BitGet.bool-    nameIndex <- BitGet.label "nameIndex"-      $ Monad.whenMaybe (hasNameIndex matchType version) U32.bitGet+    nameIndex <-+      BitGet.label "nameIndex" $+        Monad.whenMaybe (hasNameIndex matchType version) U32.bitGet     name <- lookupName classAttributeMap nameIndex     objectId <- BitGet.label "objectId" U32.bitGet     objectName <- lookupObjectName classAttributeMap objectId     className <- lookupClassName objectName     let hasLocation = ClassAttributeMap.classHasLocation className     let hasRotation = ClassAttributeMap.classHasRotation className-    initialization <- BitGet.label "initialization"-      $ Initialization.bitGet version hasLocation hasRotation+    initialization <-+      BitGet.label "initialization" $+        Initialization.bitGet version hasLocation hasRotation     pure-      ( Map.insert actorId objectId actorMap-      , Spawned-        { flag-        , nameIndex-        , name-        , objectId-        , objectName-        , className-        , initialization-        }+      ( Map.insert actorId objectId actorMap,+        Spawned+          { flag,+            nameIndex,+            name,+            objectId,+            objectName,+            className,+            initialization+          }       )  hasNameIndex :: Maybe Str.Str -> Version.Version -> Bool hasNameIndex matchType version =   Version.atLeast 868 20 0 version     || Version.atLeast 868 14 0 version-    && (matchType /= Just (Str.fromString "Lan"))+      && (matchType /= Just (Str.fromString "Lan")) -lookupName-  :: ClassAttributeMap.ClassAttributeMap-  -> Maybe U32.U32-  -> BitGet.BitGet (Maybe Str.Str)+lookupName ::+  ClassAttributeMap.ClassAttributeMap ->+  Maybe U32.U32 ->+  BitGet.BitGet (Maybe Str.Str) lookupName classAttributeMap maybeNameIndex = case maybeNameIndex of   Nothing -> pure Nothing   Just nameIndex_ ->-    case-        ClassAttributeMap.getName-          (ClassAttributeMap.nameMap classAttributeMap)-          nameIndex_-      of-        Nothing ->-          BitGet.throw . UnknownName.UnknownName $ U32.toWord32 nameIndex_-        Just name_ -> pure (Just name_)+    case ClassAttributeMap.getName+      (ClassAttributeMap.nameMap classAttributeMap)+      nameIndex_ of+      Nothing ->+        BitGet.throw . UnknownName.UnknownName $ U32.toWord32 nameIndex_+      Just name_ -> pure (Just name_) -lookupObjectName-  :: ClassAttributeMap.ClassAttributeMap -> U32.U32 -> BitGet.BitGet Str.Str+lookupObjectName ::+  ClassAttributeMap.ClassAttributeMap -> U32.U32 -> BitGet.BitGet Str.Str lookupObjectName classAttributeMap objectId_ =-  case-      ClassAttributeMap.getObjectName-        (ClassAttributeMap.objectMap classAttributeMap)-        objectId_-    of-      Nothing ->-        BitGet.throw . MissingObjectName.MissingObjectName $ U32.toWord32+  case ClassAttributeMap.getObjectName+    (ClassAttributeMap.objectMap classAttributeMap)+    objectId_ of+    Nothing ->+      BitGet.throw . MissingObjectName.MissingObjectName $+        U32.toWord32           objectId_-      Just objectName_ -> pure objectName_+    Just objectName_ -> pure objectName_  lookupClassName :: Str.Str -> BitGet.BitGet Str.Str lookupClassName objectName_ =   case ClassAttributeMap.getClassName objectName_ of-    Nothing -> BitGet.throw . MissingClassName.MissingClassName $ Str.toString-      objectName_+    Nothing ->+      BitGet.throw . MissingClassName.MissingClassName $+        Str.toString+          objectName_     Just className_ -> pure className_
src/lib/Rattletrap/Type/Replication/Updated.hs view
@@ -16,7 +16,8 @@  newtype Updated = Updated   { attributes :: List.List Attribute.Attribute-  } deriving (Eq, Show)+  }+  deriving (Eq, Show)  instance Json.FromJSON Updated where   parseJSON = fmap Updated . Json.parseJSON@@ -25,25 +26,27 @@   toJSON = Json.toJSON . attributes  schema :: Schema.Schema-schema = Schema.named "replication-updated" . Schema.json $ List.schema-  Attribute.schema+schema =+  Schema.named "replication-updated" . Schema.json $+    List.schema+      Attribute.schema  bitPut :: Updated -> BitPut.BitPut bitPut x =   foldMap-      (\y -> BitPut.bool True <> Attribute.bitPut y)-      (List.toList $ attributes x)+    (\y -> BitPut.bool True <> Attribute.bitPut y)+    (List.toList $ attributes x)     <> BitPut.bool False -bitGet-  :: Version.Version-  -> Maybe Str.Str-  -> ClassAttributeMap.ClassAttributeMap-  -> Map.Map CompressedWord.CompressedWord U32.U32-  -> CompressedWord.CompressedWord-  -> BitGet.BitGet Updated+bitGet ::+  Version.Version ->+  Maybe Str.Str ->+  ClassAttributeMap.ClassAttributeMap ->+  Map.Map CompressedWord.CompressedWord U32.U32 ->+  CompressedWord.CompressedWord ->+  BitGet.BitGet Updated bitGet version buildVersion classes actors actor =   BitGet.label "Updated" . fmap Updated . List.untilM $ do     p <- BitGet.bool-    Monad.whenMaybe p-      $ Attribute.bitGet version buildVersion classes actors actor+    Monad.whenMaybe p $+      Attribute.bitGet version buildVersion classes actors actor
src/lib/Rattletrap/Type/ReplicationValue.hs view
@@ -16,20 +16,21 @@ import qualified Rattletrap.Utility.Json as Json  data ReplicationValue-  = Spawned Spawned.Spawned-  -- ^ Creates a new actor.-  | Updated Updated.Updated-  -- ^ Updates an existing actor.-  | Destroyed Destroyed.Destroyed-  -- ^ Destroys an existing actor.+  = -- | Creates a new actor.+    Spawned Spawned.Spawned+  | -- | Updates an existing actor.+    Updated Updated.Updated+  | -- | Destroys an existing actor.+    Destroyed Destroyed.Destroyed   deriving (Eq, Show)  instance Json.FromJSON ReplicationValue where-  parseJSON = Json.withObject "ReplicationValue" $ \object -> Foldable.asum-    [ fmap Spawned $ Json.required object "spawned"-    , fmap Updated $ Json.required object "updated"-    , fmap Destroyed $ Json.required object "destroyed"-    ]+  parseJSON = Json.withObject "ReplicationValue" $ \object ->+    Foldable.asum+      [ fmap Spawned $ Json.required object "spawned",+        fmap Updated $ Json.required object "updated",+        fmap Destroyed $ Json.required object "destroyed"+      ]  instance Json.ToJSON ReplicationValue where   toJSON x = case x of@@ -38,12 +39,14 @@     Destroyed y -> Json.object [Json.pair "destroyed" y]  schema :: Schema.Schema-schema = Schema.named "replicationValue" . Schema.oneOf $ fmap-  (\(k, v) -> Schema.object [(Json.pair k $ Schema.ref v, True)])-  [ ("spawned", Spawned.schema)-  , ("updated", Updated.schema)-  , ("destroyed", Destroyed.schema)-  ]+schema =+  Schema.named "replicationValue" . Schema.oneOf $+    fmap+      (\(k, v) -> Schema.object [(Json.pair k $ Schema.ref v, True)])+      [ ("spawned", Spawned.schema),+        ("updated", Updated.schema),+        ("destroyed", Destroyed.schema)+      ]  bitPut :: ReplicationValue -> BitPut.BitPut bitPut value = case value of@@ -51,17 +54,17 @@   Updated x -> BitPut.bool True <> BitPut.bool False <> Updated.bitPut x   Destroyed x -> BitPut.bool False <> Destroyed.bitPut x -bitGet-  :: Maybe Str.Str-  -> Version.Version-  -> Maybe Str.Str-  -> ClassAttributeMap.ClassAttributeMap-  -> CompressedWord.CompressedWord-  -> Map.Map CompressedWord.CompressedWord U32.U32-  -> BitGet.BitGet-       ( Map.Map CompressedWord.CompressedWord U32.U32-       , ReplicationValue-       )+bitGet ::+  Maybe Str.Str ->+  Version.Version ->+  Maybe Str.Str ->+  ClassAttributeMap.ClassAttributeMap ->+  CompressedWord.CompressedWord ->+  Map.Map CompressedWord.CompressedWord U32.U32 ->+  BitGet.BitGet+    ( Map.Map CompressedWord.CompressedWord U32.U32,+      ReplicationValue+    ) bitGet matchType version buildVersion classAttributeMap actorId actorMap =   BitGet.label "ReplicationValue" $ do     isOpen <- BitGet.bool@@ -70,20 +73,22 @@         isNew <- BitGet.bool         if isNew           then do-            (newActorMap, spawned) <- Spawned.bitGet-              matchType-              version-              classAttributeMap-              actorId-              actorMap+            (newActorMap, spawned) <-+              Spawned.bitGet+                matchType+                version+                classAttributeMap+                actorId+                actorMap             pure (newActorMap, Spawned spawned)           else do-            updated <- Updated.bitGet-              version-              buildVersion-              classAttributeMap-              actorMap-              actorId+            updated <-+              Updated.bitGet+                version+                buildVersion+                classAttributeMap+                actorMap+                actorId             pure (actorMap, Updated updated)       else do         destroyed <- Destroyed.bitGet
src/lib/Rattletrap/Type/Rotation.hs view
@@ -15,10 +15,11 @@   deriving (Eq, Show)  instance Json.FromJSON Rotation where-  parseJSON = Json.withObject "Rotation" $ \object -> Foldable.asum-    [ fmap CompressedWordVector $ Json.required object "compressed_word_vector"-    , fmap Quaternion $ Json.required object "quaternion"-    ]+  parseJSON = Json.withObject "Rotation" $ \object ->+    Foldable.asum+      [ fmap CompressedWordVector $ Json.required object "compressed_word_vector",+        fmap Quaternion $ Json.required object "quaternion"+      ]  instance Json.ToJSON Rotation where   toJSON x = case x of@@ -27,11 +28,13 @@     Quaternion y -> Json.object [Json.pair "quaternion" y]  schema :: Schema.Schema-schema = Schema.named "rotation" . Schema.oneOf $ fmap-  (\(k, v) -> Schema.object [(Json.pair k $ Schema.ref v, True)])-  [ ("compressed_word_vector", CompressedWordVector.schema)-  , ("quaternion", Quaternion.schema)-  ]+schema =+  Schema.named "rotation" . Schema.oneOf $+    fmap+      (\(k, v) -> Schema.object [(Json.pair k $ Schema.ref v, True)])+      [ ("compressed_word_vector", CompressedWordVector.schema),+        ("quaternion", Quaternion.schema)+      ]  bitPut :: Rotation -> BitPut.BitPut bitPut r = case r of@@ -39,6 +42,7 @@   Quaternion q -> Quaternion.bitPut q  bitGet :: Version.Version -> BitGet.BitGet Rotation-bitGet version = if Version.atLeast 868 22 7 version-  then fmap Quaternion Quaternion.bitGet-  else fmap CompressedWordVector CompressedWordVector.bitGet+bitGet version =+  if Version.atLeast 868 22 7 version+    then fmap Quaternion Quaternion.bitGet+    else fmap CompressedWordVector CompressedWordVector.bitGet
src/lib/Rattletrap/Type/Section.hs view
@@ -16,81 +16,81 @@ -- bunch of data (the body). This interface is provided so that you don't have -- to think about the size and CRC. data Section a = Section-  { size :: U32.U32-  -- ^ read only-  , crc :: U32.U32-  -- ^ read only-  , body :: a-  -- ^ The actual content in the section.+  { -- | read only+    size :: U32.U32,+    -- | read only+    crc :: U32.U32,+    -- | The actual content in the section.+    body :: a   }   deriving (Eq, Show) -instance Json.FromJSON a => Json.FromJSON (Section a) where+instance (Json.FromJSON a) => Json.FromJSON (Section a) where   parseJSON = Json.withObject "Section" $ \object -> do     size <- Json.required object "size"     crc <- Json.required object "crc"     body <- Json.required object "body"-    pure Section { size, crc, body }+    pure Section {size, crc, body} -instance Json.ToJSON a => Json.ToJSON (Section a) where-  toJSON x = Json.object-    [ Json.pair "size" $ size x-    , Json.pair "crc" $ crc x-    , Json.pair "body" $ body x-    ]+instance (Json.ToJSON a) => Json.ToJSON (Section a) where+  toJSON x =+    Json.object+      [ Json.pair "size" $ size x,+        Json.pair "crc" $ crc x,+        Json.pair "body" $ body x+      ]  schema :: Schema.Schema -> Schema.Schema schema s =-  Schema.named ("section-" <> Text.unpack (Schema.name s)) $ Schema.object-    [ (Json.pair "size" $ Schema.ref U32.schema, True)-    , (Json.pair "crc" $ Schema.ref U32.schema, True)-    , (Json.pair "body" $ Schema.ref s, True)-    ]+  Schema.named ("section-" <> Text.unpack (Schema.name s)) $+    Schema.object+      [ (Json.pair "size" $ Schema.ref U32.schema, True),+        (Json.pair "crc" $ Schema.ref U32.schema, True),+        (Json.pair "body" $ Schema.ref s, True)+      ]  create :: (a -> BytePut.BytePut) -> a -> Section a create encode body_ =   let bytes = BytePut.toByteString $ encode body_-  in-    Section-      { size = U32.fromWord32 . fromIntegral $ ByteString.length bytes-      , crc = U32.fromWord32 $ Crc.compute bytes-      , body = body_-      }+   in Section+        { size = U32.fromWord32 . fromIntegral $ ByteString.length bytes,+          crc = U32.fromWord32 $ Crc.compute bytes,+          body = body_+        }  -- | Given a way to put the 'body', puts a section. This will also put -- the size and CRC. bytePut :: (a -> BytePut.BytePut) -> Section a -> BytePut.BytePut bytePut putBody section =-  let-    rawBody = BytePut.toByteString . putBody $ body section-    size_ = ByteString.length rawBody-    crc_ = Crc.compute rawBody-  in-    U32.bytePut (U32.fromWord32 (fromIntegral size_))-    <> U32.bytePut (U32.fromWord32 crc_)-    <> BytePut.byteString rawBody+  let rawBody = BytePut.toByteString . putBody $ body section+      size_ = ByteString.length rawBody+      crc_ = Crc.compute rawBody+   in U32.bytePut (U32.fromWord32 (fromIntegral size_))+        <> U32.bytePut (U32.fromWord32 crc_)+        <> BytePut.byteString rawBody -byteGet-  :: Bool -> (U32.U32 -> ByteGet.ByteGet a) -> ByteGet.ByteGet (Section a)+byteGet ::+  Bool -> (U32.U32 -> ByteGet.ByteGet a) -> ByteGet.ByteGet (Section a) byteGet skip getBody = ByteGet.label "Section" $ do   size <- ByteGet.label "size" U32.byteGet   crc <- ByteGet.label "crc" U32.byteGet   body <- ByteGet.label "body" $ do     rawBody <- ByteGet.byteString . fromIntegral $ U32.toWord32 size     Monad.unless skip $ do-      let-        expected = U32.toWord32 crc-        actual = Crc.compute rawBody-      Monad.when (actual /= expected) . ByteGet.throw $ CrcMismatch.CrcMismatch-        expected-        actual+      let expected = U32.toWord32 crc+          actual = Crc.compute rawBody+      Monad.when (actual /= expected) . ByteGet.throw $+        CrcMismatch.CrcMismatch+          expected+          actual     ByteGet.embed (getBody size) rawBody-  pure Section { size, crc, body }+  pure Section {size, crc, body}  crcMessage :: U32.U32 -> U32.U32 -> String-crcMessage actual expected = unwords-  [ "[RT10] actual CRC"-  , show actual-  , "does not match expected CRC"-  , show expected-  ]+crcMessage actual expected =+  unwords+    [ "[RT10] actual CRC",+      show actual,+      "does not match expected CRC",+      show expected+    ]
src/lib/Rattletrap/Type/Str.hs view
@@ -42,31 +42,32 @@  bytePut :: Str -> BytePut.BytePut bytePut text =-  let-    size = getTextSize text-    encode = getTextEncoder size-  in I32.bytePut size <> (BytePut.byteString . encode . addNull $ toText text)+  let size = getTextSize text+      encode = getTextEncoder size+   in I32.bytePut size <> (BytePut.byteString . encode . addNull $ toText text)  bitPut :: Str -> BitPut.BitPut bitPut = BitPut.fromBytePut . bytePut  getTextSize :: Str -> I32.I32 getTextSize text =-  let-    value = toText text-    scale = if Text.all Char.isLatin1 value then 1 else -1 :: Int.Int32-    rawSize = if Text.null value-      then 0-      else fromIntegral (Text.length value) + 1 :: Int.Int32-    size = if value == Text.pack "\x00\x00\x00None"-      then 0x05000000-      else scale * rawSize :: Int.Int32-  in I32.fromInt32 size+  let value = toText text+      scale = if Text.all Char.isLatin1 value then 1 else -1 :: Int.Int32+      rawSize =+        if Text.null value+          then 0+          else fromIntegral (Text.length value) + 1 :: Int.Int32+      size =+        if value == Text.pack "\x00\x00\x00None"+          then 0x05000000+          else scale * rawSize :: Int.Int32+   in I32.fromInt32 size  getTextEncoder :: I32.I32 -> Text.Text -> ByteString.ByteString-getTextEncoder size text = if I32.toInt32 size < 0-  then Text.encodeUtf16LE text-  else Bytes.encodeLatin1 text+getTextEncoder size text =+  if I32.toInt32 size < 0+    then Text.encodeUtf16LE text+    else Bytes.encodeLatin1 text  addNull :: Text.Text -> Text.Text addNull text = if Text.null text then text else Text.snoc text '\x00'@@ -83,18 +84,18 @@   bytes <- BitGet.byteString (normalizeTextSize rawSize)   pure (fromText (dropNull (getTextDecoder rawSize bytes))) -normalizeTextSize :: Integral a => I32.I32 -> a+normalizeTextSize :: (Integral a) => I32.I32 -> a normalizeTextSize size = case I32.toInt32 size of   0x05000000 -> 8   x -> if x < 0 then (-2 * fromIntegral x) else fromIntegral x  getTextDecoder :: I32.I32 -> ByteString.ByteString -> Text.Text getTextDecoder size bytes =-  let-    decode = if I32.toInt32 size < 0-      then Text.decodeUtf16LEWith Text.lenientDecode-      else Text.decodeLatin1-  in decode bytes+  let decode =+        if I32.toInt32 size < 0+          then Text.decodeUtf16LEWith Text.lenientDecode+          else Text.decodeLatin1+   in decode bytes  dropNull :: Text.Text -> Text.Text dropNull = Text.dropWhileEnd (== '\x00')
src/lib/Rattletrap/Type/U32.hs view
@@ -19,11 +19,13 @@   toJSON = Json.toJSON . toWord32  schema :: Schema.Schema-schema = Schema.named "u32" $ Json.object-  [ Json.pair "type" "integer"-  , Json.pair "minimum" (minBound :: Word.Word32)-  , Json.pair "maximum" (maxBound :: Word.Word32)-  ]+schema =+  Schema.named "u32" $+    Json.object+      [ Json.pair "type" "integer",+        Json.pair "minimum" (minBound :: Word.Word32),+        Json.pair "maximum" (maxBound :: Word.Word32)+      ]  fromWord32 :: Word.Word32 -> U32 fromWord32 = U32
src/lib/Rattletrap/Type/U64.hs view
@@ -16,17 +16,18 @@  instance Json.FromJSON U64 where   parseJSON =-    Json.withText "U64"-      $ either fail (pure . fromWord64)-      . Read.readEither-      . Text.unpack+    Json.withText "U64" $+      either fail (pure . fromWord64)+        . Read.readEither+        . Text.unpack  instance Json.ToJSON U64 where   toJSON = Json.toJSON . show . toWord64  schema :: Schema.Schema-schema = Schema.named "u64"-  $ Json.object [Json.pair "type" "string", Json.pair "pattern" "^[0-9]+$"]+schema =+  Schema.named "u64" $+    Json.object [Json.pair "type" "string", Json.pair "pattern" "^[0-9]+$"]  fromWord64 :: Word.Word64 -> U64 fromWord64 = U64
src/lib/Rattletrap/Type/U8.hs view
@@ -19,11 +19,13 @@   toJSON = Json.toJSON . toWord8  schema :: Schema.Schema-schema = Schema.named "u8" $ Json.object-  [ Json.pair "type" "integer"-  , Json.pair "minimum" (minBound :: Word.Word8)-  , Json.pair "maximum" (maxBound :: Word.Word8)-  ]+schema =+  Schema.named "u8" $+    Json.object+      [ Json.pair "type" "integer",+        Json.pair "minimum" (minBound :: Word.Word8),+        Json.pair "maximum" (maxBound :: Word.Word8)+      ]  fromWord8 :: Word.Word8 -> U8 fromWord8 = U8
src/lib/Rattletrap/Type/Vector.hs view
@@ -8,18 +8,18 @@ import qualified Rattletrap.Utility.Json as Json  data Vector = Vector-  { size :: CompressedWord.CompressedWord-  , bias :: Word-  -- ^ This field is guaranteed to be small. In other words, it won't overflow.-  -- It's stored as a regular 'Word' rather than something more precise like a-  -- 'Word8' because it just gets passed to a functions that expect 'Word's.-  -- There's no reason to do a bunch of conversions.-  , x :: Int-  -- ^ See 'bias'.-  , y :: Int-  -- ^ See 'bias'.-  , z :: Int-  -- ^ See 'bias'.+  { size :: CompressedWord.CompressedWord,+    -- | This field is guaranteed to be small. In other words, it won't overflow.+    -- It's stored as a regular 'Word' rather than something more precise like a+    -- 'Word8' because it just gets passed to a functions that expect 'Word's.+    -- There's no reason to do a bunch of conversions.+    bias :: Word,+    -- | See 'bias'.+    x :: Int,+    -- | See 'bias'.+    y :: Int,+    -- | See 'bias'.+    z :: Int   }   deriving (Eq, Show) @@ -30,54 +30,54 @@     x <- Json.required object "x"     y <- Json.required object "y"     z <- Json.required object "z"-    pure Vector { size, bias, x, y, z }+    pure Vector {size, bias, x, y, z}  instance Json.ToJSON Vector where-  toJSON a = Json.object-    [ Json.pair "size" $ size a-    , Json.pair "bias" $ bias a-    , Json.pair "x" $ x a-    , Json.pair "y" $ y a-    , Json.pair "z" $ z a-    ]+  toJSON a =+    Json.object+      [ Json.pair "size" $ size a,+        Json.pair "bias" $ bias a,+        Json.pair "x" $ x a,+        Json.pair "y" $ y a,+        Json.pair "z" $ z a+      ]  schema :: Schema.Schema-schema = Schema.named "vector" $ Schema.object-  [ (Json.pair "size" $ Schema.ref CompressedWord.schema, True)-  , (Json.pair "bias" $ Schema.ref Schema.integer, True)-  , (Json.pair "x" $ Schema.ref Schema.integer, True)-  , (Json.pair "y" $ Schema.ref Schema.integer, True)-  , (Json.pair "z" $ Schema.ref Schema.integer, True)-  ]+schema =+  Schema.named "vector" $+    Schema.object+      [ (Json.pair "size" $ Schema.ref CompressedWord.schema, True),+        (Json.pair "bias" $ Schema.ref Schema.integer, True),+        (Json.pair "x" $ Schema.ref Schema.integer, True),+        (Json.pair "y" $ Schema.ref Schema.integer, True),+        (Json.pair "z" $ Schema.ref Schema.integer, True)+      ]  bitPut :: Vector -> BitPut.BitPut bitPut vector =-  let-    bitSize =-      round (logBase (2 :: Float) (fromIntegral (bias vector))) - 1 :: Word-    dx = fromIntegral (x vector + fromIntegral (bias vector)) :: Word-    dy = fromIntegral (y vector + fromIntegral (bias vector)) :: Word-    dz = fromIntegral (z vector + fromIntegral (bias vector)) :: Word-    limit = 2 ^ (bitSize + 2) :: Word-  in-    CompressedWord.bitPut (size vector)-    <> CompressedWord.bitPut (CompressedWord.CompressedWord limit dx)-    <> CompressedWord.bitPut (CompressedWord.CompressedWord limit dy)-    <> CompressedWord.bitPut (CompressedWord.CompressedWord limit dz)+  let bitSize =+        round (logBase (2 :: Float) (fromIntegral (bias vector))) - 1 :: Word+      dx = fromIntegral (x vector + fromIntegral (bias vector)) :: Word+      dy = fromIntegral (y vector + fromIntegral (bias vector)) :: Word+      dz = fromIntegral (z vector + fromIntegral (bias vector)) :: Word+      limit = 2 ^ (bitSize + 2) :: Word+   in CompressedWord.bitPut (size vector)+        <> CompressedWord.bitPut (CompressedWord.CompressedWord limit dx)+        <> CompressedWord.bitPut (CompressedWord.CompressedWord limit dy)+        <> CompressedWord.bitPut (CompressedWord.CompressedWord limit dz)  bitGet :: Version.Version -> BitGet.BitGet Vector bitGet version = BitGet.label "Vector" $ do   size <-     BitGet.label "size"-    . CompressedWord.bitGet-    $ if Version.atLeast 868 22 7 version then 21 else 19-  let-    limit = getLimit size-    bias = getBias size+      . CompressedWord.bitGet+      $ if Version.atLeast 868 22 7 version then 21 else 19+  let limit = getLimit size+      bias = getBias size   x <- BitGet.label "x" $ getPart limit bias   y <- BitGet.label "y" $ getPart limit bias   z <- BitGet.label "z" $ getPart limit bias-  pure Vector { size, bias, x, y, z }+  pure Vector {size, bias, x, y, z}  getPart :: Word -> Word -> BitGet.BitGet Int getPart limit bias = fmap (fromDelta bias) (CompressedWord.bitGet limit)
src/lib/Rattletrap/Type/Version.hs view
@@ -6,9 +6,9 @@ import qualified Rattletrap.Utility.Monad as Monad  data Version = Version-  { major :: U32.U32-  , minor :: U32.U32-  , patch :: Maybe U32.U32+  { major :: U32.U32,+    minor :: U32.U32,+    patch :: Maybe U32.U32   }   deriving (Eq, Show) @@ -19,15 +19,20 @@     && (maybe 0 U32.toWord32 (patch v) >= fromIntegral p)  bytePut :: Version -> BytePut.BytePut-bytePut x = U32.bytePut (major x) <> U32.bytePut (minor x) <> foldMap-  U32.bytePut-  (patch x)+bytePut x =+  U32.bytePut (major x)+    <> U32.bytePut (minor x)+    <> foldMap+      U32.bytePut+      (patch x)  byteGet :: ByteGet.ByteGet Version byteGet = ByteGet.label "Version" $ do   major <- ByteGet.label "major" U32.byteGet   minor <- ByteGet.label "minor" U32.byteGet-  patch <- ByteGet.label "patch" $ Monad.whenMaybe-    (U32.toWord32 major >= 868 && U32.toWord32 minor >= 18)-    U32.byteGet-  pure Version { major, minor, patch }+  patch <-+    ByteGet.label "patch" $+      Monad.whenMaybe+        (U32.toWord32 major >= 868 && U32.toWord32 minor >= 18)+        U32.byteGet+  pure Version {major, minor, patch}
src/lib/Rattletrap/Utility/Bytes.hs view
@@ -7,6 +7,7 @@ encodeLatin1 :: Text.Text -> ByteString.ByteString encodeLatin1 text = Latin1.pack (Text.unpack text) -padBytes :: Integral a => a -> ByteString.ByteString -> ByteString.ByteString-padBytes size bytes = bytes-  <> ByteString.replicate (fromIntegral size - ByteString.length bytes) 0x00+padBytes :: (Integral a) => a -> ByteString.ByteString -> ByteString.ByteString+padBytes size bytes =+  bytes+    <> ByteString.replicate (fromIntegral size - ByteString.length bytes) 0x00
src/lib/Rattletrap/Utility/Crc.hs view
@@ -19,11 +19,10 @@  update :: Word.Word32 -> Word.Word8 -> Word.Word32 update crc byte =-  let-    index = Bits.xor byte . unsafeWord32ToWord8 $ Bits.shiftR crc 24-    left = table Array.! index-    right = Bits.shiftL crc 8-  in Bits.xor left right+  let index = Bits.xor byte . unsafeWord32ToWord8 $ Bits.shiftR crc 24+      left = table Array.! index+      right = Bits.shiftL crc 8+   in Bits.xor left right  unsafeWord32ToWord8 :: Word.Word32 -> Word.Word8 unsafeWord32ToWord8 = fromIntegral@@ -32,262 +31,263 @@ initial = Bits.complement 0xefcbf201  table :: Array.Array Word.Word8 Word.Word32-table = Array.listArray-  (0, 255)-  [ 0x00000000-  , 0x04c11db7-  , 0x09823b6e-  , 0x0d4326d9-  , 0x130476dc-  , 0x17c56b6b-  , 0x1a864db2-  , 0x1e475005-  , 0x2608edb8-  , 0x22c9f00f-  , 0x2f8ad6d6-  , 0x2b4bcb61-  , 0x350c9b64-  , 0x31cd86d3-  , 0x3c8ea00a-  , 0x384fbdbd-  , 0x4c11db70-  , 0x48d0c6c7-  , 0x4593e01e-  , 0x4152fda9-  , 0x5f15adac-  , 0x5bd4b01b-  , 0x569796c2-  , 0x52568b75-  , 0x6a1936c8-  , 0x6ed82b7f-  , 0x639b0da6-  , 0x675a1011-  , 0x791d4014-  , 0x7ddc5da3-  , 0x709f7b7a-  , 0x745e66cd-  , 0x9823b6e0-  , 0x9ce2ab57-  , 0x91a18d8e-  , 0x95609039-  , 0x8b27c03c-  , 0x8fe6dd8b-  , 0x82a5fb52-  , 0x8664e6e5-  , 0xbe2b5b58-  , 0xbaea46ef-  , 0xb7a96036-  , 0xb3687d81-  , 0xad2f2d84-  , 0xa9ee3033-  , 0xa4ad16ea-  , 0xa06c0b5d-  , 0xd4326d90-  , 0xd0f37027-  , 0xddb056fe-  , 0xd9714b49-  , 0xc7361b4c-  , 0xc3f706fb-  , 0xceb42022-  , 0xca753d95-  , 0xf23a8028-  , 0xf6fb9d9f-  , 0xfbb8bb46-  , 0xff79a6f1-  , 0xe13ef6f4-  , 0xe5ffeb43-  , 0xe8bccd9a-  , 0xec7dd02d-  , 0x34867077-  , 0x30476dc0-  , 0x3d044b19-  , 0x39c556ae-  , 0x278206ab-  , 0x23431b1c-  , 0x2e003dc5-  , 0x2ac12072-  , 0x128e9dcf-  , 0x164f8078-  , 0x1b0ca6a1-  , 0x1fcdbb16-  , 0x018aeb13-  , 0x054bf6a4-  , 0x0808d07d-  , 0x0cc9cdca-  , 0x7897ab07-  , 0x7c56b6b0-  , 0x71159069-  , 0x75d48dde-  , 0x6b93dddb-  , 0x6f52c06c-  , 0x6211e6b5-  , 0x66d0fb02-  , 0x5e9f46bf-  , 0x5a5e5b08-  , 0x571d7dd1-  , 0x53dc6066-  , 0x4d9b3063-  , 0x495a2dd4-  , 0x44190b0d-  , 0x40d816ba-  , 0xaca5c697-  , 0xa864db20-  , 0xa527fdf9-  , 0xa1e6e04e-  , 0xbfa1b04b-  , 0xbb60adfc-  , 0xb6238b25-  , 0xb2e29692-  , 0x8aad2b2f-  , 0x8e6c3698-  , 0x832f1041-  , 0x87ee0df6-  , 0x99a95df3-  , 0x9d684044-  , 0x902b669d-  , 0x94ea7b2a-  , 0xe0b41de7-  , 0xe4750050-  , 0xe9362689-  , 0xedf73b3e-  , 0xf3b06b3b-  , 0xf771768c-  , 0xfa325055-  , 0xfef34de2-  , 0xc6bcf05f-  , 0xc27dede8-  , 0xcf3ecb31-  , 0xcbffd686-  , 0xd5b88683-  , 0xd1799b34-  , 0xdc3abded-  , 0xd8fba05a-  , 0x690ce0ee-  , 0x6dcdfd59-  , 0x608edb80-  , 0x644fc637-  , 0x7a089632-  , 0x7ec98b85-  , 0x738aad5c-  , 0x774bb0eb-  , 0x4f040d56-  , 0x4bc510e1-  , 0x46863638-  , 0x42472b8f-  , 0x5c007b8a-  , 0x58c1663d-  , 0x558240e4-  , 0x51435d53-  , 0x251d3b9e-  , 0x21dc2629-  , 0x2c9f00f0-  , 0x285e1d47-  , 0x36194d42-  , 0x32d850f5-  , 0x3f9b762c-  , 0x3b5a6b9b-  , 0x0315d626-  , 0x07d4cb91-  , 0x0a97ed48-  , 0x0e56f0ff-  , 0x1011a0fa-  , 0x14d0bd4d-  , 0x19939b94-  , 0x1d528623-  , 0xf12f560e-  , 0xf5ee4bb9-  , 0xf8ad6d60-  , 0xfc6c70d7-  , 0xe22b20d2-  , 0xe6ea3d65-  , 0xeba91bbc-  , 0xef68060b-  , 0xd727bbb6-  , 0xd3e6a601-  , 0xdea580d8-  , 0xda649d6f-  , 0xc423cd6a-  , 0xc0e2d0dd-  , 0xcda1f604-  , 0xc960ebb3-  , 0xbd3e8d7e-  , 0xb9ff90c9-  , 0xb4bcb610-  , 0xb07daba7-  , 0xae3afba2-  , 0xaafbe615-  , 0xa7b8c0cc-  , 0xa379dd7b-  , 0x9b3660c6-  , 0x9ff77d71-  , 0x92b45ba8-  , 0x9675461f-  , 0x8832161a-  , 0x8cf30bad-  , 0x81b02d74-  , 0x857130c3-  , 0x5d8a9099-  , 0x594b8d2e-  , 0x5408abf7-  , 0x50c9b640-  , 0x4e8ee645-  , 0x4a4ffbf2-  , 0x470cdd2b-  , 0x43cdc09c-  , 0x7b827d21-  , 0x7f436096-  , 0x7200464f-  , 0x76c15bf8-  , 0x68860bfd-  , 0x6c47164a-  , 0x61043093-  , 0x65c52d24-  , 0x119b4be9-  , 0x155a565e-  , 0x18197087-  , 0x1cd86d30-  , 0x029f3d35-  , 0x065e2082-  , 0x0b1d065b-  , 0x0fdc1bec-  , 0x3793a651-  , 0x3352bbe6-  , 0x3e119d3f-  , 0x3ad08088-  , 0x2497d08d-  , 0x2056cd3a-  , 0x2d15ebe3-  , 0x29d4f654-  , 0xc5a92679-  , 0xc1683bce-  , 0xcc2b1d17-  , 0xc8ea00a0-  , 0xd6ad50a5-  , 0xd26c4d12-  , 0xdf2f6bcb-  , 0xdbee767c-  , 0xe3a1cbc1-  , 0xe760d676-  , 0xea23f0af-  , 0xeee2ed18-  , 0xf0a5bd1d-  , 0xf464a0aa-  , 0xf9278673-  , 0xfde69bc4-  , 0x89b8fd09-  , 0x8d79e0be-  , 0x803ac667-  , 0x84fbdbd0-  , 0x9abc8bd5-  , 0x9e7d9662-  , 0x933eb0bb-  , 0x97ffad0c-  , 0xafb010b1-  , 0xab710d06-  , 0xa6322bdf-  , 0xa2f33668-  , 0xbcb4666d-  , 0xb8757bda-  , 0xb5365d03-  , 0xb1f740b4-  ]+table =+  Array.listArray+    (0, 255)+    [ 0x00000000,+      0x04c11db7,+      0x09823b6e,+      0x0d4326d9,+      0x130476dc,+      0x17c56b6b,+      0x1a864db2,+      0x1e475005,+      0x2608edb8,+      0x22c9f00f,+      0x2f8ad6d6,+      0x2b4bcb61,+      0x350c9b64,+      0x31cd86d3,+      0x3c8ea00a,+      0x384fbdbd,+      0x4c11db70,+      0x48d0c6c7,+      0x4593e01e,+      0x4152fda9,+      0x5f15adac,+      0x5bd4b01b,+      0x569796c2,+      0x52568b75,+      0x6a1936c8,+      0x6ed82b7f,+      0x639b0da6,+      0x675a1011,+      0x791d4014,+      0x7ddc5da3,+      0x709f7b7a,+      0x745e66cd,+      0x9823b6e0,+      0x9ce2ab57,+      0x91a18d8e,+      0x95609039,+      0x8b27c03c,+      0x8fe6dd8b,+      0x82a5fb52,+      0x8664e6e5,+      0xbe2b5b58,+      0xbaea46ef,+      0xb7a96036,+      0xb3687d81,+      0xad2f2d84,+      0xa9ee3033,+      0xa4ad16ea,+      0xa06c0b5d,+      0xd4326d90,+      0xd0f37027,+      0xddb056fe,+      0xd9714b49,+      0xc7361b4c,+      0xc3f706fb,+      0xceb42022,+      0xca753d95,+      0xf23a8028,+      0xf6fb9d9f,+      0xfbb8bb46,+      0xff79a6f1,+      0xe13ef6f4,+      0xe5ffeb43,+      0xe8bccd9a,+      0xec7dd02d,+      0x34867077,+      0x30476dc0,+      0x3d044b19,+      0x39c556ae,+      0x278206ab,+      0x23431b1c,+      0x2e003dc5,+      0x2ac12072,+      0x128e9dcf,+      0x164f8078,+      0x1b0ca6a1,+      0x1fcdbb16,+      0x018aeb13,+      0x054bf6a4,+      0x0808d07d,+      0x0cc9cdca,+      0x7897ab07,+      0x7c56b6b0,+      0x71159069,+      0x75d48dde,+      0x6b93dddb,+      0x6f52c06c,+      0x6211e6b5,+      0x66d0fb02,+      0x5e9f46bf,+      0x5a5e5b08,+      0x571d7dd1,+      0x53dc6066,+      0x4d9b3063,+      0x495a2dd4,+      0x44190b0d,+      0x40d816ba,+      0xaca5c697,+      0xa864db20,+      0xa527fdf9,+      0xa1e6e04e,+      0xbfa1b04b,+      0xbb60adfc,+      0xb6238b25,+      0xb2e29692,+      0x8aad2b2f,+      0x8e6c3698,+      0x832f1041,+      0x87ee0df6,+      0x99a95df3,+      0x9d684044,+      0x902b669d,+      0x94ea7b2a,+      0xe0b41de7,+      0xe4750050,+      0xe9362689,+      0xedf73b3e,+      0xf3b06b3b,+      0xf771768c,+      0xfa325055,+      0xfef34de2,+      0xc6bcf05f,+      0xc27dede8,+      0xcf3ecb31,+      0xcbffd686,+      0xd5b88683,+      0xd1799b34,+      0xdc3abded,+      0xd8fba05a,+      0x690ce0ee,+      0x6dcdfd59,+      0x608edb80,+      0x644fc637,+      0x7a089632,+      0x7ec98b85,+      0x738aad5c,+      0x774bb0eb,+      0x4f040d56,+      0x4bc510e1,+      0x46863638,+      0x42472b8f,+      0x5c007b8a,+      0x58c1663d,+      0x558240e4,+      0x51435d53,+      0x251d3b9e,+      0x21dc2629,+      0x2c9f00f0,+      0x285e1d47,+      0x36194d42,+      0x32d850f5,+      0x3f9b762c,+      0x3b5a6b9b,+      0x0315d626,+      0x07d4cb91,+      0x0a97ed48,+      0x0e56f0ff,+      0x1011a0fa,+      0x14d0bd4d,+      0x19939b94,+      0x1d528623,+      0xf12f560e,+      0xf5ee4bb9,+      0xf8ad6d60,+      0xfc6c70d7,+      0xe22b20d2,+      0xe6ea3d65,+      0xeba91bbc,+      0xef68060b,+      0xd727bbb6,+      0xd3e6a601,+      0xdea580d8,+      0xda649d6f,+      0xc423cd6a,+      0xc0e2d0dd,+      0xcda1f604,+      0xc960ebb3,+      0xbd3e8d7e,+      0xb9ff90c9,+      0xb4bcb610,+      0xb07daba7,+      0xae3afba2,+      0xaafbe615,+      0xa7b8c0cc,+      0xa379dd7b,+      0x9b3660c6,+      0x9ff77d71,+      0x92b45ba8,+      0x9675461f,+      0x8832161a,+      0x8cf30bad,+      0x81b02d74,+      0x857130c3,+      0x5d8a9099,+      0x594b8d2e,+      0x5408abf7,+      0x50c9b640,+      0x4e8ee645,+      0x4a4ffbf2,+      0x470cdd2b,+      0x43cdc09c,+      0x7b827d21,+      0x7f436096,+      0x7200464f,+      0x76c15bf8,+      0x68860bfd,+      0x6c47164a,+      0x61043093,+      0x65c52d24,+      0x119b4be9,+      0x155a565e,+      0x18197087,+      0x1cd86d30,+      0x029f3d35,+      0x065e2082,+      0x0b1d065b,+      0x0fdc1bec,+      0x3793a651,+      0x3352bbe6,+      0x3e119d3f,+      0x3ad08088,+      0x2497d08d,+      0x2056cd3a,+      0x2d15ebe3,+      0x29d4f654,+      0xc5a92679,+      0xc1683bce,+      0xcc2b1d17,+      0xc8ea00a0,+      0xd6ad50a5,+      0xd26c4d12,+      0xdf2f6bcb,+      0xdbee767c,+      0xe3a1cbc1,+      0xe760d676,+      0xea23f0af,+      0xeee2ed18,+      0xf0a5bd1d,+      0xf464a0aa,+      0xf9278673,+      0xfde69bc4,+      0x89b8fd09,+      0x8d79e0be,+      0x803ac667,+      0x84fbdbd0,+      0x9abc8bd5,+      0x9e7d9662,+      0x933eb0bb,+      0x97ffad0c,+      0xafb010b1,+      0xab710d06,+      0xa6322bdf,+      0xa2f33668,+      0xbcb4666d,+      0xb8757bda,+      0xb5365d03,+      0xb1f740b4+    ]
src/lib/Rattletrap/Utility/Helper.hs view
@@ -2,6 +2,10 @@ -- both their binary format and JSON. module Rattletrap.Utility.Helper where +import qualified Control.Exception as Exception+import qualified Data.Bifunctor as Bifunctor+import qualified Data.ByteString as ByteString+import qualified Data.ByteString.Lazy as LazyByteString import qualified Rattletrap.ByteGet as ByteGet import qualified Rattletrap.BytePut as BytePut import qualified Rattletrap.Exception.InvalidJson as InvalidJson@@ -10,17 +14,12 @@ import qualified Rattletrap.Type.Section as Section import qualified Rattletrap.Utility.Json as Json -import qualified Control.Exception as Exception-import qualified Data.Bifunctor as Bifunctor-import qualified Data.ByteString as ByteString-import qualified Data.ByteString.Lazy as LazyByteString- -- | Parses a raw replay.-decodeReplayFile-  :: Bool-  -> Bool-  -> ByteString.ByteString-  -> Either ([String], Exception.SomeException) Replay.Replay+decodeReplayFile ::+  Bool ->+  Bool ->+  ByteString.ByteString ->+  Either ([String], Exception.SomeException) Replay.Replay decodeReplayFile fast = ByteGet.run . Replay.byteGet fast  -- | Encodes a replay as JSON.@@ -28,9 +27,9 @@ encodeReplayJson = Json.encodePretty  -- | Parses a JSON replay.-decodeReplayJson-  :: ByteString.ByteString-  -> Either ([String], Exception.SomeException) Replay.Replay+decodeReplayJson ::+  ByteString.ByteString ->+  Either ([String], Exception.SomeException) Replay.Replay decodeReplayJson =   Bifunctor.first ((,) [] . Exception.toException . InvalidJson.InvalidJson)     . Json.decode@@ -38,8 +37,10 @@ -- | Encodes a raw replay. encodeReplayFile :: Bool -> Replay.Replay -> LazyByteString.ByteString encodeReplayFile fast replay =-  BytePut.toLazyByteString . Replay.bytePut $ if fast-    then replay-      { Replay.content = Section.create Content.bytePut Content.empty-      }-    else replay+  BytePut.toLazyByteString . Replay.bytePut $+    if fast+      then+        replay+          { Replay.content = Section.create Content.bytePut Content.empty+          }+      else replay
src/lib/Rattletrap/Utility/Json.hs view
@@ -1,15 +1,16 @@ {- hlint ignore "Avoid restricted flags" -} module Rattletrap.Utility.Json-  ( module Rattletrap.Utility.Json-  , Aeson.FromJSON(parseJSON)-  , Key.Key-  , Aeson.ToJSON(toJSON)-  , Aeson.Value-  , Aeson.encode-  , Aeson.object-  , Aeson.withObject-  , Aeson.withText-  ) where+  ( module Rattletrap.Utility.Json,+    Aeson.FromJSON (parseJSON),+    Key.Key,+    Aeson.ToJSON (toJSON),+    Aeson.Value,+    Aeson.encode,+    Aeson.object,+    Aeson.withObject,+    Aeson.withText,+  )+where  import qualified Data.Aeson as Aeson import qualified Data.Aeson.Encode.Pretty as Aeson@@ -21,26 +22,28 @@ keyToString :: Key.Key -> String keyToString = Key.toString -required-  :: Aeson.FromJSON value => Aeson.Object -> String -> Aeson.Parser value+required ::+  (Aeson.FromJSON value) => Aeson.Object -> String -> Aeson.Parser value required object key = object Aeson..: Key.fromString key -optional-  :: Aeson.FromJSON value-  => Aeson.Object-  -> String-  -> Aeson.Parser (Maybe value)+optional ::+  (Aeson.FromJSON value) =>+  Aeson.Object ->+  String ->+  Aeson.Parser (Maybe value) optional object key = object Aeson..:? Key.fromString key  pair :: (Aeson.ToJSON value, Aeson.KeyValue pair) => String -> value -> pair pair key value = Key.fromString key Aeson..= value -decode :: Aeson.FromJSON a => ByteString.ByteString -> Either String a+decode :: (Aeson.FromJSON a) => ByteString.ByteString -> Either String a decode = Aeson.eitherDecodeStrict' -encodePretty :: Aeson.ToJSON a => a -> LazyByteString.ByteString-encodePretty = Aeson.encodePretty' Aeson.defConfig-  { Aeson.confCompare = compare-  , Aeson.confIndent = Aeson.Tab-  , Aeson.confTrailingNewline = True-  }+encodePretty :: (Aeson.ToJSON a) => a -> LazyByteString.ByteString+encodePretty =+  Aeson.encodePretty'+    Aeson.defConfig+      { Aeson.confCompare = compare,+        Aeson.confIndent = Aeson.Tab,+        Aeson.confTrailingNewline = True+      }
src/lib/Rattletrap/Utility/Monad.hs view
@@ -1,4 +1,4 @@ module Rattletrap.Utility.Monad where -whenMaybe :: Applicative m => Bool -> m a -> m (Maybe a)+whenMaybe :: (Applicative m) => Bool -> m a -> m (Maybe a) whenMaybe p f = if p then fmap Just f else pure Nothing
src/test/Main.hs view
@@ -12,9 +12,10 @@   mapM_ (testReplay directory) replays  generateSchema :: FilePath -> IO ()-generateSchema directory = Rattletrap.rattletrap-  ""-  ["--schema", "--output", FilePath.combine directory "schema.json"]+generateSchema directory =+  Rattletrap.rattletrap+    ""+    ["--schema", "--output", FilePath.combine directory "schema.json"]  testReplay :: FilePath -> (FilePath, String) -> IO () testReplay directory (uuid, name) = do@@ -50,125 +51,125 @@  replays :: [(String, String)] replays =-  [ ("0008", "a flip time") -- https://github.com/tfausak/rattletrap/commit/ee7afa0-  , ("000b", "nintendo switch") -- https://github.com/tfausak/rattletrap/pull/60-  , ("0121", "RLCS 2") -- https://github.com/nickbabcock/boxcars/pull/120-  , ("0416", "v1.78 demolition") -- https://github.com/tfausak/rattletrap/pull/164-  , ("07e9", "a game mode before Neo Tokyo") -- https://github.com/tfausak/rattletrap/commit/b806f9b-  , ("0ad2", "some Latin-1 text") -- https://github.com/tfausak/rattletrap/commit/13a8b2d-  , ("0ca5", "with QQ remote ID") -- https://github.com/nickbabcock/boxcars/pull/69-  , ("0e76", "v1.95 rumble") -- https://github.com/tfausak/rattletrap/pull/237-  , ("1205", "rumble mode") -- https://github.com/tfausak/rattletrap/commit/5256500-  , ("160c", "a dedicated server IP") -- https://github.com/tfausak/rattletrap/commit/5c64a6d-  , ("16d5", "new property types") -- https://github.com/tfausak/rattletrap/pull/41-  , ("18d6", "an online loadout attribute") -- https://github.com/tfausak/rattletrap/commit/a9900e7-  , ("1a12", "overtime") -- https://github.com/tfausak/rattletrap/commit/ada6053-  , ("1ae4", "a game time") -- https://github.com/tfausak/rattletrap/commit/d08176e-  , ("1bc2", "no padding after the frames") -- https://github.com/tfausak/rattletrap/commit/c9a2dd8-  , ("1d1d", "a camera pitch") -- https://github.com/tfausak/rattletrap/commit/ee7afa0-  , ("1ec9", "a V1.63 match") -- https://github.com/tfausak/rattletrap/pull/132-  , ("1ef9", "a private hoops match") -- https://github.com/tfausak/rattletrap/commit/5570839-  , ("1f37", "splitscreen players") -- https://github.com/tfausak/rattletrap/commit/c4d2f32-  , ("2114", "a match save") -- https://github.com/tfausak/rattletrap/commit/ee7afa0-  , ("21a8", "v1.66") -- https://github.com/tfausak/rattletrap/pull/142-  , ("2266", "dropshot") -- https://github.com/tfausak/rattletrap/pull/36-  , ("22ba", "a vote to forfeit") -- https://github.com/tfausak/rattletrap/commit/86656bb-  , ("27b6", "some UTF-16 text") -- https://github.com/tfausak/rattletrap/commit/c4d2f32-  , ("29f5", "frames") -- https://github.com/tfausak/rattletrap/commit/bf4b6af-  , ("2cf8", "demo v2.01") -- https://github.com/tfausak/rattletrap/pull/243-  , ("2cfe", "a new playstation id") -- https://github.com/tfausak/rattletrap/issues/51-  , ("3381", "patch 1.37") -- https://github.com/tfausak/rattletrap/pull/48-  , ("35f6", "heatseeker v2.01") -- https://github.com/tfausak/rattletrap/commit/57d86c2-  , ("372d", "a camera yaw attribute") -- https://github.com/tfausak/rattletrap/commit/9c1516c-  , ("383e", "older unknown content field") -- https://github.com/tfausak/rattletrap/pull/123-  , ("387f", "a frozen attribute") -- https://github.com/tfausak/rattletrap/commit/93ce196-  , ("3abd", "rlcs") -- https://github.com/tfausak/rattletrap/pull/86-  , ("3ea1", "a custom team name") -- https://github.com/tfausak/rattletrap/commit/cf4d145-  , ("4050", "v2.08 dodge impulse") -- https://github.com/tfausak/rattletrap/issues/247-  , ("4126", "a game mode after Neo Tokyo") -- https://github.com/tfausak/rattletrap/commit/a1cf21e-  , ("419a", "a club match") -- https://github.com/tfausak/rattletrap/commit/8e35043-  , ("42f0", "reservations after Neo Tokyo") -- https://github.com/tfausak/rattletrap/commit/163684f-  , ("42f2", "anniversary ball") -- https://github.com/tfausak/rattletrap/issues/147-  , ("43a9", "tutorial") -- https://github.com/nickbabcock/boxcars/pull/70-  , ("4bc3", "with timed out attribute") -- https://github.com/tfausak/rattletrap/pull/98-  , ("504e", "some messages") -- https://github.com/tfausak/rattletrap/commit/1d4a538-  , ("5123", "rep stat title") -- https://github.com/nickbabcock/boxcars/pull/78-  , ("520e", "no pickup attribute") -- https://github.com/tfausak/rattletrap/pull/38-  , ("524f", "quat edge case") -- https://github.com/tfausak/rattletrap/pull/87-  , ("52aa", "a match-ending attribute") -- https://github.com/tfausak/rattletrap/commit/5c64a6d-  , ("540d", "a demolish attribute") -- https://github.com/tfausak/rattletrap/commit/65ce033-  , ("54ae", "replicated car scale") -- https://github.com/nickbabcock/boxcars/pull/79-  , ("551c", "private match settings") -- https://github.com/tfausak/rattletrap/commit/5c9ebfc-  , ("59d3", "v2.23") -- https://github.com/tfausak/rattletrap/issues/274-  , ("5a06", "esports items") -- https://github.com/tfausak/rattletrap/pull/114-  , ("5e0b", "max channels") -- https://github.com/tfausak/rattletrap/issues/254-  , ("6210", "different player history key") -- https://github.com/tfausak/rattletrap/pull/63-  , ("6320", "a forfeit attribute") -- https://github.com/tfausak/rattletrap/pull/20-  , ("6688", "a malformed byte property") -- https://github.com/tfausak/rattletrap/commit/b1ec18b-  , ("6b0d", "patch 1.37") -- https://github.com/tfausak/rattletrap/pull/48-  , ("6d1b", "a flip right") -- https://github.com/tfausak/rattletrap/commit/ee7afa0-  , ("6f7c", "a map with numbers") -- https://github.com/tfausak/rattletrap/commit/2629511-  , ("7083", "weird basketball capitalization") -- https://github.com/tfausak/rattletrap/pull/63-  , ("7109", "a boost modifier") -- https://github.com/tfausak/rattletrap/commit/ee7afa0-  , ("7256", "special edition") -- https://github.com/tfausak/rattletrap/pull/103-  , ("7588", "another malformed byte property") -- https://github.com/nickbabcock/boxcars/pull/68-  , ("75ce", "primary and secondary titles") -- https://github.com/tfausak/rattletrap/pull/69-  , ("79ae", "voice update replay") -- https://github.com/tfausak/rattletrap/pull/265-  , ("7bf6", "an online loadouts attribute") -- https://github.com/tfausak/rattletrap/commit/89d02f7-  , ("81d1", "gridiron") -- https://github.com/tfausak/rattletrap/pull/180-  , ("89cb", "remote user data") -- https://github.com/tfausak/rattletrap/commit/163684f-  , ("8ae5", "new painted items") -- https://github.com/tfausak/rattletrap/pull/43-  , ("92a6", "with server performance state") -- https://github.com/tfausak/rattletrap/pull/93-  , ("946f", "patch 1.43") -- https://github.com/tfausak/rattletrap/pull/69-  , ("9704", "a batarang") -- https://github.com/tfausak/rattletrap/commit/5958e5c-  , ("98e5", "a player using behind view") -- https://github.com/tfausak/rattletrap/commit/163684f-  , ("9a2c", "ghost hunt") -- https://github.com/tfausak/rattletrap/pull/160-  , ("9e35", "spike rush") -- https://github.com/tfausak/rattletrap/pull/160-  , ("9eaa", "newer replay without trailing bytes") -- https://github.com/tfausak/rattletrap/pull/126-  , ("a09e", "a tournament") -- https://github.com/tfausak/rattletrap/pull/69-  , ("a128", "a round count down") -- https://github.com/tfausak/rattletrap/commit/8bb778d-  , ("a184", "max score") -- https://github.com/tfausak/rattletrap/pull/158-  , ("a1c0", "epic system id") -- https://github.com/tfausak/rattletrap/pull/167-  , ("a52f", "some more mutators") -- https://github.com/tfausak/rattletrap/commit/ee7afa0-  , ("a558", "extended explosion data") -- https://github.com/tfausak/rattletrap/pull/44-  , ("a671", "a waiting player") -- https://github.com/tfausak/rattletrap/commit/163684f-  , ("a676", "new user color") -- https://github.com/tfausak/rattletrap/pull/93-  , ("a7f0", "a ready attribute") -- https://github.com/tfausak/rattletrap/commit/78af1fd-  , ("a9df", "salty shores patch 1.45") -- https://github.com/tfausak/rattletrap/pull/78-  , ("aa70", "patch 1.50 - TitleID attribute") -- https://github.com/tfausak/rattletrap/pull/93-  , ("ae46", "mvp") -- https://github.com/nickbabcock/boxcars/pull/80-  , ("afb1", "patch 1.37") -- https://github.com/tfausak/rattletrap/pull/48-  , ("b9f9", "a party leader") -- https://github.com/tfausak/rattletrap/commit/bba2cfd-  , ("c14f", "some mutators") -- https://github.com/tfausak/rattletrap/commit/bba2cfd-  , ("c23b", "new psynet id") -- https://github.com/tfausak/rattletrap/pull/118-  , ("c62c", "more boolean attributes") -- https://github.com/nickbabcock/boxcars/pull/77-  , ("c837", "a spectator") -- https://github.com/tfausak/rattletrap/commit/bba2cfd-  , ("cc4c", "after Starbase ARC") -- https://github.com/tfausak/rattletrap/pull/20-  , ("d044", "hoops mutators") -- https://github.com/tfausak/rattletrap/pull/34-  , ("d1d5", "v1.68") -- https://github.com/tfausak/rattletrap/pull/146-  , ("d236", "rlcs s2") -- https://github.com/tfausak/rattletrap/pull/88-  , ("d428", "a private hockey match") -- https://github.com/tfausak/rattletrap/commit/4c104b2-  , ("d44c", "ranked tournament") -- https://github.com/tfausak/rattletrap/pull/167-  , ("d52e", "psynet system id") -- https://github.com/tfausak/rattletrap/pull/99-  , ("d5d6", "health max") -- https://github.com/nickbabcock/boxcars/pull/80-  , ("d7fb", "an explosion attribute") -- https://github.com/tfausak/rattletrap/commit/c554e3e-  , ("d818", "heatseeker") -- https://github.com/tfausak/rattletrap/pull/160-  , ("db70", "new lag indicator") -- https://github.com/tfausak/rattletrap/pull/69-  , ("dcab", "weird ball attribute value") -- https://github.com/tfausak/rattletrap/issues/149-  , ("dcb3", "a pawn type attribute") -- https://github.com/tfausak/rattletrap/commit/7d7f438-  , ("dd14", "v1.88") -- https://github.com/tfausak/rattletrap/pull/170-  , ("de56", "a problematic product attribute") -- https://github.com/tfausak/rattletrap/issues/51-  , ("e2f9", "bTearOff") -- https://github.com/nickbabcock/boxcars/pull/76-  , ("e80d", "unlimited time") -- https://github.com/tfausak/rattletrap/pull/76-  , ("e978", "distracted") -- https://github.com/tfausak/rattletrap/issues/156-  , ("eae3", "an actor/object ID collision") -- https://github.com/tfausak/rattletrap/commit/d8fad06-  , ("eae8", "custom team colors") -- https://github.com/tfausak/rattletrap/commit/809240f-  , ("ecd5", "new match guid attribute") -- https://github.com/tfausak/rattletrap/issues/270-  , ("edbb", "remote role") -- https://github.com/tfausak/rattletrap/pull/106-  , ("f08e", "post game lobby") -- https://github.com/jjbott/RocketLeagueReplayParser/issues/46-  , ("f299", "a location attribute") -- https://github.com/tfausak/rattletrap/commit/21b09c5-  , ("f7b9", "a hockey game event") -- https://github.com/tfausak/rattletrap/commit/3e16d7f-  , ("f811", "no frames") -- https://github.com/tfausak/rattletrap/commit/bf4b6af-  , ("fdc7", "an MVP") -- https://github.com/tfausak/rattletrap/commit/65019d2-  , ("ffb7", "with difficulty") -- https://github.com/tfausak/rattletrap/pull/167+  [ ("0008", "a flip time"), -- https://github.com/tfausak/rattletrap/commit/ee7afa0+    ("000b", "nintendo switch"), -- https://github.com/tfausak/rattletrap/pull/60+    ("0121", "RLCS 2"), -- https://github.com/nickbabcock/boxcars/pull/120+    ("0416", "v1.78 demolition"), -- https://github.com/tfausak/rattletrap/pull/164+    ("07e9", "a game mode before Neo Tokyo"), -- https://github.com/tfausak/rattletrap/commit/b806f9b+    ("0ad2", "some Latin-1 text"), -- https://github.com/tfausak/rattletrap/commit/13a8b2d+    ("0ca5", "with QQ remote ID"), -- https://github.com/nickbabcock/boxcars/pull/69+    ("0e76", "v1.95 rumble"), -- https://github.com/tfausak/rattletrap/pull/237+    ("1205", "rumble mode"), -- https://github.com/tfausak/rattletrap/commit/5256500+    ("160c", "a dedicated server IP"), -- https://github.com/tfausak/rattletrap/commit/5c64a6d+    ("16d5", "new property types"), -- https://github.com/tfausak/rattletrap/pull/41+    ("18d6", "an online loadout attribute"), -- https://github.com/tfausak/rattletrap/commit/a9900e7+    ("1a12", "overtime"), -- https://github.com/tfausak/rattletrap/commit/ada6053+    ("1ae4", "a game time"), -- https://github.com/tfausak/rattletrap/commit/d08176e+    ("1bc2", "no padding after the frames"), -- https://github.com/tfausak/rattletrap/commit/c9a2dd8+    ("1d1d", "a camera pitch"), -- https://github.com/tfausak/rattletrap/commit/ee7afa0+    ("1ec9", "a V1.63 match"), -- https://github.com/tfausak/rattletrap/pull/132+    ("1ef9", "a private hoops match"), -- https://github.com/tfausak/rattletrap/commit/5570839+    ("1f37", "splitscreen players"), -- https://github.com/tfausak/rattletrap/commit/c4d2f32+    ("2114", "a match save"), -- https://github.com/tfausak/rattletrap/commit/ee7afa0+    ("21a8", "v1.66"), -- https://github.com/tfausak/rattletrap/pull/142+    ("2266", "dropshot"), -- https://github.com/tfausak/rattletrap/pull/36+    ("22ba", "a vote to forfeit"), -- https://github.com/tfausak/rattletrap/commit/86656bb+    ("27b6", "some UTF-16 text"), -- https://github.com/tfausak/rattletrap/commit/c4d2f32+    ("29f5", "frames"), -- https://github.com/tfausak/rattletrap/commit/bf4b6af+    ("2cf8", "demo v2.01"), -- https://github.com/tfausak/rattletrap/pull/243+    ("2cfe", "a new playstation id"), -- https://github.com/tfausak/rattletrap/issues/51+    ("3381", "patch 1.37"), -- https://github.com/tfausak/rattletrap/pull/48+    ("35f6", "heatseeker v2.01"), -- https://github.com/tfausak/rattletrap/commit/57d86c2+    ("372d", "a camera yaw attribute"), -- https://github.com/tfausak/rattletrap/commit/9c1516c+    ("383e", "older unknown content field"), -- https://github.com/tfausak/rattletrap/pull/123+    ("387f", "a frozen attribute"), -- https://github.com/tfausak/rattletrap/commit/93ce196+    ("3abd", "rlcs"), -- https://github.com/tfausak/rattletrap/pull/86+    ("3ea1", "a custom team name"), -- https://github.com/tfausak/rattletrap/commit/cf4d145+    ("4050", "v2.08 dodge impulse"), -- https://github.com/tfausak/rattletrap/issues/247+    ("4126", "a game mode after Neo Tokyo"), -- https://github.com/tfausak/rattletrap/commit/a1cf21e+    ("419a", "a club match"), -- https://github.com/tfausak/rattletrap/commit/8e35043+    ("42f0", "reservations after Neo Tokyo"), -- https://github.com/tfausak/rattletrap/commit/163684f+    ("42f2", "anniversary ball"), -- https://github.com/tfausak/rattletrap/issues/147+    ("43a9", "tutorial"), -- https://github.com/nickbabcock/boxcars/pull/70+    ("4bc3", "with timed out attribute"), -- https://github.com/tfausak/rattletrap/pull/98+    ("504e", "some messages"), -- https://github.com/tfausak/rattletrap/commit/1d4a538+    ("5123", "rep stat title"), -- https://github.com/nickbabcock/boxcars/pull/78+    ("520e", "no pickup attribute"), -- https://github.com/tfausak/rattletrap/pull/38+    ("524f", "quat edge case"), -- https://github.com/tfausak/rattletrap/pull/87+    ("52aa", "a match-ending attribute"), -- https://github.com/tfausak/rattletrap/commit/5c64a6d+    ("540d", "a demolish attribute"), -- https://github.com/tfausak/rattletrap/commit/65ce033+    ("54ae", "replicated car scale"), -- https://github.com/nickbabcock/boxcars/pull/79+    ("551c", "private match settings"), -- https://github.com/tfausak/rattletrap/commit/5c9ebfc+    ("59d3", "v2.23"), -- https://github.com/tfausak/rattletrap/issues/274+    ("5a06", "esports items"), -- https://github.com/tfausak/rattletrap/pull/114+    ("5e0b", "max channels"), -- https://github.com/tfausak/rattletrap/issues/254+    ("6210", "different player history key"), -- https://github.com/tfausak/rattletrap/pull/63+    ("6320", "a forfeit attribute"), -- https://github.com/tfausak/rattletrap/pull/20+    ("6688", "a malformed byte property"), -- https://github.com/tfausak/rattletrap/commit/b1ec18b+    ("6b0d", "patch 1.37"), -- https://github.com/tfausak/rattletrap/pull/48+    ("6d1b", "a flip right"), -- https://github.com/tfausak/rattletrap/commit/ee7afa0+    ("6f7c", "a map with numbers"), -- https://github.com/tfausak/rattletrap/commit/2629511+    ("7083", "weird basketball capitalization"), -- https://github.com/tfausak/rattletrap/pull/63+    ("7109", "a boost modifier"), -- https://github.com/tfausak/rattletrap/commit/ee7afa0+    ("7256", "special edition"), -- https://github.com/tfausak/rattletrap/pull/103+    ("7588", "another malformed byte property"), -- https://github.com/nickbabcock/boxcars/pull/68+    ("75ce", "primary and secondary titles"), -- https://github.com/tfausak/rattletrap/pull/69+    ("79ae", "voice update replay"), -- https://github.com/tfausak/rattletrap/pull/265+    ("7bf6", "an online loadouts attribute"), -- https://github.com/tfausak/rattletrap/commit/89d02f7+    ("81d1", "gridiron"), -- https://github.com/tfausak/rattletrap/pull/180+    ("89cb", "remote user data"), -- https://github.com/tfausak/rattletrap/commit/163684f+    ("8ae5", "new painted items"), -- https://github.com/tfausak/rattletrap/pull/43+    ("92a6", "with server performance state"), -- https://github.com/tfausak/rattletrap/pull/93+    ("946f", "patch 1.43"), -- https://github.com/tfausak/rattletrap/pull/69+    ("9704", "a batarang"), -- https://github.com/tfausak/rattletrap/commit/5958e5c+    ("98e5", "a player using behind view"), -- https://github.com/tfausak/rattletrap/commit/163684f+    ("9a2c", "ghost hunt"), -- https://github.com/tfausak/rattletrap/pull/160+    ("9e35", "spike rush"), -- https://github.com/tfausak/rattletrap/pull/160+    ("9eaa", "newer replay without trailing bytes"), -- https://github.com/tfausak/rattletrap/pull/126+    ("a09e", "a tournament"), -- https://github.com/tfausak/rattletrap/pull/69+    ("a128", "a round count down"), -- https://github.com/tfausak/rattletrap/commit/8bb778d+    ("a184", "max score"), -- https://github.com/tfausak/rattletrap/pull/158+    ("a1c0", "epic system id"), -- https://github.com/tfausak/rattletrap/pull/167+    ("a52f", "some more mutators"), -- https://github.com/tfausak/rattletrap/commit/ee7afa0+    ("a558", "extended explosion data"), -- https://github.com/tfausak/rattletrap/pull/44+    ("a671", "a waiting player"), -- https://github.com/tfausak/rattletrap/commit/163684f+    ("a676", "new user color"), -- https://github.com/tfausak/rattletrap/pull/93+    ("a7f0", "a ready attribute"), -- https://github.com/tfausak/rattletrap/commit/78af1fd+    ("a9df", "salty shores patch 1.45"), -- https://github.com/tfausak/rattletrap/pull/78+    ("aa70", "patch 1.50 - TitleID attribute"), -- https://github.com/tfausak/rattletrap/pull/93+    ("ae46", "mvp"), -- https://github.com/nickbabcock/boxcars/pull/80+    ("afb1", "patch 1.37"), -- https://github.com/tfausak/rattletrap/pull/48+    ("b9f9", "a party leader"), -- https://github.com/tfausak/rattletrap/commit/bba2cfd+    ("c14f", "some mutators"), -- https://github.com/tfausak/rattletrap/commit/bba2cfd+    ("c23b", "new psynet id"), -- https://github.com/tfausak/rattletrap/pull/118+    ("c62c", "more boolean attributes"), -- https://github.com/nickbabcock/boxcars/pull/77+    ("c837", "a spectator"), -- https://github.com/tfausak/rattletrap/commit/bba2cfd+    ("cc4c", "after Starbase ARC"), -- https://github.com/tfausak/rattletrap/pull/20+    ("d044", "hoops mutators"), -- https://github.com/tfausak/rattletrap/pull/34+    ("d1d5", "v1.68"), -- https://github.com/tfausak/rattletrap/pull/146+    ("d236", "rlcs s2"), -- https://github.com/tfausak/rattletrap/pull/88+    ("d428", "a private hockey match"), -- https://github.com/tfausak/rattletrap/commit/4c104b2+    ("d44c", "ranked tournament"), -- https://github.com/tfausak/rattletrap/pull/167+    ("d52e", "psynet system id"), -- https://github.com/tfausak/rattletrap/pull/99+    ("d5d6", "health max"), -- https://github.com/nickbabcock/boxcars/pull/80+    ("d7fb", "an explosion attribute"), -- https://github.com/tfausak/rattletrap/commit/c554e3e+    ("d818", "heatseeker"), -- https://github.com/tfausak/rattletrap/pull/160+    ("db70", "new lag indicator"), -- https://github.com/tfausak/rattletrap/pull/69+    ("dcab", "weird ball attribute value"), -- https://github.com/tfausak/rattletrap/issues/149+    ("dcb3", "a pawn type attribute"), -- https://github.com/tfausak/rattletrap/commit/7d7f438+    ("dd14", "v1.88"), -- https://github.com/tfausak/rattletrap/pull/170+    ("de56", "a problematic product attribute"), -- https://github.com/tfausak/rattletrap/issues/51+    ("e2f9", "bTearOff"), -- https://github.com/nickbabcock/boxcars/pull/76+    ("e80d", "unlimited time"), -- https://github.com/tfausak/rattletrap/pull/76+    ("e978", "distracted"), -- https://github.com/tfausak/rattletrap/issues/156+    ("eae3", "an actor/object ID collision"), -- https://github.com/tfausak/rattletrap/commit/d8fad06+    ("eae8", "custom team colors"), -- https://github.com/tfausak/rattletrap/commit/809240f+    ("ecd5", "new match guid attribute"), -- https://github.com/tfausak/rattletrap/issues/270+    ("edbb", "remote role"), -- https://github.com/tfausak/rattletrap/pull/106+    ("f08e", "post game lobby"), -- https://github.com/jjbott/RocketLeagueReplayParser/issues/46+    ("f299", "a location attribute"), -- https://github.com/tfausak/rattletrap/commit/21b09c5+    ("f7b9", "a hockey game event"), -- https://github.com/tfausak/rattletrap/commit/3e16d7f+    ("f811", "no frames"), -- https://github.com/tfausak/rattletrap/commit/bf4b6af+    ("fdc7", "an MVP"), -- https://github.com/tfausak/rattletrap/commit/65019d2+    ("ffb7", "with difficulty") -- https://github.com/tfausak/rattletrap/pull/167   ]