packages feed

rattletrap 9.0.2 → 9.0.3

raw patch · 476 files changed

+6984/−6924 lines, 476 filesdep ~aesondep ~basedep ~binary

Dependency ranges changed: aeson, base, binary, containers, http-client, template-haskell, transformers

Files

README.markdown view
@@ -11,10 +11,9 @@ can be used to modify replays in order to force everyone into the same car or change the map a game was played on. -Rattletrap supports every version of Rocket League up to [1.66][], also known-as the "season 12 update". If a replay can be played by the Rocket League-client, it can be parsed by Rattletrap. (If not, that's a bug. Please report-it!)+Rattletrap supports every version of Rocket League up to [1.68][], which was+released on 2019-10-14.  If a replay can be played by the Rocket League client,+it can be parsed by Rattletrap. (If not, that's a bug. Please report it!)  Rattletrap is a command-line application. You should only use it if you're comfortable running things in terminals or command prompts. Otherwise consider@@ -135,7 +134,7 @@ [Docker build badge]: https://img.shields.io/docker/build/taylorfausak/rattletrap.svg?label=docker&logo=docker&logoColor=white [docker build]: https://hub.docker.com/r/taylorfausak/rattletrap [Rocket League]: https://www.rocketleague.com-[1.66]: https://www.rocketleague.com/news/patch-notes-v1-66-season-12-update-/+[1.68]: https://www.rocketleague.com/news/patch-notes-v1-68-october-update/ [Ball Chasing]: https://ballchasing.com [Haskell]: https://www.haskell.org [C# parser]: https://github.com/jjbott/RocketLeagueReplayParser
− executables/Main.hs
@@ -1,6 +0,0 @@-module Main-  ( main-  )-where--import Rattletrap (main)
− library/Rattletrap.hs
@@ -1,162 +0,0 @@-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-  , Rattletrap.Type.AppliedDamageAttribute.AppliedDamageAttribute(..)-  , Rattletrap.Type.Attribute.Attribute(..)-  , Rattletrap.Type.AttributeMapping.AttributeMapping(..)-  , Rattletrap.Type.AttributeType.AttributeType(..)-  , Rattletrap.Type.AttributeValue.AttributeValue(..)-  , Rattletrap.Type.BooleanAttribute.BooleanAttribute(..)-  , Rattletrap.Type.ByteAttribute.ByteAttribute(..)-  , Rattletrap.Type.Cache.Cache(..)-  , Rattletrap.Type.CamSettingsAttribute.CamSettingsAttribute(..)-  , Rattletrap.Type.ClassAttributeMap.ClassAttributeMap(..)-  , Rattletrap.Type.ClassMapping.ClassMapping(..)-  , Rattletrap.Type.ClubColorsAttribute.ClubColorsAttribute(..)-  , Rattletrap.Type.CompressedWord.CompressedWord(..)-  , Rattletrap.Type.CompressedWordVector.CompressedWordVector(..)-  , Rattletrap.Type.Content.Content(..)-  , Rattletrap.Type.DamageStateAttribute.DamageStateAttribute(..)-  , Rattletrap.Type.DemolishAttribute.DemolishAttribute(..)-  , Rattletrap.Type.DestroyedReplication.DestroyedReplication(..)-  , Rattletrap.Type.Dictionary.Dictionary(..)-  , Rattletrap.Type.EnumAttribute.EnumAttribute(..)-  , Rattletrap.Type.ExplosionAttribute.ExplosionAttribute(..)-  , Rattletrap.Type.ExtendedExplosionAttribute.ExtendedExplosionAttribute(..)-  , Rattletrap.Type.FlaggedIntAttribute.FlaggedIntAttribute(..)-  , Rattletrap.Type.Float32le.Float32le(..)-  , Rattletrap.Type.FloatAttribute.FloatAttribute(..)-  , Rattletrap.Type.Frame.Frame(..)-  , Rattletrap.Type.GameModeAttribute.GameModeAttribute(..)-  , Rattletrap.Type.Header.Header(..)-  , Rattletrap.Type.Initialization.Initialization(..)-  , Rattletrap.Type.Int32le.Int32le(..)-  , Rattletrap.Type.Int64Attribute.Int64Attribute(..)-  , Rattletrap.Type.Int64le.Int64le(..)-  , Rattletrap.Type.Int8le.Int8le(..)-  , Rattletrap.Type.Int8Vector.Int8Vector(..)-  , Rattletrap.Type.IntAttribute.IntAttribute(..)-  , Rattletrap.Type.KeyFrame.KeyFrame(..)-  , Rattletrap.Type.List.List(..)-  , Rattletrap.Type.LoadoutAttribute.LoadoutAttribute(..)-  , Rattletrap.Type.LoadoutOnlineAttribute.LoadoutOnlineAttribute(..)-  , Rattletrap.Type.LoadoutsAttribute.LoadoutsAttribute(..)-  , Rattletrap.Type.LoadoutsOnlineAttribute.LoadoutsOnlineAttribute(..)-  , Rattletrap.Type.LocationAttribute.LocationAttribute(..)-  , Rattletrap.Type.Mark.Mark(..)-  , Rattletrap.Type.Message.Message(..)-  , Rattletrap.Type.MusicStingerAttribute.MusicStingerAttribute(..)-  , Rattletrap.Type.PartyLeaderAttribute.PartyLeaderAttribute(..)-  , Rattletrap.Type.PickupAttribute.PickupAttribute(..)-  , Rattletrap.Type.PlayerHistoryKeyAttribute.PlayerHistoryKeyAttribute(..)-  , Rattletrap.Type.PrivateMatchSettingsAttribute.PrivateMatchSettingsAttribute(..)-  , Rattletrap.Type.ProductAttribute.ProductAttribute(..)-  , Rattletrap.Type.Property.Property(..)-  , Rattletrap.Type.PropertyValue.PropertyValue(..)-  , Rattletrap.Type.Quaternion.Quaternion(..)-  , Rattletrap.Type.QWordAttribute.QWordAttribute(..)-  , Rattletrap.Type.RemoteId.RemoteId(..)-  , Rattletrap.Type.Replay.Replay(..)-  , Rattletrap.Type.Replication.Replication(..)-  , Rattletrap.Type.ReplicationValue.ReplicationValue(..)-  , Rattletrap.Type.ReservationAttribute.ReservationAttribute(..)-  , Rattletrap.Type.RigidBodyStateAttribute.RigidBodyStateAttribute(..)-  , Rattletrap.Type.Rotation.Rotation(..)-  , Rattletrap.Type.Section.Section(..)-  , Rattletrap.Type.SpawnedReplication.SpawnedReplication(..)-  , Rattletrap.Type.StatEventAttribute.StatEventAttribute(..)-  , Rattletrap.Type.Str.Str(..)-  , Rattletrap.Type.StringAttribute.StringAttribute(..)-  , Rattletrap.Type.TeamPaintAttribute.TeamPaintAttribute(..)-  , Rattletrap.Type.TitleAttribute.TitleAttribute(..)-  , Rattletrap.Type.UniqueIdAttribute.UniqueIdAttribute(..)-  , Rattletrap.Type.UpdatedReplication.UpdatedReplication(..)-  , Rattletrap.Type.Vector.Vector(..)-  , Rattletrap.Type.WeldedInfoAttribute.WeldedInfoAttribute(..)-  , Rattletrap.Type.Word32le.Word32le(..)-  , Rattletrap.Type.Word64le.Word64le(..)-  , Rattletrap.Type.Word8le.Word8le(..)-  )-where--import qualified Rattletrap.Console.Main-import qualified Rattletrap.Type.AppliedDamageAttribute-import qualified Rattletrap.Type.Attribute-import qualified Rattletrap.Type.AttributeMapping-import qualified Rattletrap.Type.AttributeType-import qualified Rattletrap.Type.AttributeValue-import qualified Rattletrap.Type.BooleanAttribute-import qualified Rattletrap.Type.ByteAttribute-import qualified Rattletrap.Type.Cache-import qualified Rattletrap.Type.CamSettingsAttribute-import qualified Rattletrap.Type.ClassAttributeMap-import qualified Rattletrap.Type.ClassMapping-import qualified Rattletrap.Type.ClubColorsAttribute-import qualified Rattletrap.Type.CompressedWord-import qualified Rattletrap.Type.CompressedWordVector-import qualified Rattletrap.Type.Content-import qualified Rattletrap.Type.DamageStateAttribute-import qualified Rattletrap.Type.DemolishAttribute-import qualified Rattletrap.Type.DestroyedReplication-import qualified Rattletrap.Type.Dictionary-import qualified Rattletrap.Type.EnumAttribute-import qualified Rattletrap.Type.ExplosionAttribute-import qualified Rattletrap.Type.ExtendedExplosionAttribute-import qualified Rattletrap.Type.FlaggedIntAttribute-import qualified Rattletrap.Type.Float32le-import qualified Rattletrap.Type.FloatAttribute-import qualified Rattletrap.Type.Frame-import qualified Rattletrap.Type.GameModeAttribute-import qualified Rattletrap.Type.Header-import qualified Rattletrap.Type.Initialization-import qualified Rattletrap.Type.Int32le-import qualified Rattletrap.Type.Int64Attribute-import qualified Rattletrap.Type.Int64le-import qualified Rattletrap.Type.Int8le-import qualified Rattletrap.Type.Int8Vector-import qualified Rattletrap.Type.IntAttribute-import qualified Rattletrap.Type.KeyFrame-import qualified Rattletrap.Type.List-import qualified Rattletrap.Type.LoadoutAttribute-import qualified Rattletrap.Type.LoadoutOnlineAttribute-import qualified Rattletrap.Type.LoadoutsAttribute-import qualified Rattletrap.Type.LoadoutsOnlineAttribute-import qualified Rattletrap.Type.LocationAttribute-import qualified Rattletrap.Type.Mark-import qualified Rattletrap.Type.Message-import qualified Rattletrap.Type.MusicStingerAttribute-import qualified Rattletrap.Type.PartyLeaderAttribute-import qualified Rattletrap.Type.PickupAttribute-import qualified Rattletrap.Type.PlayerHistoryKeyAttribute-import qualified Rattletrap.Type.PrivateMatchSettingsAttribute-import qualified Rattletrap.Type.ProductAttribute-import qualified Rattletrap.Type.Property-import qualified Rattletrap.Type.PropertyValue-import qualified Rattletrap.Type.Quaternion-import qualified Rattletrap.Type.QWordAttribute-import qualified Rattletrap.Type.RemoteId-import qualified Rattletrap.Type.Replay-import qualified Rattletrap.Type.Replication-import qualified Rattletrap.Type.ReplicationValue-import qualified Rattletrap.Type.ReservationAttribute-import qualified Rattletrap.Type.RigidBodyStateAttribute-import qualified Rattletrap.Type.Rotation-import qualified Rattletrap.Type.Section-import qualified Rattletrap.Type.SpawnedReplication-import qualified Rattletrap.Type.StatEventAttribute-import qualified Rattletrap.Type.Str-import qualified Rattletrap.Type.StringAttribute-import qualified Rattletrap.Type.TeamPaintAttribute-import qualified Rattletrap.Type.TitleAttribute-import qualified Rattletrap.Type.UniqueIdAttribute-import qualified Rattletrap.Type.UpdatedReplication-import qualified Rattletrap.Type.Vector-import qualified Rattletrap.Type.WeldedInfoAttribute-import qualified Rattletrap.Type.Word32le-import qualified Rattletrap.Type.Word64le-import qualified Rattletrap.Type.Word8le-import qualified Rattletrap.Utility.Helper
− library/Rattletrap/Console/Main.hs
@@ -1,240 +0,0 @@-module Rattletrap.Console.Main-  ( main-  , rattletrap-  )-where--import qualified Control.Monad as Monad-import qualified Data.Aeson as Json-import qualified Data.ByteString as Bytes-import qualified Data.ByteString.Lazy as LazyBytes-import qualified Data.Version as Version-import qualified Network.HTTP.Client as Client-import qualified Network.HTTP.Client.TLS as Client-import qualified Paths_rattletrap as This-import qualified Rattletrap.Type.Replay as Rattletrap-import qualified Rattletrap.Utility.Helper as Rattletrap-import qualified System.Console.GetOpt as Console-import qualified System.Environment as Environment-import qualified System.Exit as Exit-import qualified System.FilePath as Path-import qualified System.IO as IO-import qualified Text.Printf as Printf--main :: IO ()-main = do-  name <- Environment.getProgName-  arguments <- Environment.getArgs-  rattletrap name arguments--rattletrap :: String -> [String] -> IO ()-rattletrap name arguments = do-  config <- getConfig arguments-  Monad.when (configHelp config) (printHelp name *> Exit.exitFailure)-  Monad.when (configVersion config) (printVersion *> Exit.exitFailure)-  input <- getInput config-  let decode = getDecoder config-  replay <- either fail pure (decode input)-  let encode = getEncoder config-  putOutput config (encode replay)--getDecoder :: Config -> Bytes.ByteString -> Either String Rattletrap.Replay-getDecoder config = case getMode config of-  ModeDecode -> Rattletrap.decodeReplayFile $ configFast config-  ModeEncode -> Rattletrap.decodeReplayJson--getEncoder :: Config -> Rattletrap.Replay -> Bytes.ByteString-getEncoder config = case getMode config of-  ModeDecode -> if configCompact config-    then LazyBytes.toStrict . Json.encode-    else Rattletrap.encodeReplayJson-  ModeEncode -> Rattletrap.encodeReplayFile $ configFast config--getInput :: Config -> IO Bytes.ByteString-getInput config = case configInput config of-  Nothing -> Bytes.getContents-  Just fileOrUrl -> case Client.parseUrlThrow fileOrUrl of-    Nothing -> Bytes.readFile fileOrUrl-    Just request -> do-      manager <- Client.newTlsManager-      response <- Client.httpLbs request manager-      pure (LazyBytes.toStrict (Client.responseBody response))--putOutput :: Config -> Bytes.ByteString -> IO ()-putOutput config = case configOutput config of-  Nothing -> Bytes.putStr-  Just file -> Bytes.writeFile file--getConfig :: [String] -> IO Config-getConfig arguments = do-  let-    (updates, unexpectedArguments, unknownOptions, problems) =-      Console.getOpt' Console.Permute options arguments-  printUnexpectedArguments unexpectedArguments-  printUnknownOptions unknownOptions-  printProblems problems-  Monad.unless (null problems) Exit.exitFailure-  either fail pure (Monad.foldM applyUpdate defaultConfig updates)--type Option = Console.OptDescr Update--type Update = Config -> Either String Config--options :: [Option]-options =-  [ compactOption-  , fastOption-  , helpOption-  , inputOption-  , modeOption-  , outputOption-  , versionOption-  ]--compactOption :: Option-compactOption = Console.Option-  ['c']-  ["compact"]-  (Console.NoArg (\config -> pure config { configCompact = True }))-  "minify JSON output"--fastOption :: Option-fastOption = Console.Option-  ['f']-  ["fast"]-  (Console.NoArg (\config -> pure config { configFast = True }))-  "only encode or decode the header"--helpOption :: Option-helpOption = Console.Option-  ['h']-  ["help"]-  (Console.NoArg (\config -> pure config { configHelp = True }))-  "show the help"--inputOption :: Option-inputOption = Console.Option-  ['i']-  ["input"]-  (Console.ReqArg-    (\input config -> pure config { configInput = Just input })-    "FILE|URL"-  )-  "input file or URL"--modeOption :: Option-modeOption = Console.Option-  ['m']-  ["mode"]-  (Console.ReqArg-    (\rawMode config -> do-      mode <- parseMode rawMode-      pure config { configMode = Just mode }-    )-    "MODE"-  )-  "decode or encode"--outputOption :: Option-outputOption = Console.Option-  ['o']-  ["output"]-  (Console.ReqArg-    (\output config -> pure config { configOutput = Just output })-    "FILE"-  )-  "output file"--versionOption :: Option-versionOption = Console.Option-  ['v']-  ["version"]-  (Console.NoArg (\config -> pure config { configVersion = True }))-  "show the version"--applyUpdate :: Config -> Update -> Either String Config-applyUpdate config update = update config--data Config = Config-  { configCompact :: Bool-  , configFast :: Bool-  , configHelp :: Bool-  , configInput :: Maybe String-  , configMode :: Maybe Mode-  , configOutput :: Maybe String-  , configVersion :: Bool-  } deriving (Show)--defaultConfig :: Config-defaultConfig = Config-  { configCompact = False-  , configFast = False-  , configHelp = False-  , configInput = Nothing-  , configMode = Nothing-  , configOutput = Nothing-  , configVersion = False-  }--getMode :: Config -> Mode-getMode config = case getExtension (configInput config) of-  ".json" -> ModeEncode-  ".replay" -> ModeDecode-  _ -> case getExtension (configOutput config) of-    ".json" -> ModeDecode-    ".replay" -> ModeEncode-    _ -> ModeDecode--getExtension :: Maybe String -> String-getExtension = maybe "" Path.takeExtension--data Mode-  = ModeDecode-  | ModeEncode-  deriving (Show)--parseMode :: String -> Either String Mode-parseMode mode = case mode of-  "decode" -> Right ModeDecode-  "encode" -> Right ModeEncode-  _ -> Left (Printf.printf "invalid mode: %s" (show mode))--printUnexpectedArguments :: [String] -> IO ()-printUnexpectedArguments = mapM_ printUnexpectedArgument--printUnexpectedArgument :: String -> IO ()-printUnexpectedArgument =-  warnLn . Printf.printf "WARNING: unexpected argument `%s'"--printUnknownOptions :: [String] -> IO ()-printUnknownOptions = mapM_ printUnknownOption--printUnknownOption :: String -> IO ()-printUnknownOption = warnLn . Printf.printf "WARNING: unknown option `%s'"--printProblems :: [String] -> IO ()-printProblems = mapM_ printProblem--printProblem :: String -> IO ()-printProblem = warn . Printf.printf "ERROR: %s"--printHelp :: String -> IO ()-printHelp = warn . help--help :: String -> String-help name = Console.usageInfo (header name) options--header :: String -> String-header name = unwords [name, "version", version]--version :: String-version = Version.showVersion This.version--printVersion :: IO ()-printVersion = warnLn version--warn :: String -> IO ()-warn = IO.hPutStr IO.stderr--warnLn :: String -> IO ()-warnLn = IO.hPutStrLn IO.stderr
− library/Rattletrap/Data.hs
@@ -1,642 +0,0 @@--- brittany --columns 120-module Rattletrap.Data-  ( rawParentClasses-  , rawClassesWithLocation-  , rawClassesWithRotation-  , rawObjectClasses-  , rawAttributeTypes-  , rawCrc32Table-  )-where--import Rattletrap.Type.AttributeType--rawParentClasses :: [(String, String)]-rawParentClasses =-  [ ("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_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_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.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_GrapplingHook_TA", "TAGame.SpecialPickup_Targeted_TA")-  , ("TAGame.SpecialPickup_HitForce_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.SpecialPickup_HauntedBallBeam_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")-  ]--rawClassesWithLocation :: [String]-rawClassesWithLocation =-  [ "TAGame.Ball_Breakout_TA"-  , "Archetypes.Ball.Ball_Breakout"-  , "TAGame.Ball_TA"-  , "Archetypes.Ball.Ball_BasketBall_Mutator"-  , "Archetypes.Ball.Ball_BasketBall"-  , "Archetypes.Ball.Ball_Basketball"-  , "Archetypes.Ball.Ball_Default"-  , "Archetypes.Ball.Ball_Puck"-  , "Archetypes.Ball.CubeBall"-  , "Archetypes.Ball.Ball_Haunted"-  , "TAGame.Ball_Haunted_TA"-  , "TAGame.Car_Season_TA"-  , "TAGame.Car_TA"-  , "Archetypes.Car.Car_Default"-  , "Archetypes.GameEvent.GameEvent_Season:CarArchetype"-  , "Archetypes.SpecialPickups.SpecialPickup_HauntedBallBeam"-  , "Archetypes.SpecialPickups.SpecialPickup_Rugby"-  , "TAGame.CameraSettingsActor_TA"-  , "TAGame.CarComponent_Boost_TA"-  , "TAGame.CarComponent_Dodge_TA"-  , "TAGame.CarComponent_DoubleJump_TA"-  , "TAGame.CarComponent_FlipCar_TA"-  , "TAGame.CarComponent_Jump_TA"-  , "TAGame.GameEvent_Season_TA"-  , "TAGame.GameEvent_Soccar_TA"-  , "TAGame.GameEvent_SoccarPrivate_TA"-  , "TAGame.GameEvent_SoccarSplitscreen_TA"-  , "TAGame.GRI_TA"-  , "TAGame.PRI_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_GrapplingHook_TA"-  , "TAGame.SpecialPickup_HitForce_TA"-  , "TAGame.SpecialPickup_Swapper_TA"-  , "TAGame.SpecialPickup_Tornado_TA"-  , "TAGame.Team_Soccar_TA"-  , "TAGame.Default__CameraSettingsActor_TA"-  , "TAGame.Default__PRI_TA"-  , "TheWorld:PersistentLevel.BreakOutActor_Platform_TA"-  , "TheWorld:PersistentLevel.CrowdActor_TA"-  , "TheWorld:PersistentLevel.CrowdManager_TA"-  , "TheWorld:PersistentLevel.InMapScoreboard_TA"-  , "TheWorld:PersistentLevel.VehiclePickup_Boost_TA"-  , "TAGame.HauntedBallTrapTrigger_TA"-  , "ProjectX.NetModeReplicator"-  ]--rawClassesWithRotation :: [String]-rawClassesWithRotation =-  [ "TAGame.Ball_Breakout_TA"-  , "Archetypes.Ball.Ball_Breakout"-  , "TAGame.Ball_TA"-  , "Archetypes.Ball.Ball_BasketBall_Mutator"-  , "Archetypes.Ball.Ball_BasketBall"-  , "Archetypes.Ball.Ball_Basketball"-  , "Archetypes.Ball.Ball_Default"-  , "Archetypes.Ball.Ball_Puck"-  , "Archetypes.Ball.CubeBall"-  , "Archetypes.Ball.Ball_Haunted"-  , "TAGame.Ball_Haunted_TA"-  , "TAGame.Car_Season_TA"-  , "TAGame.Car_TA"-  , "Archetypes.Car.Car_Default"-  , "Archetypes.GameEvent.GameEvent_Season:CarArchetype"-  , "Archetypes.SpecialPickups.SpecialPickup_HauntedBallBeam"-  , "Archetypes.SpecialPickups.SpecialPickup_Rugby"-  -- This comments forces Brittany to use a multi-line layout for this list.-  ]--rawObjectClasses :: [(String, String)]-rawObjectClasses =-  [ ("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_Haunted", "TAGame.Ball_Haunted_TA")-  , ("Archetypes.Ball.Ball_Puck", "TAGame.Ball_TA")-  , ("Archetypes.Ball.CubeBall", "TAGame.Ball_TA")-  , ("Archetypes.Car.Car_Default", "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", "TAGame.GameEvent_Season_TA")-  , ("Archetypes.GameEvent.GameEvent_Season:CarArchetype", "TAGame.Car_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_GravityWell", "TAGame.SpecialPickup_BallGravity_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.SpecialPickups.SpecialPickup_HauntedBallBeam", "TAGame.SpecialPickup_HauntedBallBeam_TA")-  , ("Archetypes.SpecialPickups.SpecialPickup_Rugby", "TAGame.SpecialPickup_Rugby_TA")-  , ("Archetypes.Teams.Team0", "TAGame.Team_Soccar_TA")-  , ("Archetypes.Teams.Team1", "TAGame.Team_Soccar_TA")-  , ("GameInfo_Basketball.GameInfo.GameInfo_Basketball:GameReplicationInfoArchetype", "TAGame.GRI_TA")-  , ("GameInfo_Breakout.GameInfo.GameInfo_Breakout: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")-  , ("ProjectX.Default__NetModeReplicator_X", "ProjectX.NetModeReplicator")-  , ("TAGame.Default__CameraSettingsActor_TA", "TAGame.CameraSettingsActor_TA")-  , ("TAGame.Default__PRI_TA", "TAGame.PRI_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")-  , ("Haunted_TrainStation_P.TheWorld:PersistentLevel.HauntedBallTrapTrigger_TA_1", "TAGame.HauntedBallTrapTrigger_TA")-  , ("Haunted_TrainStation_P.TheWorld:PersistentLevel.HauntedBallTrapTrigger_TA_0", "TAGame.HauntedBallTrapTrigger_TA")-  ]--rawAttributeTypes :: [(String, AttributeType)]-rawAttributeTypes =-  [ ("Engine.Actor:bBlockActors", AttributeTypeBoolean)-  , ("Engine.Actor:bCollideActors", AttributeTypeBoolean)-  , ("Engine.Actor:bHidden", AttributeTypeBoolean)-  , ("Engine.Actor:DrawScale", AttributeTypeFloat)-  , ("Engine.Actor:RemoteRole", AttributeTypeEnum)-  , ("Engine.Actor:Role", AttributeTypeEnum)-  , ("Engine.GameReplicationInfo:bMatchIsOver", AttributeTypeBoolean)-  , ("Engine.GameReplicationInfo:GameClass", AttributeTypeFlaggedInt)-  , ("Engine.GameReplicationInfo:ServerName", AttributeTypeString)-  , ("Engine.Pawn:PlayerReplicationInfo", AttributeTypeFlaggedInt)-  , ("Engine.PlayerReplicationInfo:bBot", AttributeTypeBoolean)-  , ("Engine.PlayerReplicationInfo:bIsSpectator", AttributeTypeBoolean)-  , ("Engine.PlayerReplicationInfo:bReadyToPlay", AttributeTypeBoolean)-  , ("Engine.PlayerReplicationInfo:bTimedOut", AttributeTypeBoolean)-  , ("Engine.PlayerReplicationInfo:bWaitingPlayer", AttributeTypeBoolean)-  , ("Engine.PlayerReplicationInfo:Ping", AttributeTypeByte)-  , ("Engine.PlayerReplicationInfo:PlayerID", AttributeTypeInt)-  , ("Engine.PlayerReplicationInfo:PlayerName", AttributeTypeString)-  , ("Engine.PlayerReplicationInfo:RemoteUserData", AttributeTypeString)-  , ("Engine.PlayerReplicationInfo:Score", AttributeTypeInt)-  , ("Engine.PlayerReplicationInfo:Team", AttributeTypeFlaggedInt)-  , ("Engine.PlayerReplicationInfo:UniqueId", AttributeTypeUniqueId)-  , ("Engine.TeamInfo:Score", AttributeTypeInt)-  , ("ProjectX.GRI_X:bGameStarted", AttributeTypeBoolean)-  , ("ProjectX.GRI_X:GameServerID", AttributeTypeQWord)-  , ("ProjectX.GRI_X:MatchGUID", AttributeTypeString)-  , ("ProjectX.GRI_X:ReplicatedGameMutatorIndex", AttributeTypeInt)-  , ("ProjectX.GRI_X:ReplicatedGamePlaylist", AttributeTypeInt)-  , ("ProjectX.GRI_X:Reservations", AttributeTypeReservation)-  , ("TAGame.Ball_Breakout_TA:AppliedDamage", AttributeTypeAppliedDamage)-  , ("TAGame.Ball_Breakout_TA:DamageIndex", AttributeTypeInt)-  , ("TAGame.Ball_Breakout_TA:LastTeamTouch", AttributeTypeByte)-  , ("TAGame.Ball_TA:GameEvent", AttributeTypeFlaggedInt)-  , ("TAGame.Ball_TA:HitTeamNum", AttributeTypeByte)-  , ("TAGame.Ball_TA:ReplicatedAddedCarBounceScale", AttributeTypeFloat)-  , ("TAGame.Ball_TA:ReplicatedBallMaxLinearSpeedScale", AttributeTypeFloat)-  , ("TAGame.Ball_TA:ReplicatedBallScale", AttributeTypeFloat)-  , ("TAGame.Ball_TA:ReplicatedExplosionData", AttributeTypeExplosion)-  , ("TAGame.Ball_TA:ReplicatedExplosionDataExtended", AttributeTypeExtendedExplosion)-  , ("TAGame.Ball_TA:ReplicatedWorldBounceScale", AttributeTypeFloat)-  , ("TAGame.BreakOutActor_Platform_TA:DamageState", AttributeTypeDamageState)-  , ("TAGame.CameraSettingsActor_TA:bUsingBehindView", AttributeTypeBoolean)-  , ("TAGame.CameraSettingsActor_TA:bMouseCameraToggleEnabled", AttributeTypeBoolean)-  , ("TAGame.CameraSettingsActor_TA:bUsingSecondaryCamera", AttributeTypeBoolean)-  , ("TAGame.CameraSettingsActor_TA:bUsingSwivel", AttributeTypeBoolean)-  , ("TAGame.CameraSettingsActor_TA:CameraPitch", AttributeTypeByte)-  , ("TAGame.CameraSettingsActor_TA:CameraYaw", AttributeTypeByte)-  , ("TAGame.CameraSettingsActor_TA:PRI", AttributeTypeFlaggedInt)-  , ("TAGame.CameraSettingsActor_TA:ProfileSettings", AttributeTypeCamSettings)-  , ("TAGame.Car_TA:AddedBallForceMultiplier", AttributeTypeFloat)-  , ("TAGame.Car_TA:AddedCarForceMultiplier", AttributeTypeFloat)-  , ("TAGame.Car_TA:AttachedPickup", AttributeTypeFlaggedInt)-  , ("TAGame.Car_TA:ClubColors", AttributeTypeClubColors)-  , ("TAGame.Car_TA:ReplicatedDemolish", AttributeTypeDemolish)-  , ("TAGame.Car_TA:TeamPaint", AttributeTypeTeamPaint)-  , ("TAGame.CarComponent_Boost_TA:bNoBoost", AttributeTypeBoolean)-  , ("TAGame.CarComponent_Boost_TA:BoostModifier", AttributeTypeFloat)-  , ("TAGame.CarComponent_Boost_TA:bUnlimitedBoost", AttributeTypeBoolean)-  , ("TAGame.CarComponent_Boost_TA:RechargeDelay", AttributeTypeFloat)-  , ("TAGame.CarComponent_Boost_TA:RechargeRate", AttributeTypeFloat)-  , ("TAGame.CarComponent_Boost_TA:ReplicatedBoostAmount", AttributeTypeByte)-  , ("TAGame.CarComponent_Boost_TA:UnlimitedBoostRefCount", AttributeTypeInt)-  , ("TAGame.CarComponent_Dodge_TA:DodgeTorque", AttributeTypeLocation)-  , ("TAGame.CarComponent_FlipCar_TA:bFlipRight", AttributeTypeBoolean)-  , ("TAGame.CarComponent_FlipCar_TA:FlipCarTime", AttributeTypeFloat)-  , ("TAGame.CarComponent_TA:ReplicatedActive", AttributeTypeByte)-  , ("TAGame.CarComponent_TA:ReplicatedActivityTime", AttributeTypeFloat)-  , ("TAGame.CarComponent_TA:Vehicle", AttributeTypeFlaggedInt)-  , ("TAGame.CrowdActor_TA:GameEvent", AttributeTypeFlaggedInt)-  , ("TAGame.CrowdActor_TA:ModifiedNoise", AttributeTypeFloat)-  , ("TAGame.CrowdActor_TA:ReplicatedCountDownNumber", AttributeTypeInt)-  , ("TAGame.CrowdActor_TA:ReplicatedOneShotSound", AttributeTypeFlaggedInt)-  , ("TAGame.CrowdActor_TA:ReplicatedRoundCountDownNumber", AttributeTypeInt)-  , ("TAGame.CrowdManager_TA:GameEvent", AttributeTypeFlaggedInt)-  , ("TAGame.CrowdManager_TA:ReplicatedGlobalOneShotSound", AttributeTypeFlaggedInt)-  , ("TAGame.GameEvent_Soccar_TA:bBallHasBeenHit", AttributeTypeBoolean)-  , ("TAGame.GameEvent_Soccar_TA:bClubMatch", AttributeTypeBoolean)-  , ("TAGame.GameEvent_Soccar_TA:bOverTime", AttributeTypeBoolean)-  , ("TAGame.GameEvent_Soccar_TA:bUnlimitedTime", AttributeTypeBoolean)-  , ("TAGame.GameEvent_Soccar_TA:GameTime", AttributeTypeInt)-  , ("TAGame.GameEvent_Soccar_TA:ReplicatedMusicStinger", AttributeTypeMusicStinger)-  , ("TAGame.GameEvent_Soccar_TA:ReplicatedScoredOnTeam", AttributeTypeByte)-  , ("TAGame.GameEvent_Soccar_TA:ReplicatedServerPerformanceState", AttributeTypeByte)-  , ("TAGame.GameEvent_Soccar_TA:ReplicatedStatEvent", AttributeTypeStatEvent)-  , ("TAGame.GameEvent_Soccar_TA:RoundNum", AttributeTypeInt)-  , ("TAGame.GameEvent_Soccar_TA:SecondsRemaining", AttributeTypeInt)-  , ("TAGame.GameEvent_Soccar_TA:SeriesLength", AttributeTypeInt)-  , ("TAGame.GameEvent_Soccar_TA:SubRulesArchetype", AttributeTypeFlaggedInt)-  , ("TAGame.GameEvent_SoccarPrivate_TA:MatchSettings", AttributeTypePrivateMatchSettings)-  , ("TAGame.GameEvent_TA:bCanVoteToForfeit", AttributeTypeBoolean)-  , ("TAGame.GameEvent_TA:bHasLeaveMatchPenalty", AttributeTypeBoolean)-  , ("TAGame.GameEvent_TA:BotSkill", AttributeTypeInt)-  , ("TAGame.GameEvent_TA:GameMode", AttributeTypeGameMode)-  , ("TAGame.GameEvent_TA:MatchTypeClass", AttributeTypeFlaggedInt)-  , ("TAGame.GameEvent_TA:ReplicatedGameStateTimeRemaining", AttributeTypeInt)-  , ("TAGame.GameEvent_TA:ReplicatedRoundCountDownNumber", AttributeTypeInt)-  , ("TAGame.GameEvent_TA:ReplicatedStateIndex", AttributeTypeByte)-  , ("TAGame.GameEvent_TA:ReplicatedStateName", AttributeTypeInt)-  , ("TAGame.GameEvent_Team_TA:bForfeit", AttributeTypeBoolean)-  , ("TAGame.GameEvent_Team_TA:MaxTeamSize", AttributeTypeInt)-  , ("TAGame.GRI_TA:NewDedicatedServerIP", AttributeTypeString)-  , ("TAGame.PRI_TA:bIsInSplitScreen", AttributeTypeBoolean)-  , ("TAGame.PRI_TA:bMatchMVP", AttributeTypeBoolean)-  , ("TAGame.PRI_TA:bOnlineLoadoutSet", AttributeTypeBoolean)-  , ("TAGame.PRI_TA:bOnlineLoadoutsSet", AttributeTypeBoolean)-  , ("TAGame.PRI_TA:BotProductName", AttributeTypeInt)-  , ("TAGame.PRI_TA:bReady", AttributeTypeBoolean)-  , ("TAGame.PRI_TA:bUsingBehindView", AttributeTypeBoolean)-  , ("TAGame.PRI_TA:bUsingItems", AttributeTypeBoolean)-  , ("TAGame.PRI_TA:bUsingSecondaryCamera", AttributeTypeBoolean)-  , ("TAGame.PRI_TA:CameraPitch", AttributeTypeByte)-  , ("TAGame.PRI_TA:CameraSettings", AttributeTypeCamSettings)-  , ("TAGame.PRI_TA:CameraYaw", AttributeTypeByte)-  , ("TAGame.PRI_TA:ClientLoadout", AttributeTypeLoadout)-  , ("TAGame.PRI_TA:ClientLoadoutOnline", AttributeTypeLoadoutOnline)-  , ("TAGame.PRI_TA:ClientLoadouts", AttributeTypeLoadouts)-  , ("TAGame.PRI_TA:ClientLoadoutsOnline", AttributeTypeLoadoutsOnline)-  , ("TAGame.PRI_TA:ClubID", AttributeTypeInt64)-  , ("TAGame.PRI_TA:MatchAssists", AttributeTypeInt)-  , ("TAGame.PRI_TA:MatchBreakoutDamage", AttributeTypeInt)-  , ("TAGame.PRI_TA:MatchGoals", AttributeTypeInt)-  , ("TAGame.PRI_TA:MatchSaves", AttributeTypeInt)-  , ("TAGame.PRI_TA:MatchScore", AttributeTypeInt)-  , ("TAGame.PRI_TA:MatchShots", AttributeTypeInt)-  , ("TAGame.PRI_TA:MaxTimeTillItem", AttributeTypeInt)-  , ("TAGame.PRI_TA:PartyLeader", AttributeTypePartyLeader)-  , ("TAGame.PRI_TA:PawnType", AttributeTypeByte)-  , ("TAGame.PRI_TA:PersistentCamera", AttributeTypeFlaggedInt)-  , ("TAGame.PRI_TA:PlayerHistoryKey", AttributeTypePlayerHistoryKey)-  , ("TAGame.PRI_TA:PlayerHistoryValid", AttributeTypeBoolean)-  , ("TAGame.PRI_TA:ReplicatedGameEvent", AttributeTypeFlaggedInt)-  , ("TAGame.PRI_TA:ReplicatedWorstNetQualityBeyondLatency", AttributeTypeByte)-  , ("TAGame.PRI_TA:SteeringSensitivity", AttributeTypeFloat)-  , ("TAGame.PRI_TA:SkillTier", AttributeTypeFlaggedByte)-  , ("TAGame.PRI_TA:TimeTillItem", AttributeTypeInt)-  , ("TAGame.PRI_TA:Title", AttributeTypeInt)-  , ("TAGame.PRI_TA:TotalXP", AttributeTypeInt)-  , ("TAGame.PRI_TA:PrimaryTitle", AttributeTypeTitle)-  , ("TAGame.PRI_TA:SecondaryTitle", AttributeTypeTitle)-  , ("TAGame.PRI_TA:SpectatorShortcut", AttributeTypeInt)-  , ("TAGame.RBActor_TA:bFrozen", AttributeTypeBoolean)-  , ("TAGame.RBActor_TA:bIgnoreSyncing", AttributeTypeBoolean)-  , ("TAGame.RBActor_TA:bReplayActor", AttributeTypeBoolean)-  , ("TAGame.RBActor_TA:ReplicatedRBState", AttributeTypeRigidBodyState)-  , ("TAGame.RBActor_TA:WeldedInfo", AttributeTypeWeldedInfo)-  , ("TAGame.SpecialPickup_BallFreeze_TA:RepOrigSpeed", AttributeTypeFloat)-  , ("TAGame.SpecialPickup_BallVelcro_TA:AttachTime", AttributeTypeFloat)-  , ("TAGame.SpecialPickup_BallVelcro_TA:bBroken", AttributeTypeBoolean)-  , ("TAGame.SpecialPickup_BallVelcro_TA:bHit", AttributeTypeBoolean)-  , ("TAGame.SpecialPickup_BallVelcro_TA:BreakTime", AttributeTypeFloat)-  , ("TAGame.SpecialPickup_Targeted_TA:Targeted", AttributeTypeFlaggedInt)-  , ("TAGame.Team_Soccar_TA:GameScore", AttributeTypeInt)-  , ("TAGame.Team_TA:ClubColors", AttributeTypeClubColors)-  , ("TAGame.Team_TA:ClubID", AttributeTypeInt64)-  , ("TAGame.Team_TA:CustomTeamName", AttributeTypeString)-  , ("TAGame.Team_TA:GameEvent", AttributeTypeFlaggedInt)-  , ("TAGame.Team_TA:LogoData", AttributeTypeFlaggedInt)-  , ("TAGame.Vehicle_TA:bDriving", AttributeTypeBoolean)-  , ("TAGame.Vehicle_TA:bReplicatedHandbrake", AttributeTypeBoolean)-  , ("TAGame.Vehicle_TA:ReplicatedSteer", AttributeTypeByte)-  , ("TAGame.Vehicle_TA:ReplicatedThrottle", AttributeTypeByte)-  , ("TAGame.VehiclePickup_TA:bNoPickup", AttributeTypeBoolean)-  , ("TAGame.VehiclePickup_TA:ReplicatedPickupData", AttributeTypePickup)-  , ("TAGame.Ball_Haunted_TA:LastTeamTouch", AttributeTypeByte)-  , ("TAGame.Ball_Haunted_TA:TotalActiveBeams", AttributeTypeByte)-  , ("TAGame.Ball_Haunted_TA:DeactivatedGoalIndex", AttributeTypeByte)-  , ("TAGame.Ball_Haunted_TA:ReplicatedBeamBrokenValue", AttributeTypeByte)-  , ("TAGame.Ball_Haunted_TA:bIsBallBeamed", AttributeTypeBoolean)-  , ("TAGame.SpecialPickup_Rugby_TA:bBallWelded", AttributeTypeBoolean)-  ]--rawCrc32Table :: Integral a => [a]-rawCrc32Table =-  [ 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-  ]
− library/Rattletrap/Decode/AppliedDamageAttribute.hs
@@ -1,19 +0,0 @@-module Rattletrap.Decode.AppliedDamageAttribute-  ( decodeAppliedDamageAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Int32le-import Rattletrap.Decode.Vector-import Rattletrap.Decode.Word8le-import Rattletrap.Type.AppliedDamageAttribute--decodeAppliedDamageAttributeBits-  :: (Int, Int, Int) -> DecodeBits AppliedDamageAttribute-decodeAppliedDamageAttributeBits version =-  AppliedDamageAttribute-    <$> decodeWord8leBits-    <*> decodeVectorBits version-    <*> decodeInt32leBits-    <*> decodeInt32leBits
− library/Rattletrap/Decode/Attribute.hs
@@ -1,74 +0,0 @@-module Rattletrap.Decode.Attribute-  ( decodeAttributesBits-  )-where--import Data.Semigroup ((<>))-import Rattletrap.Decode.AttributeValue-import Rattletrap.Decode.Common-import Rattletrap.Decode.CompressedWord-import Rattletrap.Type.Attribute-import Rattletrap.Type.ClassAttributeMap-import Rattletrap.Type.Common-import Rattletrap.Type.CompressedWord-import Rattletrap.Type.Str-import Rattletrap.Type.Word32le--decodeAttributesBits-  :: (Int, Int, Int)-  -> ClassAttributeMap-  -> Map CompressedWord Word32le-  -> CompressedWord-  -> DecodeBits [Attribute]-decodeAttributesBits version classes actors actor = do-  hasAttribute <- getBool-  if hasAttribute-    then-      (:)-      <$> decodeAttributeBits version classes actors actor-      <*> decodeAttributesBits version classes actors actor-    else pure []--decodeAttributeBits-  :: (Int, Int, Int)-  -> ClassAttributeMap-  -> Map CompressedWord Word32le-  -> CompressedWord-  -> DecodeBits Attribute-decodeAttributeBits version classes actors actor = do-  attributes <- lookupAttributeMap classes actors actor-  limit <- lookupAttributeIdLimit attributes actor-  attribute <- decodeCompressedWordBits limit-  name <- lookupAttributeName classes attributes attribute-  Attribute attribute name-    <$> decodeAttributeValueBits-          version-          (classAttributeMapObjectMap classes)-          name--lookupAttributeMap-  :: ClassAttributeMap-  -> Map CompressedWord Word32le-  -> CompressedWord-  -> DecodeBits (Map Word32le Word32le)-lookupAttributeMap classes actors actor = fromMaybe-  ("could not get attribute map for " <> show actor)-  (getAttributeMap classes actors actor)--lookupAttributeIdLimit-  :: Map Word32le Word32le -> CompressedWord -> DecodeBits Word-lookupAttributeIdLimit attributes actor = fromMaybe-  ("could not get attribute ID limit for " <> show actor)-  (getAttributeIdLimit attributes)--lookupAttributeName-  :: ClassAttributeMap-  -> Map Word32le Word32le-  -> CompressedWord-  -> DecodeBits Str-lookupAttributeName classes attributes attribute = fromMaybe-  ("could not get attribute name for " <> show attribute)-  (getAttributeName classes attributes attribute)--fromMaybe :: String -> Maybe a -> DecodeBits a-fromMaybe message = maybe (fail message) pure
− library/Rattletrap/Decode/AttributeMapping.hs
@@ -1,12 +0,0 @@-module Rattletrap.Decode.AttributeMapping-  ( decodeAttributeMapping-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Word32le-import Rattletrap.Type.AttributeMapping--decodeAttributeMapping :: Decode AttributeMapping-decodeAttributeMapping =-  AttributeMapping <$> decodeWord32le <*> decodeWord32le
− library/Rattletrap/Decode/AttributeValue.hs
@@ -1,126 +0,0 @@-module Rattletrap.Decode.AttributeValue-  ( decodeAttributeValueBits-  )-where--import Data.Semigroup ((<>))-import Rattletrap.Data-import Rattletrap.Decode.AppliedDamageAttribute-import Rattletrap.Decode.BooleanAttribute-import Rattletrap.Decode.ByteAttribute-import Rattletrap.Decode.CamSettingsAttribute-import Rattletrap.Decode.ClubColorsAttribute-import Rattletrap.Decode.Common-import Rattletrap.Decode.DamageStateAttribute-import Rattletrap.Decode.DemolishAttribute-import Rattletrap.Decode.EnumAttribute-import Rattletrap.Decode.ExplosionAttribute-import Rattletrap.Decode.ExtendedExplosionAttribute-import Rattletrap.Decode.FlaggedIntAttribute-import Rattletrap.Decode.FlaggedByteAttribute-import Rattletrap.Decode.FloatAttribute-import Rattletrap.Decode.GameModeAttribute-import Rattletrap.Decode.Int64Attribute-import Rattletrap.Decode.IntAttribute-import Rattletrap.Decode.LoadoutAttribute-import Rattletrap.Decode.LoadoutOnlineAttribute-import Rattletrap.Decode.LoadoutsAttribute-import Rattletrap.Decode.LoadoutsOnlineAttribute-import Rattletrap.Decode.LocationAttribute-import Rattletrap.Decode.MusicStingerAttribute-import Rattletrap.Decode.PartyLeaderAttribute-import Rattletrap.Decode.PickupAttribute-import Rattletrap.Decode.PlayerHistoryKeyAttribute-import Rattletrap.Decode.PrivateMatchSettingsAttribute-import Rattletrap.Decode.QWordAttribute-import Rattletrap.Decode.ReservationAttribute-import Rattletrap.Decode.RigidBodyStateAttribute-import Rattletrap.Decode.StatEventAttribute-import Rattletrap.Decode.StringAttribute-import Rattletrap.Decode.TeamPaintAttribute-import Rattletrap.Decode.TitleAttribute-import Rattletrap.Decode.UniqueIdAttribute-import Rattletrap.Decode.WeldedInfoAttribute-import Rattletrap.Type.AttributeType-import Rattletrap.Type.AttributeValue-import Rattletrap.Type.Common-import Rattletrap.Type.Str-import Rattletrap.Type.Word32le--import qualified Data.Map as Map--decodeAttributeValueBits-  :: (Int, Int, Int) -> Map Word32le Str -> Str -> DecodeBits AttributeValue-decodeAttributeValueBits version objectMap name = do-  constructor <- maybe-    (fail ("don't know how to get attribute value " <> show name))-    pure-    (Map.lookup name attributeTypes)-  case constructor of-    AttributeTypeAppliedDamage ->-      AttributeValueAppliedDamage <$> decodeAppliedDamageAttributeBits version-    AttributeTypeBoolean ->-      AttributeValueBoolean <$> decodeBooleanAttributeBits-    AttributeTypeByte -> AttributeValueByte <$> decodeByteAttributeBits-    AttributeTypeCamSettings ->-      AttributeValueCamSettings <$> decodeCamSettingsAttributeBits version-    AttributeTypeClubColors ->-      AttributeValueClubColors <$> decodeClubColorsAttributeBits-    AttributeTypeDamageState ->-      AttributeValueDamageState <$> decodeDamageStateAttributeBits version-    AttributeTypeDemolish ->-      AttributeValueDemolish <$> decodeDemolishAttributeBits version-    AttributeTypeEnum -> AttributeValueEnum <$> decodeEnumAttributeBits-    AttributeTypeExplosion ->-      AttributeValueExplosion <$> decodeExplosionAttributeBits version-    AttributeTypeExtendedExplosion -> AttributeValueExtendedExplosion-      <$> decodeExtendedExplosionAttributeBits version-    AttributeTypeFlaggedInt ->-      AttributeValueFlaggedInt <$> decodeFlaggedIntAttributeBits-    AttributeTypeFlaggedByte ->-      AttributeValueFlaggedByte <$> decodeFlaggedByteAttributeBits-    AttributeTypeFloat -> AttributeValueFloat <$> decodeFloatAttributeBits-    AttributeTypeGameMode ->-      AttributeValueGameMode <$> decodeGameModeAttributeBits version-    AttributeTypeInt -> AttributeValueInt <$> decodeIntAttributeBits-    AttributeTypeInt64 -> AttributeValueInt64 <$> decodeInt64AttributeBits-    AttributeTypeLoadout ->-      AttributeValueLoadout <$> decodeLoadoutAttributeBits-    AttributeTypeLoadoutOnline ->-      AttributeValueLoadoutOnline-        <$> decodeLoadoutOnlineAttributeBits version objectMap-    AttributeTypeLoadouts ->-      AttributeValueLoadouts <$> decodeLoadoutsAttributeBits-    AttributeTypeLoadoutsOnline ->-      AttributeValueLoadoutsOnline-        <$> decodeLoadoutsOnlineAttributeBits version objectMap-    AttributeTypeLocation ->-      AttributeValueLocation <$> decodeLocationAttributeBits version-    AttributeTypeMusicStinger ->-      AttributeValueMusicStinger <$> decodeMusicStingerAttributeBits-    AttributeTypePartyLeader ->-      AttributeValuePartyLeader <$> decodePartyLeaderAttributeBits version-    AttributeTypePickup -> AttributeValuePickup <$> decodePickupAttributeBits-    AttributeTypePlayerHistoryKey ->-      AttributeValuePlayerHistoryKey <$> decodePlayerHistoryKeyAttributeBits-    AttributeTypePrivateMatchSettings ->-      AttributeValuePrivateMatchSettings-        <$> decodePrivateMatchSettingsAttributeBits-    AttributeTypeQWord -> AttributeValueQWord <$> decodeQWordAttributeBits-    AttributeTypeReservation ->-      AttributeValueReservation <$> decodeReservationAttributeBits version-    AttributeTypeRigidBodyState -> AttributeValueRigidBodyState-      <$> decodeRigidBodyStateAttributeBits version-    AttributeTypeStatEvent ->-      AttributeValueStatEvent <$> decodeStatEventAttributeBits-    AttributeTypeString -> AttributeValueString <$> decodeStringAttributeBits-    AttributeTypeTeamPaint ->-      AttributeValueTeamPaint <$> decodeTeamPaintAttributeBits-    AttributeTypeTitle -> AttributeValueTitle <$> decodeTitleAttributeBits-    AttributeTypeUniqueId ->-      AttributeValueUniqueId <$> decodeUniqueIdAttributeBits version-    AttributeTypeWeldedInfo ->-      AttributeValueWeldedInfo <$> decodeWeldedInfoAttributeBits version--attributeTypes :: Map Str AttributeType-attributeTypes = Map.mapKeys toStr (Map.fromList rawAttributeTypes)
− library/Rattletrap/Decode/BooleanAttribute.hs
@@ -1,10 +0,0 @@-module Rattletrap.Decode.BooleanAttribute-  ( decodeBooleanAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Type.BooleanAttribute--decodeBooleanAttributeBits :: DecodeBits BooleanAttribute-decodeBooleanAttributeBits = BooleanAttribute <$> getBool
− library/Rattletrap/Decode/ByteAttribute.hs
@@ -1,11 +0,0 @@-module Rattletrap.Decode.ByteAttribute-  ( decodeByteAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Word8le-import Rattletrap.Type.ByteAttribute--decodeByteAttributeBits :: DecodeBits ByteAttribute-decodeByteAttributeBits = ByteAttribute <$> decodeWord8leBits
− library/Rattletrap/Decode/Cache.hs
@@ -1,18 +0,0 @@-module Rattletrap.Decode.Cache-  ( decodeCache-  )-where--import Rattletrap.Decode.AttributeMapping-import Rattletrap.Decode.Common-import Rattletrap.Decode.List-import Rattletrap.Decode.Word32le-import Rattletrap.Type.Cache--decodeCache :: Decode Cache-decodeCache =-  Cache-    <$> decodeWord32le-    <*> decodeWord32le-    <*> decodeWord32le-    <*> decodeList decodeAttributeMapping
− library/Rattletrap/Decode/CamSettingsAttribute.hs
@@ -1,20 +0,0 @@-module Rattletrap.Decode.CamSettingsAttribute-  ( decodeCamSettingsAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Float32le-import Rattletrap.Type.CamSettingsAttribute--decodeCamSettingsAttributeBits-  :: (Int, Int, Int) -> DecodeBits CamSettingsAttribute-decodeCamSettingsAttributeBits version =-  CamSettingsAttribute-    <$> decodeFloat32leBits-    <*> decodeFloat32leBits-    <*> decodeFloat32leBits-    <*> decodeFloat32leBits-    <*> decodeFloat32leBits-    <*> decodeFloat32leBits-    <*> decodeWhen (version >= (868, 20, 0)) decodeFloat32leBits
− library/Rattletrap/Decode/ClassMapping.hs
@@ -1,12 +0,0 @@-module Rattletrap.Decode.ClassMapping-  ( decodeClassMapping-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Str-import Rattletrap.Decode.Word32le-import Rattletrap.Type.ClassMapping--decodeClassMapping :: Decode ClassMapping-decodeClassMapping = ClassMapping <$> decodeStr <*> decodeWord32le
− library/Rattletrap/Decode/ClubColorsAttribute.hs
@@ -1,16 +0,0 @@-module Rattletrap.Decode.ClubColorsAttribute-  ( decodeClubColorsAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Word8le-import Rattletrap.Type.ClubColorsAttribute--decodeClubColorsAttributeBits :: DecodeBits ClubColorsAttribute-decodeClubColorsAttributeBits =-  ClubColorsAttribute-    <$> getBool-    <*> decodeWord8leBits-    <*> getBool-    <*> decodeWord8leBits
− library/Rattletrap/Decode/Common.hs
@@ -1,70 +0,0 @@-module Rattletrap.Decode.Common-  ( Decode-  , DecodeBits-  , decodeWhen-  , getBitsLE-  , getByteStringBits-  , getWord8Bits-  , runDecode-  , runDecodeBits-  , toBits-  , Binary.getFloatle-  , Binary.getByteString-  , Binary.getInt8-  , Binary.getInt32le-  , Binary.getInt64le-  , Binary.getWord8-  , Binary.getWord32le-  , Binary.getWord64le-  , BinaryBits.getBool-  )-where--import qualified Control.Applicative as Applicative-import qualified Control.Monad as Monad-import qualified Data.Binary as Binary-import qualified Data.Binary.Bits.Get as BinaryBits-import qualified Data.Binary.Get as Binary-import qualified Data.Bits as Bits-import qualified Data.ByteString as Bytes-import qualified Data.ByteString.Lazy as LazyBytes-import qualified Data.Word as Word-import qualified Rattletrap.Utility.Bytes as Utility--type Decode = Binary.Get--type DecodeBits = BinaryBits.BitGet--decodeWhen-  :: (Applicative m, Applicative.Alternative f) => Bool -> m a -> m (f a)-decodeWhen p f = if p then fmap pure f else pure Applicative.empty--getByteStringBits :: Int -> DecodeBits Bytes.ByteString-getByteStringBits = BinaryBits.getByteString--getWord8Bits :: Int -> DecodeBits Word.Word8-getWord8Bits = BinaryBits.getWord8--runDecode :: Decode a -> Bytes.ByteString -> Either String a-runDecode decode bytes =-  case Binary.runGetOrFail decode (LazyBytes.fromStrict bytes) of-    Left (_, _, x) -> Left x-    Right (_, _, x) -> Right x--runDecodeBits :: DecodeBits a -> Bytes.ByteString -> Either String a-runDecodeBits = runDecode . BinaryBits.runBitGet--toBits :: Decode a -> Int -> DecodeBits a-toBits decode size = do-  bytes <- BinaryBits.getByteString size-  case runDecode decode (Utility.reverseBytes bytes) of-    Left problem -> fail problem-    Right result -> pure result--getBitsLE :: Bits.Bits a => Int -> BinaryBits.BitGet a-getBitsLE size = do-  bits <- Monad.replicateM size BinaryBits.getBool-  pure $ foldr-    (\bit x -> let y = Bits.shiftL x 1 in if bit then Bits.setBit y 0 else y)-    Bits.zeroBits-    bits
− library/Rattletrap/Decode/CompressedWord.hs
@@ -1,30 +0,0 @@-module Rattletrap.Decode.CompressedWord-  ( decodeCompressedWordBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Type.CompressedWord--import qualified Data.Bits as Bits--decodeCompressedWordBits :: Word -> DecodeBits CompressedWord-decodeCompressedWordBits limit =-  CompressedWord limit <$> step limit (getMaxBits limit) 0 0--getMaxBits :: Word -> Word-getMaxBits x = do-  let-    n :: Word-    n = max 1 (ceiling (logBase (2 :: Double) (fromIntegral (max 1 x))))-  if x < 1024 && x == 2 ^ n then n + 1 else n--step :: Word -> Word -> Word -> Word -> DecodeBits Word-step limit maxBits position value = do-  let x = Bits.shiftL 1 (fromIntegral position) :: Word-  if position < maxBits && value + x <= limit-    then do-      bit <- getBool-      let newValue = if bit then value + x else value-      step limit maxBits (position + 1) newValue-    else pure value
− library/Rattletrap/Decode/CompressedWordVector.hs
@@ -1,18 +0,0 @@-module Rattletrap.Decode.CompressedWordVector-  ( decodeCompressedWordVectorBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.CompressedWord-import Rattletrap.Type.CompressedWordVector--decodeCompressedWordVectorBits :: DecodeBits CompressedWordVector-decodeCompressedWordVectorBits =-  CompressedWordVector-    <$> decodeCompressedWordBits limit-    <*> decodeCompressedWordBits limit-    <*> decodeCompressedWordBits limit--limit :: Word-limit = 65536
− library/Rattletrap/Decode/Content.hs
@@ -1,73 +0,0 @@-module Rattletrap.Decode.Content-  ( decodeContent-  )-where--import Rattletrap.Decode.Cache-import Rattletrap.Decode.ClassMapping-import Rattletrap.Decode.Common-import Rattletrap.Decode.Frame-import Rattletrap.Decode.KeyFrame-import Rattletrap.Decode.List-import Rattletrap.Decode.Mark-import Rattletrap.Decode.Message-import Rattletrap.Decode.Str-import Rattletrap.Decode.Word32le-import Rattletrap.Type.ClassAttributeMap-import Rattletrap.Type.Content-import Rattletrap.Type.Word32le-import Rattletrap.Utility.Bytes--import qualified Control.Monad.Trans.State as State-import qualified Data.Binary.Get as Binary-import qualified Data.ByteString.Lazy as LazyBytes--decodeContent-  :: (Int, Int, Int)-  -- ^ Version numbers, usually from 'Rattletrap.Header.getVersion'.-  -> Int-  -- ^ The number of frames in the stream, usually from-  -- 'Rattletrap.Header.getNumFrames'.-  -> Word-  -- ^ The maximum number of channels in the stream, usually from-  -- 'Rattletrap.Header.getMaxChannels'.-  -> Decode Content-decodeContent version numFrames maxChannels = do-  (levels, keyFrames, streamSize) <--    (,,)-    <$> decodeList decodeStr-    <*> decodeList decodeKeyFrame-    <*> decodeWord32le-  (stream, messages, marks, packages, objects, names, classMappings, caches) <--    (,,,,,,,)-    <$> getByteString (fromIntegral (word32leValue streamSize))-    <*> decodeList decodeMessage-    <*> decodeList decodeMark-    <*> decodeList decodeStr-    <*> decodeList decodeStr-    <*> decodeList decodeStr-    <*> decodeList decodeClassMapping-    <*> decodeList decodeCache-  let-    classAttributeMap =-      makeClassAttributeMap objects classMappings caches names-    bitGet = State.evalStateT-      (decodeFramesBits version numFrames maxChannels classAttributeMap)-      mempty-  frames <- either fail pure (runDecodeBits bitGet (reverseBytes stream))-  unknown <- Binary.getRemainingLazyByteString-  pure-    (Content-      levels-      keyFrames-      streamSize-      frames-      messages-      marks-      packages-      objects-      names-      classMappings-      caches-      (LazyBytes.unpack unknown)-    )
− library/Rattletrap/Decode/DamageStateAttribute.hs
@@ -1,21 +0,0 @@-module Rattletrap.Decode.DamageStateAttribute-  ( decodeDamageStateAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Int32le-import Rattletrap.Decode.Vector-import Rattletrap.Decode.Word8le-import Rattletrap.Type.DamageStateAttribute--decodeDamageStateAttributeBits-  :: (Int, Int, Int) -> DecodeBits DamageStateAttribute-decodeDamageStateAttributeBits version =-  DamageStateAttribute-    <$> decodeWord8leBits-    <*> getBool-    <*> decodeInt32leBits-    <*> decodeVectorBits version-    <*> getBool-    <*> getBool
− library/Rattletrap/Decode/DemolishAttribute.hs
@@ -1,19 +0,0 @@-module Rattletrap.Decode.DemolishAttribute-  ( decodeDemolishAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Vector-import Rattletrap.Decode.Word32le-import Rattletrap.Type.DemolishAttribute--decodeDemolishAttributeBits :: (Int, Int, Int) -> DecodeBits DemolishAttribute-decodeDemolishAttributeBits version =-  DemolishAttribute-    <$> getBool-    <*> decodeWord32leBits-    <*> getBool-    <*> decodeWord32leBits-    <*> decodeVectorBits version-    <*> decodeVectorBits version
− library/Rattletrap/Decode/DestroyedReplication.hs
@@ -1,10 +0,0 @@-module Rattletrap.Decode.DestroyedReplication-  ( decodeDestroyedReplicationBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Type.DestroyedReplication--decodeDestroyedReplicationBits :: DecodeBits DestroyedReplication-decodeDestroyedReplicationBits = pure DestroyedReplication
− library/Rattletrap/Decode/Dictionary.hs
@@ -1,17 +0,0 @@-module Rattletrap.Decode.Dictionary-  ( decodeDictionary-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Str-import Rattletrap.Type.Dictionary-import Rattletrap.Type.Str--decodeDictionary :: Decode a -> Decode (Dictionary a)-decodeDictionary decodeValue = do-  key <- decodeStr-  case filter (/= '\x00') (fromStr key) of-    "None" -> pure (DictionaryEnd key)-    _ ->-      DictionaryElement key <$> decodeValue <*> decodeDictionary decodeValue
− library/Rattletrap/Decode/EnumAttribute.hs
@@ -1,10 +0,0 @@-module Rattletrap.Decode.EnumAttribute-  ( decodeEnumAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Type.EnumAttribute--decodeEnumAttributeBits :: DecodeBits EnumAttribute-decodeEnumAttributeBits = EnumAttribute <$> getBitsLE 11
− library/Rattletrap/Decode/ExplosionAttribute.hs
@@ -1,17 +0,0 @@-module Rattletrap.Decode.ExplosionAttribute-  ( decodeExplosionAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Int32le-import Rattletrap.Decode.Vector-import Rattletrap.Type.ExplosionAttribute--decodeExplosionAttributeBits-  :: (Int, Int, Int) -> DecodeBits ExplosionAttribute-decodeExplosionAttributeBits version =-  ExplosionAttribute-    <$> getBool-    <*> decodeInt32leBits-    <*> decodeVectorBits version
− library/Rattletrap/Decode/ExtendedExplosionAttribute.hs
@@ -1,16 +0,0 @@-module Rattletrap.Decode.ExtendedExplosionAttribute-  ( decodeExtendedExplosionAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.ExplosionAttribute-import Rattletrap.Decode.FlaggedIntAttribute-import Rattletrap.Type.ExtendedExplosionAttribute--decodeExtendedExplosionAttributeBits-  :: (Int, Int, Int) -> DecodeBits ExtendedExplosionAttribute-decodeExtendedExplosionAttributeBits version =-  ExtendedExplosionAttribute-    <$> decodeExplosionAttributeBits version-    <*> decodeFlaggedIntAttributeBits
− library/Rattletrap/Decode/FlaggedByteAttribute.hs
@@ -1,12 +0,0 @@-module Rattletrap.Decode.FlaggedByteAttribute-  ( decodeFlaggedByteAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Word8le-import Rattletrap.Type.FlaggedByteAttribute---decodeFlaggedByteAttributeBits :: DecodeBits FlaggedByteAttribute-decodeFlaggedByteAttributeBits = FlaggedByteAttribute <$> getBool <*> decodeWord8leBits
− library/Rattletrap/Decode/FlaggedIntAttribute.hs
@@ -1,12 +0,0 @@-module Rattletrap.Decode.FlaggedIntAttribute-  ( decodeFlaggedIntAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Int32le-import Rattletrap.Type.FlaggedIntAttribute--decodeFlaggedIntAttributeBits :: DecodeBits FlaggedIntAttribute-decodeFlaggedIntAttributeBits =-  FlaggedIntAttribute <$> getBool <*> decodeInt32leBits
− library/Rattletrap/Decode/Float32le.hs
@@ -1,14 +0,0 @@-module Rattletrap.Decode.Float32le-  ( decodeFloat32le-  , decodeFloat32leBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Type.Float32le--decodeFloat32le :: Decode Float32le-decodeFloat32le = Float32le <$> getFloatle--decodeFloat32leBits :: DecodeBits Float32le-decodeFloat32leBits = toBits decodeFloat32le 4
− library/Rattletrap/Decode/FloatAttribute.hs
@@ -1,11 +0,0 @@-module Rattletrap.Decode.FloatAttribute-  ( decodeFloatAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Float32le-import Rattletrap.Type.FloatAttribute--decodeFloatAttributeBits :: DecodeBits FloatAttribute-decodeFloatAttributeBits = FloatAttribute <$> decodeFloat32leBits
− library/Rattletrap/Decode/Frame.hs
@@ -1,43 +0,0 @@-module Rattletrap.Decode.Frame-  ( decodeFramesBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Float32le-import Rattletrap.Decode.Replication-import Rattletrap.Type.ClassAttributeMap-import Rattletrap.Type.CompressedWord-import Rattletrap.Type.Frame-import Rattletrap.Type.Word32le--import qualified Control.Monad.Trans.Class as Trans-import qualified Control.Monad.Trans.State as State-import qualified Data.Map as Map--decodeFramesBits-  :: (Int, Int, Int)-  -> Int-  -> Word-  -> ClassAttributeMap-  -> State.StateT-       (Map.Map CompressedWord Word32le)-       DecodeBits-       [Frame]-decodeFramesBits version count limit classes = if count <= 0-  then pure []-  else-    (:)-    <$> decodeFrameBits version limit classes-    <*> decodeFramesBits version (count - 1) limit classes--decodeFrameBits-  :: (Int, Int, Int)-  -> Word-  -> ClassAttributeMap-  -> State.StateT (Map.Map CompressedWord Word32le) DecodeBits Frame-decodeFrameBits version limit classes =-  Frame-    <$> Trans.lift decodeFloat32leBits-    <*> Trans.lift decodeFloat32leBits-    <*> decodeReplicationsBits version limit classes
− library/Rattletrap/Decode/GameModeAttribute.hs
@@ -1,15 +0,0 @@-module Rattletrap.Decode.GameModeAttribute-  ( decodeGameModeAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Type.GameModeAttribute--decodeGameModeAttributeBits :: (Int, Int, Int) -> DecodeBits GameModeAttribute-decodeGameModeAttributeBits version =-  GameModeAttribute <$> pure (numBits version) <*> getWord8Bits-    (numBits version)--numBits :: (Int, Int, Int) -> Int-numBits version = if version >= (868, 12, 0) then 8 else 2
− library/Rattletrap/Decode/Header.hs
@@ -1,22 +0,0 @@-module Rattletrap.Decode.Header-  ( decodeHeader-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Dictionary-import Rattletrap.Decode.Property-import Rattletrap.Decode.Str-import Rattletrap.Decode.Word32le-import Rattletrap.Type.Header-import Rattletrap.Type.Word32le--decodeHeader :: Decode Header-decodeHeader = do-  (major, minor) <- (,) <$> decodeWord32le <*> decodeWord32le-  Header major minor-    <$> decodeWhen-          (major >= Word32le 868 && minor >= Word32le 18)-          decodeWord32le-    <*> decodeStr-    <*> decodeDictionary decodeProperty
− library/Rattletrap/Decode/Initialization.hs
@@ -1,16 +0,0 @@-module Rattletrap.Decode.Initialization-  ( decodeInitializationBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Int8Vector-import Rattletrap.Decode.Vector-import Rattletrap.Type.Initialization--decodeInitializationBits-  :: (Int, Int, Int) -> Bool -> Bool -> DecodeBits Initialization-decodeInitializationBits version hasLocation hasRotation =-  Initialization-    <$> decodeWhen hasLocation (decodeVectorBits version)-    <*> decodeWhen hasRotation decodeInt8VectorBits
− library/Rattletrap/Decode/Int32le.hs
@@ -1,14 +0,0 @@-module Rattletrap.Decode.Int32le-  ( decodeInt32le-  , decodeInt32leBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Type.Int32le--decodeInt32le :: Decode Int32le-decodeInt32le = Int32le <$> getInt32le--decodeInt32leBits :: DecodeBits Int32le-decodeInt32leBits = toBits decodeInt32le 4
− library/Rattletrap/Decode/Int64Attribute.hs
@@ -1,11 +0,0 @@-module Rattletrap.Decode.Int64Attribute-  ( decodeInt64AttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Int64le-import Rattletrap.Type.Int64Attribute--decodeInt64AttributeBits :: DecodeBits Int64Attribute-decodeInt64AttributeBits = Int64Attribute <$> decodeInt64leBits
− library/Rattletrap/Decode/Int64le.hs
@@ -1,13 +0,0 @@-module Rattletrap.Decode.Int64le-  ( decodeInt64leBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Type.Int64le--decodeInt64le :: Decode Int64le-decodeInt64le = Int64le <$> getInt64le--decodeInt64leBits :: DecodeBits Int64le-decodeInt64leBits = toBits decodeInt64le 8
− library/Rattletrap/Decode/Int8Vector.hs
@@ -1,18 +0,0 @@-module Rattletrap.Decode.Int8Vector-  ( decodeInt8VectorBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Int8le-import Rattletrap.Type.Int8Vector-import Rattletrap.Type.Int8le--decodeInt8VectorBits :: DecodeBits Int8Vector-decodeInt8VectorBits =-  Int8Vector <$> decodeFieldBits <*> decodeFieldBits <*> decodeFieldBits--decodeFieldBits :: DecodeBits (Maybe Int8le)-decodeFieldBits = do-  hasField <- getBool-  decodeWhen hasField decodeInt8leBits
− library/Rattletrap/Decode/Int8le.hs
@@ -1,13 +0,0 @@-module Rattletrap.Decode.Int8le-  ( decodeInt8leBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Type.Int8le--decodeInt8le :: Decode Int8le-decodeInt8le = Int8le <$> getInt8--decodeInt8leBits :: DecodeBits Int8le-decodeInt8leBits = toBits decodeInt8le 1
− library/Rattletrap/Decode/IntAttribute.hs
@@ -1,11 +0,0 @@-module Rattletrap.Decode.IntAttribute-  ( decodeIntAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Int32le-import Rattletrap.Type.IntAttribute--decodeIntAttributeBits :: DecodeBits IntAttribute-decodeIntAttributeBits = IntAttribute <$> decodeInt32leBits
− library/Rattletrap/Decode/KeyFrame.hs
@@ -1,13 +0,0 @@-module Rattletrap.Decode.KeyFrame-  ( decodeKeyFrame-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Float32le-import Rattletrap.Decode.Word32le-import Rattletrap.Type.KeyFrame--decodeKeyFrame :: Decode KeyFrame-decodeKeyFrame =-  KeyFrame <$> decodeFloat32le <*> decodeWord32le <*> decodeWord32le
− library/Rattletrap/Decode/List.hs
@@ -1,16 +0,0 @@-module Rattletrap.Decode.List-  ( decodeList-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Word32le-import Rattletrap.Type.List-import Rattletrap.Type.Word32le--import qualified Control.Monad as Monad--decodeList :: Decode a -> Decode (List a)-decodeList decodeElement = do-  size <- decodeWord32le-  List <$> Monad.replicateM (fromIntegral (word32leValue size)) decodeElement
− library/Rattletrap/Decode/LoadoutAttribute.hs
@@ -1,31 +0,0 @@-module Rattletrap.Decode.LoadoutAttribute-  ( decodeLoadoutAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Word32le-import Rattletrap.Decode.Word8le-import Rattletrap.Type.LoadoutAttribute-import Rattletrap.Type.Word8le--decodeLoadoutAttributeBits :: DecodeBits LoadoutAttribute-decodeLoadoutAttributeBits = do-  version <- decodeWord8leBits-  LoadoutAttribute version-    <$> decodeWord32leBits-    <*> decodeWord32leBits-    <*> decodeWord32leBits-    <*> decodeWord32leBits-    <*> decodeWord32leBits-    <*> decodeWord32leBits-    <*> decodeWord32leBits-    <*> decodeWhen (version >= Word8le 11) decodeWord32leBits-    <*> decodeWhen (version >= Word8le 16) decodeWord32leBits-    <*> decodeWhen (version >= Word8le 16) decodeWord32leBits-    <*> decodeWhen (version >= Word8le 16) decodeWord32leBits-    <*> decodeWhen (version >= Word8le 17) decodeWord32leBits-    <*> decodeWhen (version >= Word8le 19) decodeWord32leBits-    <*> decodeWhen (version >= Word8le 22) decodeWord32leBits-    <*> decodeWhen (version >= Word8le 22) decodeWord32leBits-    <*> decodeWhen (version >= Word8le 22) decodeWord32leBits
− library/Rattletrap/Decode/LoadoutOnlineAttribute.hs
@@ -1,25 +0,0 @@-module Rattletrap.Decode.LoadoutOnlineAttribute-  ( decodeLoadoutOnlineAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.ProductAttribute-import Rattletrap.Decode.Word8le-import Rattletrap.Type.LoadoutOnlineAttribute-import Rattletrap.Type.Str-import Rattletrap.Type.Word32le-import Rattletrap.Type.Word8le--import qualified Control.Monad as Monad-import qualified Data.Map as Map--decodeLoadoutOnlineAttributeBits-  :: (Int, Int, Int)-  -> Map.Map Word32le Str-  -> DecodeBits LoadoutOnlineAttribute-decodeLoadoutOnlineAttributeBits version objectMap = do-  size <- decodeWord8leBits-  LoadoutOnlineAttribute <$> Monad.replicateM-    (fromIntegral (word8leValue size))-    (decodeProductAttributesBits version objectMap)
− library/Rattletrap/Decode/LoadoutsAttribute.hs
@@ -1,14 +0,0 @@-module Rattletrap.Decode.LoadoutsAttribute-  ( decodeLoadoutsAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.LoadoutAttribute-import Rattletrap.Type.LoadoutsAttribute--decodeLoadoutsAttributeBits :: DecodeBits LoadoutsAttribute-decodeLoadoutsAttributeBits =-  LoadoutsAttribute-    <$> decodeLoadoutAttributeBits-    <*> decodeLoadoutAttributeBits
− library/Rattletrap/Decode/LoadoutsOnlineAttribute.hs
@@ -1,23 +0,0 @@-module Rattletrap.Decode.LoadoutsOnlineAttribute-  ( decodeLoadoutsOnlineAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.LoadoutOnlineAttribute-import Rattletrap.Type.LoadoutsOnlineAttribute-import Rattletrap.Type.Str-import Rattletrap.Type.Word32le--import qualified Data.Map as Map--decodeLoadoutsOnlineAttributeBits-  :: (Int, Int, Int)-  -> Map.Map Word32le Str-  -> DecodeBits LoadoutsOnlineAttribute-decodeLoadoutsOnlineAttributeBits version objectMap =-  LoadoutsOnlineAttribute-    <$> decodeLoadoutOnlineAttributeBits version objectMap-    <*> decodeLoadoutOnlineAttributeBits version objectMap-    <*> getBool-    <*> getBool
− library/Rattletrap/Decode/LocationAttribute.hs
@@ -1,12 +0,0 @@-module Rattletrap.Decode.LocationAttribute-  ( decodeLocationAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Vector-import Rattletrap.Type.LocationAttribute--decodeLocationAttributeBits :: (Int, Int, Int) -> DecodeBits LocationAttribute-decodeLocationAttributeBits version =-  LocationAttribute <$> decodeVectorBits version
− library/Rattletrap/Decode/Mark.hs
@@ -1,12 +0,0 @@-module Rattletrap.Decode.Mark-  ( decodeMark-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Str-import Rattletrap.Decode.Word32le-import Rattletrap.Type.Mark--decodeMark :: Decode Mark-decodeMark = Mark <$> decodeStr <*> decodeWord32le
− library/Rattletrap/Decode/Message.hs
@@ -1,12 +0,0 @@-module Rattletrap.Decode.Message-  ( decodeMessage-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Str-import Rattletrap.Decode.Word32le-import Rattletrap.Type.Message--decodeMessage :: Decode Message-decodeMessage = Message <$> decodeWord32le <*> decodeStr <*> decodeStr
− library/Rattletrap/Decode/MusicStingerAttribute.hs
@@ -1,16 +0,0 @@-module Rattletrap.Decode.MusicStingerAttribute-  ( decodeMusicStingerAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Word32le-import Rattletrap.Decode.Word8le-import Rattletrap.Type.MusicStingerAttribute--decodeMusicStingerAttributeBits :: DecodeBits MusicStingerAttribute-decodeMusicStingerAttributeBits =-  MusicStingerAttribute-    <$> getBool-    <*> decodeWord32leBits-    <*> decodeWord8leBits
− library/Rattletrap/Decode/PartyLeaderAttribute.hs
@@ -1,18 +0,0 @@-module Rattletrap.Decode.PartyLeaderAttribute-  ( decodePartyLeaderAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.RemoteId-import Rattletrap.Decode.Word8le-import Rattletrap.Type.PartyLeaderAttribute-import Rattletrap.Type.Word8le--decodePartyLeaderAttributeBits-  :: (Int, Int, Int) -> DecodeBits PartyLeaderAttribute-decodePartyLeaderAttributeBits version = do-  systemId <- decodeWord8leBits-  PartyLeaderAttribute systemId <$> decodeWhen-    (systemId /= Word8le 0)-    ((,) <$> decodeRemoteIdBits version systemId <*> decodeWord8leBits)
− library/Rattletrap/Decode/PickupAttribute.hs
@@ -1,13 +0,0 @@-module Rattletrap.Decode.PickupAttribute-  ( decodePickupAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Word32le-import Rattletrap.Type.PickupAttribute--decodePickupAttributeBits :: DecodeBits PickupAttribute-decodePickupAttributeBits = do-  instigator <- getBool-  PickupAttribute <$> decodeWhen instigator decodeWord32leBits <*> getBool
− library/Rattletrap/Decode/PlayerHistoryKeyAttribute.hs
@@ -1,11 +0,0 @@-module Rattletrap.Decode.PlayerHistoryKeyAttribute-  ( decodePlayerHistoryKeyAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Type.PlayerHistoryKeyAttribute--decodePlayerHistoryKeyAttributeBits :: DecodeBits PlayerHistoryKeyAttribute-decodePlayerHistoryKeyAttributeBits =-  PlayerHistoryKeyAttribute <$> getBitsLE 14
− library/Rattletrap/Decode/PrivateMatchSettingsAttribute.hs
@@ -1,20 +0,0 @@-module Rattletrap.Decode.PrivateMatchSettingsAttribute-  ( decodePrivateMatchSettingsAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Str-import Rattletrap.Decode.Word32le-import Rattletrap.Type.PrivateMatchSettingsAttribute--decodePrivateMatchSettingsAttributeBits-  :: DecodeBits PrivateMatchSettingsAttribute-decodePrivateMatchSettingsAttributeBits =-  PrivateMatchSettingsAttribute-    <$> decodeStrBits-    <*> decodeWord32leBits-    <*> decodeWord32leBits-    <*> decodeStrBits-    <*> decodeStrBits-    <*> getBool
− library/Rattletrap/Decode/ProductAttribute.hs
@@ -1,72 +0,0 @@-module Rattletrap.Decode.ProductAttribute-  ( decodeProductAttributesBits-  )-where--import Data.Semigroup ((<>))-import Rattletrap.Decode.Common-import Rattletrap.Decode.CompressedWord-import Rattletrap.Decode.Word32le-import Rattletrap.Decode.Word8le-import Rattletrap.Decode.Str-import Rattletrap.Type.Common-import Rattletrap.Type.ProductAttribute-import Rattletrap.Type.Str-import Rattletrap.Type.Word32le-import Rattletrap.Type.Word8le--import qualified Control.Monad as Monad-import qualified Data.Map as Map--decodeProductAttributesBits-  :: (Int, Int, Int) -> Map Word32le Str -> DecodeBits [ProductAttribute]-decodeProductAttributesBits version objectMap = do-  size <- decodeWord8leBits-  Monad.replicateM-    (fromIntegral (word8leValue size))-    (decodeProductAttributeBits version objectMap)--decodeProductAttributeBits-  :: (Int, Int, Int) -> Map Word32le Str -> DecodeBits ProductAttribute-decodeProductAttributeBits version objectMap = do-  flag <- getBool-  objectId <- decodeWord32leBits-  let maybeObjectName = Map.lookup objectId objectMap-  value <- case fromStr <$> maybeObjectName of-    Just "TAGame.ProductAttribute_Painted_TA" -> decodePainted version-    Just "TAGame.ProductAttribute_SpecialEdition_TA" -> decodeSpecialEdition-    Just "TAGame.ProductAttribute_TeamEdition_TA" -> decodeTeamEdition version-    Just "TAGame.ProductAttribute_TitleID_TA" -> decodeTitle-    Just "TAGame.ProductAttribute_UserColor_TA" -> decodeColor version-    Just objectName ->-      fail-        ("unknown object name "-        <> show objectName-        <> " for ID "-        <> show objectId-        )-    Nothing -> fail ("missing object name for ID " <> show objectId)-  pure (ProductAttribute flag objectId maybeObjectName value)--decodeSpecialEdition :: DecodeBits ProductAttributeValue-decodeSpecialEdition = ProductAttributeValueSpecialEdition <$> getBitsLE 31--decodePainted :: (Int, Int, Int) -> DecodeBits ProductAttributeValue-decodePainted version = if version >= (868, 18, 0)-  then ProductAttributeValuePaintedNew <$> getBitsLE 31-  else ProductAttributeValuePaintedOld <$> decodeCompressedWordBits 13--decodeTeamEdition :: (Int, Int, Int) -> DecodeBits ProductAttributeValue-decodeTeamEdition version = if version >= (868, 18, 0)-  then ProductAttributeValueTeamEditionNew <$> getBitsLE 31-  else ProductAttributeValueTeamEditionOld <$> decodeCompressedWordBits 13--decodeColor :: (Int, Int, Int) -> DecodeBits ProductAttributeValue-decodeColor version = if version >= (868, 23, 8)-  then ProductAttributeValueUserColorNew <$> decodeWord32leBits-  else do-    hasValue <- getBool-    ProductAttributeValueUserColorOld <$> decodeWhen hasValue (getBitsLE 31)--decodeTitle :: DecodeBits ProductAttributeValue-decodeTitle = ProductAttributeValueTitleId <$> decodeStrBits
− library/Rattletrap/Decode/Property.hs
@@ -1,15 +0,0 @@-module Rattletrap.Decode.Property-  ( decodeProperty-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.PropertyValue-import Rattletrap.Decode.Str-import Rattletrap.Decode.Word64le-import Rattletrap.Type.Property--decodeProperty :: Decode Property-decodeProperty = do-  kind <- decodeStr-  Property kind <$> decodeWord64le <*> decodePropertyValue decodeProperty kind
− library/Rattletrap/Decode/PropertyValue.hs
@@ -1,32 +0,0 @@-module Rattletrap.Decode.PropertyValue-  ( decodePropertyValue-  )-where--import Data.Semigroup ((<>))-import Rattletrap.Decode.Common-import Rattletrap.Decode.Dictionary-import Rattletrap.Decode.Float32le-import Rattletrap.Decode.Int32le-import Rattletrap.Decode.List-import Rattletrap.Decode.Str-import Rattletrap.Decode.Word64le-import Rattletrap.Decode.Word8le-import Rattletrap.Type.PropertyValue-import Rattletrap.Type.Str--decodePropertyValue :: Decode a -> Str -> Decode (PropertyValue a)-decodePropertyValue getProperty kind = case fromStr kind of-  "ArrayProperty" ->-    PropertyValueArray <$> decodeList (decodeDictionary getProperty)-  "BoolProperty" -> PropertyValueBool <$> decodeWord8le-  "ByteProperty" -> do-    k <- decodeStr-    PropertyValueByte k-      <$> decodeWhen (fromStr k /= "OnlinePlatform_Steam") decodeStr-  "FloatProperty" -> PropertyValueFloat <$> decodeFloat32le-  "IntProperty" -> PropertyValueInt <$> decodeInt32le-  "NameProperty" -> PropertyValueName <$> decodeStr-  "QWordProperty" -> PropertyValueQWord <$> decodeWord64le-  "StrProperty" -> PropertyValueStr <$> decodeStr-  _ -> fail ("don't know how to read property value " <> show kind)
− library/Rattletrap/Decode/QWordAttribute.hs
@@ -1,11 +0,0 @@-module Rattletrap.Decode.QWordAttribute-  ( decodeQWordAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Word64le-import Rattletrap.Type.QWordAttribute--decodeQWordAttributeBits :: DecodeBits QWordAttribute-decodeQWordAttributeBits = QWordAttribute <$> decodeWord64leBits
− library/Rattletrap/Decode/Quaternion.hs
@@ -1,26 +0,0 @@-module Rattletrap.Decode.Quaternion-  ( decodeQuaternionBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.CompressedWord-import Rattletrap.Type.CompressedWord-import Rattletrap.Type.Quaternion--decodeQuaternionBits :: DecodeBits Quaternion-decodeQuaternionBits =-  toQuaternion <$> decodeComponent <*> decodePart <*> decodePart <*> decodePart--decodeComponent :: DecodeBits Component-decodeComponent = do-  x <- decodeCompressedWordBits 3-  case compressedWordValue x of-    0 -> pure ComponentX-    1 -> pure ComponentY-    2 -> pure ComponentZ-    3 -> pure ComponentW-    y -> fail ("invalid component: " <> show y)--decodePart :: DecodeBits Double-decodePart = decompressPart <$> decodeCompressedWordBits maxCompressedValue
− library/Rattletrap/Decode/RemoteId.hs
@@ -1,48 +0,0 @@-module Rattletrap.Decode.RemoteId-  ( decodeRemoteIdBits-  )-where--import Data.Semigroup ((<>))-import Rattletrap.Decode.Common-import Rattletrap.Decode.Word64le-import Rattletrap.Type.RemoteId-import Rattletrap.Type.Word64le-import Rattletrap.Type.Word8le-import Rattletrap.Utility.Bytes--import qualified Data.ByteString as Bytes-import qualified Data.Text as Text-import qualified Data.Text.Encoding as Text-import qualified Data.Word as Word--decodeRemoteIdBits :: (Int, Int, Int) -> Word8le -> DecodeBits RemoteId-decodeRemoteIdBits version systemId = case word8leValue systemId of-  0 -> RemoteIdSplitscreen <$> getBitsLE 24-  1 -> RemoteIdSteam <$> decodeWord64leBits-  2 -> RemoteIdPlayStation <$> decodePsName <*> decodePsBytes version-  4 -> RemoteIdXbox <$> decodeWord64leBits-  6 -> do-    (a, b, c, d) <- getWord256-    pure $ RemoteIdSwitch a b c d-  7 -> if version >= (868, 24, 10)-    then RemoteIdPsyNet . Left <$> decodeWord64leBits-    else RemoteIdPsyNet . Right <$> getWord256-  _ -> fail ("unknown system id " <> show systemId)--decodePsName :: DecodeBits Text.Text-decodePsName = fmap-  (Text.dropWhileEnd (== '\x00') . Text.decodeLatin1 . reverseBytes)-  (getByteStringBits 16)--decodePsBytes :: (Int, Int, Int) -> DecodeBits [Word.Word8]-decodePsBytes version = Bytes.unpack-  <$> getByteStringBits (if version >= (868, 20, 1) then 24 else 16)--getWord256 :: DecodeBits (Word64le, Word64le, Word64le, Word64le)-getWord256 = do-  a <- decodeWord64leBits-  b <- decodeWord64leBits-  c <- decodeWord64leBits-  d <- decodeWord64leBits-  pure (a, b, c, d)
− library/Rattletrap/Decode/Replay.hs
@@ -1,66 +0,0 @@-module Rattletrap.Decode.Replay-  ( decodeReplay-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Content-import Rattletrap.Decode.Header-import Rattletrap.Decode.Section-import Rattletrap.Encode.Content-import Rattletrap.Type.Content-import Rattletrap.Type.Dictionary-import Rattletrap.Type.Header-import Rattletrap.Type.Int32le-import Rattletrap.Type.Property-import Rattletrap.Type.PropertyValue-import Rattletrap.Type.Replay-import Rattletrap.Type.Section-import Rattletrap.Type.Str-import Rattletrap.Type.Word32le--decodeReplay :: Bool -> Decode Replay-decodeReplay fast = do-  header <- decodeSection decodeHeader-  content <- if fast-    then pure $ toSection putContent defaultContent-    else-      let body = sectionBody header-      in-        decodeSection $ decodeContent-          (getVersion body)-          (getNumFrames body)-          (getMaxChannels body)-  pure $ Replay header content--getVersion :: Header -> (Int, Int, Int)-getVersion header =-  ( fromIntegral (word32leValue (headerEngineVersion header))-  , fromIntegral (word32leValue (headerLicenseeVersion header))-  , getPatchVersion header-  )--getPatchVersion :: Header -> Int-getPatchVersion header = case headerPatchVersion header of-  Just version -> fromIntegral (word32leValue version)-  Nothing ->-    case dictionaryLookup (toStr "MatchType") (headerProperties header) of-      -- This is an ugly, ugly hack to handle replays from season 2 of RLCS.-      -- See `decodeSpawnedReplicationBits` and #85.-      Just Property { propertyValue = PropertyValueName str }-        | fromStr str == "Lan" -> -1-      _ -> 0--getNumFrames :: Header -> Int-getNumFrames header =-  case dictionaryLookup (toStr "NumFrames") (headerProperties header) of-    Just (Property _ _ (PropertyValueInt numFrames)) ->-      fromIntegral (int32leValue numFrames)-    _ -> 0--getMaxChannels :: Header -> Word-getMaxChannels header =-  case dictionaryLookup (toStr "MaxChannels") (headerProperties header) of-    Just (Property _ _ (PropertyValueInt numFrames)) ->-      fromIntegral (int32leValue numFrames)-    _ -> 1023
− library/Rattletrap/Decode/Replication.hs
@@ -1,45 +0,0 @@-module Rattletrap.Decode.Replication-  ( decodeReplicationsBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.CompressedWord-import Rattletrap.Decode.ReplicationValue-import Rattletrap.Type.ClassAttributeMap-import Rattletrap.Type.CompressedWord-import Rattletrap.Type.Replication-import Rattletrap.Type.Word32le--import qualified Control.Monad.Trans.Class as Trans-import qualified Control.Monad.Trans.State as State-import qualified Data.Map as Map--decodeReplicationsBits-  :: (Int, Int, Int)-  -> Word-  -> ClassAttributeMap-  -> State.StateT-       (Map.Map CompressedWord Word32le)-       DecodeBits-       [Replication]-decodeReplicationsBits version limit classes = do-  hasReplication <- Trans.lift getBool-  if hasReplication-    then-      (:)-      <$> decodeReplicationBits version limit classes-      <*> decodeReplicationsBits version limit classes-    else pure []--decodeReplicationBits-  :: (Int, Int, Int)-  -> Word-  -> ClassAttributeMap-  -> State.StateT-       (Map.Map CompressedWord Word32le)-       DecodeBits-       Replication-decodeReplicationBits version limit classes = do-  actor <- Trans.lift (decodeCompressedWordBits limit)-  Replication actor <$> decodeReplicationValueBits version classes actor
− library/Rattletrap/Decode/ReplicationValue.hs
@@ -1,45 +0,0 @@-module Rattletrap.Decode.ReplicationValue-  ( decodeReplicationValueBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.DestroyedReplication-import Rattletrap.Decode.SpawnedReplication-import Rattletrap.Decode.UpdatedReplication-import Rattletrap.Type.ClassAttributeMap-import Rattletrap.Type.CompressedWord-import Rattletrap.Type.ReplicationValue-import Rattletrap.Type.Word32le--import qualified Control.Monad.Trans.Class as Trans-import qualified Control.Monad.Trans.State as State-import qualified Data.Map as Map--decodeReplicationValueBits-  :: (Int, Int, Int)-  -> ClassAttributeMap-  -> CompressedWord-  -> State.StateT-       (Map.Map CompressedWord Word32le)-       DecodeBits-       ReplicationValue-decodeReplicationValueBits version classAttributeMap actorId = do-  actorMap <- State.get-  isOpen <- Trans.lift getBool-  if isOpen-    then do-      isNew <- Trans.lift getBool-      if isNew-        then-          ReplicationValueSpawned-            <$> decodeSpawnedReplicationBits version classAttributeMap actorId-        else ReplicationValueUpdated <$> Trans.lift-          (decodeUpdatedReplicationBits-            version-            classAttributeMap-            actorMap-            actorId-          )-    else ReplicationValueDestroyed-      <$> Trans.lift decodeDestroyedReplicationBits
− library/Rattletrap/Decode/ReservationAttribute.hs
@@ -1,25 +0,0 @@-module Rattletrap.Decode.ReservationAttribute-  ( decodeReservationAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.CompressedWord-import Rattletrap.Decode.Str-import Rattletrap.Decode.UniqueIdAttribute-import Rattletrap.Type.ReservationAttribute-import Rattletrap.Type.UniqueIdAttribute-import Rattletrap.Type.Word8le--decodeReservationAttributeBits-  :: (Int, Int, Int) -> DecodeBits ReservationAttribute-decodeReservationAttributeBits version = do-  number <- decodeCompressedWordBits 7-  uniqueId <- decodeUniqueIdAttributeBits version-  ReservationAttribute number uniqueId-    <$> decodeWhen-          (uniqueIdAttributeSystemId uniqueId /= Word8le 0)-          decodeStrBits-    <*> getBool-    <*> getBool-    <*> decodeWhen (version >= (868, 12, 0)) (getWord8Bits 6)
− library/Rattletrap/Decode/RigidBodyStateAttribute.hs
@@ -1,19 +0,0 @@-module Rattletrap.Decode.RigidBodyStateAttribute-  ( decodeRigidBodyStateAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Rotation-import Rattletrap.Decode.Vector-import Rattletrap.Type.RigidBodyStateAttribute--decodeRigidBodyStateAttributeBits-  :: (Int, Int, Int) -> DecodeBits RigidBodyStateAttribute-decodeRigidBodyStateAttributeBits version = do-  sleeping <- getBool-  RigidBodyStateAttribute sleeping-    <$> decodeVectorBits version-    <*> decodeRotationBits version-    <*> decodeWhen (not sleeping) (decodeVectorBits version)-    <*> decodeWhen (not sleeping) (decodeVectorBits version)
− library/Rattletrap/Decode/Rotation.hs
@@ -1,14 +0,0 @@-module Rattletrap.Decode.Rotation-  ( decodeRotationBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.CompressedWordVector-import Rattletrap.Decode.Quaternion-import Rattletrap.Type.Rotation--decodeRotationBits :: (Int, Int, Int) -> DecodeBits Rotation-decodeRotationBits version = if version >= (868, 22, 7)-  then RotationQuaternion <$> decodeQuaternionBits-  else RotationCompressedWordVector <$> decodeCompressedWordVectorBits
− library/Rattletrap/Decode/Section.hs
@@ -1,26 +0,0 @@-module Rattletrap.Decode.Section-  ( decodeSection-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Word32le-import Rattletrap.Type.Section-import Rattletrap.Type.Word32le-import Rattletrap.Utility.Crc--import qualified Control.Monad as Monad--decodeSection :: Decode a -> Decode (Section a)-decodeSection getBody = do-  size <- decodeWord32le-  crc <- decodeWord32le-  rawBody <- getByteString (fromIntegral (word32leValue size))-  let actualCrc = Word32le (getCrc32 rawBody)-  Monad.when (actualCrc /= crc) (fail (crcMessage actualCrc crc))-  body <- either fail pure (runDecode getBody rawBody)-  pure (Section size crc body)--crcMessage :: Word32le -> Word32le -> String-crcMessage actual expected = unwords-  ["actual CRC", show actual, "does not match expected CRC", show expected]
− library/Rattletrap/Decode/SpawnedReplication.hs
@@ -1,70 +0,0 @@-module Rattletrap.Decode.SpawnedReplication-  ( decodeSpawnedReplicationBits-  )-where--import Data.Semigroup ((<>))-import Rattletrap.Decode.Common-import Rattletrap.Decode.Initialization-import Rattletrap.Decode.Word32le-import Rattletrap.Type.ClassAttributeMap-import Rattletrap.Type.CompressedWord-import Rattletrap.Type.SpawnedReplication-import Rattletrap.Type.Str-import Rattletrap.Type.Word32le--import qualified Control.Monad.Trans.Class as Trans-import qualified Control.Monad.Trans.State as State-import qualified Data.Map as Map--decodeSpawnedReplicationBits-  :: (Int, Int, Int)-  -> ClassAttributeMap-  -> CompressedWord-  -> State.StateT-       (Map.Map CompressedWord Word32le)-       DecodeBits-       SpawnedReplication-decodeSpawnedReplicationBits version classAttributeMap actorId = do-  flag <- Trans.lift getBool-  nameIndex <- decodeWhen-    (version >= (868, 14, 0))-    (Trans.lift decodeWord32leBits)-  name <- either fail pure (lookupName classAttributeMap nameIndex)-  objectId <- Trans.lift decodeWord32leBits-  State.modify (Map.insert actorId objectId)-  objectName <- either fail pure (lookupObjectName classAttributeMap objectId)-  className <- either fail pure (lookupClassName objectName)-  let hasLocation = classHasLocation className-  let hasRotation = classHasRotation className-  initialization <- Trans.lift-    (decodeInitializationBits version hasLocation hasRotation)-  pure-    (SpawnedReplication-      flag-      nameIndex-      name-      objectId-      objectName-      className-      initialization-    )--lookupName :: ClassAttributeMap -> Maybe Word32le -> Either String (Maybe Str)-lookupName classAttributeMap maybeNameIndex = case maybeNameIndex of-  Nothing -> Right Nothing-  Just nameIndex ->-    case getName (classAttributeMapNameMap classAttributeMap) nameIndex of-      Nothing -> Left ("could not get name for index " <> show nameIndex)-      Just name -> Right (Just name)--lookupObjectName :: ClassAttributeMap -> Word32le -> Either String Str-lookupObjectName classAttributeMap objectId =-  case getObjectName (classAttributeMapObjectMap classAttributeMap) objectId of-    Nothing -> Left ("could not get object name for id " <> show objectId)-    Just objectName -> Right objectName--lookupClassName :: Str -> Either String Str-lookupClassName objectName = case getClassName objectName of-  Nothing -> Left ("could not get class name for object " <> show objectName)-  Just className -> Right className
− library/Rattletrap/Decode/StatEventAttribute.hs
@@ -1,12 +0,0 @@-module Rattletrap.Decode.StatEventAttribute-  ( decodeStatEventAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Int32le-import Rattletrap.Type.StatEventAttribute--decodeStatEventAttributeBits :: DecodeBits StatEventAttribute-decodeStatEventAttributeBits =-  StatEventAttribute <$> getBool <*> decodeInt32leBits
− library/Rattletrap/Decode/Str.hs
@@ -1,42 +0,0 @@-module Rattletrap.Decode.Str-  ( decodeStr-  , decodeStrBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Int32le-import Rattletrap.Type.Int32le-import Rattletrap.Type.Str-import Rattletrap.Utility.Bytes--import qualified Data.ByteString as Bytes-import qualified Data.Text as Text-import qualified Data.Text.Encoding as Text--decodeStr :: Decode Str-decodeStr = do-  rawSize <- decodeInt32le-  bytes <- getByteString (normalizeTextSize rawSize)-  pure (Str (dropNull (getTextDecoder rawSize bytes)))--decodeStrBits :: DecodeBits Str-decodeStrBits = do-  rawSize <- decodeInt32leBits-  bytes <- getByteStringBits (normalizeTextSize rawSize)-  pure (Str (dropNull (getTextDecoder rawSize (reverseBytes bytes))))--normalizeTextSize :: Integral a => Int32le -> a-normalizeTextSize size = case int32leValue size of-  0x05000000 -> 8-  x -> if x < 0 then (-2 * fromIntegral x) else fromIntegral x--getTextDecoder :: Int32le -> Bytes.ByteString -> Text.Text-getTextDecoder size bytes =-  let-    decode =-      if size < Int32le 0 then Text.decodeUtf16LE else Text.decodeLatin1-  in decode bytes--dropNull :: Text.Text -> Text.Text-dropNull = Text.dropWhileEnd (== '\x00')
− library/Rattletrap/Decode/StringAttribute.hs
@@ -1,11 +0,0 @@-module Rattletrap.Decode.StringAttribute-  ( decodeStringAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Str-import Rattletrap.Type.StringAttribute--decodeStringAttributeBits :: DecodeBits StringAttribute-decodeStringAttributeBits = StringAttribute <$> decodeStrBits
− library/Rattletrap/Decode/TeamPaintAttribute.hs
@@ -1,18 +0,0 @@-module Rattletrap.Decode.TeamPaintAttribute-  ( decodeTeamPaintAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Word32le-import Rattletrap.Decode.Word8le-import Rattletrap.Type.TeamPaintAttribute--decodeTeamPaintAttributeBits :: DecodeBits TeamPaintAttribute-decodeTeamPaintAttributeBits =-  TeamPaintAttribute-    <$> decodeWord8leBits-    <*> decodeWord8leBits-    <*> decodeWord8leBits-    <*> decodeWord32leBits-    <*> decodeWord32leBits
− library/Rattletrap/Decode/TitleAttribute.hs
@@ -1,20 +0,0 @@-module Rattletrap.Decode.TitleAttribute-  ( decodeTitleAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Word32le-import Rattletrap.Type.TitleAttribute--decodeTitleAttributeBits :: DecodeBits TitleAttribute-decodeTitleAttributeBits =-  TitleAttribute-    <$> getBool-    <*> getBool-    <*> decodeWord32leBits-    <*> decodeWord32leBits-    <*> decodeWord32leBits-    <*> decodeWord32leBits-    <*> decodeWord32leBits-    <*> getBool
− library/Rattletrap/Decode/UniqueIdAttribute.hs
@@ -1,16 +0,0 @@-module Rattletrap.Decode.UniqueIdAttribute-  ( decodeUniqueIdAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.RemoteId-import Rattletrap.Decode.Word8le-import Rattletrap.Type.UniqueIdAttribute--decodeUniqueIdAttributeBits :: (Int, Int, Int) -> DecodeBits UniqueIdAttribute-decodeUniqueIdAttributeBits version = do-  systemId <- decodeWord8leBits-  UniqueIdAttribute systemId-    <$> decodeRemoteIdBits version systemId-    <*> decodeWord8leBits
− library/Rattletrap/Decode/UpdatedReplication.hs
@@ -1,22 +0,0 @@-module Rattletrap.Decode.UpdatedReplication-  ( decodeUpdatedReplicationBits-  )-where--import Rattletrap.Decode.Attribute-import Rattletrap.Decode.Common-import Rattletrap.Type.ClassAttributeMap-import Rattletrap.Type.CompressedWord-import Rattletrap.Type.UpdatedReplication-import Rattletrap.Type.Word32le--import qualified Data.Map as Map--decodeUpdatedReplicationBits-  :: (Int, Int, Int)-  -> ClassAttributeMap-  -> Map.Map CompressedWord Word32le-  -> CompressedWord-  -> DecodeBits UpdatedReplication-decodeUpdatedReplicationBits version classes actors actor =-  UpdatedReplication <$> decodeAttributesBits version classes actors actor
− library/Rattletrap/Decode/Vector.hs
@@ -1,29 +0,0 @@-module Rattletrap.Decode.Vector-  ( decodeVectorBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.CompressedWord-import Rattletrap.Type.CompressedWord-import Rattletrap.Type.Vector--decodeVectorBits :: (Int, Int, Int) -> DecodeBits Vector-decodeVectorBits version = do-  size <- decodeCompressedWordBits (if version >= (868, 22, 7) then 21 else 19)-  let-    limit = getLimit size-    bias = getBias size-  Vector size bias-    <$> fmap (fromDelta bias) (decodeCompressedWordBits limit)-    <*> fmap (fromDelta bias) (decodeCompressedWordBits limit)-    <*> fmap (fromDelta bias) (decodeCompressedWordBits limit)--getLimit :: CompressedWord -> Word-getLimit = (2 ^) . (+ 2) . compressedWordValue--getBias :: CompressedWord -> Word-getBias = (2 ^) . (+ 1) . compressedWordValue--fromDelta :: Word -> CompressedWord -> Int-fromDelta bias x = fromIntegral (compressedWordValue x) - fromIntegral bias
− library/Rattletrap/Decode/WeldedInfoAttribute.hs
@@ -1,21 +0,0 @@-module Rattletrap.Decode.WeldedInfoAttribute-  ( decodeWeldedInfoAttributeBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Decode.Float32le-import Rattletrap.Decode.Int32le-import Rattletrap.Decode.Int8Vector-import Rattletrap.Decode.Vector-import Rattletrap.Type.WeldedInfoAttribute--decodeWeldedInfoAttributeBits-  :: (Int, Int, Int) -> DecodeBits WeldedInfoAttribute-decodeWeldedInfoAttributeBits version =-  WeldedInfoAttribute-    <$> getBool-    <*> decodeInt32leBits-    <*> decodeVectorBits version-    <*> decodeFloat32leBits-    <*> decodeInt8VectorBits
− library/Rattletrap/Decode/Word32le.hs
@@ -1,14 +0,0 @@-module Rattletrap.Decode.Word32le-  ( decodeWord32le-  , decodeWord32leBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Type.Word32le--decodeWord32le :: Decode Word32le-decodeWord32le = Word32le <$> getWord32le--decodeWord32leBits :: DecodeBits Word32le-decodeWord32leBits = toBits decodeWord32le 4
− library/Rattletrap/Decode/Word64le.hs
@@ -1,14 +0,0 @@-module Rattletrap.Decode.Word64le-  ( decodeWord64le-  , decodeWord64leBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Type.Word64le--decodeWord64le :: Decode Word64le-decodeWord64le = Word64le <$> getWord64le--decodeWord64leBits :: DecodeBits Word64le-decodeWord64leBits = toBits decodeWord64le 8
− library/Rattletrap/Decode/Word8le.hs
@@ -1,14 +0,0 @@-module Rattletrap.Decode.Word8le-  ( decodeWord8le-  , decodeWord8leBits-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Type.Word8le--decodeWord8le :: Decode Word8le-decodeWord8le = Word8le <$> getWord8--decodeWord8leBits :: DecodeBits Word8le-decodeWord8leBits = toBits decodeWord8le 1
− library/Rattletrap/Encode/AppliedDamageAttribute.hs
@@ -1,18 +0,0 @@-module Rattletrap.Encode.AppliedDamageAttribute-  ( putAppliedDamageAttribute-  )-where--import Rattletrap.Encode.Int32le-import Rattletrap.Encode.Vector-import Rattletrap.Encode.Word8le-import Rattletrap.Type.AppliedDamageAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putAppliedDamageAttribute :: AppliedDamageAttribute -> BinaryBits.BitPut ()-putAppliedDamageAttribute appliedDamageAttribute = do-  putWord8Bits (appliedDamageAttributeUnknown1 appliedDamageAttribute)-  putVector (appliedDamageAttributeLocation appliedDamageAttribute)-  putInt32Bits (appliedDamageAttributeUnknown3 appliedDamageAttribute)-  putInt32Bits (appliedDamageAttributeUnknown4 appliedDamageAttribute)
− library/Rattletrap/Encode/Attribute.hs
@@ -1,26 +0,0 @@-module Rattletrap.Encode.Attribute-  ( putAttributes-  )-where--import Rattletrap.Encode.AttributeValue-import Rattletrap.Encode.CompressedWord-import Rattletrap.Type.Attribute--import qualified Data.Binary.Bits.Put as BinaryBits--putAttributes :: [Attribute] -> BinaryBits.BitPut ()-putAttributes attributes = case attributes of-  [] -> BinaryBits.putBool False-  [attribute] -> do-    putAttribute attribute-    BinaryBits.putBool False-  first : rest -> do-    putAttribute first-    putAttributes rest--putAttribute :: Attribute -> BinaryBits.BitPut ()-putAttribute attribute = do-  BinaryBits.putBool True-  putCompressedWord (attributeId attribute)-  putAttributeValue (attributeValue attribute)
− library/Rattletrap/Encode/AttributeMapping.hs
@@ -1,14 +0,0 @@-module Rattletrap.Encode.AttributeMapping-  ( putAttributeMapping-  )-where--import Rattletrap.Encode.Word32le-import Rattletrap.Type.AttributeMapping--import qualified Data.Binary as Binary--putAttributeMapping :: AttributeMapping -> Binary.Put-putAttributeMapping attributeMapping = do-  putWord32 (attributeMappingObjectId attributeMapping)-  putWord32 (attributeMappingStreamId attributeMapping)
− library/Rattletrap/Encode/AttributeValue.hs
@@ -1,81 +0,0 @@-module Rattletrap.Encode.AttributeValue-  ( putAttributeValue-  )-where--import Rattletrap.Encode.AppliedDamageAttribute-import Rattletrap.Encode.BooleanAttribute-import Rattletrap.Encode.ByteAttribute-import Rattletrap.Encode.CamSettingsAttribute-import Rattletrap.Encode.ClubColorsAttribute-import Rattletrap.Encode.DamageStateAttribute-import Rattletrap.Encode.DemolishAttribute-import Rattletrap.Encode.EnumAttribute-import Rattletrap.Encode.ExplosionAttribute-import Rattletrap.Encode.ExtendedExplosionAttribute-import Rattletrap.Encode.FlaggedIntAttribute-import Rattletrap.Encode.FlaggedByteAttribute-import Rattletrap.Encode.FloatAttribute-import Rattletrap.Encode.GameModeAttribute-import Rattletrap.Encode.Int64Attribute-import Rattletrap.Encode.IntAttribute-import Rattletrap.Encode.LoadoutAttribute-import Rattletrap.Encode.LoadoutOnlineAttribute-import Rattletrap.Encode.LoadoutsAttribute-import Rattletrap.Encode.LoadoutsOnlineAttribute-import Rattletrap.Encode.LocationAttribute-import Rattletrap.Encode.MusicStingerAttribute-import Rattletrap.Encode.PartyLeaderAttribute-import Rattletrap.Encode.PickupAttribute-import Rattletrap.Encode.PlayerHistoryKeyAttribute-import Rattletrap.Encode.PrivateMatchSettingsAttribute-import Rattletrap.Encode.QWordAttribute-import Rattletrap.Encode.ReservationAttribute-import Rattletrap.Encode.RigidBodyStateAttribute-import Rattletrap.Encode.StatEventAttribute-import Rattletrap.Encode.StringAttribute-import Rattletrap.Encode.TeamPaintAttribute-import Rattletrap.Encode.TitleAttribute-import Rattletrap.Encode.UniqueIdAttribute-import Rattletrap.Encode.WeldedInfoAttribute-import Rattletrap.Type.AttributeValue--import qualified Data.Binary.Bits.Put as BinaryBits--putAttributeValue :: AttributeValue -> BinaryBits.BitPut ()-putAttributeValue value = case value of-  AttributeValueAppliedDamage x -> putAppliedDamageAttribute x-  AttributeValueBoolean x -> putBooleanAttribute x-  AttributeValueByte x -> putByteAttribute x-  AttributeValueCamSettings x -> putCamSettingsAttribute x-  AttributeValueClubColors x -> putClubColorsAttribute x-  AttributeValueDamageState x -> putDamageStateAttribute x-  AttributeValueDemolish x -> putDemolishAttribute x-  AttributeValueEnum x -> putEnumAttribute x-  AttributeValueExplosion x -> putExplosionAttribute x-  AttributeValueExtendedExplosion x -> putExtendedExplosionAttribute x-  AttributeValueFlaggedInt x -> putFlaggedIntAttribute x-  AttributeValueFlaggedByte x -> putFlaggedByteAttribute x-  AttributeValueFloat x -> putFloatAttribute x-  AttributeValueGameMode x -> putGameModeAttribute x-  AttributeValueInt x -> putIntAttribute x-  AttributeValueInt64 x -> putInt64Attribute x-  AttributeValueLoadout x -> putLoadoutAttribute x-  AttributeValueLoadoutOnline x -> putLoadoutOnlineAttribute x-  AttributeValueLoadouts x -> putLoadoutsAttribute x-  AttributeValueLoadoutsOnline x -> putLoadoutsOnlineAttribute x-  AttributeValueLocation x -> putLocationAttribute x-  AttributeValueMusicStinger x -> putMusicStingerAttribute x-  AttributeValuePartyLeader x -> putPartyLeaderAttribute x-  AttributeValuePickup x -> putPickupAttribute x-  AttributeValuePlayerHistoryKey x -> putPlayerHistoryKeyAttribute x-  AttributeValuePrivateMatchSettings x -> putPrivateMatchSettingsAttribute x-  AttributeValueQWord x -> putQWordAttribute x-  AttributeValueReservation x -> putReservationAttribute x-  AttributeValueRigidBodyState x -> putRigidBodyStateAttribute x-  AttributeValueStatEvent x -> putStatEventAttribute x-  AttributeValueString x -> putStringAttribute x-  AttributeValueTeamPaint x -> putTeamPaintAttribute x-  AttributeValueTitle x -> putTitleAttribute x-  AttributeValueUniqueId x -> putUniqueIdAttribute x-  AttributeValueWeldedInfo x -> putWeldedInfoAttribute x
− library/Rattletrap/Encode/BooleanAttribute.hs
@@ -1,12 +0,0 @@-module Rattletrap.Encode.BooleanAttribute-  ( putBooleanAttribute-  )-where--import Rattletrap.Type.BooleanAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putBooleanAttribute :: BooleanAttribute -> BinaryBits.BitPut ()-putBooleanAttribute booleanAttribute =-  BinaryBits.putBool (booleanAttributeValue booleanAttribute)
− library/Rattletrap/Encode/ByteAttribute.hs
@@ -1,13 +0,0 @@-module Rattletrap.Encode.ByteAttribute-  ( putByteAttribute-  )-where--import Rattletrap.Encode.Word8le-import Rattletrap.Type.ByteAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putByteAttribute :: ByteAttribute -> BinaryBits.BitPut ()-putByteAttribute byteAttribute =-  putWord8Bits (byteAttributeValue byteAttribute)
− library/Rattletrap/Encode/Cache.hs
@@ -1,18 +0,0 @@-module Rattletrap.Encode.Cache-  ( putCache-  )-where--import Rattletrap.Encode.AttributeMapping-import Rattletrap.Encode.List-import Rattletrap.Encode.Word32le-import Rattletrap.Type.Cache--import qualified Data.Binary as Binary--putCache :: Cache -> Binary.Put-putCache cache = do-  putWord32 (cacheClassId cache)-  putWord32 (cacheParentCacheId cache)-  putWord32 (cacheCacheId cache)-  putList putAttributeMapping (cacheAttributeMappings cache)
− library/Rattletrap/Encode/CamSettingsAttribute.hs
@@ -1,21 +0,0 @@-module Rattletrap.Encode.CamSettingsAttribute-  ( putCamSettingsAttribute-  )-where--import Rattletrap.Encode.Float32le-import Rattletrap.Type.CamSettingsAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putCamSettingsAttribute :: CamSettingsAttribute -> BinaryBits.BitPut ()-putCamSettingsAttribute camSettingsAttribute = do-  putFloat32Bits (camSettingsAttributeFov camSettingsAttribute)-  putFloat32Bits (camSettingsAttributeHeight camSettingsAttribute)-  putFloat32Bits (camSettingsAttributeAngle camSettingsAttribute)-  putFloat32Bits (camSettingsAttributeDistance camSettingsAttribute)-  putFloat32Bits (camSettingsAttributeStiffness camSettingsAttribute)-  putFloat32Bits (camSettingsAttributeSwivelSpeed camSettingsAttribute)-  case camSettingsAttributeTransitionSpeed camSettingsAttribute of-    Nothing -> pure ()-    Just transitionSpeed -> putFloat32Bits transitionSpeed
− library/Rattletrap/Encode/ClassMapping.hs
@@ -1,15 +0,0 @@-module Rattletrap.Encode.ClassMapping-  ( putClassMapping-  )-where--import Rattletrap.Encode.Str-import Rattletrap.Encode.Word32le-import Rattletrap.Type.ClassMapping--import qualified Data.Binary as Binary--putClassMapping :: ClassMapping -> Binary.Put-putClassMapping classMapping = do-  putText (classMappingName classMapping)-  putWord32 (classMappingStreamId classMapping)
− library/Rattletrap/Encode/ClubColorsAttribute.hs
@@ -1,16 +0,0 @@-module Rattletrap.Encode.ClubColorsAttribute-  ( putClubColorsAttribute-  )-where--import Rattletrap.Encode.Word8le-import Rattletrap.Type.ClubColorsAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putClubColorsAttribute :: ClubColorsAttribute -> BinaryBits.BitPut ()-putClubColorsAttribute clubColorsAttribute = do-  BinaryBits.putBool (clubColorsAttributeBlueFlag clubColorsAttribute)-  putWord8Bits (clubColorsAttributeBlueColor clubColorsAttribute)-  BinaryBits.putBool (clubColorsAttributeOrangeFlag clubColorsAttribute)-  putWord8Bits (clubColorsAttributeOrangeColor clubColorsAttribute)
− library/Rattletrap/Encode/Common.hs
@@ -1,10 +0,0 @@-module Rattletrap.Encode.Common-  ( putBitsLE-  )-where--import qualified Data.Binary.Bits.Put as BinaryBits-import qualified Data.Bits as Bits--putBitsLE :: Bits.Bits a => Int -> a -> BinaryBits.BitPut ()-putBitsLE size x = mapM_ (BinaryBits.putBool . Bits.testBit x) [0 .. size - 1]
− library/Rattletrap/Encode/CompressedWord.hs
@@ -1,44 +0,0 @@-module Rattletrap.Encode.CompressedWord-  ( putCompressedWord-  )-where--import Rattletrap.Type.CompressedWord--import qualified Data.Binary.Bits.Put as BinaryBits-import qualified Data.Bits as Bits--putCompressedWord :: CompressedWord -> BinaryBits.BitPut ()-putCompressedWord compressedWord =-  let-    limit = compressedWordLimit compressedWord-    value = compressedWordValue compressedWord-    maxBits = getMaxBits limit-  in putCompressedWordStep limit value maxBits 0 0--putCompressedWordStep-  :: Word -> Word -> Int -> Int -> Word -> BinaryBits.BitPut ()-putCompressedWordStep limit value maxBits position soFar =-  if position < maxBits-    then do-      let x = Bits.shiftL 1 position :: Word-      if maxBits > 1 && position == maxBits - 1 && soFar + x > limit-        then pure ()-        else do-          let bit = Bits.testBit value position-          BinaryBits.putBool bit-          let delta = if bit then x else 0-          putCompressedWordStep-            limit-            value-            maxBits-            (position + 1)-            (soFar + delta)-    else pure ()--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
− library/Rattletrap/Encode/CompressedWordVector.hs
@@ -1,15 +0,0 @@-module Rattletrap.Encode.CompressedWordVector-  ( putCompressedWordVector-  )-where--import Rattletrap.Encode.CompressedWord-import Rattletrap.Type.CompressedWordVector--import qualified Data.Binary.Bits.Put as BinaryBits--putCompressedWordVector :: CompressedWordVector -> BinaryBits.BitPut ()-putCompressedWordVector compressedWordVector = do-  putCompressedWord (compressedWordVectorX compressedWordVector)-  putCompressedWord (compressedWordVectorY compressedWordVector)-  putCompressedWord (compressedWordVectorZ compressedWordVector)
− library/Rattletrap/Encode/Content.hs
@@ -1,43 +0,0 @@-module Rattletrap.Encode.Content-  ( putContent-  )-where--import Rattletrap.Encode.Cache-import Rattletrap.Encode.ClassMapping-import Rattletrap.Encode.Frame-import Rattletrap.Encode.KeyFrame-import Rattletrap.Encode.List-import Rattletrap.Encode.Mark-import Rattletrap.Encode.Message-import Rattletrap.Encode.Str-import Rattletrap.Encode.Word32le-import Rattletrap.Type.Content-import Rattletrap.Type.Word32le-import Rattletrap.Utility.Bytes--import qualified Data.Binary as Binary-import qualified Data.Binary.Bits.Put as BinaryBits-import qualified Data.Binary.Put as Binary-import qualified Data.ByteString.Lazy as LazyBytes--putContent :: Content -> Binary.Put-putContent content = do-  putList putText (contentLevels content)-  putList putKeyFrame (contentKeyFrames content)-  let streamSize = contentStreamSize content-  putWord32 streamSize-  let-    stream = LazyBytes.toStrict-      (Binary.runPut (BinaryBits.runBitPut (putFrames (contentFrames content)))-      )-  Binary.putByteString-    (reverseBytes (padBytes (word32leValue streamSize) stream))-  putList putMessage (contentMessages content)-  putList putMark (contentMarks content)-  putList putText (contentPackages content)-  putList putText (contentObjects content)-  putList putText (contentNames content)-  putList putClassMapping (contentClassMappings content)-  putList putCache (contentCaches content)-  mapM_ Binary.putWord8 (contentUnknown content)
− library/Rattletrap/Encode/DamageStateAttribute.hs
@@ -1,20 +0,0 @@-module Rattletrap.Encode.DamageStateAttribute-  ( putDamageStateAttribute-  )-where--import Rattletrap.Encode.Int32le-import Rattletrap.Encode.Vector-import Rattletrap.Encode.Word8le-import Rattletrap.Type.DamageStateAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putDamageStateAttribute :: DamageStateAttribute -> BinaryBits.BitPut ()-putDamageStateAttribute damageStateAttribute = do-  putWord8Bits (damageStateAttributeUnknown1 damageStateAttribute)-  BinaryBits.putBool (damageStateAttributeUnknown2 damageStateAttribute)-  putInt32Bits (damageStateAttributeUnknown3 damageStateAttribute)-  putVector (damageStateAttributeUnknown4 damageStateAttribute)-  BinaryBits.putBool (damageStateAttributeUnknown5 damageStateAttribute)-  BinaryBits.putBool (damageStateAttributeUnknown6 damageStateAttribute)
− library/Rattletrap/Encode/DemolishAttribute.hs
@@ -1,19 +0,0 @@-module Rattletrap.Encode.DemolishAttribute-  ( putDemolishAttribute-  )-where--import Rattletrap.Encode.Vector-import Rattletrap.Encode.Word32le-import Rattletrap.Type.DemolishAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putDemolishAttribute :: DemolishAttribute -> BinaryBits.BitPut ()-putDemolishAttribute demolishAttribute = do-  BinaryBits.putBool (demolishAttributeAttackerFlag demolishAttribute)-  putWord32Bits (demolishAttributeAttackerActorId demolishAttribute)-  BinaryBits.putBool (demolishAttributeVictimFlag demolishAttribute)-  putWord32Bits (demolishAttributeVictimActorId demolishAttribute)-  putVector (demolishAttributeAttackerVelocity demolishAttribute)-  putVector (demolishAttributeVictimVelocity demolishAttribute)
− library/Rattletrap/Encode/DestroyedReplication.hs
@@ -1,11 +0,0 @@-module Rattletrap.Encode.DestroyedReplication-  ( putDestroyedReplication-  )-where--import Rattletrap.Type.DestroyedReplication--import qualified Data.Binary.Bits.Put as BinaryBits--putDestroyedReplication :: DestroyedReplication -> BinaryBits.BitPut ()-putDestroyedReplication _ = pure ()
− library/Rattletrap/Encode/Dictionary.hs
@@ -1,17 +0,0 @@-module Rattletrap.Encode.Dictionary-  ( putDictionary-  )-where--import Rattletrap.Encode.Str-import Rattletrap.Type.Dictionary--import qualified Data.Binary as Binary--putDictionary :: (a -> Binary.Put) -> Dictionary a -> Binary.Put-putDictionary f x = case x of-  DictionaryElement k v y -> do-    putText k-    f v-    putDictionary f y-  DictionaryEnd y -> putText y
− library/Rattletrap/Encode/EnumAttribute.hs
@@ -1,13 +0,0 @@-module Rattletrap.Encode.EnumAttribute-  ( putEnumAttribute-  )-where--import Rattletrap.Encode.Common-import Rattletrap.Type.EnumAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putEnumAttribute :: EnumAttribute -> BinaryBits.BitPut ()-putEnumAttribute enumAttribute =-  putBitsLE 11 (enumAttributeValue enumAttribute)
− library/Rattletrap/Encode/ExplosionAttribute.hs
@@ -1,16 +0,0 @@-module Rattletrap.Encode.ExplosionAttribute-  ( putExplosionAttribute-  )-where--import Rattletrap.Encode.Int32le-import Rattletrap.Encode.Vector-import Rattletrap.Type.ExplosionAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putExplosionAttribute :: ExplosionAttribute -> BinaryBits.BitPut ()-putExplosionAttribute explosionAttribute = do-  BinaryBits.putBool False-  putInt32Bits (explosionAttributeActorId explosionAttribute)-  putVector (explosionAttributeLocation explosionAttribute)
− library/Rattletrap/Encode/ExtendedExplosionAttribute.hs
@@ -1,16 +0,0 @@-module Rattletrap.Encode.ExtendedExplosionAttribute-  ( putExtendedExplosionAttribute-  )-where--import Rattletrap.Encode.ExplosionAttribute-import Rattletrap.Encode.FlaggedIntAttribute-import Rattletrap.Type.ExtendedExplosionAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putExtendedExplosionAttribute-  :: ExtendedExplosionAttribute -> BinaryBits.BitPut ()-putExtendedExplosionAttribute x = do-  putExplosionAttribute (extendedExplosionAttributeExplosion x)-  putFlaggedIntAttribute (extendedExplosionAttributeUnknown x)
− library/Rattletrap/Encode/FlaggedByteAttribute.hs
@@ -1,14 +0,0 @@-module Rattletrap.Encode.FlaggedByteAttribute-  ( putFlaggedByteAttribute-  )-where--import Rattletrap.Encode.Word8le-import Rattletrap.Type.FlaggedByteAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putFlaggedByteAttribute :: FlaggedByteAttribute -> BinaryBits.BitPut ()-putFlaggedByteAttribute flaggedByteAttribute = do-  BinaryBits.putBool (flaggedByteAttributeFlag flaggedByteAttribute)-  putWord8Bits (flaggedByteAttributeByte flaggedByteAttribute)
− library/Rattletrap/Encode/FlaggedIntAttribute.hs
@@ -1,14 +0,0 @@-module Rattletrap.Encode.FlaggedIntAttribute-  ( putFlaggedIntAttribute-  )-where--import Rattletrap.Encode.Int32le-import Rattletrap.Type.FlaggedIntAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putFlaggedIntAttribute :: FlaggedIntAttribute -> BinaryBits.BitPut ()-putFlaggedIntAttribute flaggedIntAttribute = do-  BinaryBits.putBool (flaggedIntAttributeFlag flaggedIntAttribute)-  putInt32Bits (flaggedIntAttributeInt flaggedIntAttribute)
− library/Rattletrap/Encode/Float32le.hs
@@ -1,21 +0,0 @@-module Rattletrap.Encode.Float32le-  ( putFloat32-  , putFloat32Bits-  )-where--import Rattletrap.Type.Float32le-import Rattletrap.Utility.Bytes--import qualified Data.Binary as Binary-import qualified Data.Binary.Bits.Put as BinaryBits-import qualified Data.Binary.Put as Binary-import qualified Data.ByteString.Lazy as LazyBytes--putFloat32 :: Float32le -> Binary.Put-putFloat32 = Binary.putFloatle . float32leValue--putFloat32Bits :: Float32le -> BinaryBits.BitPut ()-putFloat32Bits float32 = do-  let bytes = LazyBytes.toStrict (Binary.runPut (putFloat32 float32))-  BinaryBits.putByteString (reverseBytes bytes)
− library/Rattletrap/Encode/FloatAttribute.hs
@@ -1,13 +0,0 @@-module Rattletrap.Encode.FloatAttribute-  ( putFloatAttribute-  )-where--import Rattletrap.Encode.Float32le-import Rattletrap.Type.FloatAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putFloatAttribute :: FloatAttribute -> BinaryBits.BitPut ()-putFloatAttribute floatAttribute =-  putFloat32Bits (floatAttributeValue floatAttribute)
− library/Rattletrap/Encode/Frame.hs
@@ -1,24 +0,0 @@-module Rattletrap.Encode.Frame-  ( putFrames-  )-where--import Rattletrap.Encode.Float32le-import Rattletrap.Encode.Replication-import Rattletrap.Type.Frame--import qualified Data.Binary.Bits.Put as BinaryBits--putFrames :: [Frame] -> BinaryBits.BitPut ()-putFrames frames = case frames of-  [] -> pure ()-  [frame] -> putFrame frame-  first : rest -> do-    putFrame first-    putFrames rest--putFrame :: Frame -> BinaryBits.BitPut ()-putFrame frame = do-  putFloat32Bits (frameTime frame)-  putFloat32Bits (frameDelta frame)-  putReplications (frameReplications frame)
− library/Rattletrap/Encode/GameModeAttribute.hs
@@ -1,14 +0,0 @@-module Rattletrap.Encode.GameModeAttribute-  ( putGameModeAttribute-  )-where--import Rattletrap.Type.GameModeAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putGameModeAttribute :: GameModeAttribute -> BinaryBits.BitPut ()-putGameModeAttribute gameModeAttribute = do-  let numBits = gameModeAttributeNumBits gameModeAttribute-  let word = gameModeAttributeWord gameModeAttribute-  BinaryBits.putWord8 numBits word
− library/Rattletrap/Encode/Header.hs
@@ -1,22 +0,0 @@-module Rattletrap.Encode.Header-  ( putHeader-  )-where--import Rattletrap.Encode.Dictionary-import Rattletrap.Encode.Property-import Rattletrap.Encode.Str-import Rattletrap.Encode.Word32le-import Rattletrap.Type.Header--import qualified Data.Binary as Binary--putHeader :: Header -> Binary.Put-putHeader header = do-  putWord32 (headerEngineVersion header)-  putWord32 (headerLicenseeVersion header)-  case headerPatchVersion header of-    Nothing -> pure ()-    Just patchVersion -> putWord32 patchVersion-  putText (headerLabel header)-  putDictionary putProperty (headerProperties header)
− library/Rattletrap/Encode/Initialization.hs
@@ -1,19 +0,0 @@-module Rattletrap.Encode.Initialization-  ( putInitialization-  )-where--import Rattletrap.Encode.Int8Vector-import Rattletrap.Encode.Vector-import Rattletrap.Type.Initialization--import qualified Data.Binary.Bits.Put as BinaryBits--putInitialization :: Initialization -> BinaryBits.BitPut ()-putInitialization initialization = do-  case initializationLocation initialization of-    Nothing -> pure ()-    Just location -> putVector location-  case initializationRotation initialization of-    Nothing -> pure ()-    Just rotation -> putInt8Vector rotation
− library/Rattletrap/Encode/Int32le.hs
@@ -1,21 +0,0 @@-module Rattletrap.Encode.Int32le-  ( putInt32-  , putInt32Bits-  )-where--import Rattletrap.Type.Int32le-import Rattletrap.Utility.Bytes--import qualified Data.Binary as Binary-import qualified Data.Binary.Bits.Put as BinaryBits-import qualified Data.Binary.Put as Binary-import qualified Data.ByteString.Lazy as LazyBytes--putInt32 :: Int32le -> Binary.Put-putInt32 int32 = Binary.putInt32le (int32leValue int32)--putInt32Bits :: Int32le -> BinaryBits.BitPut ()-putInt32Bits int32 = do-  let bytes = LazyBytes.toStrict (Binary.runPut (putInt32 int32))-  BinaryBits.putByteString (reverseBytes bytes)
− library/Rattletrap/Encode/Int64Attribute.hs
@@ -1,13 +0,0 @@-module Rattletrap.Encode.Int64Attribute-  ( putInt64Attribute-  )-where--import Rattletrap.Encode.Int64le-import Rattletrap.Type.Int64Attribute--import qualified Data.Binary.Bits.Put as BinaryBits--putInt64Attribute :: Int64Attribute -> BinaryBits.BitPut ()-putInt64Attribute int64Attribute =-  putInt64Bits (int64AttributeValue int64Attribute)
− library/Rattletrap/Encode/Int64le.hs
@@ -1,20 +0,0 @@-module Rattletrap.Encode.Int64le-  ( putInt64Bits-  )-where--import Rattletrap.Type.Int64le-import Rattletrap.Utility.Bytes--import qualified Data.Binary as Binary-import qualified Data.Binary.Bits.Put as BinaryBits-import qualified Data.Binary.Put as Binary-import qualified Data.ByteString.Lazy as LazyBytes--putInt64 :: Int64le -> Binary.Put-putInt64 int64 = Binary.putInt64le (int64leValue int64)--putInt64Bits :: Int64le -> BinaryBits.BitPut ()-putInt64Bits int64 = do-  let bytes = LazyBytes.toStrict (Binary.runPut (putInt64 int64))-  BinaryBits.putByteString (reverseBytes bytes)
− library/Rattletrap/Encode/Int8Vector.hs
@@ -1,23 +0,0 @@-module Rattletrap.Encode.Int8Vector-  ( putInt8Vector-  )-where--import Rattletrap.Encode.Int8le-import Rattletrap.Type.Int8Vector-import Rattletrap.Type.Int8le--import qualified Data.Binary.Bits.Put as BinaryBits--putInt8Vector :: Int8Vector -> BinaryBits.BitPut ()-putInt8Vector int8Vector = do-  putInt8VectorField (int8VectorX int8Vector)-  putInt8VectorField (int8VectorY int8Vector)-  putInt8VectorField (int8VectorZ int8Vector)--putInt8VectorField :: Maybe Int8le -> BinaryBits.BitPut ()-putInt8VectorField maybeField = case maybeField of-  Nothing -> BinaryBits.putBool False-  Just field -> do-    BinaryBits.putBool True-    putInt8Bits field
− library/Rattletrap/Encode/Int8le.hs
@@ -1,19 +0,0 @@-module Rattletrap.Encode.Int8le-  ( putInt8Bits-  )-where--import Rattletrap.Type.Int8le-import Rattletrap.Utility.Bytes--import qualified Data.Binary.Bits.Put as BinaryBits-import qualified Data.Binary.Put as Binary-import qualified Data.ByteString.Lazy as LazyBytes--putInt8 :: Int8le -> Binary.Put-putInt8 int8 = Binary.putInt8 (int8leValue int8)--putInt8Bits :: Int8le -> BinaryBits.BitPut ()-putInt8Bits int8 = do-  let bytes = LazyBytes.toStrict (Binary.runPut (putInt8 int8))-  BinaryBits.putByteString (reverseBytes bytes)
− library/Rattletrap/Encode/IntAttribute.hs
@@ -1,12 +0,0 @@-module Rattletrap.Encode.IntAttribute-  ( putIntAttribute-  )-where--import Rattletrap.Encode.Int32le-import Rattletrap.Type.IntAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putIntAttribute :: IntAttribute -> BinaryBits.BitPut ()-putIntAttribute intAttribute = putInt32Bits (intAttributeValue intAttribute)
− library/Rattletrap/Encode/KeyFrame.hs
@@ -1,16 +0,0 @@-module Rattletrap.Encode.KeyFrame-  ( putKeyFrame-  )-where--import Rattletrap.Encode.Float32le-import Rattletrap.Encode.Word32le-import Rattletrap.Type.KeyFrame--import qualified Data.Binary as Binary--putKeyFrame :: KeyFrame -> Binary.Put-putKeyFrame keyFrame = do-  putFloat32 (keyFrameTime keyFrame)-  putWord32 (keyFrameFrame keyFrame)-  putWord32 (keyFramePosition keyFrame)
− library/Rattletrap/Encode/List.hs
@@ -1,16 +0,0 @@-module Rattletrap.Encode.List-  ( putList-  )-where--import Rattletrap.Encode.Word32le-import Rattletrap.Type.List-import Rattletrap.Type.Word32le--import qualified Data.Binary as Binary--putList :: (a -> Binary.Put) -> List a -> Binary.Put-putList putElement list = do-  let elements = listValue list-  putWord32 (Word32le (fromIntegral (length elements)))-  mapM_ putElement elements
− library/Rattletrap/Encode/LoadoutAttribute.hs
@@ -1,35 +0,0 @@-module Rattletrap.Encode.LoadoutAttribute-  ( putLoadoutAttribute-  )-where--import Rattletrap.Encode.Word32le-import Rattletrap.Encode.Word8le-import Rattletrap.Type.LoadoutAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putLoadoutAttribute :: LoadoutAttribute -> BinaryBits.BitPut ()-putLoadoutAttribute loadoutAttribute = do-  putWord8Bits (loadoutAttributeVersion loadoutAttribute)-  putWord32Bits (loadoutAttributeBody loadoutAttribute)-  putWord32Bits (loadoutAttributeDecal loadoutAttribute)-  putWord32Bits (loadoutAttributeWheels loadoutAttribute)-  putWord32Bits (loadoutAttributeRocketTrail loadoutAttribute)-  putWord32Bits (loadoutAttributeAntenna loadoutAttribute)-  putWord32Bits (loadoutAttributeTopper loadoutAttribute)-  putWord32Bits (loadoutAttributeUnknown1 loadoutAttribute)-  putOptional (loadoutAttributeUnknown2 loadoutAttribute) putWord32Bits-  putOptional (loadoutAttributeEngineAudio loadoutAttribute) putWord32Bits-  putOptional (loadoutAttributeTrail loadoutAttribute) putWord32Bits-  putOptional (loadoutAttributeGoalExplosion loadoutAttribute) putWord32Bits-  putOptional (loadoutAttributeBanner loadoutAttribute) putWord32Bits-  putOptional (loadoutAttributeUnknown3 loadoutAttribute) putWord32Bits-  putOptional (loadoutAttributeUnknown4 loadoutAttribute) putWord32Bits-  putOptional (loadoutAttributeUnknown5 loadoutAttribute) putWord32Bits-  putOptional (loadoutAttributeUnknown6 loadoutAttribute) putWord32Bits--putOptional :: Maybe a -> (a -> BinaryBits.BitPut ()) -> BinaryBits.BitPut ()-putOptional m f = case m of-  Just x -> f x-  Nothing -> pure ()
− library/Rattletrap/Encode/LoadoutOnlineAttribute.hs
@@ -1,17 +0,0 @@-module Rattletrap.Encode.LoadoutOnlineAttribute-  ( putLoadoutOnlineAttribute-  )-where--import Rattletrap.Encode.ProductAttribute-import Rattletrap.Encode.Word8le-import Rattletrap.Type.LoadoutOnlineAttribute-import Rattletrap.Type.Word8le--import qualified Data.Binary.Bits.Put as BinaryBits--putLoadoutOnlineAttribute :: LoadoutOnlineAttribute -> BinaryBits.BitPut ()-putLoadoutOnlineAttribute loadoutAttribute = do-  let attributes = loadoutAttributeValue loadoutAttribute-  putWord8Bits (Word8le (fromIntegral (length attributes)))-  mapM_ putProductAttributes attributes
− library/Rattletrap/Encode/LoadoutsAttribute.hs
@@ -1,14 +0,0 @@-module Rattletrap.Encode.LoadoutsAttribute-  ( putLoadoutsAttribute-  )-where--import Rattletrap.Encode.LoadoutAttribute-import Rattletrap.Type.LoadoutsAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putLoadoutsAttribute :: LoadoutsAttribute -> BinaryBits.BitPut ()-putLoadoutsAttribute loadoutsAttribute = do-  putLoadoutAttribute (loadoutsAttributeBlue loadoutsAttribute)-  putLoadoutAttribute (loadoutsAttributeOrange loadoutsAttribute)
− library/Rattletrap/Encode/LoadoutsOnlineAttribute.hs
@@ -1,18 +0,0 @@-module Rattletrap.Encode.LoadoutsOnlineAttribute-  ( putLoadoutsOnlineAttribute-  )-where--import Rattletrap.Encode.LoadoutOnlineAttribute-import Rattletrap.Type.LoadoutsOnlineAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putLoadoutsOnlineAttribute :: LoadoutsOnlineAttribute -> BinaryBits.BitPut ()-putLoadoutsOnlineAttribute loadoutsOnlineAttribute = do-  putLoadoutOnlineAttribute-    (loadoutsOnlineAttributeBlue loadoutsOnlineAttribute)-  putLoadoutOnlineAttribute-    (loadoutsOnlineAttributeOrange loadoutsOnlineAttribute)-  BinaryBits.putBool (loadoutsOnlineAttributeUnknown1 loadoutsOnlineAttribute)-  BinaryBits.putBool (loadoutsOnlineAttributeUnknown2 loadoutsOnlineAttribute)
− library/Rattletrap/Encode/LocationAttribute.hs
@@ -1,13 +0,0 @@-module Rattletrap.Encode.LocationAttribute-  ( putLocationAttribute-  )-where--import Rattletrap.Encode.Vector-import Rattletrap.Type.LocationAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putLocationAttribute :: LocationAttribute -> BinaryBits.BitPut ()-putLocationAttribute locationAttribute =-  putVector (locationAttributeValue locationAttribute)
− library/Rattletrap/Encode/Mark.hs
@@ -1,15 +0,0 @@-module Rattletrap.Encode.Mark-  ( putMark-  )-where--import Rattletrap.Encode.Str-import Rattletrap.Encode.Word32le-import Rattletrap.Type.Mark--import qualified Data.Binary as Binary--putMark :: Mark -> Binary.Put-putMark mark = do-  putText (markValue mark)-  putWord32 (markFrame mark)
− library/Rattletrap/Encode/Message.hs
@@ -1,16 +0,0 @@-module Rattletrap.Encode.Message-  ( putMessage-  )-where--import Rattletrap.Encode.Str-import Rattletrap.Encode.Word32le-import Rattletrap.Type.Message--import qualified Data.Binary as Binary--putMessage :: Message -> Binary.Put-putMessage message = do-  putWord32 (messageFrame message)-  putText (messageName message)-  putText (messageValue message)
− library/Rattletrap/Encode/MusicStingerAttribute.hs
@@ -1,16 +0,0 @@-module Rattletrap.Encode.MusicStingerAttribute-  ( putMusicStingerAttribute-  )-where--import Rattletrap.Encode.Word32le-import Rattletrap.Encode.Word8le-import Rattletrap.Type.MusicStingerAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putMusicStingerAttribute :: MusicStingerAttribute -> BinaryBits.BitPut ()-putMusicStingerAttribute musicStingerAttribute = do-  BinaryBits.putBool (musicStingerAttributeFlag musicStingerAttribute)-  putWord32Bits (musicStingerAttributeCue musicStingerAttribute)-  putWord8Bits (musicStingerAttributeTrigger musicStingerAttribute)
− library/Rattletrap/Encode/PartyLeaderAttribute.hs
@@ -1,19 +0,0 @@-module Rattletrap.Encode.PartyLeaderAttribute-  ( putPartyLeaderAttribute-  )-where--import Rattletrap.Encode.RemoteId-import Rattletrap.Encode.Word8le-import Rattletrap.Type.PartyLeaderAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putPartyLeaderAttribute :: PartyLeaderAttribute -> BinaryBits.BitPut ()-putPartyLeaderAttribute partyLeaderAttribute = do-  putWord8Bits (partyLeaderAttributeSystemId partyLeaderAttribute)-  case partyLeaderAttributeId partyLeaderAttribute of-    Nothing -> pure ()-    Just (remoteId, localId) -> do-      putRemoteId remoteId-      putWord8Bits localId
− library/Rattletrap/Encode/PickupAttribute.hs
@@ -1,18 +0,0 @@-module Rattletrap.Encode.PickupAttribute-  ( putPickupAttribute-  )-where--import Rattletrap.Encode.Word32le-import Rattletrap.Type.PickupAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putPickupAttribute :: PickupAttribute -> BinaryBits.BitPut ()-putPickupAttribute pickupAttribute = do-  case pickupAttributeInstigatorId pickupAttribute of-    Nothing -> BinaryBits.putBool False-    Just instigatorId -> do-      BinaryBits.putBool True-      putWord32Bits instigatorId-  BinaryBits.putBool (pickupAttributePickedUp pickupAttribute)
− library/Rattletrap/Encode/PlayerHistoryKeyAttribute.hs
@@ -1,13 +0,0 @@-module Rattletrap.Encode.PlayerHistoryKeyAttribute-  ( putPlayerHistoryKeyAttribute-  )-where--import Rattletrap.Encode.Common-import Rattletrap.Type.PlayerHistoryKeyAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putPlayerHistoryKeyAttribute-  :: PlayerHistoryKeyAttribute -> BinaryBits.BitPut ()-putPlayerHistoryKeyAttribute = putBitsLE 14 . playerHistoryKeyAttributeUnknown
− library/Rattletrap/Encode/PrivateMatchSettingsAttribute.hs
@@ -1,26 +0,0 @@-module Rattletrap.Encode.PrivateMatchSettingsAttribute-  ( putPrivateMatchSettingsAttribute-  )-where--import Rattletrap.Encode.Str-import Rattletrap.Encode.Word32le-import Rattletrap.Type.PrivateMatchSettingsAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putPrivateMatchSettingsAttribute-  :: PrivateMatchSettingsAttribute -> BinaryBits.BitPut ()-putPrivateMatchSettingsAttribute privateMatchSettingsAttribute = do-  putTextBits-    (privateMatchSettingsAttributeMutators privateMatchSettingsAttribute)-  putWord32Bits-    (privateMatchSettingsAttributeJoinableBy privateMatchSettingsAttribute)-  putWord32Bits-    (privateMatchSettingsAttributeMaxPlayers privateMatchSettingsAttribute)-  putTextBits-    (privateMatchSettingsAttributeGameName privateMatchSettingsAttribute)-  putTextBits-    (privateMatchSettingsAttributePassword privateMatchSettingsAttribute)-  BinaryBits.putBool-    (privateMatchSettingsAttributeFlag privateMatchSettingsAttribute)
− library/Rattletrap/Encode/ProductAttribute.hs
@@ -1,37 +0,0 @@-module Rattletrap.Encode.ProductAttribute-  ( putProductAttributes-  )-where--import Rattletrap.Encode.Common-import Rattletrap.Encode.CompressedWord-import Rattletrap.Encode.Word32le-import Rattletrap.Encode.Word8le-import Rattletrap.Encode.Str-import Rattletrap.Type.ProductAttribute-import Rattletrap.Type.Word8le--import qualified Data.Binary.Bits.Put as BinaryBits--putProductAttributes :: [ProductAttribute] -> BinaryBits.BitPut ()-putProductAttributes attributes = do-  putWord8Bits (Word8le (fromIntegral (length attributes)))-  mapM_ putProductAttribute attributes--putProductAttribute :: ProductAttribute -> BinaryBits.BitPut ()-putProductAttribute attribute = do-  BinaryBits.putBool (productAttributeUnknown attribute)-  putWord32Bits (productAttributeObjectId attribute)-  case productAttributeValue attribute of-    ProductAttributeValuePaintedOld x -> putCompressedWord x-    ProductAttributeValuePaintedNew x -> putBitsLE 31 x-    ProductAttributeValueTeamEditionOld x -> putCompressedWord x-    ProductAttributeValueTeamEditionNew x -> putBitsLE 31 x-    ProductAttributeValueSpecialEdition x -> putBitsLE 31 x-    ProductAttributeValueUserColorOld x -> case x of-      Nothing -> BinaryBits.putBool False-      Just y -> do-        BinaryBits.putBool True-        putBitsLE 31 y-    ProductAttributeValueUserColorNew x -> putWord32Bits x-    ProductAttributeValueTitleId x -> putTextBits x
− library/Rattletrap/Encode/Property.hs
@@ -1,17 +0,0 @@-module Rattletrap.Encode.Property-  ( putProperty-  )-where--import Rattletrap.Encode.PropertyValue-import Rattletrap.Encode.Str-import Rattletrap.Encode.Word64le-import Rattletrap.Type.Property--import qualified Data.Binary as Binary--putProperty :: Property -> Binary.Put-putProperty property = do-  putText (propertyKind property)-  putWord64 (propertySize property)-  putPropertyValue putProperty (propertyValue property)
− library/Rattletrap/Encode/PropertyValue.hs
@@ -1,30 +0,0 @@-module Rattletrap.Encode.PropertyValue-  ( putPropertyValue-  )-where--import Rattletrap.Encode.Dictionary-import Rattletrap.Encode.Float32le-import Rattletrap.Encode.Int32le-import Rattletrap.Encode.List-import Rattletrap.Encode.Str-import Rattletrap.Encode.Word64le-import Rattletrap.Encode.Word8le-import Rattletrap.Type.PropertyValue--import qualified Data.Binary as Binary--putPropertyValue :: (a -> Binary.Put) -> PropertyValue a -> Binary.Put-putPropertyValue putProperty value = case value of-  PropertyValueArray list -> putList (putDictionary putProperty) list-  PropertyValueBool word8 -> putWord8 word8-  PropertyValueByte k mv -> do-    putText k-    case mv of-      Nothing -> pure ()-      Just v -> putText v-  PropertyValueFloat float32 -> putFloat32 float32-  PropertyValueInt int32 -> putInt32 int32-  PropertyValueName text -> putText text-  PropertyValueQWord word64 -> putWord64 word64-  PropertyValueStr text -> putText text
− library/Rattletrap/Encode/QWordAttribute.hs
@@ -1,13 +0,0 @@-module Rattletrap.Encode.QWordAttribute-  ( putQWordAttribute-  )-where--import Rattletrap.Encode.Word64le-import Rattletrap.Type.QWordAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putQWordAttribute :: QWordAttribute -> BinaryBits.BitPut ()-putQWordAttribute qWordAttribute =-  putWord64Bits (qWordAttributeValue qWordAttribute)
− library/Rattletrap/Encode/Quaternion.hs
@@ -1,41 +0,0 @@-module Rattletrap.Encode.Quaternion-  ( putQuaternion-  )-where--import Rattletrap.Encode.CompressedWord-import Rattletrap.Type.CompressedWord-import Rattletrap.Type.Quaternion--import qualified Data.Binary.Bits.Put as BinaryBits--putQuaternion :: Quaternion -> BinaryBits.BitPut ()-putQuaternion q = do-  let c = maxComponent q-  putComponent c-  case c of-    ComponentX -> putParts (quaternionY q) (quaternionZ q) (quaternionW q)-    ComponentY -> putParts (quaternionX q) (quaternionZ q) (quaternionW q)-    ComponentZ -> putParts (quaternionX q) (quaternionY q) (quaternionW q)-    ComponentW -> putParts (quaternionX q) (quaternionY q) (quaternionZ q)--putComponent :: Component -> BinaryBits.BitPut ()-putComponent component = putCompressedWord-  (CompressedWord-    3-    (case component of-      ComponentX -> 0-      ComponentY -> 1-      ComponentZ -> 2-      ComponentW -> 3-    )-  )--putParts :: Double -> Double -> Double -> BinaryBits.BitPut ()-putParts a b c = do-  putPart a-  putPart b-  putPart c--putPart :: Double -> BinaryBits.BitPut ()-putPart = putCompressedWord . compressPart
− library/Rattletrap/Encode/RemoteId.hs
@@ -1,35 +0,0 @@-module Rattletrap.Encode.RemoteId-  ( putRemoteId-  )-where--import Rattletrap.Encode.Common-import Rattletrap.Encode.Word64le-import Rattletrap.Type.RemoteId-import Rattletrap.Type.Word64le-import Rattletrap.Utility.Bytes--import qualified Data.Binary.Bits.Put as BinaryBits-import qualified Data.ByteString as Bytes--putRemoteId :: RemoteId -> BinaryBits.BitPut ()-putRemoteId remoteId = case remoteId of-  RemoteIdPlayStation name bytes -> do-    let rawName = reverseBytes (padBytes (16 :: Int) (encodeLatin1 name))-    BinaryBits.putByteString rawName-    BinaryBits.putByteString (Bytes.pack bytes)-  RemoteIdPsyNet e -> case e of-    Left l -> putWord64Bits l-    Right (a, b, c, d) -> putWord256 a b c d-  RemoteIdSplitscreen word24 -> putBitsLE 24 word24-  RemoteIdSteam word64 -> putWord64Bits word64-  RemoteIdSwitch a b c d -> putWord256 a b c d-  RemoteIdXbox word64 -> putWord64Bits word64--putWord256-  :: Word64le -> Word64le -> Word64le -> Word64le -> BinaryBits.BitPut ()-putWord256 a b c d = do-  putWord64Bits a-  putWord64Bits b-  putWord64Bits c-  putWord64Bits d
− library/Rattletrap/Encode/Replay.hs
@@ -1,21 +0,0 @@-module Rattletrap.Encode.Replay-  ( putReplay-  )-where--import Rattletrap.Encode.Content-import Rattletrap.Encode.Header-import Rattletrap.Encode.Section-import Rattletrap.Type.Replay--import qualified Data.Binary as Binary---- | Generates a raw replay. Use this with 'Data.Binary.Put.runPut'.------ @--- let bytes = 'Data.Binary.Put.runPut' ('putReplay' replay)--- @-putReplay :: Replay -> Binary.Put-putReplay replay = do-  putSection putHeader (replayHeader replay)-  putSection putContent (replayContent replay)
− library/Rattletrap/Encode/Replication.hs
@@ -1,26 +0,0 @@-module Rattletrap.Encode.Replication-  ( putReplications-  )-where--import Rattletrap.Encode.CompressedWord-import Rattletrap.Encode.ReplicationValue-import Rattletrap.Type.Replication--import qualified Data.Binary.Bits.Put as BinaryBits--putReplications :: [Replication] -> BinaryBits.BitPut ()-putReplications replications = case replications of-  [] -> BinaryBits.putBool False-  [replication] -> do-    putReplication replication-    BinaryBits.putBool False-  first : rest -> do-    putReplication first-    putReplications rest--putReplication :: Replication -> BinaryBits.BitPut ()-putReplication replication = do-  BinaryBits.putBool True-  putCompressedWord (replicationActorId replication)-  putReplicationValue (replicationValue replication)
− library/Rattletrap/Encode/ReplicationValue.hs
@@ -1,25 +0,0 @@-module Rattletrap.Encode.ReplicationValue-  ( putReplicationValue-  )-where--import Rattletrap.Encode.DestroyedReplication-import Rattletrap.Encode.SpawnedReplication-import Rattletrap.Encode.UpdatedReplication-import Rattletrap.Type.ReplicationValue--import qualified Data.Binary.Bits.Put as BinaryBits--putReplicationValue :: ReplicationValue -> BinaryBits.BitPut ()-putReplicationValue value = case value of-  ReplicationValueSpawned x -> do-    BinaryBits.putBool True-    BinaryBits.putBool True-    putSpawnedReplication x-  ReplicationValueUpdated x -> do-    BinaryBits.putBool True-    BinaryBits.putBool False-    putUpdatedReplication x-  ReplicationValueDestroyed x -> do-    BinaryBits.putBool False-    putDestroyedReplication x
− library/Rattletrap/Encode/ReservationAttribute.hs
@@ -1,24 +0,0 @@-module Rattletrap.Encode.ReservationAttribute-  ( putReservationAttribute-  )-where--import Rattletrap.Encode.CompressedWord-import Rattletrap.Encode.Str-import Rattletrap.Encode.UniqueIdAttribute-import Rattletrap.Type.ReservationAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putReservationAttribute :: ReservationAttribute -> BinaryBits.BitPut ()-putReservationAttribute reservationAttribute = do-  putCompressedWord (reservationAttributeNumber reservationAttribute)-  putUniqueIdAttribute (reservationAttributeUniqueId reservationAttribute)-  case reservationAttributeName reservationAttribute of-    Nothing -> pure ()-    Just name -> putTextBits name-  BinaryBits.putBool (reservationAttributeUnknown1 reservationAttribute)-  BinaryBits.putBool (reservationAttributeUnknown2 reservationAttribute)-  case reservationAttributeUnknown3 reservationAttribute of-    Nothing -> pure ()-    Just c -> BinaryBits.putWord8 6 c
− library/Rattletrap/Encode/RigidBodyStateAttribute.hs
@@ -1,22 +0,0 @@-module Rattletrap.Encode.RigidBodyStateAttribute-  ( putRigidBodyStateAttribute-  )-where--import Rattletrap.Encode.Rotation-import Rattletrap.Encode.Vector-import Rattletrap.Type.RigidBodyStateAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putRigidBodyStateAttribute :: RigidBodyStateAttribute -> BinaryBits.BitPut ()-putRigidBodyStateAttribute rigidBodyStateAttribute = do-  BinaryBits.putBool (rigidBodyStateAttributeSleeping rigidBodyStateAttribute)-  putVector (rigidBodyStateAttributeLocation rigidBodyStateAttribute)-  putRotation (rigidBodyStateAttributeRotation rigidBodyStateAttribute)-  case rigidBodyStateAttributeLinearVelocity rigidBodyStateAttribute of-    Nothing -> pure ()-    Just linearVelocity -> putVector linearVelocity-  case rigidBodyStateAttributeAngularVelocity rigidBodyStateAttribute of-    Nothing -> pure ()-    Just angularVelocity -> putVector angularVelocity
− library/Rattletrap/Encode/Rotation.hs
@@ -1,15 +0,0 @@-module Rattletrap.Encode.Rotation-  ( putRotation-  )-where--import Rattletrap.Encode.CompressedWordVector-import Rattletrap.Encode.Quaternion-import Rattletrap.Type.Rotation--import qualified Data.Binary.Bits.Put as BinaryBits--putRotation :: Rotation -> BinaryBits.BitPut ()-putRotation r = case r of-  RotationCompressedWordVector cwv -> putCompressedWordVector cwv-  RotationQuaternion q -> putQuaternion q
− library/Rattletrap/Encode/Section.hs
@@ -1,31 +0,0 @@-module Rattletrap.Encode.Section-  ( putSection-  )-where--import Rattletrap.Encode.Word32le-import Rattletrap.Type.Section-import Rattletrap.Type.Word32le-import Rattletrap.Utility.Crc--import qualified Data.Binary as Binary-import qualified Data.Binary.Put as Binary-import qualified Data.ByteString as Bytes-import qualified Data.ByteString.Lazy as LazyBytes---- | Given a way to put the 'sectionBody', puts a section. This will also put--- the size and CRC.------ @--- let bytes = 'Data.Binary.Put.runPut' ('putSection' 'Rattletrap.Content.putContent' content)--- @-putSection :: (a -> Binary.Put) -> Section a -> Binary.Put-putSection putBody section = do-  let-    rawBody =-      LazyBytes.toStrict (Binary.runPut (putBody (sectionBody section)))-  let size = Bytes.length rawBody-  let crc = getCrc32 rawBody-  putWord32 (Word32le (fromIntegral size))-  putWord32 (Word32le crc)-  Binary.putByteString rawBody
− library/Rattletrap/Encode/SpawnedReplication.hs
@@ -1,19 +0,0 @@-module Rattletrap.Encode.SpawnedReplication-  ( putSpawnedReplication-  )-where--import Rattletrap.Encode.Initialization-import Rattletrap.Encode.Word32le-import Rattletrap.Type.SpawnedReplication--import qualified Data.Binary.Bits.Put as BinaryBits--putSpawnedReplication :: SpawnedReplication -> BinaryBits.BitPut ()-putSpawnedReplication spawnedReplication = do-  BinaryBits.putBool (spawnedReplicationFlag spawnedReplication)-  case spawnedReplicationNameIndex spawnedReplication of-    Nothing -> pure ()-    Just nameIndex -> putWord32Bits nameIndex-  putWord32Bits (spawnedReplicationObjectId spawnedReplication)-  putInitialization (spawnedReplicationInitialization spawnedReplication)
− library/Rattletrap/Encode/StatEventAttribute.hs
@@ -1,14 +0,0 @@-module Rattletrap.Encode.StatEventAttribute-  ( putStatEventAttribute-  )-where--import Rattletrap.Encode.Int32le-import Rattletrap.Type.StatEventAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putStatEventAttribute :: StatEventAttribute -> BinaryBits.BitPut ()-putStatEventAttribute statEventAttribute = do-  BinaryBits.putBool (statEventAttributeUnknown statEventAttribute)-  putInt32Bits (statEventAttributeObjectId statEventAttribute)
− library/Rattletrap/Encode/Str.hs
@@ -1,53 +0,0 @@-module Rattletrap.Encode.Str-  ( putText-  , putTextBits-  )-where--import Rattletrap.Encode.Int32le-import Rattletrap.Type.Common-import Rattletrap.Type.Int32le-import Rattletrap.Type.Str-import Rattletrap.Utility.Bytes--import qualified Data.Binary as Binary-import qualified Data.Binary.Bits.Put as BinaryBits-import qualified Data.Binary.Put as Binary-import qualified Data.ByteString as Bytes-import qualified Data.Char as Char-import qualified Data.Text as Text-import qualified Data.Text.Encoding as Text--putText :: Str -> Binary.Put-putText text = do-  let size = getTextSize text-  let encode = getTextEncoder size-  putInt32 size-  Binary.putByteString (encode (addNull (strValue text)))--putTextBits :: Str -> BinaryBits.BitPut ()-putTextBits text = do-  let size = getTextSize text-  let encode = getTextEncoder size-  putInt32Bits size-  BinaryBits.putByteString (reverseBytes (encode (addNull (strValue text))))--getTextSize :: Str -> Int32le-getTextSize text =-  let-    value = strValue text-    scale = if Text.all Char.isLatin1 value then 1 else -1 :: Int32-    rawSize = if Text.null value-      then 0-      else fromIntegral (Text.length value) + 1 :: Int32-    size = if value == Text.pack "\x00\x00\x00None"-      then 0x05000000-      else scale * rawSize :: Int32-  in Int32le size--getTextEncoder :: Int32le -> Text.Text -> Bytes.ByteString-getTextEncoder size text =-  if size < Int32le 0 then Text.encodeUtf16LE text else encodeLatin1 text--addNull :: Text.Text -> Text.Text-addNull text = if Text.null text then text else Text.snoc text '\x00'
− library/Rattletrap/Encode/StringAttribute.hs
@@ -1,13 +0,0 @@-module Rattletrap.Encode.StringAttribute-  ( putStringAttribute-  )-where--import Rattletrap.Encode.Str-import Rattletrap.Type.StringAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putStringAttribute :: StringAttribute -> BinaryBits.BitPut ()-putStringAttribute stringAttribute =-  putTextBits (stringAttributeValue stringAttribute)
− library/Rattletrap/Encode/TeamPaintAttribute.hs
@@ -1,18 +0,0 @@-module Rattletrap.Encode.TeamPaintAttribute-  ( putTeamPaintAttribute-  )-where--import Rattletrap.Encode.Word32le-import Rattletrap.Encode.Word8le-import Rattletrap.Type.TeamPaintAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putTeamPaintAttribute :: TeamPaintAttribute -> BinaryBits.BitPut ()-putTeamPaintAttribute teamPaintAttribute = do-  putWord8Bits (teamPaintAttributeTeam teamPaintAttribute)-  putWord8Bits (teamPaintAttributePrimaryColor teamPaintAttribute)-  putWord8Bits (teamPaintAttributeAccentColor teamPaintAttribute)-  putWord32Bits (teamPaintAttributePrimaryFinish teamPaintAttribute)-  putWord32Bits (teamPaintAttributeAccentFinish teamPaintAttribute)
− library/Rattletrap/Encode/TitleAttribute.hs
@@ -1,20 +0,0 @@-module Rattletrap.Encode.TitleAttribute-  ( putTitleAttribute-  )-where--import Rattletrap.Encode.Word32le-import Rattletrap.Type.TitleAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putTitleAttribute :: TitleAttribute -> BinaryBits.BitPut ()-putTitleAttribute titleAttribute = do-  BinaryBits.putBool (titleAttributeUnknown1 titleAttribute)-  BinaryBits.putBool (titleAttributeUnknown2 titleAttribute)-  putWord32Bits (titleAttributeUnknown3 titleAttribute)-  putWord32Bits (titleAttributeUnknown4 titleAttribute)-  putWord32Bits (titleAttributeUnknown5 titleAttribute)-  putWord32Bits (titleAttributeUnknown6 titleAttribute)-  putWord32Bits (titleAttributeUnknown7 titleAttribute)-  BinaryBits.putBool (titleAttributeUnknown8 titleAttribute)
− library/Rattletrap/Encode/UniqueIdAttribute.hs
@@ -1,16 +0,0 @@-module Rattletrap.Encode.UniqueIdAttribute-  ( putUniqueIdAttribute-  )-where--import Rattletrap.Encode.RemoteId-import Rattletrap.Encode.Word8le-import Rattletrap.Type.UniqueIdAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putUniqueIdAttribute :: UniqueIdAttribute -> BinaryBits.BitPut ()-putUniqueIdAttribute uniqueIdAttribute = do-  putWord8Bits (uniqueIdAttributeSystemId uniqueIdAttribute)-  putRemoteId (uniqueIdAttributeRemoteId uniqueIdAttribute)-  putWord8Bits (uniqueIdAttributeLocalId uniqueIdAttribute)
− library/Rattletrap/Encode/UpdatedReplication.hs
@@ -1,13 +0,0 @@-module Rattletrap.Encode.UpdatedReplication-  ( putUpdatedReplication-  )-where--import Rattletrap.Encode.Attribute-import Rattletrap.Type.UpdatedReplication--import qualified Data.Binary.Bits.Put as BinaryBits--putUpdatedReplication :: UpdatedReplication -> BinaryBits.BitPut ()-putUpdatedReplication updatedReplication =-  putAttributes (updatedReplicationAttributes updatedReplication)
− library/Rattletrap/Encode/Vector.hs
@@ -1,27 +0,0 @@-module Rattletrap.Encode.Vector-  ( putVector-  )-where--import Rattletrap.Encode.CompressedWord-import Rattletrap.Type.CompressedWord-import Rattletrap.Type.Vector--import qualified Data.Binary.Bits.Put as BinaryBits--putVector :: Vector -> BinaryBits.BitPut ()-putVector vector = do-  let-    bitSize =-      round (logBase (2 :: Float) (fromIntegral (vectorBias vector))) - 1 :: Word-    dx =-      fromIntegral (vectorX vector + fromIntegral (vectorBias vector)) :: Word-    dy =-      fromIntegral (vectorY vector + fromIntegral (vectorBias vector)) :: Word-    dz =-      fromIntegral (vectorZ vector + fromIntegral (vectorBias vector)) :: Word-    limit = 2 ^ (bitSize + 2) :: Word-  putCompressedWord (vectorSize vector)-  putCompressedWord (CompressedWord limit dx)-  putCompressedWord (CompressedWord limit dy)-  putCompressedWord (CompressedWord limit dz)
− library/Rattletrap/Encode/WeldedInfoAttribute.hs
@@ -1,20 +0,0 @@-module Rattletrap.Encode.WeldedInfoAttribute-  ( putWeldedInfoAttribute-  )-where--import Rattletrap.Encode.Float32le-import Rattletrap.Encode.Int32le-import Rattletrap.Encode.Int8Vector-import Rattletrap.Encode.Vector-import Rattletrap.Type.WeldedInfoAttribute--import qualified Data.Binary.Bits.Put as BinaryBits--putWeldedInfoAttribute :: WeldedInfoAttribute -> BinaryBits.BitPut ()-putWeldedInfoAttribute weldedInfoAttribute = do-  BinaryBits.putBool (weldedInfoAttributeActive weldedInfoAttribute)-  putInt32Bits (weldedInfoAttributeActorId weldedInfoAttribute)-  putVector (weldedInfoAttributeOffset weldedInfoAttribute)-  putFloat32Bits (weldedInfoAttributeMass weldedInfoAttribute)-  putInt8Vector (weldedInfoAttributeRotation weldedInfoAttribute)
− library/Rattletrap/Encode/Word32le.hs
@@ -1,21 +0,0 @@-module Rattletrap.Encode.Word32le-  ( putWord32-  , putWord32Bits-  )-where--import Rattletrap.Type.Word32le-import Rattletrap.Utility.Bytes--import qualified Data.Binary as Binary-import qualified Data.Binary.Bits.Put as BinaryBits-import qualified Data.Binary.Put as Binary-import qualified Data.ByteString.Lazy as LazyBytes--putWord32 :: Word32le -> Binary.Put-putWord32 word32 = Binary.putWord32le (word32leValue word32)--putWord32Bits :: Word32le -> BinaryBits.BitPut ()-putWord32Bits word32 = do-  let bytes = LazyBytes.toStrict (Binary.runPut (putWord32 word32))-  BinaryBits.putByteString (reverseBytes bytes)
− library/Rattletrap/Encode/Word64le.hs
@@ -1,21 +0,0 @@-module Rattletrap.Encode.Word64le-  ( putWord64-  , putWord64Bits-  )-where--import Rattletrap.Type.Word64le-import Rattletrap.Utility.Bytes--import qualified Data.Binary as Binary-import qualified Data.Binary.Bits.Put as BinaryBits-import qualified Data.Binary.Put as Binary-import qualified Data.ByteString.Lazy as LazyBytes--putWord64 :: Word64le -> Binary.Put-putWord64 word64 = Binary.putWord64le (word64leValue word64)--putWord64Bits :: Word64le -> BinaryBits.BitPut ()-putWord64Bits word64 = do-  let bytes = LazyBytes.toStrict (Binary.runPut (putWord64 word64))-  BinaryBits.putByteString (reverseBytes bytes)
− library/Rattletrap/Encode/Word8le.hs
@@ -1,21 +0,0 @@-module Rattletrap.Encode.Word8le-  ( putWord8-  , putWord8Bits-  )-where--import Rattletrap.Type.Word8le-import Rattletrap.Utility.Bytes--import qualified Data.Binary as Binary-import qualified Data.Binary.Bits.Put as BinaryBits-import qualified Data.Binary.Put as Binary-import qualified Data.ByteString.Lazy as LazyBytes--putWord8 :: Word8le -> Binary.Put-putWord8 word8 = Binary.putWord8 (word8leValue word8)--putWord8Bits :: Word8le -> BinaryBits.BitPut ()-putWord8Bits word8 = do-  let bytes = LazyBytes.toStrict (Binary.runPut (putWord8 word8))-  BinaryBits.putByteString (reverseBytes bytes)
− library/Rattletrap/Type/AppliedDamageAttribute.hs
@@ -1,20 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.AppliedDamageAttribute-  ( AppliedDamageAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Int32le-import Rattletrap.Type.Vector-import Rattletrap.Type.Word8le--data AppliedDamageAttribute = AppliedDamageAttribute-  { appliedDamageAttributeUnknown1 :: Word8le-  , appliedDamageAttributeLocation :: Vector-  , appliedDamageAttributeUnknown3 :: Int32le-  , appliedDamageAttributeUnknown4 :: Int32le-  } deriving (Eq, Ord, Show)--$(deriveJson ''AppliedDamageAttribute)
− library/Rattletrap/Type/Attribute.hs
@@ -1,21 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Attribute-  ( Attribute(..)-  )-where--import Rattletrap.Type.AttributeValue-import Rattletrap.Type.Common-import Rattletrap.Type.CompressedWord-import Rattletrap.Type.Str--data Attribute = Attribute-  { attributeId :: CompressedWord-  , attributeName :: Str-  -- ^ Read-only! Changing an attribute's name requires editing the class-  -- attribute map.-  , attributeValue :: AttributeValue-  } deriving (Eq, Ord, Show)--$(deriveJson ''Attribute)
− library/Rattletrap/Type/AttributeMapping.hs
@@ -1,16 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.AttributeMapping-  ( AttributeMapping(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Word32le--data AttributeMapping = AttributeMapping-  { attributeMappingObjectId :: Word32le-  , attributeMappingStreamId :: Word32le-  } deriving (Eq, Ord, Show)--$(deriveJson ''AttributeMapping)
− library/Rattletrap/Type/AttributeType.hs
@@ -1,48 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.AttributeType-  ( AttributeType(..)-  )-where--import Rattletrap.Type.Common--data AttributeType-  = AttributeTypeAppliedDamage-  | AttributeTypeBoolean-  | AttributeTypeByte-  | AttributeTypeCamSettings-  | AttributeTypeClubColors-  | AttributeTypeDamageState-  | AttributeTypeDemolish-  | AttributeTypeEnum-  | AttributeTypeExplosion-  | AttributeTypeExtendedExplosion-  | AttributeTypeFlaggedInt-  | AttributeTypeFlaggedByte-  | AttributeTypeFloat-  | AttributeTypeGameMode-  | AttributeTypeInt-  | AttributeTypeInt64-  | AttributeTypeLoadout-  | AttributeTypeLoadoutOnline-  | AttributeTypeLoadouts-  | AttributeTypeLoadoutsOnline-  | AttributeTypeLocation-  | AttributeTypeMusicStinger-  | AttributeTypePartyLeader-  | AttributeTypePickup-  | AttributeTypePlayerHistoryKey-  | AttributeTypePrivateMatchSettings-  | AttributeTypeQWord-  | AttributeTypeReservation-  | AttributeTypeRigidBodyState-  | AttributeTypeStatEvent-  | AttributeTypeString-  | AttributeTypeTeamPaint-  | AttributeTypeTitle-  | AttributeTypeUniqueId-  | AttributeTypeWeldedInfo-  deriving (Eq, Ord, Show)--$(deriveJson ''AttributeType)
− library/Rattletrap/Type/AttributeValue.hs
@@ -1,83 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.AttributeValue-  ( AttributeValue(..)-  )-where--import Rattletrap.Type.AppliedDamageAttribute-import Rattletrap.Type.BooleanAttribute-import Rattletrap.Type.ByteAttribute-import Rattletrap.Type.CamSettingsAttribute-import Rattletrap.Type.ClubColorsAttribute-import Rattletrap.Type.Common-import Rattletrap.Type.DamageStateAttribute-import Rattletrap.Type.DemolishAttribute-import Rattletrap.Type.EnumAttribute-import Rattletrap.Type.ExplosionAttribute-import Rattletrap.Type.ExtendedExplosionAttribute-import Rattletrap.Type.FlaggedIntAttribute-import Rattletrap.Type.FlaggedByteAttribute-import Rattletrap.Type.FloatAttribute-import Rattletrap.Type.GameModeAttribute-import Rattletrap.Type.Int64Attribute-import Rattletrap.Type.IntAttribute-import Rattletrap.Type.LoadoutAttribute-import Rattletrap.Type.LoadoutOnlineAttribute-import Rattletrap.Type.LoadoutsAttribute-import Rattletrap.Type.LoadoutsOnlineAttribute-import Rattletrap.Type.LocationAttribute-import Rattletrap.Type.MusicStingerAttribute-import Rattletrap.Type.PartyLeaderAttribute-import Rattletrap.Type.PickupAttribute-import Rattletrap.Type.PlayerHistoryKeyAttribute-import Rattletrap.Type.PrivateMatchSettingsAttribute-import Rattletrap.Type.QWordAttribute-import Rattletrap.Type.ReservationAttribute-import Rattletrap.Type.RigidBodyStateAttribute-import Rattletrap.Type.StatEventAttribute-import Rattletrap.Type.StringAttribute-import Rattletrap.Type.TeamPaintAttribute-import Rattletrap.Type.TitleAttribute-import Rattletrap.Type.UniqueIdAttribute-import Rattletrap.Type.WeldedInfoAttribute--data AttributeValue-  = AttributeValueAppliedDamage AppliedDamageAttribute-  | AttributeValueBoolean BooleanAttribute-  | AttributeValueByte ByteAttribute-  | AttributeValueCamSettings CamSettingsAttribute-  | AttributeValueClubColors ClubColorsAttribute-  | AttributeValueDamageState DamageStateAttribute-  | AttributeValueDemolish DemolishAttribute-  | AttributeValueEnum EnumAttribute-  | AttributeValueExplosion ExplosionAttribute-  | AttributeValueExtendedExplosion ExtendedExplosionAttribute-  | AttributeValueFlaggedInt FlaggedIntAttribute-  | AttributeValueFlaggedByte FlaggedByteAttribute-  | AttributeValueFloat FloatAttribute-  | AttributeValueGameMode GameModeAttribute-  | AttributeValueInt IntAttribute-  | AttributeValueInt64 Int64Attribute-  | AttributeValueLoadout LoadoutAttribute-  | AttributeValueLoadoutOnline LoadoutOnlineAttribute-  | AttributeValueLoadouts LoadoutsAttribute-  | AttributeValueLoadoutsOnline LoadoutsOnlineAttribute-  | AttributeValueLocation LocationAttribute-  | AttributeValueMusicStinger MusicStingerAttribute-  | AttributeValuePartyLeader PartyLeaderAttribute-  | AttributeValuePickup PickupAttribute-  | AttributeValuePlayerHistoryKey PlayerHistoryKeyAttribute-  | AttributeValuePrivateMatchSettings PrivateMatchSettingsAttribute-  | AttributeValueQWord QWordAttribute-  | AttributeValueReservation ReservationAttribute-  | AttributeValueRigidBodyState RigidBodyStateAttribute-  | AttributeValueStatEvent StatEventAttribute-  | AttributeValueString StringAttribute-  | AttributeValueTeamPaint TeamPaintAttribute-  | AttributeValueTitle TitleAttribute-  | AttributeValueUniqueId UniqueIdAttribute-  | AttributeValueWeldedInfo WeldedInfoAttribute-  deriving (Eq, Ord, Show)--$(deriveJson ''AttributeValue)
− library/Rattletrap/Type/BooleanAttribute.hs
@@ -1,14 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.BooleanAttribute-  ( BooleanAttribute(..)-  )-where--import Rattletrap.Type.Common--newtype BooleanAttribute = BooleanAttribute-  { booleanAttributeValue :: Bool-  } deriving (Eq, Ord, Show)--$(deriveJson ''BooleanAttribute)
− library/Rattletrap/Type/ByteAttribute.hs
@@ -1,15 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.ByteAttribute-  ( ByteAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Word8le--newtype ByteAttribute = ByteAttribute-  { byteAttributeValue :: Word8le-  } deriving (Eq, Ord, Show)--$(deriveJson ''ByteAttribute)
− library/Rattletrap/Type/Cache.hs
@@ -1,20 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Cache-  ( Cache(..)-  )-where--import Rattletrap.Type.AttributeMapping-import Rattletrap.Type.Common-import Rattletrap.Type.List-import Rattletrap.Type.Word32le--data Cache = Cache-  { cacheClassId :: Word32le-  , cacheParentCacheId :: Word32le-  , cacheCacheId :: Word32le-  , cacheAttributeMappings :: List AttributeMapping-  } deriving (Eq, Ord, Show)--$(deriveJson ''Cache)
− library/Rattletrap/Type/CamSettingsAttribute.hs
@@ -1,21 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.CamSettingsAttribute-  ( CamSettingsAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Float32le--data CamSettingsAttribute = CamSettingsAttribute-  { camSettingsAttributeFov :: Float32le-  , camSettingsAttributeHeight :: Float32le-  , camSettingsAttributeAngle :: Float32le-  , camSettingsAttributeDistance :: Float32le-  , camSettingsAttributeStiffness :: Float32le-  , camSettingsAttributeSwivelSpeed :: Float32le-  , camSettingsAttributeTransitionSpeed :: Maybe Float32le-  } deriving (Eq, Ord, Show)--$(deriveJson ''CamSettingsAttribute)
− library/Rattletrap/Type/ClassAttributeMap.hs
@@ -1,324 +0,0 @@-module Rattletrap.Type.ClassAttributeMap-  ( ClassAttributeMap(..)-  , classHasLocation-  , classHasRotation-  , getAttributeIdLimit-  , getAttributeMap-  , getAttributeName-  , getClassName-  , getName-  , getObjectName-  , makeClassAttributeMap-  )-where--import Rattletrap.Data-import Rattletrap.Type.AttributeMapping-import Rattletrap.Type.Cache-import Rattletrap.Type.ClassMapping-import Rattletrap.Type.Common-import Rattletrap.Type.CompressedWord-import Rattletrap.Type.List-import Rattletrap.Type.Str-import Rattletrap.Type.Word32le--import qualified Data.IntMap as IntMap-import qualified Data.List as List-import qualified Data.Map as Map-import qualified Data.Maybe as Maybe-import qualified Data.Set as Set-import qualified Data.Text as Text-import qualified Data.Tuple as Tuple---- | This data structure holds all the information about classes, objects, and--- attributes in the replay. The class hierarchy is not fixed; it is encoded--- in the 'Rattletrap.Content.Content'. Similarly, the attributes that belong--- to each class are not fixed either. Converting the raw data into a usable--- structure is tedious; see 'makeClassAttributeMap'.-data ClassAttributeMap = ClassAttributeMap-  { classAttributeMapObjectMap :: Map Word32le Str-  -- ^ A map from object IDs to their names.-  , classAttributeMapObjectClassMap :: Map Word32le Word32le-  -- ^ A map from object IDs to their class IDs.-    , classAttributeMapValue :: Map Word32le (Map Word32le Word32le)-  -- ^ A map from class IDs to a map from attribute stream IDs to attribute-  -- IDs.-  , classAttributeMapNameMap :: IntMap.IntMap Str-  } deriving (Eq, Ord, Show)--type Bimap l r = (Map l r, Map r l)--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 k = Map.lookup k . fst--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'.-makeClassAttributeMap-  :: List Str-  -- ^ From 'Rattletrap.Content.contentObjects'.-  -> List ClassMapping-  -- ^ From 'Rattletrap.Content.contentClassMappings'.-  -> List Cache-  -- ^ From 'Rattletrap.Content.contentCaches'.-  -> List Str-  -- ^ From 'Rattletrap.Content.contentNames'.-  -> ClassAttributeMap-makeClassAttributeMap 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--makeNameMap :: List Str -> IntMap.IntMap Str-makeNameMap names = IntMap.fromDistinctAscList (zip [0 ..] (listValue names))--getName :: IntMap.IntMap Str -> Word32le -> Maybe Str-getName nameMap nameIndex =-  IntMap.lookup (fromIntegral (word32leValue nameIndex)) nameMap--makeObjectClassMap-  :: Map Word32le Str -> Bimap Word32le Str -> Map Word32le Word32le-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-  Map.fromList pairs--getClassId-  :: Map Word32le Str -> Bimap Word32le Str -> Word32le -> Maybe Word32le-getClassId objectMap classMap objectId = do-  objectName <- getObjectName objectMap objectId-  className <- getClassName objectName-  lookupR className classMap--makeClassCache-  :: Bimap Word32le Str-  -> List Cache-  -> [(Maybe Str, Word32le, Word32le, Word32le)]-makeClassCache classMap caches = fmap-  (\cache ->-    let classId = cacheClassId cache-    in-      ( lookupL classId classMap-      , classId-      , cacheCacheId cache-      , cacheParentCacheId cache-      )-  )-  (listValue caches)--makeClassMap :: List ClassMapping -> Bimap Word32le Str-makeClassMap classMappings = bimap-  (fmap-    (\classMapping ->-      (classMappingStreamId classMapping, classMappingName classMapping)-    )-    (listValue classMappings)-  )--makeAttributeMap :: List Cache -> Map Word32le (Map Word32le Word32le)-makeAttributeMap caches = Map.fromList-  (fmap-    (\cache ->-      ( cacheClassId cache-      , Map.fromList-        (fmap-          (\attributeMapping ->-            ( attributeMappingStreamId attributeMapping-            , attributeMappingObjectId attributeMapping-            )-          )-          (listValue (cacheAttributeMappings cache))-        )-      )-    )-    (listValue caches)-  )--makeShallowParentMap-  :: [(Maybe Str, Word32le, Word32le, Word32le)] -> Map Word32le Word32le-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))-  )--makeParentMap-  :: [(Maybe Str, Word32le, Word32le, Word32le)] -> Map Word32le [Word32le]-makeParentMap classCache =-  let shallowParentMap = makeShallowParentMap classCache-  in-    Map.mapWithKey-      (\classId _ -> getParentClasses shallowParentMap classId)-      shallowParentMap--getParentClasses :: Map Word32le Word32le -> Word32le -> [Word32le]-getParentClasses shallowParentMap classId =-  case Map.lookup classId shallowParentMap of-    Nothing -> []-    Just parentClassId ->-      parentClassId : getParentClasses shallowParentMap parentClassId--getParentClass-  :: Maybe Str-  -> Word32le-  -> [(Maybe Str, Word32le, Word32le, Word32le)]-  -> Maybe Word32le-getParentClass maybeClassName parentCacheId xs = case maybeClassName of-  Nothing -> getParentClassById parentCacheId xs-  Just className -> getParentClassByName className parentCacheId xs--getParentClassById-  :: Word32le -> [(Maybe Str, Word32le, Word32le, Word32le)] -> Maybe Word32le-getParentClassById parentCacheId xs =-  case dropWhile (\(_, _, cacheId, _) -> cacheId /= parentCacheId) xs of-    [] -> if parentCacheId == Word32le 0-      then Nothing-      else getParentClassById (Word32le (word32leValue parentCacheId - 1)) xs-    (_, parentClassId, _, _) : _ -> Just parentClassId--getParentClassByName-  :: Str-  -> Word32le-  -> [(Maybe Str, Word32le, Word32le, Word32le)]-  -> Maybe Word32le-getParentClassByName className parentCacheId xs =-  case Map.lookup className 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, _, _, _) ->-                maybeClassName == Just parentClassName-              )-              xs-            )-          )-        )-      )--parentClasses :: Map Str Str-parentClasses =-  Map.map toStr (Map.mapKeys toStr (Map.fromList rawParentClasses))--makeObjectMap :: List Str -> Map Word32le Str-makeObjectMap objects =-  Map.fromAscList (zip (fmap Word32le [0 ..]) (listValue objects))--getObjectName :: Map Word32le Str -> Word32le -> Maybe Str-getObjectName objectMap objectId = Map.lookup objectId objectMap--getClassName :: Str -> Maybe Str-getClassName rawObjectName =-  Map.lookup (normalizeObjectName rawObjectName) objectClasses--normalizeObjectName :: Str -> Str-normalizeObjectName objectName =-  let-    name = strValue 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 crowdActor-    else if Text.isInfixOf crowdManager name-      then Str crowdManager-      else if Text.isInfixOf boostPickup name-        then Str boostPickup-        else if Text.isInfixOf mapScoreboard name-          then Str mapScoreboard-          else if Text.isInfixOf breakout name-            then Str breakout-            else objectName--objectClasses :: Map Str Str-objectClasses =-  Map.map toStr (Map.mapKeys toStr (Map.fromList rawObjectClasses))--classHasLocation :: Str -> Bool-classHasLocation className = Set.member className classesWithLocation--classesWithLocation :: Set.Set Str-classesWithLocation = Set.fromList (fmap toStr rawClassesWithLocation)--classHasRotation :: Str -> Bool-classHasRotation className = Set.member className classesWithRotation--classesWithRotation :: Set.Set Str-classesWithRotation = Set.fromList (fmap toStr rawClassesWithRotation)--getAttributeIdLimit :: Map Word32le Word32le -> Maybe Word-getAttributeIdLimit attributeMap = do-  ((streamId, _), _) <- Map.maxViewWithKey attributeMap-  pure (fromIntegral (word32leValue streamId))--getAttributeName-  :: ClassAttributeMap -> Map Word32le Word32le -> CompressedWord -> Maybe Str-getAttributeName classAttributeMap attributeMap streamId = do-  let key = Word32le (fromIntegral (compressedWordValue streamId))-  attributeId <- Map.lookup key attributeMap-  let objectMap = classAttributeMapObjectMap classAttributeMap-  Map.lookup attributeId objectMap--getAttributeMap-  :: ClassAttributeMap-  -> Map CompressedWord Word32le-  -> CompressedWord-  -> Maybe (Map Word32le Word32le)-getAttributeMap classAttributeMap actorMap actorId = do-  objectId <- Map.lookup actorId actorMap-  let objectClassMap = classAttributeMapObjectClassMap classAttributeMap-  classId <- Map.lookup objectId objectClassMap-  let value = classAttributeMapValue classAttributeMap-  Map.lookup classId value
− library/Rattletrap/Type/ClassMapping.hs
@@ -1,17 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.ClassMapping-  ( ClassMapping(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Str-import Rattletrap.Type.Word32le--data ClassMapping = ClassMapping-  { classMappingName :: Str-  , classMappingStreamId :: Word32le-  } deriving (Eq, Ord, Show)--$(deriveJson ''ClassMapping)
− library/Rattletrap/Type/ClubColorsAttribute.hs
@@ -1,18 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.ClubColorsAttribute-  ( ClubColorsAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Word8le--data ClubColorsAttribute = ClubColorsAttribute-  { clubColorsAttributeBlueFlag :: Bool-  , clubColorsAttributeBlueColor :: Word8le-  , clubColorsAttributeOrangeFlag :: Bool-  , clubColorsAttributeOrangeColor :: Word8le-  } deriving (Eq, Ord, Show)--$(deriveJson ''ClubColorsAttribute)
− library/Rattletrap/Type/Common.hs
@@ -1,56 +0,0 @@-module Rattletrap.Type.Common-  ( Int.Int8-  , Int.Int32-  , Int.Int64-  , Map.Map-  , Text.Text-  , Word.Word8-  , Word.Word16-  , Word.Word32-  , Word.Word64-  , deriveJson-  )-where--import qualified Data.Aeson as Json-import qualified Data.Aeson.TH as Json-import qualified Data.Char as Char-import qualified Data.Int as Int-import qualified Data.Map as Map-import qualified Data.Maybe as Maybe-import qualified Data.Text as Text-import qualified Data.Word as Word-import qualified Language.Haskell.TH as TH--deriveJson :: TH.Name -> TH.Q [TH.Dec]-deriveJson name = Json.deriveJSON (jsonOptions (TH.nameBase name)) name--jsonOptions :: String -> Json.Options-jsonOptions prefix = Json.defaultOptions-  { Json.constructorTagModifier = toSnakeCase . partialDropPrefix prefix-  , Json.fieldLabelModifier = toSnakeCase-    . partialDropPrefix (lowerFirst prefix)-  , Json.omitNothingFields = True-  , Json.sumEncoding = Json.ObjectWithSingleField-  , Json.unwrapUnaryRecords = True-  }--lowerFirst :: String -> String-lowerFirst string = case string of-  "" -> string-  first : rest -> Char.toLower first : rest--toSnakeCase :: String -> String-toSnakeCase = Json.camelTo2 '_'--partialDropPrefix :: (Eq a, Show a) => [a] -> [a] -> [a]-partialDropPrefix prefix list = Maybe.fromMaybe-  (error (unwords [show prefix, "is not a prefix of", show list]))-  (dropPrefix prefix list)--dropPrefix :: Eq a => [a] -> [a] -> Maybe [a]-dropPrefix prefix list = case prefix of-  [] -> Just list-  ph : pt -> case list of-    [] -> Nothing-    lh : lt -> if ph == lh then dropPrefix pt lt else Nothing
− library/Rattletrap/Type/CompressedWord.hs
@@ -1,17 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.CompressedWord-  ( CompressedWord(..)-  )-where--import Rattletrap.Type.Common---- | Although there's no guarantee that these values will not overflow, it's--- exceptionally unlikely. Most 'CompressedWord's are very small.-data CompressedWord = CompressedWord-  { compressedWordLimit :: Word-  , compressedWordValue :: Word-  } deriving (Eq, Ord, Show)--$(deriveJson ''CompressedWord)
− library/Rattletrap/Type/CompressedWordVector.hs
@@ -1,17 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.CompressedWordVector-  ( CompressedWordVector(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.CompressedWord--data CompressedWordVector = CompressedWordVector-  { compressedWordVectorX :: CompressedWord-  , compressedWordVectorY :: CompressedWord-  , compressedWordVectorZ :: CompressedWord-  } deriving (Eq, Ord, Show)--$(deriveJson ''CompressedWordVector)
− library/Rattletrap/Type/Content.hs
@@ -1,71 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Content-  ( Content(..)-  , defaultContent-  )-where--import Rattletrap.Type.Cache-import Rattletrap.Type.ClassMapping-import Rattletrap.Type.Common-import Rattletrap.Type.Frame-import Rattletrap.Type.KeyFrame-import Rattletrap.Type.List-import Rattletrap.Type.Mark-import Rattletrap.Type.Message-import Rattletrap.Type.Str-import Rattletrap.Type.Word32le---- | Contains low-level game data about a 'Rattletrap.Replay.Replay'.-data Content = Content-  { contentLevels :: List Str-  -- ^ This typically only has one element, like @stadium_oob_audio_map@.-  , contentKeyFrames :: List 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.-  , contentStreamSize :: Word32le-  -- ^ The size of the stream in bytes. This is only really necessary because-  -- the stream has some arbitrary amount of padding at the end.-  , contentFrames :: [Frame]-  -- ^ The actual game data. This is where all the interesting information is.-  , contentMessages :: List Message-  -- ^ Debugging messages. In newer replays, this is always empty.-  , contentMarks :: List Mark-  -- ^ Tick marks shown on the scrubber when watching a replay.-  , contentPackages :: List Str-  -- ^ A list of @.upk@ files to load, like-  -- @..\\..\\TAGame\\CookedPCConsole\\Stadium_P.upk@.-  , contentObjects :: List Str-  -- ^ Objects in the stream. Used for the-  -- 'Rattletrap.Type.ClassAttributeMap.ClassAttributeMap'.-  , contentNames :: List Str-  -- ^ It's not clear what these are used for. This list is usually not empty,-  -- but appears unused otherwise.-  , contentClassMappings :: List ClassMapping-  -- ^ A mapping between classes and their ID in the stream. Used for the-  -- 'Rattletrap.Type.ClassAttributeMap.ClassAttributeMap'.-  , contentCaches :: List Cache-  -- ^ A list of classes along with their parent classes and attributes. Used-  -- for the 'Rattletrap.Type.ClassAttributeMap.ClassAttributeMap'.-  , contentUnknown :: [Word8]-  } deriving (Eq, Ord, Show)--$(deriveJson ''Content)--defaultContent :: Content-defaultContent = Content-  { contentLevels = List []-  , contentKeyFrames = List []-  , contentStreamSize = Word32le 0-  , contentFrames = []-  , contentMessages = List []-  , contentMarks = List []-  , contentPackages = List []-  , contentObjects = List []-  , contentNames = List []-  , contentClassMappings = List []-  , contentCaches = List []-  , contentUnknown = []-  }
− library/Rattletrap/Type/DamageStateAttribute.hs
@@ -1,22 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.DamageStateAttribute-  ( DamageStateAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Int32le-import Rattletrap.Type.Vector-import Rattletrap.Type.Word8le--data DamageStateAttribute = DamageStateAttribute-  { damageStateAttributeUnknown1 :: Word8le-  , damageStateAttributeUnknown2 :: Bool-  , damageStateAttributeUnknown3 :: Int32le-  , damageStateAttributeUnknown4 :: Vector-  , damageStateAttributeUnknown5 :: Bool-  , damageStateAttributeUnknown6 :: Bool-  } deriving (Eq, Ord, Show)--$(deriveJson ''DamageStateAttribute)
− library/Rattletrap/Type/DemolishAttribute.hs
@@ -1,21 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.DemolishAttribute-  ( DemolishAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Vector-import Rattletrap.Type.Word32le--data DemolishAttribute = DemolishAttribute-  { demolishAttributeAttackerFlag :: Bool-  , demolishAttributeAttackerActorId :: Word32le-  , demolishAttributeVictimFlag :: Bool-  , demolishAttributeVictimActorId :: Word32le-  , demolishAttributeAttackerVelocity :: Vector-  , demolishAttributeVictimVelocity :: Vector-  } deriving (Eq, Ord, Show)--$(deriveJson ''DemolishAttribute)
− library/Rattletrap/Type/DestroyedReplication.hs
@@ -1,16 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.DestroyedReplication-  ( DestroyedReplication(..)-  )-where--import Rattletrap.Type.Common---- | Destroyed replications don't actually contain any extra information. All--- you need to know is the actor's ID, which is given by the--- 'Rattletrap.Replication.Replication'.-data DestroyedReplication = DestroyedReplication-  deriving (Eq, Ord, Show)--$(deriveJson ''DestroyedReplication)
− library/Rattletrap/Type/Dictionary.hs
@@ -1,69 +0,0 @@-module Rattletrap.Type.Dictionary-  ( Dictionary(..)-  , dictionaryLookup-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Str--import qualified Control.Monad as Monad-import qualified Data.Aeson as Json-import qualified Data.Aeson.Types as Json-import qualified Data.Map as Map-import qualified Data.Text as Text--data Dictionary a-  = DictionaryElement Str a (Dictionary a)-  | DictionaryEnd Str-  deriving (Eq, Ord, Show)--instance Json.FromJSON a => Json.FromJSON (Dictionary a) where-  parseJSON = Json.withObject-    "Dictionary"-    (\o -> do-      keys <- get o "keys"-      lastKey <- get o "last_key"-      value <- get o "value"-      Monad.foldM-        (\d k -> case Map.lookup k value of-          Nothing -> fail (unwords ["missing key", show k])-          Just v -> pure (DictionaryElement (Str k) v d)-        )-        (DictionaryEnd lastKey)-        (reverse keys)-    )--instance Json.ToJSON a => Json.ToJSON (Dictionary a) where-  toJSON d = Json.object-    [ pair "keys" (dictionaryKeys d)-    , pair "last_key" (dictionaryLastKey d)-    , pair "value" (dictionaryValue d)-    ]--dictionaryKeys :: Dictionary a -> [Str]-dictionaryKeys = fmap fst . toList--dictionaryLastKey :: Dictionary a -> Str-dictionaryLastKey x = case x of-  DictionaryElement _ _ y -> dictionaryLastKey y-  DictionaryEnd y -> y--dictionaryLookup :: Str -> Dictionary a -> Maybe a-dictionaryLookup k x = case x of-  DictionaryElement j v y -> if k == j then Just v else dictionaryLookup k y-  DictionaryEnd _ -> Nothing--dictionaryValue :: Dictionary a -> Map Text a-dictionaryValue = Map.mapKeys strValue . Map.fromList . toList--get :: Json.FromJSON a => Json.Object -> String -> Json.Parser a-get o k = o Json..: Text.pack k--pair :: Json.ToJSON a => String -> a -> (Text, Json.Value)-pair k v = (Text.pack k, Json.toJSON v)--toList :: Dictionary a -> [(Str, a)]-toList x = case x of-  DictionaryElement k v y -> (k, v) : toList y-  DictionaryEnd _ -> []
− library/Rattletrap/Type/EnumAttribute.hs
@@ -1,14 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.EnumAttribute-  ( EnumAttribute(..)-  )-where--import Rattletrap.Type.Common--newtype EnumAttribute = EnumAttribute-  { enumAttributeValue :: Word16-  } deriving (Eq, Ord, Show)--$(deriveJson ''EnumAttribute)
− library/Rattletrap/Type/ExplosionAttribute.hs
@@ -1,18 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.ExplosionAttribute-  ( ExplosionAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Int32le-import Rattletrap.Type.Vector--data ExplosionAttribute = ExplosionAttribute-  { explosionAttributeFlag :: Bool-  , explosionAttributeActorId :: Int32le-  , explosionAttributeLocation :: Vector-  } deriving (Eq, Ord, Show)--$(deriveJson ''ExplosionAttribute)
− library/Rattletrap/Type/ExtendedExplosionAttribute.hs
@@ -1,17 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.ExtendedExplosionAttribute-  ( ExtendedExplosionAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.ExplosionAttribute-import Rattletrap.Type.FlaggedIntAttribute--data ExtendedExplosionAttribute = ExtendedExplosionAttribute-  { extendedExplosionAttributeExplosion :: ExplosionAttribute-  , extendedExplosionAttributeUnknown :: FlaggedIntAttribute-  } deriving (Eq, Ord, Show)--$(deriveJson ''ExtendedExplosionAttribute)
− library/Rattletrap/Type/FlaggedByteAttribute.hs
@@ -1,16 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.FlaggedByteAttribute-  ( FlaggedByteAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Word8le--data FlaggedByteAttribute = FlaggedByteAttribute-  { flaggedByteAttributeFlag :: Bool-  , flaggedByteAttributeByte :: Word8le-  } deriving (Eq, Ord, Show)--$(deriveJson ''FlaggedByteAttribute)
− library/Rattletrap/Type/FlaggedIntAttribute.hs
@@ -1,16 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.FlaggedIntAttribute-  ( FlaggedIntAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Int32le--data FlaggedIntAttribute = FlaggedIntAttribute-  { flaggedIntAttributeFlag :: Bool-  , flaggedIntAttributeInt :: Int32le-  } deriving (Eq, Ord, Show)--$(deriveJson ''FlaggedIntAttribute)
− library/Rattletrap/Type/Float32le.hs
@@ -1,14 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Float32le-  ( Float32le(..)-  )-where--import Rattletrap.Type.Common--newtype Float32le = Float32le-  { float32leValue :: Float-  } deriving (Eq, Ord, Show)--$(deriveJson ''Float32le)
− library/Rattletrap/Type/FloatAttribute.hs
@@ -1,15 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.FloatAttribute-  ( FloatAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Float32le--newtype FloatAttribute = FloatAttribute-  { floatAttributeValue :: Float32le-  } deriving (Eq, Ord, Show)--$(deriveJson ''FloatAttribute)
− library/Rattletrap/Type/Frame.hs
@@ -1,21 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Frame-  ( Frame(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Float32le-import Rattletrap.Type.Replication--data Frame = Frame-  { frameTime :: Float32le-  -- ^ Time in seconds since the beginning of the match.-  , frameDelta :: Float32le-  -- ^ Time in seconds since the last frame. Usually about 0.03 since there-  -- are 30 frames per second.-  , frameReplications :: [Replication]-  } deriving (Eq, Ord, Show)--$(deriveJson ''Frame)
− library/Rattletrap/Type/GameModeAttribute.hs
@@ -1,19 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.GameModeAttribute-  ( GameModeAttribute(..)-  )-where--import Rattletrap.Type.Common--data GameModeAttribute = GameModeAttribute-  { gameModeAttributeNumBits :: 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.-  , gameModeAttributeWord :: Word8-  } deriving (Eq, Ord, Show)--$(deriveJson ''GameModeAttribute)
− library/Rattletrap/Type/Header.hs
@@ -1,61 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Header-  ( Header(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Dictionary-import Rattletrap.Type.Property-import Rattletrap.Type.Str-import Rattletrap.Type.Word32le---- | Contains high-level metadata about a 'Rattletrap.Replay.Replay'.-data Header = Header-  { headerEngineVersion :: Word32le-  -- ^ The "major" ("engine") version number.-  , headerLicenseeVersion :: Word32le-  -- ^ The "minor" ("licensee") version number.-  , headerPatchVersion :: Maybe Word32le-  -- ^ The "patch" ("net") version number.-  , headerLabel :: Str-  -- ^ Always @TAGame.Replay_Soccar_TA@.-  , headerProperties :: Dictionary 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@.-  } deriving (Eq, Ord, Show)--$(deriveJson ''Header)
− library/Rattletrap/Type/Initialization.hs
@@ -1,21 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Initialization-  ( Initialization(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Int8Vector-import Rattletrap.Type.Vector--data Initialization = Initialization-  { initializationLocation :: Maybe Vector-  -- ^ Not every class has an initial location. See-  -- 'Rattletrap.Data.rawClassesWithLocation'.-  , initializationRotation :: Maybe Int8Vector-  -- ^ Only classes with location can have rotation, but not every one does.-  -- See 'Rattletrap.Data.rawClassesWithRotation'.-  } deriving (Eq, Ord, Show)--$(deriveJson ''Initialization)
− library/Rattletrap/Type/Int32le.hs
@@ -1,14 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Int32le-  ( Int32le(..)-  )-where--import Rattletrap.Type.Common--newtype Int32le = Int32le-  { int32leValue :: Int32-  } deriving (Eq, Ord, Show)--$(deriveJson ''Int32le)
− library/Rattletrap/Type/Int64Attribute.hs
@@ -1,15 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Int64Attribute-  ( Int64Attribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Int64le--newtype Int64Attribute = Int64Attribute-  { int64AttributeValue :: Int64le-  } deriving (Eq, Ord, Show)--$(deriveJson ''Int64Attribute)
− library/Rattletrap/Type/Int64le.hs
@@ -1,28 +0,0 @@-module Rattletrap.Type.Int64le-  ( Int64le(..)-  )-where--import qualified Data.Aeson as Aeson-import qualified Data.Aeson.Types as Aeson-import qualified Data.Int as Int-import qualified Data.Scientific as Scientific-import qualified Data.Text as Text-import qualified Text.Read as Read--newtype Int64le = Int64le-  { int64leValue :: Int.Int64-  } deriving (Eq, Ord, Show)--instance Aeson.FromJSON Int64le where-  parseJSON value = case value of-    Aeson.String text -> case Read.readEither $ Text.unpack text of-      Left _ -> Aeson.typeMismatch "Int64le" value-      Right int64 -> pure $ Int64le int64-    Aeson.Number number -> case Scientific.toBoundedInteger number of-      Nothing -> Aeson.typeMismatch "Int64le" value-      Just int64 -> pure $ Int64le int64-    _ -> Aeson.typeMismatch "Int64le" value--instance Aeson.ToJSON Int64le where-  toJSON = Aeson.toJSON . show . int64leValue
− library/Rattletrap/Type/Int8Vector.hs
@@ -1,17 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Int8Vector-  ( Int8Vector(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Int8le--data Int8Vector = Int8Vector-  { int8VectorX :: Maybe Int8le-  , int8VectorY :: Maybe Int8le-  , int8VectorZ :: Maybe Int8le-  } deriving (Eq, Ord, Show)--$(deriveJson ''Int8Vector)
− library/Rattletrap/Type/Int8le.hs
@@ -1,14 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Int8le-  ( Int8le(..)-  )-where--import Rattletrap.Type.Common--newtype Int8le = Int8le-  { int8leValue :: Int8-  } deriving (Eq, Ord, Show)--$(deriveJson ''Int8le)
− library/Rattletrap/Type/IntAttribute.hs
@@ -1,15 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.IntAttribute-  ( IntAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Int32le--newtype IntAttribute = IntAttribute-  { intAttributeValue :: Int32le-  } deriving (Eq, Ord, Show)--$(deriveJson ''IntAttribute)
− library/Rattletrap/Type/KeyFrame.hs
@@ -1,21 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.KeyFrame-  ( KeyFrame(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Float32le-import Rattletrap.Type.Word32le--data KeyFrame = KeyFrame-  { keyFrameTime :: Float32le-  -- ^ When this key frame occurs, in seconds.-  , keyFrameFrame :: Word32le-  -- ^ The frame number of this key frame, starting from 0.-  , keyFramePosition :: Word32le-  -- ^ The bit position of this key frame in the stream.-  } deriving (Eq, Ord, Show)--$(deriveJson ''KeyFrame)
− library/Rattletrap/Type/List.hs
@@ -1,14 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.List-  ( List(..)-  )-where--import Rattletrap.Type.Common--newtype List a = List-  { listValue :: [a]-  } deriving (Eq, Ord, Show)--$(deriveJson ''List)
− library/Rattletrap/Type/LoadoutAttribute.hs
@@ -1,33 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.LoadoutAttribute-  ( LoadoutAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Word32le-import Rattletrap.Type.Word8le--data LoadoutAttribute = LoadoutAttribute-  { loadoutAttributeVersion :: Word8le-  , loadoutAttributeBody :: Word32le-  , loadoutAttributeDecal :: Word32le-  , loadoutAttributeWheels :: Word32le-  , loadoutAttributeRocketTrail :: Word32le-  -- ^ Now known as "rocket boost".-  , loadoutAttributeAntenna :: Word32le-  , loadoutAttributeTopper :: Word32le-  , loadoutAttributeUnknown1 :: Word32le-  , loadoutAttributeUnknown2 :: Maybe Word32le-  , loadoutAttributeEngineAudio :: Maybe Word32le-  , loadoutAttributeTrail :: Maybe Word32le-  , loadoutAttributeGoalExplosion :: Maybe Word32le-  , loadoutAttributeBanner :: Maybe Word32le-  , loadoutAttributeUnknown3 :: Maybe Word32le-  , loadoutAttributeUnknown4 :: Maybe Word32le-  , loadoutAttributeUnknown5 :: Maybe Word32le-  , loadoutAttributeUnknown6 :: Maybe Word32le-  } deriving (Eq, Ord, Show)--$(deriveJson ''LoadoutAttribute)
− library/Rattletrap/Type/LoadoutOnlineAttribute.hs
@@ -1,15 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.LoadoutOnlineAttribute-  ( LoadoutOnlineAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.ProductAttribute--newtype LoadoutOnlineAttribute = LoadoutOnlineAttribute-  { loadoutAttributeValue :: [[ProductAttribute]]-  } deriving (Eq, Ord, Show)--$(deriveJson ''LoadoutOnlineAttribute)
− library/Rattletrap/Type/LoadoutsAttribute.hs
@@ -1,16 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.LoadoutsAttribute-  ( LoadoutsAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.LoadoutAttribute--data LoadoutsAttribute = LoadoutsAttribute-  { loadoutsAttributeBlue :: LoadoutAttribute-  , loadoutsAttributeOrange :: LoadoutAttribute-  } deriving (Eq, Ord, Show)--$(deriveJson ''LoadoutsAttribute)
− library/Rattletrap/Type/LoadoutsOnlineAttribute.hs
@@ -1,18 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.LoadoutsOnlineAttribute-  ( LoadoutsOnlineAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.LoadoutOnlineAttribute--data LoadoutsOnlineAttribute = LoadoutsOnlineAttribute-  { loadoutsOnlineAttributeBlue :: LoadoutOnlineAttribute-  , loadoutsOnlineAttributeOrange :: LoadoutOnlineAttribute-  , loadoutsOnlineAttributeUnknown1 :: Bool-  , loadoutsOnlineAttributeUnknown2 :: Bool-  } deriving (Eq, Ord, Show)--$(deriveJson ''LoadoutsOnlineAttribute)
− library/Rattletrap/Type/LocationAttribute.hs
@@ -1,15 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.LocationAttribute-  ( LocationAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Vector--newtype LocationAttribute = LocationAttribute-  { locationAttributeValue :: Vector-  } deriving (Eq, Ord, Show)--$(deriveJson ''LocationAttribute)
− library/Rattletrap/Type/Mark.hs
@@ -1,19 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Mark-  ( Mark(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Str-import Rattletrap.Type.Word32le--data Mark = Mark-  { markValue :: Str-  -- ^ Which type of mark this is, like @Team0Goal@.-  , markFrame :: Word32le-  -- ^ Which frame this mark belongs to, starting from 0.-  } deriving (Eq, Ord, Show)--$(deriveJson ''Mark)
− library/Rattletrap/Type/Message.hs
@@ -1,21 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Message-  ( Message(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Str-import Rattletrap.Type.Word32le--data Message = Message-  { messageFrame :: Word32le-  -- ^ Which frame this message belongs to, starting from 0.-  , messageName :: Str-  -- ^ The primary player's name.-  , messageValue :: Str-  -- ^ The content of the message.-  } deriving (Eq, Ord, Show)--$(deriveJson ''Message)
− library/Rattletrap/Type/MusicStingerAttribute.hs
@@ -1,18 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.MusicStingerAttribute-  ( MusicStingerAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Word32le-import Rattletrap.Type.Word8le--data MusicStingerAttribute = MusicStingerAttribute-  { musicStingerAttributeFlag :: Bool-  , musicStingerAttributeCue :: Word32le-  , musicStingerAttributeTrigger :: Word8le-  } deriving (Eq, Ord, Show)--$(deriveJson ''MusicStingerAttribute)
− library/Rattletrap/Type/PartyLeaderAttribute.hs
@@ -1,17 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.PartyLeaderAttribute-  ( PartyLeaderAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.RemoteId-import Rattletrap.Type.Word8le--data PartyLeaderAttribute = PartyLeaderAttribute-  { partyLeaderAttributeSystemId :: Word8le-  , partyLeaderAttributeId :: Maybe (RemoteId, Word8le)-  } deriving (Eq, Ord, Show)--$(deriveJson ''PartyLeaderAttribute)
− library/Rattletrap/Type/PickupAttribute.hs
@@ -1,16 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.PickupAttribute-  ( PickupAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Word32le--data PickupAttribute = PickupAttribute-  { pickupAttributeInstigatorId :: Maybe Word32le-  , pickupAttributePickedUp :: Bool-  } deriving (Eq, Ord, Show)--$(deriveJson ''PickupAttribute)
− library/Rattletrap/Type/PlayerHistoryKeyAttribute.hs
@@ -1,14 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.PlayerHistoryKeyAttribute-  ( PlayerHistoryKeyAttribute(..)-  )-where--import Rattletrap.Type.Common--newtype PlayerHistoryKeyAttribute = PlayerHistoryKeyAttribute-  { playerHistoryKeyAttributeUnknown :: Word16-  } deriving (Eq, Ord, Show)--$(deriveJson ''PlayerHistoryKeyAttribute)
− library/Rattletrap/Type/PrivateMatchSettingsAttribute.hs
@@ -1,21 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.PrivateMatchSettingsAttribute-  ( PrivateMatchSettingsAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Str-import Rattletrap.Type.Word32le--data PrivateMatchSettingsAttribute = PrivateMatchSettingsAttribute-  { privateMatchSettingsAttributeMutators :: Str-  , privateMatchSettingsAttributeJoinableBy :: Word32le-  , privateMatchSettingsAttributeMaxPlayers :: Word32le-  , privateMatchSettingsAttributeGameName :: Str-  , privateMatchSettingsAttributePassword :: Str-  , privateMatchSettingsAttributeFlag :: Bool-  } deriving (Eq, Ord, Show)--$(deriveJson ''PrivateMatchSettingsAttribute)
− library/Rattletrap/Type/ProductAttribute.hs
@@ -1,35 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.ProductAttribute-  ( ProductAttribute(..)-  , ProductAttributeValue(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.CompressedWord-import Rattletrap.Type.Str-import Rattletrap.Type.Word32le--data ProductAttributeValue-  = ProductAttributeValuePaintedOld CompressedWord-  | ProductAttributeValuePaintedNew Word32-  | ProductAttributeValueTeamEditionOld CompressedWord-  | ProductAttributeValueTeamEditionNew Word32-  | ProductAttributeValueSpecialEdition Word32-  | ProductAttributeValueUserColorOld (Maybe Word32)-  | ProductAttributeValueUserColorNew Word32le-  | ProductAttributeValueTitleId Str-  deriving (Eq, Ord, Show)--$(deriveJson ''ProductAttributeValue)--data ProductAttribute = ProductAttribute-  { productAttributeUnknown :: Bool-  , productAttributeObjectId :: Word32le-  , productAttributeObjectName :: Maybe Str-  -- ^ read-only-  , productAttributeValue :: ProductAttributeValue-  } deriving (Eq, Ord, Show)--$(deriveJson ''ProductAttribute)
− library/Rattletrap/Type/Property.hs
@@ -1,20 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Property-  ( Property(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.PropertyValue-import Rattletrap.Type.Str-import Rattletrap.Type.Word64le--data Property = Property-  { propertyKind :: Str-  , propertySize :: Word64le-  -- ^ Not used.-  , propertyValue :: PropertyValue Property-  } deriving (Eq, Ord, Show)--$(deriveJson ''Property)
− library/Rattletrap/Type/PropertyValue.hs
@@ -1,32 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.PropertyValue-  ( PropertyValue(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Dictionary-import Rattletrap.Type.Float32le-import Rattletrap.Type.Int32le-import Rattletrap.Type.List-import Rattletrap.Type.Str-import Rattletrap.Type.Word64le-import Rattletrap.Type.Word8le--data PropertyValue a-  = PropertyValueArray (List (Dictionary a))-  -- ^ Yes, a list of dictionaries. No, it doesn't make sense. These usually-  -- only have one element.-  | PropertyValueBool Word8le-  | PropertyValueByte Str (Maybe Str)-  -- ^ This is a strange name for essentially a key-value pair.-  | PropertyValueFloat Float32le-  | PropertyValueInt Int32le-  | PropertyValueName Str-  -- ^ It's unclear how exactly this is different than a 'StrProperty'.-  | PropertyValueQWord Word64le-  | PropertyValueStr Str-  deriving (Eq, Ord, Show)--$(deriveJson ''PropertyValue)
− library/Rattletrap/Type/QWordAttribute.hs
@@ -1,15 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.QWordAttribute-  ( QWordAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Word64le--newtype QWordAttribute = QWordAttribute-  { qWordAttributeValue :: Word64le-  } deriving (Eq, Ord, Show)--$(deriveJson ''QWordAttribute)
− library/Rattletrap/Type/Quaternion.hs
@@ -1,99 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Quaternion-  ( Quaternion(..)-  , Component(..)-  , toQuaternion-  , compressPart-  , decompressPart-  , maxComponent-  , maxCompressedValue-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.CompressedWord--import qualified Data.Maybe as Maybe--data Quaternion = Quaternion-  { quaternionX :: Double-  , quaternionY :: Double-  , quaternionZ :: Double-  , quaternionW :: Double-  } deriving (Eq, Ord, Show)--$(deriveJson ''Quaternion)--data Component-  = ComponentX-  | ComponentY-  | ComponentZ-  | ComponentW-  deriving (Eq, Ord, Show)--toQuaternion :: Component -> Double -> Double -> Double -> Quaternion-toQuaternion component a b c =-  let d = toPart a b c-  in-    case component of-      ComponentX -> Quaternion d a b c-      ComponentY -> Quaternion a d b c-      ComponentZ -> Quaternion a b d c-      ComponentW -> Quaternion a b c d--toPart :: Double -> Double -> Double -> Double-toPart a b c = sqrt (1 - (a * a) - (b * b) - (c * c))--compressPart :: Double -> CompressedWord-compressPart =-  CompressedWord maxCompressedValue-    . round-    . (* wordToDouble maxCompressedValue)-    . (+ 0.5)-    . (/ 2.0)-    . (/ maxValue)--decompressPart :: CompressedWord -> Double-decompressPart x =-  (* maxValue)-    . (* 2.0)-    . subtract 0.5-    . (/ wordToDouble (compressedWordLimit x))-    . wordToDouble-    $ compressedWordValue x--maxComponent :: Quaternion -> Component-maxComponent quaternion =-  let-    x = quaternionX quaternion-    y = quaternionY quaternion-    z = quaternionZ quaternion-    w = quaternionW quaternion-    parts =-      [(x, ComponentX), (y, ComponentY), (z, ComponentZ), (w, ComponentW)]-    biggestPart = maximum parts-    roundTrip = decompressPart . compressPart-    computedPart = Maybe.fromMaybe-      biggestPart-      (Maybe.listToMaybe-        (filter (\(value, _) -> value /= roundTrip value) parts)-      )-  in snd-    (if (biggestPart == computedPart)-        || (abs (fst biggestPart - fst computedPart) > 0.00001)-      then biggestPart-      else computedPart-    )--numBits :: Word-numBits = 18--wordToDouble :: Word -> Double-wordToDouble = fromIntegral--maxCompressedValue :: Word-maxCompressedValue = (2 ^ numBits) - 1--maxValue :: Double-maxValue = 1.0 / sqrt 2.0
− library/Rattletrap/Type/RemoteId.hs
@@ -1,21 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.RemoteId-  ( RemoteId(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Word64le--data RemoteId-  = RemoteIdPlayStation Text [Word8]-  | RemoteIdPsyNet (Either Word64le (Word64le, Word64le, Word64le, Word64le))-  | RemoteIdSplitscreen Word32-  -- ^ Really only 24 bits.-  | RemoteIdSteam Word64le-  | RemoteIdSwitch Word64le Word64le Word64le Word64le-  | RemoteIdXbox Word64le-  deriving (Eq, Ord, Show)--$(deriveJson ''RemoteId)
− library/Rattletrap/Type/Replay.hs
@@ -1,21 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Replay-  ( Replay(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Content-import Rattletrap.Type.Header-import Rattletrap.Type.Section---- | A Rocket League replay.-data Replay = Replay-  { replayHeader :: Section Header-  -- ^ This has most of the high-level metadata.-  , replayContent :: Section Content-  -- ^ This has most of the low-level game data.-  } deriving (Eq, Ord, Show)--$(deriveJson ''Replay)
− library/Rattletrap/Type/Replication.hs
@@ -1,17 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Replication-  ( Replication(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.CompressedWord-import Rattletrap.Type.ReplicationValue--data Replication = Replication-  { replicationActorId :: CompressedWord-  , replicationValue :: ReplicationValue-  } deriving (Eq, Ord, Show)--$(deriveJson ''Replication)
− library/Rattletrap/Type/ReplicationValue.hs
@@ -1,22 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.ReplicationValue-  ( ReplicationValue(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.DestroyedReplication-import Rattletrap.Type.SpawnedReplication-import Rattletrap.Type.UpdatedReplication--data ReplicationValue-  = ReplicationValueSpawned SpawnedReplication-  -- ^ Creates a new actor.-  | ReplicationValueUpdated UpdatedReplication-  -- ^ Updates an existing actor.-  | ReplicationValueDestroyed DestroyedReplication-  -- ^ Destroys an existing actor.-  deriving (Eq, Ord, Show)--$(deriveJson ''ReplicationValue)
− library/Rattletrap/Type/ReservationAttribute.hs
@@ -1,22 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.ReservationAttribute-  ( ReservationAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.CompressedWord-import Rattletrap.Type.Str-import Rattletrap.Type.UniqueIdAttribute--data ReservationAttribute = ReservationAttribute-  { reservationAttributeNumber :: CompressedWord-  , reservationAttributeUniqueId :: UniqueIdAttribute-  , reservationAttributeName :: Maybe Str-  , reservationAttributeUnknown1 :: Bool-  , reservationAttributeUnknown2 :: Bool-  , reservationAttributeUnknown3 :: Maybe Word8-  } deriving (Eq, Ord, Show)--$(deriveJson ''ReservationAttribute)
− library/Rattletrap/Type/RigidBodyStateAttribute.hs
@@ -1,20 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.RigidBodyStateAttribute-  ( RigidBodyStateAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Rotation-import Rattletrap.Type.Vector--data RigidBodyStateAttribute = RigidBodyStateAttribute-  { rigidBodyStateAttributeSleeping :: Bool-  , rigidBodyStateAttributeLocation :: Vector-  , rigidBodyStateAttributeRotation :: Rotation-  , rigidBodyStateAttributeLinearVelocity :: Maybe Vector-  , rigidBodyStateAttributeAngularVelocity :: Maybe Vector-  } deriving (Eq, Ord, Show)--$(deriveJson ''RigidBodyStateAttribute)
− library/Rattletrap/Type/Rotation.hs
@@ -1,17 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Rotation-  ( Rotation(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Quaternion-import Rattletrap.Type.CompressedWordVector--data Rotation-  = RotationCompressedWordVector CompressedWordVector-  | RotationQuaternion Quaternion-  deriving (Eq, Ord, Show)--$(deriveJson ''Rotation)
− library/Rattletrap/Type/Section.hs
@@ -1,41 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Section-  ( Section(..)-  , toSection-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Word32le-import Rattletrap.Utility.Crc--import qualified Data.Binary as Binary-import qualified Data.Binary.Put as Binary-import qualified Data.ByteString as Bytes-import qualified Data.ByteString.Lazy as LazyBytes---- | A section is a large piece of a 'Rattletrap.Replay.Replay'. It has a--- 32-bit size (in bytes), a 32-bit CRC (see "Rattletrap.Utility.Crc"), and then a--- 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-  { sectionSize :: Word32le-  -- ^ read only-  , sectionCrc :: Word32le-  -- ^ read only-  , sectionBody :: a-  -- ^ The actual content in the section.-  } deriving (Eq, Ord, Show)--$(deriveJson ''Section)--toSection :: (a -> Binary.Put) -> a -> Section a-toSection encode body =-  let bytes = LazyBytes.toStrict . Binary.runPut $ encode body-  in-    Section-      { sectionSize = Word32le . fromIntegral $ Bytes.length bytes-      , sectionCrc = Word32le $ getCrc32 bytes-      , sectionBody = body-      }
− library/Rattletrap/Type/SpawnedReplication.hs
@@ -1,30 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.SpawnedReplication-  ( SpawnedReplication(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Initialization-import Rattletrap.Type.Str-import Rattletrap.Type.Word32le--data SpawnedReplication = SpawnedReplication-  { spawnedReplicationFlag :: Bool-  -- ^ Unclear what this is.-  , spawnedReplicationNameIndex :: Maybe Word32le-  , spawnedReplicationName :: Maybe Str-  -- ^ Read-only! Changing a replication's name requires editing the-  -- 'spawnedReplicationNameIndex' and maybe the class attribute map.-  , spawnedReplicationObjectId :: Word32le-  , spawnedReplicationObjectName :: Str-  -- ^ Read-only! Changing a replication's object requires editing the class-  -- attribute map.-  , spawnedReplicationClassName :: Str-  -- ^ Read-only! Changing a replication's class requires editing the class-  -- attribute map.-  , spawnedReplicationInitialization :: Initialization-  } deriving (Eq, Ord, Show)--$(deriveJson ''SpawnedReplication)
− library/Rattletrap/Type/StatEventAttribute.hs
@@ -1,16 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.StatEventAttribute-  ( StatEventAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Int32le--data StatEventAttribute = StatEventAttribute-  { statEventAttributeUnknown :: Bool-  , statEventAttributeObjectId :: Int32le-  } deriving (Eq, Ord, Show)--$(deriveJson ''StatEventAttribute)
− library/Rattletrap/Type/Str.hs
@@ -1,24 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Str-  ( Str(..)-  , toStr-  , fromStr-  )-where--import Rattletrap.Type.Common--import qualified Data.Text as Text--newtype Str = Str-  { strValue :: Text-  } deriving (Eq, Ord, Show)--$(deriveJson ''Str)--toStr :: String -> Str-toStr string = Str (Text.pack string)--fromStr :: Str -> String-fromStr text = Text.unpack (strValue text)
− library/Rattletrap/Type/StringAttribute.hs
@@ -1,15 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.StringAttribute-  ( StringAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Str--newtype StringAttribute = StringAttribute-  { stringAttributeValue :: Str-  } deriving (Eq, Ord, Show)--$(deriveJson ''StringAttribute)
− library/Rattletrap/Type/TeamPaintAttribute.hs
@@ -1,20 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.TeamPaintAttribute-  ( TeamPaintAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Word32le-import Rattletrap.Type.Word8le--data TeamPaintAttribute = TeamPaintAttribute-  { teamPaintAttributeTeam :: Word8le-  , teamPaintAttributePrimaryColor :: Word8le-  , teamPaintAttributeAccentColor :: Word8le-  , teamPaintAttributePrimaryFinish :: Word32le-  , teamPaintAttributeAccentFinish :: Word32le-  } deriving (Eq, Ord, Show)--$(deriveJson ''TeamPaintAttribute)
− library/Rattletrap/Type/TitleAttribute.hs
@@ -1,22 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.TitleAttribute-  ( TitleAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Word32le--data TitleAttribute = TitleAttribute-  { titleAttributeUnknown1 :: Bool-  , titleAttributeUnknown2 :: Bool-  , titleAttributeUnknown3 :: Word32le-  , titleAttributeUnknown4 :: Word32le-  , titleAttributeUnknown5 :: Word32le-  , titleAttributeUnknown6 :: Word32le-  , titleAttributeUnknown7 :: Word32le-  , titleAttributeUnknown8 :: Bool-  } deriving (Eq, Ord, Show)--$(deriveJson ''TitleAttribute)
− library/Rattletrap/Type/UniqueIdAttribute.hs
@@ -1,18 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.UniqueIdAttribute-  ( UniqueIdAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.RemoteId-import Rattletrap.Type.Word8le--data UniqueIdAttribute = UniqueIdAttribute-  { uniqueIdAttributeSystemId :: Word8le-  , uniqueIdAttributeRemoteId :: RemoteId-  , uniqueIdAttributeLocalId :: Word8le-  } deriving (Eq, Ord, Show)--$(deriveJson ''UniqueIdAttribute)
− library/Rattletrap/Type/UpdatedReplication.hs
@@ -1,15 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.UpdatedReplication-  ( UpdatedReplication(..)-  )-where--import Rattletrap.Type.Attribute-import Rattletrap.Type.Common--newtype UpdatedReplication = UpdatedReplication-  { updatedReplicationAttributes :: [Attribute]-  } deriving (Eq, Ord, Show)--$(deriveJson ''UpdatedReplication)
− library/Rattletrap/Type/Vector.hs
@@ -1,26 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Vector-  ( Vector(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.CompressedWord--data Vector = Vector-  { vectorSize :: CompressedWord-  , vectorBias :: 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.-  , vectorX :: Int-  -- ^ See 'vectorBias'.-  , vectorY :: Int-  -- ^ See 'vectorBias'.-  , vectorZ :: Int-  -- ^ See 'vectorBias'.-  } deriving (Eq, Ord, Show)--$(deriveJson ''Vector)
− library/Rattletrap/Type/WeldedInfoAttribute.hs
@@ -1,22 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.WeldedInfoAttribute-  ( WeldedInfoAttribute(..)-  )-where--import Rattletrap.Type.Common-import Rattletrap.Type.Float32le-import Rattletrap.Type.Int32le-import Rattletrap.Type.Int8Vector-import Rattletrap.Type.Vector--data WeldedInfoAttribute = WeldedInfoAttribute-  { weldedInfoAttributeActive :: Bool-  , weldedInfoAttributeActorId :: Int32le-  , weldedInfoAttributeOffset :: Vector-  , weldedInfoAttributeMass :: Float32le-  , weldedInfoAttributeRotation :: Int8Vector-  } deriving (Eq, Ord, Show)--$(deriveJson ''WeldedInfoAttribute)
− library/Rattletrap/Type/Word32le.hs
@@ -1,14 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Word32le-  ( Word32le(..)-  )-where--import Rattletrap.Type.Common--newtype Word32le = Word32le-  { word32leValue :: Word32-  } deriving (Eq, Ord, Show)--$(deriveJson ''Word32le)
− library/Rattletrap/Type/Word64le.hs
@@ -1,28 +0,0 @@-module Rattletrap.Type.Word64le-  ( Word64le(..)-  )-where--import qualified Data.Aeson as Aeson-import qualified Data.Aeson.Types as Aeson-import qualified Data.Scientific as Scientific-import qualified Data.Text as Text-import qualified Data.Word as Word-import qualified Text.Read as Read--newtype Word64le = Word64le-  { word64leValue :: Word.Word64-  } deriving (Eq, Ord, Show)--instance Aeson.FromJSON Word64le where-  parseJSON value = case value of-    Aeson.String text -> case Read.readEither $ Text.unpack text of-      Left _ -> Aeson.typeMismatch "Word64le" value-      Right word64 -> pure $ Word64le word64-    Aeson.Number number -> case Scientific.toBoundedInteger number of-      Nothing -> Aeson.typeMismatch "Word64le" value-      Just word64 -> pure $ Word64le word64-    _ -> Aeson.typeMismatch "Word64le" value--instance Aeson.ToJSON Word64le where-  toJSON = Aeson.toJSON . show . word64leValue
− library/Rattletrap/Type/Word8le.hs
@@ -1,14 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Rattletrap.Type.Word8le-  ( Word8le(..)-  )-where--import Rattletrap.Type.Common--newtype Word8le = Word8le-  { word8leValue :: Word8-  } deriving (Eq, Ord, Show)--$(deriveJson ''Word8le)
− library/Rattletrap/Utility/Bytes.hs
@@ -1,33 +0,0 @@-module Rattletrap.Utility.Bytes-  ( encodeLatin1-  , padBytes-  , reverseBytes-  )-where--import qualified Data.Bits as Bits-import qualified Data.ByteString as Bytes-import qualified Data.ByteString.Char8 as Bytes8-import qualified Data.Text as Text-import qualified Data.Word as Word--encodeLatin1 :: Text.Text -> Bytes.ByteString-encodeLatin1 text = Bytes8.pack (Text.unpack text)--padBytes :: Integral a => a -> Bytes.ByteString -> Bytes.ByteString-padBytes size bytes =-  bytes <> Bytes.replicate (fromIntegral size - Bytes.length bytes) 0x00--reverseByte :: Word.Word8 -> Word.Word8-reverseByte byte =-  Bits.shiftR (byte Bits..&. Bits.bit 7) 7-    + Bits.shiftR (byte Bits..&. Bits.bit 6) 5-    + Bits.shiftR (byte Bits..&. Bits.bit 5) 3-    + Bits.shiftR (byte Bits..&. Bits.bit 4) 1-    + Bits.shiftL (byte Bits..&. Bits.bit 3) 1-    + Bits.shiftL (byte Bits..&. Bits.bit 2) 3-    + Bits.shiftL (byte Bits..&. Bits.bit 1) 5-    + Bits.shiftL (byte Bits..&. Bits.bit 0) 7--reverseBytes :: Bytes.ByteString -> Bytes.ByteString-reverseBytes = Bytes.map reverseByte
− library/Rattletrap/Utility/Crc.hs
@@ -1,47 +0,0 @@-module Rattletrap.Utility.Crc-  ( getCrc32-  )-where--import Rattletrap.Data--import qualified Data.Bits as Bits-import qualified Data.ByteString as Bytes-import qualified Data.IntMap as IntMap-import qualified Data.Word as Word---- | Computes the CRC32 of some bytes. This is done to ensure that the bytes--- are valid before trying to parse them.------ @--- getCrc32 ('Data.ByteString.Lazy.pack' [0x00])--- @------ This CRC uses an initial value of @0xefcbf201@ and a polynomial of--- @0x04c11db7@.-getCrc32 :: Bytes.ByteString -> Word.Word32-getCrc32 bytes = do-  let-    update = crc32Update crc32Table-    initial = Bits.complement crc32Initial-    crc = Bytes.foldl update initial bytes-  Bits.complement crc--crc32Update-  :: IntMap.IntMap Word.Word32 -> Word.Word32 -> Word.Word8 -> Word.Word32-crc32Update table crc byte = do-  let-    toWord8 :: (Integral a) => a -> Word.Word8-    toWord8 = fromIntegral-    toInt :: (Integral a) => a -> Int-    toInt = fromIntegral-    index = toInt (Bits.xor byte (toWord8 (Bits.shiftR crc 24)))-    left = table IntMap.! index-    right = Bits.shiftL crc 8-  Bits.xor left right--crc32Initial :: Word.Word32-crc32Initial = 0xefcbf201--crc32Table :: IntMap.IntMap Word.Word32-crc32Table = IntMap.fromDistinctAscList (zip [0 ..] rawCrc32Table)
− library/Rattletrap/Utility/Helper.hs
@@ -1,46 +0,0 @@--- | This module provides helper functions for converting replays to and from--- both their binary format and JSON.-module Rattletrap.Utility.Helper-  ( decodeReplayFile-  , encodeReplayJson-  , decodeReplayJson-  , encodeReplayFile-  )-where--import Rattletrap.Decode.Common-import Rattletrap.Encode.Content-import Rattletrap.Decode.Replay-import Rattletrap.Encode.Replay-import Rattletrap.Type.Replay-import Rattletrap.Type.Section-import Rattletrap.Type.Content--import qualified Data.Aeson as Json-import qualified Data.Aeson.Encode.Pretty as Json-import qualified Data.Binary.Put as Binary-import qualified Data.ByteString as Bytes-import qualified Data.ByteString.Lazy as LazyBytes---- | Parses a raw replay.-decodeReplayFile :: Bool -> Bytes.ByteString -> Either String Replay-decodeReplayFile fast = runDecode $ decodeReplay fast---- | Encodes a replay as JSON.-encodeReplayJson :: Replay -> Bytes.ByteString-encodeReplayJson = LazyBytes.toStrict . Json.encodePretty' Json.defConfig-  { Json.confCompare = compare-  , Json.confIndent = Json.Spaces 2-  , Json.confTrailingNewline = True-  }---- | Parses a JSON replay.-decodeReplayJson :: Bytes.ByteString -> Either String Replay-decodeReplayJson = Json.eitherDecodeStrict'---- | Encodes a raw replay.-encodeReplayFile :: Bool -> Replay -> Bytes.ByteString-encodeReplayFile fast replay =-  LazyBytes.toStrict . Binary.runPut . putReplay $ if fast-    then replay { replayContent = toSection putContent defaultContent }-    else replay
rattletrap.cabal view
@@ -1,11 +1,11 @@ cabal-version: 2.2  name: rattletrap-version: 9.0.2+version: 9.0.3  category: Game description: Rattletrap parses and generates Rocket League replays.-extra-source-files: CHANGELOG.markdown README.markdown stack.yaml+extra-source-files: CHANGELOG.markdown README.markdown license-file: LICENSE.markdown license: MIT maintainer: Taylor Fausak@@ -21,20 +21,20 @@  common basics   build-depends:-    aeson ^>= 1.4.2,+    aeson ^>= 1.3.1,     aeson-pretty ^>= 0.8.7,-    base ^>= 4.11.1 || ^>= 4.12.0,-    binary ^>= 0.8.6,+    base ^>= 4.11.1,+    binary ^>= 0.8.5,     binary-bits ^>= 0.5,     bytestring ^>= 0.10.8,-    containers ^>= 0.6.0,+    containers ^>= 0.5.11,     filepath ^>= 1.4.2,-    http-client ^>= 0.6.4,+    http-client ^>= 0.5.13,     http-client-tls ^>= 0.3.5,     scientific ^>= 0.3.6,-    template-haskell ^>= 2.13.0 || ^>= 2.14.0,+    template-haskell ^>= 2.13.0,     text ^>= 1.2.3,-    transformers ^>= 0.5.6,+    transformers ^>= 0.5.5,   default-language: Haskell2010   ghc-options:     -optP -Wno-nonportable-include-path@@ -51,7 +51,7 @@    autogen-modules: Paths_rattletrap   exposed-modules: Rattletrap-  hs-source-dirs: library+  hs-source-dirs: source/library   other-modules:     Paths_rattletrap     Rattletrap.Console.Main@@ -103,6 +103,7 @@     Rattletrap.Decode.MusicStingerAttribute     Rattletrap.Decode.PartyLeaderAttribute     Rattletrap.Decode.PickupAttribute+    Rattletrap.Decode.PickupAttributeNew     Rattletrap.Decode.PlayerHistoryKeyAttribute     Rattletrap.Decode.PrivateMatchSettingsAttribute     Rattletrap.Decode.ProductAttribute@@ -178,6 +179,7 @@     Rattletrap.Encode.MusicStingerAttribute     Rattletrap.Encode.PartyLeaderAttribute     Rattletrap.Encode.PickupAttribute+    Rattletrap.Encode.PickupAttributeNew     Rattletrap.Encode.PlayerHistoryKeyAttribute     Rattletrap.Encode.PrivateMatchSettingsAttribute     Rattletrap.Encode.ProductAttribute@@ -255,6 +257,7 @@     Rattletrap.Type.MusicStingerAttribute     Rattletrap.Type.PartyLeaderAttribute     Rattletrap.Type.PickupAttribute+    Rattletrap.Type.PickupAttributeNew     Rattletrap.Type.PlayerHistoryKeyAttribute     Rattletrap.Type.PrivateMatchSettingsAttribute     Rattletrap.Type.ProductAttribute@@ -292,7 +295,7 @@    build-depends: rattletrap   ghc-options: -rtsopts -threaded-  hs-source-dirs: executables+  hs-source-dirs: source/executable   main-is: Main.hs    if flag(static)@@ -306,6 +309,6 @@     rattletrap,     temporary ^>= 1.3,   ghc-options: -rtsopts -threaded-  hs-source-dirs: tests+  hs-source-dirs: source/test-suite   main-is: Main.hs   type: exitcode-stdio-1.0
+ source/executable/Main.hs view
@@ -0,0 +1,6 @@+module Main+  ( main+  )+where++import Rattletrap (main)
+ source/library/Rattletrap.hs view
@@ -0,0 +1,162 @@+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+  , Rattletrap.Type.AppliedDamageAttribute.AppliedDamageAttribute(..)+  , Rattletrap.Type.Attribute.Attribute(..)+  , Rattletrap.Type.AttributeMapping.AttributeMapping(..)+  , Rattletrap.Type.AttributeType.AttributeType(..)+  , Rattletrap.Type.AttributeValue.AttributeValue(..)+  , Rattletrap.Type.BooleanAttribute.BooleanAttribute(..)+  , Rattletrap.Type.ByteAttribute.ByteAttribute(..)+  , Rattletrap.Type.Cache.Cache(..)+  , Rattletrap.Type.CamSettingsAttribute.CamSettingsAttribute(..)+  , Rattletrap.Type.ClassAttributeMap.ClassAttributeMap(..)+  , Rattletrap.Type.ClassMapping.ClassMapping(..)+  , Rattletrap.Type.ClubColorsAttribute.ClubColorsAttribute(..)+  , Rattletrap.Type.CompressedWord.CompressedWord(..)+  , Rattletrap.Type.CompressedWordVector.CompressedWordVector(..)+  , Rattletrap.Type.Content.Content(..)+  , Rattletrap.Type.DamageStateAttribute.DamageStateAttribute(..)+  , Rattletrap.Type.DemolishAttribute.DemolishAttribute(..)+  , Rattletrap.Type.DestroyedReplication.DestroyedReplication(..)+  , Rattletrap.Type.Dictionary.Dictionary(..)+  , Rattletrap.Type.EnumAttribute.EnumAttribute(..)+  , Rattletrap.Type.ExplosionAttribute.ExplosionAttribute(..)+  , Rattletrap.Type.ExtendedExplosionAttribute.ExtendedExplosionAttribute(..)+  , Rattletrap.Type.FlaggedIntAttribute.FlaggedIntAttribute(..)+  , Rattletrap.Type.Float32le.Float32le(..)+  , Rattletrap.Type.FloatAttribute.FloatAttribute(..)+  , Rattletrap.Type.Frame.Frame(..)+  , Rattletrap.Type.GameModeAttribute.GameModeAttribute(..)+  , Rattletrap.Type.Header.Header(..)+  , Rattletrap.Type.Initialization.Initialization(..)+  , Rattletrap.Type.Int32le.Int32le(..)+  , Rattletrap.Type.Int64Attribute.Int64Attribute(..)+  , Rattletrap.Type.Int64le.Int64le(..)+  , Rattletrap.Type.Int8le.Int8le(..)+  , Rattletrap.Type.Int8Vector.Int8Vector(..)+  , Rattletrap.Type.IntAttribute.IntAttribute(..)+  , Rattletrap.Type.KeyFrame.KeyFrame(..)+  , Rattletrap.Type.List.List(..)+  , Rattletrap.Type.LoadoutAttribute.LoadoutAttribute(..)+  , Rattletrap.Type.LoadoutOnlineAttribute.LoadoutOnlineAttribute(..)+  , Rattletrap.Type.LoadoutsAttribute.LoadoutsAttribute(..)+  , Rattletrap.Type.LoadoutsOnlineAttribute.LoadoutsOnlineAttribute(..)+  , Rattletrap.Type.LocationAttribute.LocationAttribute(..)+  , Rattletrap.Type.Mark.Mark(..)+  , Rattletrap.Type.Message.Message(..)+  , Rattletrap.Type.MusicStingerAttribute.MusicStingerAttribute(..)+  , Rattletrap.Type.PartyLeaderAttribute.PartyLeaderAttribute(..)+  , Rattletrap.Type.PickupAttribute.PickupAttribute(..)+  , Rattletrap.Type.PlayerHistoryKeyAttribute.PlayerHistoryKeyAttribute(..)+  , Rattletrap.Type.PrivateMatchSettingsAttribute.PrivateMatchSettingsAttribute(..)+  , Rattletrap.Type.ProductAttribute.ProductAttribute(..)+  , Rattletrap.Type.Property.Property(..)+  , Rattletrap.Type.PropertyValue.PropertyValue(..)+  , Rattletrap.Type.Quaternion.Quaternion(..)+  , Rattletrap.Type.QWordAttribute.QWordAttribute(..)+  , Rattletrap.Type.RemoteId.RemoteId(..)+  , Rattletrap.Type.Replay.Replay(..)+  , Rattletrap.Type.Replication.Replication(..)+  , Rattletrap.Type.ReplicationValue.ReplicationValue(..)+  , Rattletrap.Type.ReservationAttribute.ReservationAttribute(..)+  , Rattletrap.Type.RigidBodyStateAttribute.RigidBodyStateAttribute(..)+  , Rattletrap.Type.Rotation.Rotation(..)+  , Rattletrap.Type.Section.Section(..)+  , Rattletrap.Type.SpawnedReplication.SpawnedReplication(..)+  , Rattletrap.Type.StatEventAttribute.StatEventAttribute(..)+  , Rattletrap.Type.Str.Str(..)+  , Rattletrap.Type.StringAttribute.StringAttribute(..)+  , Rattletrap.Type.TeamPaintAttribute.TeamPaintAttribute(..)+  , Rattletrap.Type.TitleAttribute.TitleAttribute(..)+  , Rattletrap.Type.UniqueIdAttribute.UniqueIdAttribute(..)+  , Rattletrap.Type.UpdatedReplication.UpdatedReplication(..)+  , Rattletrap.Type.Vector.Vector(..)+  , Rattletrap.Type.WeldedInfoAttribute.WeldedInfoAttribute(..)+  , Rattletrap.Type.Word32le.Word32le(..)+  , Rattletrap.Type.Word64le.Word64le(..)+  , Rattletrap.Type.Word8le.Word8le(..)+  )+where++import qualified Rattletrap.Console.Main+import qualified Rattletrap.Type.AppliedDamageAttribute+import qualified Rattletrap.Type.Attribute+import qualified Rattletrap.Type.AttributeMapping+import qualified Rattletrap.Type.AttributeType+import qualified Rattletrap.Type.AttributeValue+import qualified Rattletrap.Type.BooleanAttribute+import qualified Rattletrap.Type.ByteAttribute+import qualified Rattletrap.Type.Cache+import qualified Rattletrap.Type.CamSettingsAttribute+import qualified Rattletrap.Type.ClassAttributeMap+import qualified Rattletrap.Type.ClassMapping+import qualified Rattletrap.Type.ClubColorsAttribute+import qualified Rattletrap.Type.CompressedWord+import qualified Rattletrap.Type.CompressedWordVector+import qualified Rattletrap.Type.Content+import qualified Rattletrap.Type.DamageStateAttribute+import qualified Rattletrap.Type.DemolishAttribute+import qualified Rattletrap.Type.DestroyedReplication+import qualified Rattletrap.Type.Dictionary+import qualified Rattletrap.Type.EnumAttribute+import qualified Rattletrap.Type.ExplosionAttribute+import qualified Rattletrap.Type.ExtendedExplosionAttribute+import qualified Rattletrap.Type.FlaggedIntAttribute+import qualified Rattletrap.Type.Float32le+import qualified Rattletrap.Type.FloatAttribute+import qualified Rattletrap.Type.Frame+import qualified Rattletrap.Type.GameModeAttribute+import qualified Rattletrap.Type.Header+import qualified Rattletrap.Type.Initialization+import qualified Rattletrap.Type.Int32le+import qualified Rattletrap.Type.Int64Attribute+import qualified Rattletrap.Type.Int64le+import qualified Rattletrap.Type.Int8le+import qualified Rattletrap.Type.Int8Vector+import qualified Rattletrap.Type.IntAttribute+import qualified Rattletrap.Type.KeyFrame+import qualified Rattletrap.Type.List+import qualified Rattletrap.Type.LoadoutAttribute+import qualified Rattletrap.Type.LoadoutOnlineAttribute+import qualified Rattletrap.Type.LoadoutsAttribute+import qualified Rattletrap.Type.LoadoutsOnlineAttribute+import qualified Rattletrap.Type.LocationAttribute+import qualified Rattletrap.Type.Mark+import qualified Rattletrap.Type.Message+import qualified Rattletrap.Type.MusicStingerAttribute+import qualified Rattletrap.Type.PartyLeaderAttribute+import qualified Rattletrap.Type.PickupAttribute+import qualified Rattletrap.Type.PlayerHistoryKeyAttribute+import qualified Rattletrap.Type.PrivateMatchSettingsAttribute+import qualified Rattletrap.Type.ProductAttribute+import qualified Rattletrap.Type.Property+import qualified Rattletrap.Type.PropertyValue+import qualified Rattletrap.Type.Quaternion+import qualified Rattletrap.Type.QWordAttribute+import qualified Rattletrap.Type.RemoteId+import qualified Rattletrap.Type.Replay+import qualified Rattletrap.Type.Replication+import qualified Rattletrap.Type.ReplicationValue+import qualified Rattletrap.Type.ReservationAttribute+import qualified Rattletrap.Type.RigidBodyStateAttribute+import qualified Rattletrap.Type.Rotation+import qualified Rattletrap.Type.Section+import qualified Rattletrap.Type.SpawnedReplication+import qualified Rattletrap.Type.StatEventAttribute+import qualified Rattletrap.Type.Str+import qualified Rattletrap.Type.StringAttribute+import qualified Rattletrap.Type.TeamPaintAttribute+import qualified Rattletrap.Type.TitleAttribute+import qualified Rattletrap.Type.UniqueIdAttribute+import qualified Rattletrap.Type.UpdatedReplication+import qualified Rattletrap.Type.Vector+import qualified Rattletrap.Type.WeldedInfoAttribute+import qualified Rattletrap.Type.Word32le+import qualified Rattletrap.Type.Word64le+import qualified Rattletrap.Type.Word8le+import qualified Rattletrap.Utility.Helper
+ source/library/Rattletrap/Console/Main.hs view
@@ -0,0 +1,240 @@+module Rattletrap.Console.Main+  ( main+  , rattletrap+  )+where++import qualified Control.Monad as Monad+import qualified Data.Aeson as Json+import qualified Data.ByteString as Bytes+import qualified Data.ByteString.Lazy as LazyBytes+import qualified Data.Version as Version+import qualified Network.HTTP.Client as Client+import qualified Network.HTTP.Client.TLS as Client+import qualified Paths_rattletrap as This+import qualified Rattletrap.Type.Replay as Rattletrap+import qualified Rattletrap.Utility.Helper as Rattletrap+import qualified System.Console.GetOpt as Console+import qualified System.Environment as Environment+import qualified System.Exit as Exit+import qualified System.FilePath as Path+import qualified System.IO as IO+import qualified Text.Printf as Printf++main :: IO ()+main = do+  name <- Environment.getProgName+  arguments <- Environment.getArgs+  rattletrap name arguments++rattletrap :: String -> [String] -> IO ()+rattletrap name arguments = do+  config <- getConfig arguments+  Monad.when (configHelp config) (printHelp name *> Exit.exitFailure)+  Monad.when (configVersion config) (printVersion *> Exit.exitFailure)+  input <- getInput config+  let decode = getDecoder config+  replay <- either fail pure (decode input)+  let encode = getEncoder config+  putOutput config (encode replay)++getDecoder :: Config -> Bytes.ByteString -> Either String Rattletrap.Replay+getDecoder config = case getMode config of+  ModeDecode -> Rattletrap.decodeReplayFile $ configFast config+  ModeEncode -> Rattletrap.decodeReplayJson++getEncoder :: Config -> Rattletrap.Replay -> Bytes.ByteString+getEncoder config = case getMode config of+  ModeDecode -> if configCompact config+    then LazyBytes.toStrict . Json.encode+    else Rattletrap.encodeReplayJson+  ModeEncode -> Rattletrap.encodeReplayFile $ configFast config++getInput :: Config -> IO Bytes.ByteString+getInput config = case configInput config of+  Nothing -> Bytes.getContents+  Just fileOrUrl -> case Client.parseUrlThrow fileOrUrl of+    Nothing -> Bytes.readFile fileOrUrl+    Just request -> do+      manager <- Client.newTlsManager+      response <- Client.httpLbs request manager+      pure (LazyBytes.toStrict (Client.responseBody response))++putOutput :: Config -> Bytes.ByteString -> IO ()+putOutput config = case configOutput config of+  Nothing -> Bytes.putStr+  Just file -> Bytes.writeFile file++getConfig :: [String] -> IO Config+getConfig arguments = do+  let+    (updates, unexpectedArguments, unknownOptions, problems) =+      Console.getOpt' Console.Permute options arguments+  printUnexpectedArguments unexpectedArguments+  printUnknownOptions unknownOptions+  printProblems problems+  Monad.unless (null problems) Exit.exitFailure+  either fail pure (Monad.foldM applyUpdate defaultConfig updates)++type Option = Console.OptDescr Update++type Update = Config -> Either String Config++options :: [Option]+options =+  [ compactOption+  , fastOption+  , helpOption+  , inputOption+  , modeOption+  , outputOption+  , versionOption+  ]++compactOption :: Option+compactOption = Console.Option+  ['c']+  ["compact"]+  (Console.NoArg (\config -> pure config { configCompact = True }))+  "minify JSON output"++fastOption :: Option+fastOption = Console.Option+  ['f']+  ["fast"]+  (Console.NoArg (\config -> pure config { configFast = True }))+  "only encode or decode the header"++helpOption :: Option+helpOption = Console.Option+  ['h']+  ["help"]+  (Console.NoArg (\config -> pure config { configHelp = True }))+  "show the help"++inputOption :: Option+inputOption = Console.Option+  ['i']+  ["input"]+  (Console.ReqArg+    (\input config -> pure config { configInput = Just input })+    "FILE|URL"+  )+  "input file or URL"++modeOption :: Option+modeOption = Console.Option+  ['m']+  ["mode"]+  (Console.ReqArg+    (\rawMode config -> do+      mode <- parseMode rawMode+      pure config { configMode = Just mode }+    )+    "MODE"+  )+  "decode or encode"++outputOption :: Option+outputOption = Console.Option+  ['o']+  ["output"]+  (Console.ReqArg+    (\output config -> pure config { configOutput = Just output })+    "FILE"+  )+  "output file"++versionOption :: Option+versionOption = Console.Option+  ['v']+  ["version"]+  (Console.NoArg (\config -> pure config { configVersion = True }))+  "show the version"++applyUpdate :: Config -> Update -> Either String Config+applyUpdate config update = update config++data Config = Config+  { configCompact :: Bool+  , configFast :: Bool+  , configHelp :: Bool+  , configInput :: Maybe String+  , configMode :: Maybe Mode+  , configOutput :: Maybe String+  , configVersion :: Bool+  } deriving (Show)++defaultConfig :: Config+defaultConfig = Config+  { configCompact = False+  , configFast = False+  , configHelp = False+  , configInput = Nothing+  , configMode = Nothing+  , configOutput = Nothing+  , configVersion = False+  }++getMode :: Config -> Mode+getMode config = case getExtension (configInput config) of+  ".json" -> ModeEncode+  ".replay" -> ModeDecode+  _ -> case getExtension (configOutput config) of+    ".json" -> ModeDecode+    ".replay" -> ModeEncode+    _ -> ModeDecode++getExtension :: Maybe String -> String+getExtension = maybe "" Path.takeExtension++data Mode+  = ModeDecode+  | ModeEncode+  deriving (Show)++parseMode :: String -> Either String Mode+parseMode mode = case mode of+  "decode" -> Right ModeDecode+  "encode" -> Right ModeEncode+  _ -> Left (Printf.printf "invalid mode: %s" (show mode))++printUnexpectedArguments :: [String] -> IO ()+printUnexpectedArguments = mapM_ printUnexpectedArgument++printUnexpectedArgument :: String -> IO ()+printUnexpectedArgument =+  warnLn . Printf.printf "WARNING: unexpected argument `%s'"++printUnknownOptions :: [String] -> IO ()+printUnknownOptions = mapM_ printUnknownOption++printUnknownOption :: String -> IO ()+printUnknownOption = warnLn . Printf.printf "WARNING: unknown option `%s'"++printProblems :: [String] -> IO ()+printProblems = mapM_ printProblem++printProblem :: String -> IO ()+printProblem = warn . Printf.printf "ERROR: %s"++printHelp :: String -> IO ()+printHelp = warn . help++help :: String -> String+help name = Console.usageInfo (header name) options++header :: String -> String+header name = unwords [name, "version", version]++version :: String+version = Version.showVersion This.version++printVersion :: IO ()+printVersion = warnLn version++warn :: String -> IO ()+warn = IO.hPutStr IO.stderr++warnLn :: String -> IO ()+warnLn = IO.hPutStrLn IO.stderr
+ source/library/Rattletrap/Data.hs view
@@ -0,0 +1,643 @@+-- brittany --columns 120+module Rattletrap.Data+  ( rawParentClasses+  , rawClassesWithLocation+  , rawClassesWithRotation+  , rawObjectClasses+  , rawAttributeTypes+  , rawCrc32Table+  )+where++import Rattletrap.Type.AttributeType++rawParentClasses :: [(String, String)]+rawParentClasses =+  [ ("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_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_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.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_GrapplingHook_TA", "TAGame.SpecialPickup_Targeted_TA")+  , ("TAGame.SpecialPickup_HitForce_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.SpecialPickup_HauntedBallBeam_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")+  ]++rawClassesWithLocation :: [String]+rawClassesWithLocation =+  [ "TAGame.Ball_Breakout_TA"+  , "Archetypes.Ball.Ball_Breakout"+  , "TAGame.Ball_TA"+  , "Archetypes.Ball.Ball_BasketBall_Mutator"+  , "Archetypes.Ball.Ball_BasketBall"+  , "Archetypes.Ball.Ball_Basketball"+  , "Archetypes.Ball.Ball_Default"+  , "Archetypes.Ball.Ball_Puck"+  , "Archetypes.Ball.CubeBall"+  , "Archetypes.Ball.Ball_Haunted"+  , "TAGame.Ball_Haunted_TA"+  , "TAGame.Car_Season_TA"+  , "TAGame.Car_TA"+  , "Archetypes.Car.Car_Default"+  , "Archetypes.GameEvent.GameEvent_Season:CarArchetype"+  , "Archetypes.SpecialPickups.SpecialPickup_HauntedBallBeam"+  , "Archetypes.SpecialPickups.SpecialPickup_Rugby"+  , "TAGame.CameraSettingsActor_TA"+  , "TAGame.CarComponent_Boost_TA"+  , "TAGame.CarComponent_Dodge_TA"+  , "TAGame.CarComponent_DoubleJump_TA"+  , "TAGame.CarComponent_FlipCar_TA"+  , "TAGame.CarComponent_Jump_TA"+  , "TAGame.GameEvent_Season_TA"+  , "TAGame.GameEvent_Soccar_TA"+  , "TAGame.GameEvent_SoccarPrivate_TA"+  , "TAGame.GameEvent_SoccarSplitscreen_TA"+  , "TAGame.GRI_TA"+  , "TAGame.PRI_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_GrapplingHook_TA"+  , "TAGame.SpecialPickup_HitForce_TA"+  , "TAGame.SpecialPickup_Swapper_TA"+  , "TAGame.SpecialPickup_Tornado_TA"+  , "TAGame.Team_Soccar_TA"+  , "TAGame.Default__CameraSettingsActor_TA"+  , "TAGame.Default__PRI_TA"+  , "TheWorld:PersistentLevel.BreakOutActor_Platform_TA"+  , "TheWorld:PersistentLevel.CrowdActor_TA"+  , "TheWorld:PersistentLevel.CrowdManager_TA"+  , "TheWorld:PersistentLevel.InMapScoreboard_TA"+  , "TheWorld:PersistentLevel.VehiclePickup_Boost_TA"+  , "TAGame.HauntedBallTrapTrigger_TA"+  , "ProjectX.NetModeReplicator"+  ]++rawClassesWithRotation :: [String]+rawClassesWithRotation =+  [ "TAGame.Ball_Breakout_TA"+  , "Archetypes.Ball.Ball_Breakout"+  , "TAGame.Ball_TA"+  , "Archetypes.Ball.Ball_BasketBall_Mutator"+  , "Archetypes.Ball.Ball_BasketBall"+  , "Archetypes.Ball.Ball_Basketball"+  , "Archetypes.Ball.Ball_Default"+  , "Archetypes.Ball.Ball_Puck"+  , "Archetypes.Ball.CubeBall"+  , "Archetypes.Ball.Ball_Haunted"+  , "TAGame.Ball_Haunted_TA"+  , "TAGame.Car_Season_TA"+  , "TAGame.Car_TA"+  , "Archetypes.Car.Car_Default"+  , "Archetypes.GameEvent.GameEvent_Season:CarArchetype"+  , "Archetypes.SpecialPickups.SpecialPickup_HauntedBallBeam"+  , "Archetypes.SpecialPickups.SpecialPickup_Rugby"+  -- This comments forces Brittany to use a multi-line layout for this list.+  ]++rawObjectClasses :: [(String, String)]+rawObjectClasses =+  [ ("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_Haunted", "TAGame.Ball_Haunted_TA")+  , ("Archetypes.Ball.Ball_Puck", "TAGame.Ball_TA")+  , ("Archetypes.Ball.CubeBall", "TAGame.Ball_TA")+  , ("Archetypes.Car.Car_Default", "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", "TAGame.GameEvent_Season_TA")+  , ("Archetypes.GameEvent.GameEvent_Season:CarArchetype", "TAGame.Car_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_GravityWell", "TAGame.SpecialPickup_BallGravity_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.SpecialPickups.SpecialPickup_HauntedBallBeam", "TAGame.SpecialPickup_HauntedBallBeam_TA")+  , ("Archetypes.SpecialPickups.SpecialPickup_Rugby", "TAGame.SpecialPickup_Rugby_TA")+  , ("Archetypes.Teams.Team0", "TAGame.Team_Soccar_TA")+  , ("Archetypes.Teams.Team1", "TAGame.Team_Soccar_TA")+  , ("GameInfo_Basketball.GameInfo.GameInfo_Basketball:GameReplicationInfoArchetype", "TAGame.GRI_TA")+  , ("GameInfo_Breakout.GameInfo.GameInfo_Breakout: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")+  , ("ProjectX.Default__NetModeReplicator_X", "ProjectX.NetModeReplicator")+  , ("TAGame.Default__CameraSettingsActor_TA", "TAGame.CameraSettingsActor_TA")+  , ("TAGame.Default__PRI_TA", "TAGame.PRI_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")+  , ("Haunted_TrainStation_P.TheWorld:PersistentLevel.HauntedBallTrapTrigger_TA_1", "TAGame.HauntedBallTrapTrigger_TA")+  , ("Haunted_TrainStation_P.TheWorld:PersistentLevel.HauntedBallTrapTrigger_TA_0", "TAGame.HauntedBallTrapTrigger_TA")+  ]++rawAttributeTypes :: [(String, AttributeType)]+rawAttributeTypes =+  [ ("Engine.Actor:bBlockActors", AttributeTypeBoolean)+  , ("Engine.Actor:bCollideActors", AttributeTypeBoolean)+  , ("Engine.Actor:bHidden", AttributeTypeBoolean)+  , ("Engine.Actor:DrawScale", AttributeTypeFloat)+  , ("Engine.Actor:RemoteRole", AttributeTypeEnum)+  , ("Engine.Actor:Role", AttributeTypeEnum)+  , ("Engine.GameReplicationInfo:bMatchIsOver", AttributeTypeBoolean)+  , ("Engine.GameReplicationInfo:GameClass", AttributeTypeFlaggedInt)+  , ("Engine.GameReplicationInfo:ServerName", AttributeTypeString)+  , ("Engine.Pawn:PlayerReplicationInfo", AttributeTypeFlaggedInt)+  , ("Engine.PlayerReplicationInfo:bBot", AttributeTypeBoolean)+  , ("Engine.PlayerReplicationInfo:bIsSpectator", AttributeTypeBoolean)+  , ("Engine.PlayerReplicationInfo:bReadyToPlay", AttributeTypeBoolean)+  , ("Engine.PlayerReplicationInfo:bTimedOut", AttributeTypeBoolean)+  , ("Engine.PlayerReplicationInfo:bWaitingPlayer", AttributeTypeBoolean)+  , ("Engine.PlayerReplicationInfo:Ping", AttributeTypeByte)+  , ("Engine.PlayerReplicationInfo:PlayerID", AttributeTypeInt)+  , ("Engine.PlayerReplicationInfo:PlayerName", AttributeTypeString)+  , ("Engine.PlayerReplicationInfo:RemoteUserData", AttributeTypeString)+  , ("Engine.PlayerReplicationInfo:Score", AttributeTypeInt)+  , ("Engine.PlayerReplicationInfo:Team", AttributeTypeFlaggedInt)+  , ("Engine.PlayerReplicationInfo:UniqueId", AttributeTypeUniqueId)+  , ("Engine.TeamInfo:Score", AttributeTypeInt)+  , ("ProjectX.GRI_X:bGameStarted", AttributeTypeBoolean)+  , ("ProjectX.GRI_X:GameServerID", AttributeTypeQWord)+  , ("ProjectX.GRI_X:MatchGUID", AttributeTypeString)+  , ("ProjectX.GRI_X:ReplicatedGameMutatorIndex", AttributeTypeInt)+  , ("ProjectX.GRI_X:ReplicatedGamePlaylist", AttributeTypeInt)+  , ("ProjectX.GRI_X:Reservations", AttributeTypeReservation)+  , ("TAGame.Ball_Breakout_TA:AppliedDamage", AttributeTypeAppliedDamage)+  , ("TAGame.Ball_Breakout_TA:DamageIndex", AttributeTypeInt)+  , ("TAGame.Ball_Breakout_TA:LastTeamTouch", AttributeTypeByte)+  , ("TAGame.Ball_TA:GameEvent", AttributeTypeFlaggedInt)+  , ("TAGame.Ball_TA:HitTeamNum", AttributeTypeByte)+  , ("TAGame.Ball_TA:ReplicatedAddedCarBounceScale", AttributeTypeFloat)+  , ("TAGame.Ball_TA:ReplicatedBallMaxLinearSpeedScale", AttributeTypeFloat)+  , ("TAGame.Ball_TA:ReplicatedBallScale", AttributeTypeFloat)+  , ("TAGame.Ball_TA:ReplicatedExplosionData", AttributeTypeExplosion)+  , ("TAGame.Ball_TA:ReplicatedExplosionDataExtended", AttributeTypeExtendedExplosion)+  , ("TAGame.Ball_TA:ReplicatedWorldBounceScale", AttributeTypeFloat)+  , ("TAGame.BreakOutActor_Platform_TA:DamageState", AttributeTypeDamageState)+  , ("TAGame.CameraSettingsActor_TA:bUsingBehindView", AttributeTypeBoolean)+  , ("TAGame.CameraSettingsActor_TA:bMouseCameraToggleEnabled", AttributeTypeBoolean)+  , ("TAGame.CameraSettingsActor_TA:bUsingSecondaryCamera", AttributeTypeBoolean)+  , ("TAGame.CameraSettingsActor_TA:bUsingSwivel", AttributeTypeBoolean)+  , ("TAGame.CameraSettingsActor_TA:CameraPitch", AttributeTypeByte)+  , ("TAGame.CameraSettingsActor_TA:CameraYaw", AttributeTypeByte)+  , ("TAGame.CameraSettingsActor_TA:PRI", AttributeTypeFlaggedInt)+  , ("TAGame.CameraSettingsActor_TA:ProfileSettings", AttributeTypeCamSettings)+  , ("TAGame.Car_TA:AddedBallForceMultiplier", AttributeTypeFloat)+  , ("TAGame.Car_TA:AddedCarForceMultiplier", AttributeTypeFloat)+  , ("TAGame.Car_TA:AttachedPickup", AttributeTypeFlaggedInt)+  , ("TAGame.Car_TA:ClubColors", AttributeTypeClubColors)+  , ("TAGame.Car_TA:ReplicatedDemolish", AttributeTypeDemolish)+  , ("TAGame.Car_TA:TeamPaint", AttributeTypeTeamPaint)+  , ("TAGame.CarComponent_Boost_TA:bNoBoost", AttributeTypeBoolean)+  , ("TAGame.CarComponent_Boost_TA:BoostModifier", AttributeTypeFloat)+  , ("TAGame.CarComponent_Boost_TA:bUnlimitedBoost", AttributeTypeBoolean)+  , ("TAGame.CarComponent_Boost_TA:RechargeDelay", AttributeTypeFloat)+  , ("TAGame.CarComponent_Boost_TA:RechargeRate", AttributeTypeFloat)+  , ("TAGame.CarComponent_Boost_TA:ReplicatedBoostAmount", AttributeTypeByte)+  , ("TAGame.CarComponent_Boost_TA:UnlimitedBoostRefCount", AttributeTypeInt)+  , ("TAGame.CarComponent_Dodge_TA:DodgeTorque", AttributeTypeLocation)+  , ("TAGame.CarComponent_FlipCar_TA:bFlipRight", AttributeTypeBoolean)+  , ("TAGame.CarComponent_FlipCar_TA:FlipCarTime", AttributeTypeFloat)+  , ("TAGame.CarComponent_TA:ReplicatedActive", AttributeTypeByte)+  , ("TAGame.CarComponent_TA:ReplicatedActivityTime", AttributeTypeFloat)+  , ("TAGame.CarComponent_TA:Vehicle", AttributeTypeFlaggedInt)+  , ("TAGame.CrowdActor_TA:GameEvent", AttributeTypeFlaggedInt)+  , ("TAGame.CrowdActor_TA:ModifiedNoise", AttributeTypeFloat)+  , ("TAGame.CrowdActor_TA:ReplicatedCountDownNumber", AttributeTypeInt)+  , ("TAGame.CrowdActor_TA:ReplicatedOneShotSound", AttributeTypeFlaggedInt)+  , ("TAGame.CrowdActor_TA:ReplicatedRoundCountDownNumber", AttributeTypeInt)+  , ("TAGame.CrowdManager_TA:GameEvent", AttributeTypeFlaggedInt)+  , ("TAGame.CrowdManager_TA:ReplicatedGlobalOneShotSound", AttributeTypeFlaggedInt)+  , ("TAGame.GameEvent_Soccar_TA:bBallHasBeenHit", AttributeTypeBoolean)+  , ("TAGame.GameEvent_Soccar_TA:bClubMatch", AttributeTypeBoolean)+  , ("TAGame.GameEvent_Soccar_TA:bOverTime", AttributeTypeBoolean)+  , ("TAGame.GameEvent_Soccar_TA:bUnlimitedTime", AttributeTypeBoolean)+  , ("TAGame.GameEvent_Soccar_TA:GameTime", AttributeTypeInt)+  , ("TAGame.GameEvent_Soccar_TA:ReplicatedMusicStinger", AttributeTypeMusicStinger)+  , ("TAGame.GameEvent_Soccar_TA:ReplicatedScoredOnTeam", AttributeTypeByte)+  , ("TAGame.GameEvent_Soccar_TA:ReplicatedServerPerformanceState", AttributeTypeByte)+  , ("TAGame.GameEvent_Soccar_TA:ReplicatedStatEvent", AttributeTypeStatEvent)+  , ("TAGame.GameEvent_Soccar_TA:RoundNum", AttributeTypeInt)+  , ("TAGame.GameEvent_Soccar_TA:SecondsRemaining", AttributeTypeInt)+  , ("TAGame.GameEvent_Soccar_TA:SeriesLength", AttributeTypeInt)+  , ("TAGame.GameEvent_Soccar_TA:SubRulesArchetype", AttributeTypeFlaggedInt)+  , ("TAGame.GameEvent_SoccarPrivate_TA:MatchSettings", AttributeTypePrivateMatchSettings)+  , ("TAGame.GameEvent_TA:bCanVoteToForfeit", AttributeTypeBoolean)+  , ("TAGame.GameEvent_TA:bHasLeaveMatchPenalty", AttributeTypeBoolean)+  , ("TAGame.GameEvent_TA:BotSkill", AttributeTypeInt)+  , ("TAGame.GameEvent_TA:GameMode", AttributeTypeGameMode)+  , ("TAGame.GameEvent_TA:MatchTypeClass", AttributeTypeFlaggedInt)+  , ("TAGame.GameEvent_TA:ReplicatedGameStateTimeRemaining", AttributeTypeInt)+  , ("TAGame.GameEvent_TA:ReplicatedRoundCountDownNumber", AttributeTypeInt)+  , ("TAGame.GameEvent_TA:ReplicatedStateIndex", AttributeTypeByte)+  , ("TAGame.GameEvent_TA:ReplicatedStateName", AttributeTypeInt)+  , ("TAGame.GameEvent_Team_TA:bForfeit", AttributeTypeBoolean)+  , ("TAGame.GameEvent_Team_TA:MaxTeamSize", AttributeTypeInt)+  , ("TAGame.GRI_TA:NewDedicatedServerIP", AttributeTypeString)+  , ("TAGame.PRI_TA:bIsInSplitScreen", AttributeTypeBoolean)+  , ("TAGame.PRI_TA:bMatchMVP", AttributeTypeBoolean)+  , ("TAGame.PRI_TA:bOnlineLoadoutSet", AttributeTypeBoolean)+  , ("TAGame.PRI_TA:bOnlineLoadoutsSet", AttributeTypeBoolean)+  , ("TAGame.PRI_TA:BotProductName", AttributeTypeInt)+  , ("TAGame.PRI_TA:bReady", AttributeTypeBoolean)+  , ("TAGame.PRI_TA:bUsingBehindView", AttributeTypeBoolean)+  , ("TAGame.PRI_TA:bUsingItems", AttributeTypeBoolean)+  , ("TAGame.PRI_TA:bUsingSecondaryCamera", AttributeTypeBoolean)+  , ("TAGame.PRI_TA:CameraPitch", AttributeTypeByte)+  , ("TAGame.PRI_TA:CameraSettings", AttributeTypeCamSettings)+  , ("TAGame.PRI_TA:CameraYaw", AttributeTypeByte)+  , ("TAGame.PRI_TA:ClientLoadout", AttributeTypeLoadout)+  , ("TAGame.PRI_TA:ClientLoadoutOnline", AttributeTypeLoadoutOnline)+  , ("TAGame.PRI_TA:ClientLoadouts", AttributeTypeLoadouts)+  , ("TAGame.PRI_TA:ClientLoadoutsOnline", AttributeTypeLoadoutsOnline)+  , ("TAGame.PRI_TA:ClubID", AttributeTypeInt64)+  , ("TAGame.PRI_TA:MatchAssists", AttributeTypeInt)+  , ("TAGame.PRI_TA:MatchBreakoutDamage", AttributeTypeInt)+  , ("TAGame.PRI_TA:MatchGoals", AttributeTypeInt)+  , ("TAGame.PRI_TA:MatchSaves", AttributeTypeInt)+  , ("TAGame.PRI_TA:MatchScore", AttributeTypeInt)+  , ("TAGame.PRI_TA:MatchShots", AttributeTypeInt)+  , ("TAGame.PRI_TA:MaxTimeTillItem", AttributeTypeInt)+  , ("TAGame.PRI_TA:PartyLeader", AttributeTypePartyLeader)+  , ("TAGame.PRI_TA:PawnType", AttributeTypeByte)+  , ("TAGame.PRI_TA:PersistentCamera", AttributeTypeFlaggedInt)+  , ("TAGame.PRI_TA:PlayerHistoryKey", AttributeTypePlayerHistoryKey)+  , ("TAGame.PRI_TA:PlayerHistoryValid", AttributeTypeBoolean)+  , ("TAGame.PRI_TA:ReplicatedGameEvent", AttributeTypeFlaggedInt)+  , ("TAGame.PRI_TA:ReplicatedWorstNetQualityBeyondLatency", AttributeTypeByte)+  , ("TAGame.PRI_TA:SteeringSensitivity", AttributeTypeFloat)+  , ("TAGame.PRI_TA:SkillTier", AttributeTypeFlaggedByte)+  , ("TAGame.PRI_TA:TimeTillItem", AttributeTypeInt)+  , ("TAGame.PRI_TA:Title", AttributeTypeInt)+  , ("TAGame.PRI_TA:TotalXP", AttributeTypeInt)+  , ("TAGame.PRI_TA:PrimaryTitle", AttributeTypeTitle)+  , ("TAGame.PRI_TA:SecondaryTitle", AttributeTypeTitle)+  , ("TAGame.PRI_TA:SpectatorShortcut", AttributeTypeInt)+  , ("TAGame.RBActor_TA:bFrozen", AttributeTypeBoolean)+  , ("TAGame.RBActor_TA:bIgnoreSyncing", AttributeTypeBoolean)+  , ("TAGame.RBActor_TA:bReplayActor", AttributeTypeBoolean)+  , ("TAGame.RBActor_TA:ReplicatedRBState", AttributeTypeRigidBodyState)+  , ("TAGame.RBActor_TA:WeldedInfo", AttributeTypeWeldedInfo)+  , ("TAGame.SpecialPickup_BallFreeze_TA:RepOrigSpeed", AttributeTypeFloat)+  , ("TAGame.SpecialPickup_BallVelcro_TA:AttachTime", AttributeTypeFloat)+  , ("TAGame.SpecialPickup_BallVelcro_TA:bBroken", AttributeTypeBoolean)+  , ("TAGame.SpecialPickup_BallVelcro_TA:bHit", AttributeTypeBoolean)+  , ("TAGame.SpecialPickup_BallVelcro_TA:BreakTime", AttributeTypeFloat)+  , ("TAGame.SpecialPickup_Targeted_TA:Targeted", AttributeTypeFlaggedInt)+  , ("TAGame.Team_Soccar_TA:GameScore", AttributeTypeInt)+  , ("TAGame.Team_TA:ClubColors", AttributeTypeClubColors)+  , ("TAGame.Team_TA:ClubID", AttributeTypeInt64)+  , ("TAGame.Team_TA:CustomTeamName", AttributeTypeString)+  , ("TAGame.Team_TA:GameEvent", AttributeTypeFlaggedInt)+  , ("TAGame.Team_TA:LogoData", AttributeTypeFlaggedInt)+  , ("TAGame.Vehicle_TA:bDriving", AttributeTypeBoolean)+  , ("TAGame.Vehicle_TA:bReplicatedHandbrake", AttributeTypeBoolean)+  , ("TAGame.Vehicle_TA:ReplicatedSteer", AttributeTypeByte)+  , ("TAGame.Vehicle_TA:ReplicatedThrottle", AttributeTypeByte)+  , ("TAGame.VehiclePickup_TA:bNoPickup", AttributeTypeBoolean)+  , ("TAGame.VehiclePickup_TA:ReplicatedPickupData", AttributeTypePickup)+  , ("TAGame.VehiclePickup_TA:NewReplicatedPickupData", AttributeTypePickupNew)+  , ("TAGame.Ball_Haunted_TA:LastTeamTouch", AttributeTypeByte)+  , ("TAGame.Ball_Haunted_TA:TotalActiveBeams", AttributeTypeByte)+  , ("TAGame.Ball_Haunted_TA:DeactivatedGoalIndex", AttributeTypeByte)+  , ("TAGame.Ball_Haunted_TA:ReplicatedBeamBrokenValue", AttributeTypeByte)+  , ("TAGame.Ball_Haunted_TA:bIsBallBeamed", AttributeTypeBoolean)+  , ("TAGame.SpecialPickup_Rugby_TA:bBallWelded", AttributeTypeBoolean)+  ]++rawCrc32Table :: Integral a => [a]+rawCrc32Table =+  [ 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+  ]
+ source/library/Rattletrap/Decode/AppliedDamageAttribute.hs view
@@ -0,0 +1,19 @@+module Rattletrap.Decode.AppliedDamageAttribute+  ( decodeAppliedDamageAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Int32le+import Rattletrap.Decode.Vector+import Rattletrap.Decode.Word8le+import Rattletrap.Type.AppliedDamageAttribute++decodeAppliedDamageAttributeBits+  :: (Int, Int, Int) -> DecodeBits AppliedDamageAttribute+decodeAppliedDamageAttributeBits version =+  AppliedDamageAttribute+    <$> decodeWord8leBits+    <*> decodeVectorBits version+    <*> decodeInt32leBits+    <*> decodeInt32leBits
+ source/library/Rattletrap/Decode/Attribute.hs view
@@ -0,0 +1,74 @@+module Rattletrap.Decode.Attribute+  ( decodeAttributesBits+  )+where++import Data.Semigroup ((<>))+import Rattletrap.Decode.AttributeValue+import Rattletrap.Decode.Common+import Rattletrap.Decode.CompressedWord+import Rattletrap.Type.Attribute+import Rattletrap.Type.ClassAttributeMap+import Rattletrap.Type.Common+import Rattletrap.Type.CompressedWord+import Rattletrap.Type.Str+import Rattletrap.Type.Word32le++decodeAttributesBits+  :: (Int, Int, Int)+  -> ClassAttributeMap+  -> Map CompressedWord Word32le+  -> CompressedWord+  -> DecodeBits [Attribute]+decodeAttributesBits version classes actors actor = do+  hasAttribute <- getBool+  if hasAttribute+    then+      (:)+      <$> decodeAttributeBits version classes actors actor+      <*> decodeAttributesBits version classes actors actor+    else pure []++decodeAttributeBits+  :: (Int, Int, Int)+  -> ClassAttributeMap+  -> Map CompressedWord Word32le+  -> CompressedWord+  -> DecodeBits Attribute+decodeAttributeBits version classes actors actor = do+  attributes <- lookupAttributeMap classes actors actor+  limit <- lookupAttributeIdLimit attributes actor+  attribute <- decodeCompressedWordBits limit+  name <- lookupAttributeName classes attributes attribute+  Attribute attribute name+    <$> decodeAttributeValueBits+          version+          (classAttributeMapObjectMap classes)+          name++lookupAttributeMap+  :: ClassAttributeMap+  -> Map CompressedWord Word32le+  -> CompressedWord+  -> DecodeBits (Map Word32le Word32le)+lookupAttributeMap classes actors actor = fromMaybe+  ("could not get attribute map for " <> show actor)+  (getAttributeMap classes actors actor)++lookupAttributeIdLimit+  :: Map Word32le Word32le -> CompressedWord -> DecodeBits Word+lookupAttributeIdLimit attributes actor = fromMaybe+  ("could not get attribute ID limit for " <> show actor)+  (getAttributeIdLimit attributes)++lookupAttributeName+  :: ClassAttributeMap+  -> Map Word32le Word32le+  -> CompressedWord+  -> DecodeBits Str+lookupAttributeName classes attributes attribute = fromMaybe+  ("could not get attribute name for " <> show attribute)+  (getAttributeName classes attributes attribute)++fromMaybe :: String -> Maybe a -> DecodeBits a+fromMaybe message = maybe (fail message) pure
+ source/library/Rattletrap/Decode/AttributeMapping.hs view
@@ -0,0 +1,12 @@+module Rattletrap.Decode.AttributeMapping+  ( decodeAttributeMapping+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Word32le+import Rattletrap.Type.AttributeMapping++decodeAttributeMapping :: Decode AttributeMapping+decodeAttributeMapping =+  AttributeMapping <$> decodeWord32le <*> decodeWord32le
+ source/library/Rattletrap/Decode/AttributeValue.hs view
@@ -0,0 +1,128 @@+module Rattletrap.Decode.AttributeValue+  ( decodeAttributeValueBits+  )+where++import Data.Semigroup ((<>))+import Rattletrap.Data+import Rattletrap.Decode.AppliedDamageAttribute+import Rattletrap.Decode.BooleanAttribute+import Rattletrap.Decode.ByteAttribute+import Rattletrap.Decode.CamSettingsAttribute+import Rattletrap.Decode.ClubColorsAttribute+import Rattletrap.Decode.Common+import Rattletrap.Decode.DamageStateAttribute+import Rattletrap.Decode.DemolishAttribute+import Rattletrap.Decode.EnumAttribute+import Rattletrap.Decode.ExplosionAttribute+import Rattletrap.Decode.ExtendedExplosionAttribute+import Rattletrap.Decode.FlaggedIntAttribute+import Rattletrap.Decode.FlaggedByteAttribute+import Rattletrap.Decode.FloatAttribute+import Rattletrap.Decode.GameModeAttribute+import Rattletrap.Decode.Int64Attribute+import Rattletrap.Decode.IntAttribute+import Rattletrap.Decode.LoadoutAttribute+import Rattletrap.Decode.LoadoutOnlineAttribute+import Rattletrap.Decode.LoadoutsAttribute+import Rattletrap.Decode.LoadoutsOnlineAttribute+import Rattletrap.Decode.LocationAttribute+import Rattletrap.Decode.MusicStingerAttribute+import Rattletrap.Decode.PartyLeaderAttribute+import Rattletrap.Decode.PickupAttribute+import Rattletrap.Decode.PickupAttributeNew+import Rattletrap.Decode.PlayerHistoryKeyAttribute+import Rattletrap.Decode.PrivateMatchSettingsAttribute+import Rattletrap.Decode.QWordAttribute+import Rattletrap.Decode.ReservationAttribute+import Rattletrap.Decode.RigidBodyStateAttribute+import Rattletrap.Decode.StatEventAttribute+import Rattletrap.Decode.StringAttribute+import Rattletrap.Decode.TeamPaintAttribute+import Rattletrap.Decode.TitleAttribute+import Rattletrap.Decode.UniqueIdAttribute+import Rattletrap.Decode.WeldedInfoAttribute+import Rattletrap.Type.AttributeType+import Rattletrap.Type.AttributeValue+import Rattletrap.Type.Common+import Rattletrap.Type.Str+import Rattletrap.Type.Word32le++import qualified Data.Map as Map++decodeAttributeValueBits+  :: (Int, Int, Int) -> Map Word32le Str -> Str -> DecodeBits AttributeValue+decodeAttributeValueBits version objectMap name = do+  constructor <- maybe+    (fail ("don't know how to get attribute value " <> show name))+    pure+    (Map.lookup name attributeTypes)+  case constructor of+    AttributeTypeAppliedDamage ->+      AttributeValueAppliedDamage <$> decodeAppliedDamageAttributeBits version+    AttributeTypeBoolean ->+      AttributeValueBoolean <$> decodeBooleanAttributeBits+    AttributeTypeByte -> AttributeValueByte <$> decodeByteAttributeBits+    AttributeTypeCamSettings ->+      AttributeValueCamSettings <$> decodeCamSettingsAttributeBits version+    AttributeTypeClubColors ->+      AttributeValueClubColors <$> decodeClubColorsAttributeBits+    AttributeTypeDamageState ->+      AttributeValueDamageState <$> decodeDamageStateAttributeBits version+    AttributeTypeDemolish ->+      AttributeValueDemolish <$> decodeDemolishAttributeBits version+    AttributeTypeEnum -> AttributeValueEnum <$> decodeEnumAttributeBits+    AttributeTypeExplosion ->+      AttributeValueExplosion <$> decodeExplosionAttributeBits version+    AttributeTypeExtendedExplosion -> AttributeValueExtendedExplosion+      <$> decodeExtendedExplosionAttributeBits version+    AttributeTypeFlaggedInt ->+      AttributeValueFlaggedInt <$> decodeFlaggedIntAttributeBits+    AttributeTypeFlaggedByte ->+      AttributeValueFlaggedByte <$> decodeFlaggedByteAttributeBits+    AttributeTypeFloat -> AttributeValueFloat <$> decodeFloatAttributeBits+    AttributeTypeGameMode ->+      AttributeValueGameMode <$> decodeGameModeAttributeBits version+    AttributeTypeInt -> AttributeValueInt <$> decodeIntAttributeBits+    AttributeTypeInt64 -> AttributeValueInt64 <$> decodeInt64AttributeBits+    AttributeTypeLoadout ->+      AttributeValueLoadout <$> decodeLoadoutAttributeBits+    AttributeTypeLoadoutOnline ->+      AttributeValueLoadoutOnline+        <$> decodeLoadoutOnlineAttributeBits version objectMap+    AttributeTypeLoadouts ->+      AttributeValueLoadouts <$> decodeLoadoutsAttributeBits+    AttributeTypeLoadoutsOnline ->+      AttributeValueLoadoutsOnline+        <$> decodeLoadoutsOnlineAttributeBits version objectMap+    AttributeTypeLocation ->+      AttributeValueLocation <$> decodeLocationAttributeBits version+    AttributeTypeMusicStinger ->+      AttributeValueMusicStinger <$> decodeMusicStingerAttributeBits+    AttributeTypePartyLeader ->+      AttributeValuePartyLeader <$> decodePartyLeaderAttributeBits version+    AttributeTypePickup -> AttributeValuePickup <$> decodePickupAttributeBits+    AttributeTypePickupNew -> AttributeValuePickupNew <$> decodePickupAttributeNewBits+    AttributeTypePlayerHistoryKey ->+      AttributeValuePlayerHistoryKey <$> decodePlayerHistoryKeyAttributeBits+    AttributeTypePrivateMatchSettings ->+      AttributeValuePrivateMatchSettings+        <$> decodePrivateMatchSettingsAttributeBits+    AttributeTypeQWord -> AttributeValueQWord <$> decodeQWordAttributeBits+    AttributeTypeReservation ->+      AttributeValueReservation <$> decodeReservationAttributeBits version+    AttributeTypeRigidBodyState -> AttributeValueRigidBodyState+      <$> decodeRigidBodyStateAttributeBits version+    AttributeTypeStatEvent ->+      AttributeValueStatEvent <$> decodeStatEventAttributeBits+    AttributeTypeString -> AttributeValueString <$> decodeStringAttributeBits+    AttributeTypeTeamPaint ->+      AttributeValueTeamPaint <$> decodeTeamPaintAttributeBits+    AttributeTypeTitle -> AttributeValueTitle <$> decodeTitleAttributeBits+    AttributeTypeUniqueId ->+      AttributeValueUniqueId <$> decodeUniqueIdAttributeBits version+    AttributeTypeWeldedInfo ->+      AttributeValueWeldedInfo <$> decodeWeldedInfoAttributeBits version++attributeTypes :: Map Str AttributeType+attributeTypes = Map.mapKeys toStr (Map.fromList rawAttributeTypes)
+ source/library/Rattletrap/Decode/BooleanAttribute.hs view
@@ -0,0 +1,10 @@+module Rattletrap.Decode.BooleanAttribute+  ( decodeBooleanAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Type.BooleanAttribute++decodeBooleanAttributeBits :: DecodeBits BooleanAttribute+decodeBooleanAttributeBits = BooleanAttribute <$> getBool
+ source/library/Rattletrap/Decode/ByteAttribute.hs view
@@ -0,0 +1,11 @@+module Rattletrap.Decode.ByteAttribute+  ( decodeByteAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Word8le+import Rattletrap.Type.ByteAttribute++decodeByteAttributeBits :: DecodeBits ByteAttribute+decodeByteAttributeBits = ByteAttribute <$> decodeWord8leBits
+ source/library/Rattletrap/Decode/Cache.hs view
@@ -0,0 +1,18 @@+module Rattletrap.Decode.Cache+  ( decodeCache+  )+where++import Rattletrap.Decode.AttributeMapping+import Rattletrap.Decode.Common+import Rattletrap.Decode.List+import Rattletrap.Decode.Word32le+import Rattletrap.Type.Cache++decodeCache :: Decode Cache+decodeCache =+  Cache+    <$> decodeWord32le+    <*> decodeWord32le+    <*> decodeWord32le+    <*> decodeList decodeAttributeMapping
+ source/library/Rattletrap/Decode/CamSettingsAttribute.hs view
@@ -0,0 +1,20 @@+module Rattletrap.Decode.CamSettingsAttribute+  ( decodeCamSettingsAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Float32le+import Rattletrap.Type.CamSettingsAttribute++decodeCamSettingsAttributeBits+  :: (Int, Int, Int) -> DecodeBits CamSettingsAttribute+decodeCamSettingsAttributeBits version =+  CamSettingsAttribute+    <$> decodeFloat32leBits+    <*> decodeFloat32leBits+    <*> decodeFloat32leBits+    <*> decodeFloat32leBits+    <*> decodeFloat32leBits+    <*> decodeFloat32leBits+    <*> decodeWhen (version >= (868, 20, 0)) decodeFloat32leBits
+ source/library/Rattletrap/Decode/ClassMapping.hs view
@@ -0,0 +1,12 @@+module Rattletrap.Decode.ClassMapping+  ( decodeClassMapping+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Str+import Rattletrap.Decode.Word32le+import Rattletrap.Type.ClassMapping++decodeClassMapping :: Decode ClassMapping+decodeClassMapping = ClassMapping <$> decodeStr <*> decodeWord32le
+ source/library/Rattletrap/Decode/ClubColorsAttribute.hs view
@@ -0,0 +1,16 @@+module Rattletrap.Decode.ClubColorsAttribute+  ( decodeClubColorsAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Word8le+import Rattletrap.Type.ClubColorsAttribute++decodeClubColorsAttributeBits :: DecodeBits ClubColorsAttribute+decodeClubColorsAttributeBits =+  ClubColorsAttribute+    <$> getBool+    <*> decodeWord8leBits+    <*> getBool+    <*> decodeWord8leBits
+ source/library/Rattletrap/Decode/Common.hs view
@@ -0,0 +1,70 @@+module Rattletrap.Decode.Common+  ( Decode+  , DecodeBits+  , decodeWhen+  , getBitsLE+  , getByteStringBits+  , getWord8Bits+  , runDecode+  , runDecodeBits+  , toBits+  , Binary.getFloatle+  , Binary.getByteString+  , Binary.getInt8+  , Binary.getInt32le+  , Binary.getInt64le+  , Binary.getWord8+  , Binary.getWord32le+  , Binary.getWord64le+  , BinaryBits.getBool+  )+where++import qualified Control.Applicative as Applicative+import qualified Control.Monad as Monad+import qualified Data.Binary as Binary+import qualified Data.Binary.Bits.Get as BinaryBits+import qualified Data.Binary.Get as Binary+import qualified Data.Bits as Bits+import qualified Data.ByteString as Bytes+import qualified Data.ByteString.Lazy as LazyBytes+import qualified Data.Word as Word+import qualified Rattletrap.Utility.Bytes as Utility++type Decode = Binary.Get++type DecodeBits = BinaryBits.BitGet++decodeWhen+  :: (Applicative m, Applicative.Alternative f) => Bool -> m a -> m (f a)+decodeWhen p f = if p then fmap pure f else pure Applicative.empty++getByteStringBits :: Int -> DecodeBits Bytes.ByteString+getByteStringBits = BinaryBits.getByteString++getWord8Bits :: Int -> DecodeBits Word.Word8+getWord8Bits = BinaryBits.getWord8++runDecode :: Decode a -> Bytes.ByteString -> Either String a+runDecode decode bytes =+  case Binary.runGetOrFail decode (LazyBytes.fromStrict bytes) of+    Left (_, _, x) -> Left x+    Right (_, _, x) -> Right x++runDecodeBits :: DecodeBits a -> Bytes.ByteString -> Either String a+runDecodeBits = runDecode . BinaryBits.runBitGet++toBits :: Decode a -> Int -> DecodeBits a+toBits decode size = do+  bytes <- BinaryBits.getByteString size+  case runDecode decode (Utility.reverseBytes bytes) of+    Left problem -> fail problem+    Right result -> pure result++getBitsLE :: Bits.Bits a => Int -> BinaryBits.BitGet a+getBitsLE size = do+  bits <- Monad.replicateM size BinaryBits.getBool+  pure $ foldr+    (\bit x -> let y = Bits.shiftL x 1 in if bit then Bits.setBit y 0 else y)+    Bits.zeroBits+    bits
+ source/library/Rattletrap/Decode/CompressedWord.hs view
@@ -0,0 +1,30 @@+module Rattletrap.Decode.CompressedWord+  ( decodeCompressedWordBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Type.CompressedWord++import qualified Data.Bits as Bits++decodeCompressedWordBits :: Word -> DecodeBits CompressedWord+decodeCompressedWordBits limit =+  CompressedWord limit <$> step limit (getMaxBits limit) 0 0++getMaxBits :: Word -> Word+getMaxBits x = do+  let+    n :: Word+    n = max 1 (ceiling (logBase (2 :: Double) (fromIntegral (max 1 x))))+  if x < 1024 && x == 2 ^ n then n + 1 else n++step :: Word -> Word -> Word -> Word -> DecodeBits Word+step limit maxBits position value = do+  let x = Bits.shiftL 1 (fromIntegral position) :: Word+  if position < maxBits && value + x <= limit+    then do+      bit <- getBool+      let newValue = if bit then value + x else value+      step limit maxBits (position + 1) newValue+    else pure value
+ source/library/Rattletrap/Decode/CompressedWordVector.hs view
@@ -0,0 +1,18 @@+module Rattletrap.Decode.CompressedWordVector+  ( decodeCompressedWordVectorBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.CompressedWord+import Rattletrap.Type.CompressedWordVector++decodeCompressedWordVectorBits :: DecodeBits CompressedWordVector+decodeCompressedWordVectorBits =+  CompressedWordVector+    <$> decodeCompressedWordBits limit+    <*> decodeCompressedWordBits limit+    <*> decodeCompressedWordBits limit++limit :: Word+limit = 65536
+ source/library/Rattletrap/Decode/Content.hs view
@@ -0,0 +1,73 @@+module Rattletrap.Decode.Content+  ( decodeContent+  )+where++import Rattletrap.Decode.Cache+import Rattletrap.Decode.ClassMapping+import Rattletrap.Decode.Common+import Rattletrap.Decode.Frame+import Rattletrap.Decode.KeyFrame+import Rattletrap.Decode.List+import Rattletrap.Decode.Mark+import Rattletrap.Decode.Message+import Rattletrap.Decode.Str+import Rattletrap.Decode.Word32le+import Rattletrap.Type.ClassAttributeMap+import Rattletrap.Type.Content+import Rattletrap.Type.Word32le+import Rattletrap.Utility.Bytes++import qualified Control.Monad.Trans.State as State+import qualified Data.Binary.Get as Binary+import qualified Data.ByteString.Lazy as LazyBytes++decodeContent+  :: (Int, Int, Int)+  -- ^ Version numbers, usually from 'Rattletrap.Header.getVersion'.+  -> Int+  -- ^ The number of frames in the stream, usually from+  -- 'Rattletrap.Header.getNumFrames'.+  -> Word+  -- ^ The maximum number of channels in the stream, usually from+  -- 'Rattletrap.Header.getMaxChannels'.+  -> Decode Content+decodeContent version numFrames maxChannels = do+  (levels, keyFrames, streamSize) <-+    (,,)+    <$> decodeList decodeStr+    <*> decodeList decodeKeyFrame+    <*> decodeWord32le+  (stream, messages, marks, packages, objects, names, classMappings, caches) <-+    (,,,,,,,)+    <$> getByteString (fromIntegral (word32leValue streamSize))+    <*> decodeList decodeMessage+    <*> decodeList decodeMark+    <*> decodeList decodeStr+    <*> decodeList decodeStr+    <*> decodeList decodeStr+    <*> decodeList decodeClassMapping+    <*> decodeList decodeCache+  let+    classAttributeMap =+      makeClassAttributeMap objects classMappings caches names+    bitGet = State.evalStateT+      (decodeFramesBits version numFrames maxChannels classAttributeMap)+      mempty+  frames <- either fail pure (runDecodeBits bitGet (reverseBytes stream))+  unknown <- Binary.getRemainingLazyByteString+  pure+    (Content+      levels+      keyFrames+      streamSize+      frames+      messages+      marks+      packages+      objects+      names+      classMappings+      caches+      (LazyBytes.unpack unknown)+    )
+ source/library/Rattletrap/Decode/DamageStateAttribute.hs view
@@ -0,0 +1,21 @@+module Rattletrap.Decode.DamageStateAttribute+  ( decodeDamageStateAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Int32le+import Rattletrap.Decode.Vector+import Rattletrap.Decode.Word8le+import Rattletrap.Type.DamageStateAttribute++decodeDamageStateAttributeBits+  :: (Int, Int, Int) -> DecodeBits DamageStateAttribute+decodeDamageStateAttributeBits version =+  DamageStateAttribute+    <$> decodeWord8leBits+    <*> getBool+    <*> decodeInt32leBits+    <*> decodeVectorBits version+    <*> getBool+    <*> getBool
+ source/library/Rattletrap/Decode/DemolishAttribute.hs view
@@ -0,0 +1,19 @@+module Rattletrap.Decode.DemolishAttribute+  ( decodeDemolishAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Vector+import Rattletrap.Decode.Word32le+import Rattletrap.Type.DemolishAttribute++decodeDemolishAttributeBits :: (Int, Int, Int) -> DecodeBits DemolishAttribute+decodeDemolishAttributeBits version =+  DemolishAttribute+    <$> getBool+    <*> decodeWord32leBits+    <*> getBool+    <*> decodeWord32leBits+    <*> decodeVectorBits version+    <*> decodeVectorBits version
+ source/library/Rattletrap/Decode/DestroyedReplication.hs view
@@ -0,0 +1,10 @@+module Rattletrap.Decode.DestroyedReplication+  ( decodeDestroyedReplicationBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Type.DestroyedReplication++decodeDestroyedReplicationBits :: DecodeBits DestroyedReplication+decodeDestroyedReplicationBits = pure DestroyedReplication
+ source/library/Rattletrap/Decode/Dictionary.hs view
@@ -0,0 +1,17 @@+module Rattletrap.Decode.Dictionary+  ( decodeDictionary+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Str+import Rattletrap.Type.Dictionary+import Rattletrap.Type.Str++decodeDictionary :: Decode a -> Decode (Dictionary a)+decodeDictionary decodeValue = do+  key <- decodeStr+  case filter (/= '\x00') (fromStr key) of+    "None" -> pure (DictionaryEnd key)+    _ ->+      DictionaryElement key <$> decodeValue <*> decodeDictionary decodeValue
+ source/library/Rattletrap/Decode/EnumAttribute.hs view
@@ -0,0 +1,10 @@+module Rattletrap.Decode.EnumAttribute+  ( decodeEnumAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Type.EnumAttribute++decodeEnumAttributeBits :: DecodeBits EnumAttribute+decodeEnumAttributeBits = EnumAttribute <$> getBitsLE 11
+ source/library/Rattletrap/Decode/ExplosionAttribute.hs view
@@ -0,0 +1,17 @@+module Rattletrap.Decode.ExplosionAttribute+  ( decodeExplosionAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Int32le+import Rattletrap.Decode.Vector+import Rattletrap.Type.ExplosionAttribute++decodeExplosionAttributeBits+  :: (Int, Int, Int) -> DecodeBits ExplosionAttribute+decodeExplosionAttributeBits version =+  ExplosionAttribute+    <$> getBool+    <*> decodeInt32leBits+    <*> decodeVectorBits version
+ source/library/Rattletrap/Decode/ExtendedExplosionAttribute.hs view
@@ -0,0 +1,16 @@+module Rattletrap.Decode.ExtendedExplosionAttribute+  ( decodeExtendedExplosionAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.ExplosionAttribute+import Rattletrap.Decode.FlaggedIntAttribute+import Rattletrap.Type.ExtendedExplosionAttribute++decodeExtendedExplosionAttributeBits+  :: (Int, Int, Int) -> DecodeBits ExtendedExplosionAttribute+decodeExtendedExplosionAttributeBits version =+  ExtendedExplosionAttribute+    <$> decodeExplosionAttributeBits version+    <*> decodeFlaggedIntAttributeBits
+ source/library/Rattletrap/Decode/FlaggedByteAttribute.hs view
@@ -0,0 +1,12 @@+module Rattletrap.Decode.FlaggedByteAttribute+  ( decodeFlaggedByteAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Word8le+import Rattletrap.Type.FlaggedByteAttribute+++decodeFlaggedByteAttributeBits :: DecodeBits FlaggedByteAttribute+decodeFlaggedByteAttributeBits = FlaggedByteAttribute <$> getBool <*> decodeWord8leBits
+ source/library/Rattletrap/Decode/FlaggedIntAttribute.hs view
@@ -0,0 +1,12 @@+module Rattletrap.Decode.FlaggedIntAttribute+  ( decodeFlaggedIntAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Int32le+import Rattletrap.Type.FlaggedIntAttribute++decodeFlaggedIntAttributeBits :: DecodeBits FlaggedIntAttribute+decodeFlaggedIntAttributeBits =+  FlaggedIntAttribute <$> getBool <*> decodeInt32leBits
+ source/library/Rattletrap/Decode/Float32le.hs view
@@ -0,0 +1,14 @@+module Rattletrap.Decode.Float32le+  ( decodeFloat32le+  , decodeFloat32leBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Type.Float32le++decodeFloat32le :: Decode Float32le+decodeFloat32le = Float32le <$> getFloatle++decodeFloat32leBits :: DecodeBits Float32le+decodeFloat32leBits = toBits decodeFloat32le 4
+ source/library/Rattletrap/Decode/FloatAttribute.hs view
@@ -0,0 +1,11 @@+module Rattletrap.Decode.FloatAttribute+  ( decodeFloatAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Float32le+import Rattletrap.Type.FloatAttribute++decodeFloatAttributeBits :: DecodeBits FloatAttribute+decodeFloatAttributeBits = FloatAttribute <$> decodeFloat32leBits
+ source/library/Rattletrap/Decode/Frame.hs view
@@ -0,0 +1,43 @@+module Rattletrap.Decode.Frame+  ( decodeFramesBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Float32le+import Rattletrap.Decode.Replication+import Rattletrap.Type.ClassAttributeMap+import Rattletrap.Type.CompressedWord+import Rattletrap.Type.Frame+import Rattletrap.Type.Word32le++import qualified Control.Monad.Trans.Class as Trans+import qualified Control.Monad.Trans.State as State+import qualified Data.Map as Map++decodeFramesBits+  :: (Int, Int, Int)+  -> Int+  -> Word+  -> ClassAttributeMap+  -> State.StateT+       (Map.Map CompressedWord Word32le)+       DecodeBits+       [Frame]+decodeFramesBits version count limit classes = if count <= 0+  then pure []+  else+    (:)+    <$> decodeFrameBits version limit classes+    <*> decodeFramesBits version (count - 1) limit classes++decodeFrameBits+  :: (Int, Int, Int)+  -> Word+  -> ClassAttributeMap+  -> State.StateT (Map.Map CompressedWord Word32le) DecodeBits Frame+decodeFrameBits version limit classes =+  Frame+    <$> Trans.lift decodeFloat32leBits+    <*> Trans.lift decodeFloat32leBits+    <*> decodeReplicationsBits version limit classes
+ source/library/Rattletrap/Decode/GameModeAttribute.hs view
@@ -0,0 +1,15 @@+module Rattletrap.Decode.GameModeAttribute+  ( decodeGameModeAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Type.GameModeAttribute++decodeGameModeAttributeBits :: (Int, Int, Int) -> DecodeBits GameModeAttribute+decodeGameModeAttributeBits version =+  GameModeAttribute <$> pure (numBits version) <*> getWord8Bits+    (numBits version)++numBits :: (Int, Int, Int) -> Int+numBits version = if version >= (868, 12, 0) then 8 else 2
+ source/library/Rattletrap/Decode/Header.hs view
@@ -0,0 +1,22 @@+module Rattletrap.Decode.Header+  ( decodeHeader+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Dictionary+import Rattletrap.Decode.Property+import Rattletrap.Decode.Str+import Rattletrap.Decode.Word32le+import Rattletrap.Type.Header+import Rattletrap.Type.Word32le++decodeHeader :: Decode Header+decodeHeader = do+  (major, minor) <- (,) <$> decodeWord32le <*> decodeWord32le+  Header major minor+    <$> decodeWhen+          (major >= Word32le 868 && minor >= Word32le 18)+          decodeWord32le+    <*> decodeStr+    <*> decodeDictionary decodeProperty
+ source/library/Rattletrap/Decode/Initialization.hs view
@@ -0,0 +1,16 @@+module Rattletrap.Decode.Initialization+  ( decodeInitializationBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Int8Vector+import Rattletrap.Decode.Vector+import Rattletrap.Type.Initialization++decodeInitializationBits+  :: (Int, Int, Int) -> Bool -> Bool -> DecodeBits Initialization+decodeInitializationBits version hasLocation hasRotation =+  Initialization+    <$> decodeWhen hasLocation (decodeVectorBits version)+    <*> decodeWhen hasRotation decodeInt8VectorBits
+ source/library/Rattletrap/Decode/Int32le.hs view
@@ -0,0 +1,14 @@+module Rattletrap.Decode.Int32le+  ( decodeInt32le+  , decodeInt32leBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Type.Int32le++decodeInt32le :: Decode Int32le+decodeInt32le = Int32le <$> getInt32le++decodeInt32leBits :: DecodeBits Int32le+decodeInt32leBits = toBits decodeInt32le 4
+ source/library/Rattletrap/Decode/Int64Attribute.hs view
@@ -0,0 +1,11 @@+module Rattletrap.Decode.Int64Attribute+  ( decodeInt64AttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Int64le+import Rattletrap.Type.Int64Attribute++decodeInt64AttributeBits :: DecodeBits Int64Attribute+decodeInt64AttributeBits = Int64Attribute <$> decodeInt64leBits
+ source/library/Rattletrap/Decode/Int64le.hs view
@@ -0,0 +1,13 @@+module Rattletrap.Decode.Int64le+  ( decodeInt64leBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Type.Int64le++decodeInt64le :: Decode Int64le+decodeInt64le = Int64le <$> getInt64le++decodeInt64leBits :: DecodeBits Int64le+decodeInt64leBits = toBits decodeInt64le 8
+ source/library/Rattletrap/Decode/Int8Vector.hs view
@@ -0,0 +1,18 @@+module Rattletrap.Decode.Int8Vector+  ( decodeInt8VectorBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Int8le+import Rattletrap.Type.Int8Vector+import Rattletrap.Type.Int8le++decodeInt8VectorBits :: DecodeBits Int8Vector+decodeInt8VectorBits =+  Int8Vector <$> decodeFieldBits <*> decodeFieldBits <*> decodeFieldBits++decodeFieldBits :: DecodeBits (Maybe Int8le)+decodeFieldBits = do+  hasField <- getBool+  decodeWhen hasField decodeInt8leBits
+ source/library/Rattletrap/Decode/Int8le.hs view
@@ -0,0 +1,13 @@+module Rattletrap.Decode.Int8le+  ( decodeInt8leBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Type.Int8le++decodeInt8le :: Decode Int8le+decodeInt8le = Int8le <$> getInt8++decodeInt8leBits :: DecodeBits Int8le+decodeInt8leBits = toBits decodeInt8le 1
+ source/library/Rattletrap/Decode/IntAttribute.hs view
@@ -0,0 +1,11 @@+module Rattletrap.Decode.IntAttribute+  ( decodeIntAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Int32le+import Rattletrap.Type.IntAttribute++decodeIntAttributeBits :: DecodeBits IntAttribute+decodeIntAttributeBits = IntAttribute <$> decodeInt32leBits
+ source/library/Rattletrap/Decode/KeyFrame.hs view
@@ -0,0 +1,13 @@+module Rattletrap.Decode.KeyFrame+  ( decodeKeyFrame+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Float32le+import Rattletrap.Decode.Word32le+import Rattletrap.Type.KeyFrame++decodeKeyFrame :: Decode KeyFrame+decodeKeyFrame =+  KeyFrame <$> decodeFloat32le <*> decodeWord32le <*> decodeWord32le
+ source/library/Rattletrap/Decode/List.hs view
@@ -0,0 +1,16 @@+module Rattletrap.Decode.List+  ( decodeList+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Word32le+import Rattletrap.Type.List+import Rattletrap.Type.Word32le++import qualified Control.Monad as Monad++decodeList :: Decode a -> Decode (List a)+decodeList decodeElement = do+  size <- decodeWord32le+  List <$> Monad.replicateM (fromIntegral (word32leValue size)) decodeElement
+ source/library/Rattletrap/Decode/LoadoutAttribute.hs view
@@ -0,0 +1,31 @@+module Rattletrap.Decode.LoadoutAttribute+  ( decodeLoadoutAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Word32le+import Rattletrap.Decode.Word8le+import Rattletrap.Type.LoadoutAttribute+import Rattletrap.Type.Word8le++decodeLoadoutAttributeBits :: DecodeBits LoadoutAttribute+decodeLoadoutAttributeBits = do+  version <- decodeWord8leBits+  LoadoutAttribute version+    <$> decodeWord32leBits+    <*> decodeWord32leBits+    <*> decodeWord32leBits+    <*> decodeWord32leBits+    <*> decodeWord32leBits+    <*> decodeWord32leBits+    <*> decodeWord32leBits+    <*> decodeWhen (version >= Word8le 11) decodeWord32leBits+    <*> decodeWhen (version >= Word8le 16) decodeWord32leBits+    <*> decodeWhen (version >= Word8le 16) decodeWord32leBits+    <*> decodeWhen (version >= Word8le 16) decodeWord32leBits+    <*> decodeWhen (version >= Word8le 17) decodeWord32leBits+    <*> decodeWhen (version >= Word8le 19) decodeWord32leBits+    <*> decodeWhen (version >= Word8le 22) decodeWord32leBits+    <*> decodeWhen (version >= Word8le 22) decodeWord32leBits+    <*> decodeWhen (version >= Word8le 22) decodeWord32leBits
+ source/library/Rattletrap/Decode/LoadoutOnlineAttribute.hs view
@@ -0,0 +1,25 @@+module Rattletrap.Decode.LoadoutOnlineAttribute+  ( decodeLoadoutOnlineAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.ProductAttribute+import Rattletrap.Decode.Word8le+import Rattletrap.Type.LoadoutOnlineAttribute+import Rattletrap.Type.Str+import Rattletrap.Type.Word32le+import Rattletrap.Type.Word8le++import qualified Control.Monad as Monad+import qualified Data.Map as Map++decodeLoadoutOnlineAttributeBits+  :: (Int, Int, Int)+  -> Map.Map Word32le Str+  -> DecodeBits LoadoutOnlineAttribute+decodeLoadoutOnlineAttributeBits version objectMap = do+  size <- decodeWord8leBits+  LoadoutOnlineAttribute <$> Monad.replicateM+    (fromIntegral (word8leValue size))+    (decodeProductAttributesBits version objectMap)
+ source/library/Rattletrap/Decode/LoadoutsAttribute.hs view
@@ -0,0 +1,14 @@+module Rattletrap.Decode.LoadoutsAttribute+  ( decodeLoadoutsAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.LoadoutAttribute+import Rattletrap.Type.LoadoutsAttribute++decodeLoadoutsAttributeBits :: DecodeBits LoadoutsAttribute+decodeLoadoutsAttributeBits =+  LoadoutsAttribute+    <$> decodeLoadoutAttributeBits+    <*> decodeLoadoutAttributeBits
+ source/library/Rattletrap/Decode/LoadoutsOnlineAttribute.hs view
@@ -0,0 +1,23 @@+module Rattletrap.Decode.LoadoutsOnlineAttribute+  ( decodeLoadoutsOnlineAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.LoadoutOnlineAttribute+import Rattletrap.Type.LoadoutsOnlineAttribute+import Rattletrap.Type.Str+import Rattletrap.Type.Word32le++import qualified Data.Map as Map++decodeLoadoutsOnlineAttributeBits+  :: (Int, Int, Int)+  -> Map.Map Word32le Str+  -> DecodeBits LoadoutsOnlineAttribute+decodeLoadoutsOnlineAttributeBits version objectMap =+  LoadoutsOnlineAttribute+    <$> decodeLoadoutOnlineAttributeBits version objectMap+    <*> decodeLoadoutOnlineAttributeBits version objectMap+    <*> getBool+    <*> getBool
+ source/library/Rattletrap/Decode/LocationAttribute.hs view
@@ -0,0 +1,12 @@+module Rattletrap.Decode.LocationAttribute+  ( decodeLocationAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Vector+import Rattletrap.Type.LocationAttribute++decodeLocationAttributeBits :: (Int, Int, Int) -> DecodeBits LocationAttribute+decodeLocationAttributeBits version =+  LocationAttribute <$> decodeVectorBits version
+ source/library/Rattletrap/Decode/Mark.hs view
@@ -0,0 +1,12 @@+module Rattletrap.Decode.Mark+  ( decodeMark+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Str+import Rattletrap.Decode.Word32le+import Rattletrap.Type.Mark++decodeMark :: Decode Mark+decodeMark = Mark <$> decodeStr <*> decodeWord32le
+ source/library/Rattletrap/Decode/Message.hs view
@@ -0,0 +1,12 @@+module Rattletrap.Decode.Message+  ( decodeMessage+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Str+import Rattletrap.Decode.Word32le+import Rattletrap.Type.Message++decodeMessage :: Decode Message+decodeMessage = Message <$> decodeWord32le <*> decodeStr <*> decodeStr
+ source/library/Rattletrap/Decode/MusicStingerAttribute.hs view
@@ -0,0 +1,16 @@+module Rattletrap.Decode.MusicStingerAttribute+  ( decodeMusicStingerAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Word32le+import Rattletrap.Decode.Word8le+import Rattletrap.Type.MusicStingerAttribute++decodeMusicStingerAttributeBits :: DecodeBits MusicStingerAttribute+decodeMusicStingerAttributeBits =+  MusicStingerAttribute+    <$> getBool+    <*> decodeWord32leBits+    <*> decodeWord8leBits
+ source/library/Rattletrap/Decode/PartyLeaderAttribute.hs view
@@ -0,0 +1,18 @@+module Rattletrap.Decode.PartyLeaderAttribute+  ( decodePartyLeaderAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.RemoteId+import Rattletrap.Decode.Word8le+import Rattletrap.Type.PartyLeaderAttribute+import Rattletrap.Type.Word8le++decodePartyLeaderAttributeBits+  :: (Int, Int, Int) -> DecodeBits PartyLeaderAttribute+decodePartyLeaderAttributeBits version = do+  systemId <- decodeWord8leBits+  PartyLeaderAttribute systemId <$> decodeWhen+    (systemId /= Word8le 0)+    ((,) <$> decodeRemoteIdBits version systemId <*> decodeWord8leBits)
+ source/library/Rattletrap/Decode/PickupAttribute.hs view
@@ -0,0 +1,13 @@+module Rattletrap.Decode.PickupAttribute+  ( decodePickupAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Word32le+import Rattletrap.Type.PickupAttribute++decodePickupAttributeBits :: DecodeBits PickupAttribute+decodePickupAttributeBits = do+  instigator <- getBool+  PickupAttribute <$> decodeWhen instigator decodeWord32leBits <*> getBool
+ source/library/Rattletrap/Decode/PickupAttributeNew.hs view
@@ -0,0 +1,14 @@+module Rattletrap.Decode.PickupAttributeNew+  ( decodePickupAttributeNewBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Word8le+import Rattletrap.Decode.Word32le+import Rattletrap.Type.PickupAttributeNew++decodePickupAttributeNewBits :: DecodeBits PickupAttributeNew+decodePickupAttributeNewBits = do+  instigator <- getBool+  PickupAttributeNew <$> decodeWhen instigator decodeWord32leBits <*> decodeWord8leBits
+ source/library/Rattletrap/Decode/PlayerHistoryKeyAttribute.hs view
@@ -0,0 +1,11 @@+module Rattletrap.Decode.PlayerHistoryKeyAttribute+  ( decodePlayerHistoryKeyAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Type.PlayerHistoryKeyAttribute++decodePlayerHistoryKeyAttributeBits :: DecodeBits PlayerHistoryKeyAttribute+decodePlayerHistoryKeyAttributeBits =+  PlayerHistoryKeyAttribute <$> getBitsLE 14
+ source/library/Rattletrap/Decode/PrivateMatchSettingsAttribute.hs view
@@ -0,0 +1,20 @@+module Rattletrap.Decode.PrivateMatchSettingsAttribute+  ( decodePrivateMatchSettingsAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Str+import Rattletrap.Decode.Word32le+import Rattletrap.Type.PrivateMatchSettingsAttribute++decodePrivateMatchSettingsAttributeBits+  :: DecodeBits PrivateMatchSettingsAttribute+decodePrivateMatchSettingsAttributeBits =+  PrivateMatchSettingsAttribute+    <$> decodeStrBits+    <*> decodeWord32leBits+    <*> decodeWord32leBits+    <*> decodeStrBits+    <*> decodeStrBits+    <*> getBool
+ source/library/Rattletrap/Decode/ProductAttribute.hs view
@@ -0,0 +1,72 @@+module Rattletrap.Decode.ProductAttribute+  ( decodeProductAttributesBits+  )+where++import Data.Semigroup ((<>))+import Rattletrap.Decode.Common+import Rattletrap.Decode.CompressedWord+import Rattletrap.Decode.Word32le+import Rattletrap.Decode.Word8le+import Rattletrap.Decode.Str+import Rattletrap.Type.Common+import Rattletrap.Type.ProductAttribute+import Rattletrap.Type.Str+import Rattletrap.Type.Word32le+import Rattletrap.Type.Word8le++import qualified Control.Monad as Monad+import qualified Data.Map as Map++decodeProductAttributesBits+  :: (Int, Int, Int) -> Map Word32le Str -> DecodeBits [ProductAttribute]+decodeProductAttributesBits version objectMap = do+  size <- decodeWord8leBits+  Monad.replicateM+    (fromIntegral (word8leValue size))+    (decodeProductAttributeBits version objectMap)++decodeProductAttributeBits+  :: (Int, Int, Int) -> Map Word32le Str -> DecodeBits ProductAttribute+decodeProductAttributeBits version objectMap = do+  flag <- getBool+  objectId <- decodeWord32leBits+  let maybeObjectName = Map.lookup objectId objectMap+  value <- case fromStr <$> maybeObjectName of+    Just "TAGame.ProductAttribute_Painted_TA" -> decodePainted version+    Just "TAGame.ProductAttribute_SpecialEdition_TA" -> decodeSpecialEdition+    Just "TAGame.ProductAttribute_TeamEdition_TA" -> decodeTeamEdition version+    Just "TAGame.ProductAttribute_TitleID_TA" -> decodeTitle+    Just "TAGame.ProductAttribute_UserColor_TA" -> decodeColor version+    Just objectName ->+      fail+        ("unknown object name "+        <> show objectName+        <> " for ID "+        <> show objectId+        )+    Nothing -> fail ("missing object name for ID " <> show objectId)+  pure (ProductAttribute flag objectId maybeObjectName value)++decodeSpecialEdition :: DecodeBits ProductAttributeValue+decodeSpecialEdition = ProductAttributeValueSpecialEdition <$> getBitsLE 31++decodePainted :: (Int, Int, Int) -> DecodeBits ProductAttributeValue+decodePainted version = if version >= (868, 18, 0)+  then ProductAttributeValuePaintedNew <$> getBitsLE 31+  else ProductAttributeValuePaintedOld <$> decodeCompressedWordBits 13++decodeTeamEdition :: (Int, Int, Int) -> DecodeBits ProductAttributeValue+decodeTeamEdition version = if version >= (868, 18, 0)+  then ProductAttributeValueTeamEditionNew <$> getBitsLE 31+  else ProductAttributeValueTeamEditionOld <$> decodeCompressedWordBits 13++decodeColor :: (Int, Int, Int) -> DecodeBits ProductAttributeValue+decodeColor version = if version >= (868, 23, 8)+  then ProductAttributeValueUserColorNew <$> decodeWord32leBits+  else do+    hasValue <- getBool+    ProductAttributeValueUserColorOld <$> decodeWhen hasValue (getBitsLE 31)++decodeTitle :: DecodeBits ProductAttributeValue+decodeTitle = ProductAttributeValueTitleId <$> decodeStrBits
+ source/library/Rattletrap/Decode/Property.hs view
@@ -0,0 +1,15 @@+module Rattletrap.Decode.Property+  ( decodeProperty+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.PropertyValue+import Rattletrap.Decode.Str+import Rattletrap.Decode.Word64le+import Rattletrap.Type.Property++decodeProperty :: Decode Property+decodeProperty = do+  kind <- decodeStr+  Property kind <$> decodeWord64le <*> decodePropertyValue decodeProperty kind
+ source/library/Rattletrap/Decode/PropertyValue.hs view
@@ -0,0 +1,32 @@+module Rattletrap.Decode.PropertyValue+  ( decodePropertyValue+  )+where++import Data.Semigroup ((<>))+import Rattletrap.Decode.Common+import Rattletrap.Decode.Dictionary+import Rattletrap.Decode.Float32le+import Rattletrap.Decode.Int32le+import Rattletrap.Decode.List+import Rattletrap.Decode.Str+import Rattletrap.Decode.Word64le+import Rattletrap.Decode.Word8le+import Rattletrap.Type.PropertyValue+import Rattletrap.Type.Str++decodePropertyValue :: Decode a -> Str -> Decode (PropertyValue a)+decodePropertyValue getProperty kind = case fromStr kind of+  "ArrayProperty" ->+    PropertyValueArray <$> decodeList (decodeDictionary getProperty)+  "BoolProperty" -> PropertyValueBool <$> decodeWord8le+  "ByteProperty" -> do+    k <- decodeStr+    PropertyValueByte k+      <$> decodeWhen (fromStr k /= "OnlinePlatform_Steam") decodeStr+  "FloatProperty" -> PropertyValueFloat <$> decodeFloat32le+  "IntProperty" -> PropertyValueInt <$> decodeInt32le+  "NameProperty" -> PropertyValueName <$> decodeStr+  "QWordProperty" -> PropertyValueQWord <$> decodeWord64le+  "StrProperty" -> PropertyValueStr <$> decodeStr+  _ -> fail ("don't know how to read property value " <> show kind)
+ source/library/Rattletrap/Decode/QWordAttribute.hs view
@@ -0,0 +1,11 @@+module Rattletrap.Decode.QWordAttribute+  ( decodeQWordAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Word64le+import Rattletrap.Type.QWordAttribute++decodeQWordAttributeBits :: DecodeBits QWordAttribute+decodeQWordAttributeBits = QWordAttribute <$> decodeWord64leBits
+ source/library/Rattletrap/Decode/Quaternion.hs view
@@ -0,0 +1,26 @@+module Rattletrap.Decode.Quaternion+  ( decodeQuaternionBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.CompressedWord+import Rattletrap.Type.CompressedWord+import Rattletrap.Type.Quaternion++decodeQuaternionBits :: DecodeBits Quaternion+decodeQuaternionBits =+  toQuaternion <$> decodeComponent <*> decodePart <*> decodePart <*> decodePart++decodeComponent :: DecodeBits Component+decodeComponent = do+  x <- decodeCompressedWordBits 3+  case compressedWordValue x of+    0 -> pure ComponentX+    1 -> pure ComponentY+    2 -> pure ComponentZ+    3 -> pure ComponentW+    y -> fail ("invalid component: " <> show y)++decodePart :: DecodeBits Double+decodePart = decompressPart <$> decodeCompressedWordBits maxCompressedValue
+ source/library/Rattletrap/Decode/RemoteId.hs view
@@ -0,0 +1,48 @@+module Rattletrap.Decode.RemoteId+  ( decodeRemoteIdBits+  )+where++import Data.Semigroup ((<>))+import Rattletrap.Decode.Common+import Rattletrap.Decode.Word64le+import Rattletrap.Type.RemoteId+import Rattletrap.Type.Word64le+import Rattletrap.Type.Word8le+import Rattletrap.Utility.Bytes++import qualified Data.ByteString as Bytes+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text+import qualified Data.Word as Word++decodeRemoteIdBits :: (Int, Int, Int) -> Word8le -> DecodeBits RemoteId+decodeRemoteIdBits version systemId = case word8leValue systemId of+  0 -> RemoteIdSplitscreen <$> getBitsLE 24+  1 -> RemoteIdSteam <$> decodeWord64leBits+  2 -> RemoteIdPlayStation <$> decodePsName <*> decodePsBytes version+  4 -> RemoteIdXbox <$> decodeWord64leBits+  6 -> do+    (a, b, c, d) <- getWord256+    pure $ RemoteIdSwitch a b c d+  7 -> if version >= (868, 24, 10)+    then RemoteIdPsyNet . Left <$> decodeWord64leBits+    else RemoteIdPsyNet . Right <$> getWord256+  _ -> fail ("unknown system id " <> show systemId)++decodePsName :: DecodeBits Text.Text+decodePsName = fmap+  (Text.dropWhileEnd (== '\x00') . Text.decodeLatin1 . reverseBytes)+  (getByteStringBits 16)++decodePsBytes :: (Int, Int, Int) -> DecodeBits [Word.Word8]+decodePsBytes version = Bytes.unpack+  <$> getByteStringBits (if version >= (868, 20, 1) then 24 else 16)++getWord256 :: DecodeBits (Word64le, Word64le, Word64le, Word64le)+getWord256 = do+  a <- decodeWord64leBits+  b <- decodeWord64leBits+  c <- decodeWord64leBits+  d <- decodeWord64leBits+  pure (a, b, c, d)
+ source/library/Rattletrap/Decode/Replay.hs view
@@ -0,0 +1,66 @@+module Rattletrap.Decode.Replay+  ( decodeReplay+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Content+import Rattletrap.Decode.Header+import Rattletrap.Decode.Section+import Rattletrap.Encode.Content+import Rattletrap.Type.Content+import Rattletrap.Type.Dictionary+import Rattletrap.Type.Header+import Rattletrap.Type.Int32le+import Rattletrap.Type.Property+import Rattletrap.Type.PropertyValue+import Rattletrap.Type.Replay+import Rattletrap.Type.Section+import Rattletrap.Type.Str+import Rattletrap.Type.Word32le++decodeReplay :: Bool -> Decode Replay+decodeReplay fast = do+  header <- decodeSection decodeHeader+  content <- if fast+    then pure $ toSection putContent defaultContent+    else+      let body = sectionBody header+      in+        decodeSection $ decodeContent+          (getVersion body)+          (getNumFrames body)+          (getMaxChannels body)+  pure $ Replay header content++getVersion :: Header -> (Int, Int, Int)+getVersion header =+  ( fromIntegral (word32leValue (headerEngineVersion header))+  , fromIntegral (word32leValue (headerLicenseeVersion header))+  , getPatchVersion header+  )++getPatchVersion :: Header -> Int+getPatchVersion header = case headerPatchVersion header of+  Just version -> fromIntegral (word32leValue version)+  Nothing ->+    case dictionaryLookup (toStr "MatchType") (headerProperties header) of+      -- This is an ugly, ugly hack to handle replays from season 2 of RLCS.+      -- See `decodeSpawnedReplicationBits` and #85.+      Just Property { propertyValue = PropertyValueName str }+        | fromStr str == "Lan" -> -1+      _ -> 0++getNumFrames :: Header -> Int+getNumFrames header =+  case dictionaryLookup (toStr "NumFrames") (headerProperties header) of+    Just (Property _ _ (PropertyValueInt numFrames)) ->+      fromIntegral (int32leValue numFrames)+    _ -> 0++getMaxChannels :: Header -> Word+getMaxChannels header =+  case dictionaryLookup (toStr "MaxChannels") (headerProperties header) of+    Just (Property _ _ (PropertyValueInt numFrames)) ->+      fromIntegral (int32leValue numFrames)+    _ -> 1023
+ source/library/Rattletrap/Decode/Replication.hs view
@@ -0,0 +1,45 @@+module Rattletrap.Decode.Replication+  ( decodeReplicationsBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.CompressedWord+import Rattletrap.Decode.ReplicationValue+import Rattletrap.Type.ClassAttributeMap+import Rattletrap.Type.CompressedWord+import Rattletrap.Type.Replication+import Rattletrap.Type.Word32le++import qualified Control.Monad.Trans.Class as Trans+import qualified Control.Monad.Trans.State as State+import qualified Data.Map as Map++decodeReplicationsBits+  :: (Int, Int, Int)+  -> Word+  -> ClassAttributeMap+  -> State.StateT+       (Map.Map CompressedWord Word32le)+       DecodeBits+       [Replication]+decodeReplicationsBits version limit classes = do+  hasReplication <- Trans.lift getBool+  if hasReplication+    then+      (:)+      <$> decodeReplicationBits version limit classes+      <*> decodeReplicationsBits version limit classes+    else pure []++decodeReplicationBits+  :: (Int, Int, Int)+  -> Word+  -> ClassAttributeMap+  -> State.StateT+       (Map.Map CompressedWord Word32le)+       DecodeBits+       Replication+decodeReplicationBits version limit classes = do+  actor <- Trans.lift (decodeCompressedWordBits limit)+  Replication actor <$> decodeReplicationValueBits version classes actor
+ source/library/Rattletrap/Decode/ReplicationValue.hs view
@@ -0,0 +1,45 @@+module Rattletrap.Decode.ReplicationValue+  ( decodeReplicationValueBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.DestroyedReplication+import Rattletrap.Decode.SpawnedReplication+import Rattletrap.Decode.UpdatedReplication+import Rattletrap.Type.ClassAttributeMap+import Rattletrap.Type.CompressedWord+import Rattletrap.Type.ReplicationValue+import Rattletrap.Type.Word32le++import qualified Control.Monad.Trans.Class as Trans+import qualified Control.Monad.Trans.State as State+import qualified Data.Map as Map++decodeReplicationValueBits+  :: (Int, Int, Int)+  -> ClassAttributeMap+  -> CompressedWord+  -> State.StateT+       (Map.Map CompressedWord Word32le)+       DecodeBits+       ReplicationValue+decodeReplicationValueBits version classAttributeMap actorId = do+  actorMap <- State.get+  isOpen <- Trans.lift getBool+  if isOpen+    then do+      isNew <- Trans.lift getBool+      if isNew+        then+          ReplicationValueSpawned+            <$> decodeSpawnedReplicationBits version classAttributeMap actorId+        else ReplicationValueUpdated <$> Trans.lift+          (decodeUpdatedReplicationBits+            version+            classAttributeMap+            actorMap+            actorId+          )+    else ReplicationValueDestroyed+      <$> Trans.lift decodeDestroyedReplicationBits
+ source/library/Rattletrap/Decode/ReservationAttribute.hs view
@@ -0,0 +1,25 @@+module Rattletrap.Decode.ReservationAttribute+  ( decodeReservationAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.CompressedWord+import Rattletrap.Decode.Str+import Rattletrap.Decode.UniqueIdAttribute+import Rattletrap.Type.ReservationAttribute+import Rattletrap.Type.UniqueIdAttribute+import Rattletrap.Type.Word8le++decodeReservationAttributeBits+  :: (Int, Int, Int) -> DecodeBits ReservationAttribute+decodeReservationAttributeBits version = do+  number <- decodeCompressedWordBits 7+  uniqueId <- decodeUniqueIdAttributeBits version+  ReservationAttribute number uniqueId+    <$> decodeWhen+          (uniqueIdAttributeSystemId uniqueId /= Word8le 0)+          decodeStrBits+    <*> getBool+    <*> getBool+    <*> decodeWhen (version >= (868, 12, 0)) (getWord8Bits 6)
+ source/library/Rattletrap/Decode/RigidBodyStateAttribute.hs view
@@ -0,0 +1,19 @@+module Rattletrap.Decode.RigidBodyStateAttribute+  ( decodeRigidBodyStateAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Rotation+import Rattletrap.Decode.Vector+import Rattletrap.Type.RigidBodyStateAttribute++decodeRigidBodyStateAttributeBits+  :: (Int, Int, Int) -> DecodeBits RigidBodyStateAttribute+decodeRigidBodyStateAttributeBits version = do+  sleeping <- getBool+  RigidBodyStateAttribute sleeping+    <$> decodeVectorBits version+    <*> decodeRotationBits version+    <*> decodeWhen (not sleeping) (decodeVectorBits version)+    <*> decodeWhen (not sleeping) (decodeVectorBits version)
+ source/library/Rattletrap/Decode/Rotation.hs view
@@ -0,0 +1,14 @@+module Rattletrap.Decode.Rotation+  ( decodeRotationBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.CompressedWordVector+import Rattletrap.Decode.Quaternion+import Rattletrap.Type.Rotation++decodeRotationBits :: (Int, Int, Int) -> DecodeBits Rotation+decodeRotationBits version = if version >= (868, 22, 7)+  then RotationQuaternion <$> decodeQuaternionBits+  else RotationCompressedWordVector <$> decodeCompressedWordVectorBits
+ source/library/Rattletrap/Decode/Section.hs view
@@ -0,0 +1,26 @@+module Rattletrap.Decode.Section+  ( decodeSection+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Word32le+import Rattletrap.Type.Section+import Rattletrap.Type.Word32le+import Rattletrap.Utility.Crc++import qualified Control.Monad as Monad++decodeSection :: Decode a -> Decode (Section a)+decodeSection getBody = do+  size <- decodeWord32le+  crc <- decodeWord32le+  rawBody <- getByteString (fromIntegral (word32leValue size))+  let actualCrc = Word32le (getCrc32 rawBody)+  Monad.when (actualCrc /= crc) (fail (crcMessage actualCrc crc))+  body <- either fail pure (runDecode getBody rawBody)+  pure (Section size crc body)++crcMessage :: Word32le -> Word32le -> String+crcMessage actual expected = unwords+  ["actual CRC", show actual, "does not match expected CRC", show expected]
+ source/library/Rattletrap/Decode/SpawnedReplication.hs view
@@ -0,0 +1,70 @@+module Rattletrap.Decode.SpawnedReplication+  ( decodeSpawnedReplicationBits+  )+where++import Data.Semigroup ((<>))+import Rattletrap.Decode.Common+import Rattletrap.Decode.Initialization+import Rattletrap.Decode.Word32le+import Rattletrap.Type.ClassAttributeMap+import Rattletrap.Type.CompressedWord+import Rattletrap.Type.SpawnedReplication+import Rattletrap.Type.Str+import Rattletrap.Type.Word32le++import qualified Control.Monad.Trans.Class as Trans+import qualified Control.Monad.Trans.State as State+import qualified Data.Map as Map++decodeSpawnedReplicationBits+  :: (Int, Int, Int)+  -> ClassAttributeMap+  -> CompressedWord+  -> State.StateT+       (Map.Map CompressedWord Word32le)+       DecodeBits+       SpawnedReplication+decodeSpawnedReplicationBits version classAttributeMap actorId = do+  flag <- Trans.lift getBool+  nameIndex <- decodeWhen+    (version >= (868, 14, 0))+    (Trans.lift decodeWord32leBits)+  name <- either fail pure (lookupName classAttributeMap nameIndex)+  objectId <- Trans.lift decodeWord32leBits+  State.modify (Map.insert actorId objectId)+  objectName <- either fail pure (lookupObjectName classAttributeMap objectId)+  className <- either fail pure (lookupClassName objectName)+  let hasLocation = classHasLocation className+  let hasRotation = classHasRotation className+  initialization <- Trans.lift+    (decodeInitializationBits version hasLocation hasRotation)+  pure+    (SpawnedReplication+      flag+      nameIndex+      name+      objectId+      objectName+      className+      initialization+    )++lookupName :: ClassAttributeMap -> Maybe Word32le -> Either String (Maybe Str)+lookupName classAttributeMap maybeNameIndex = case maybeNameIndex of+  Nothing -> Right Nothing+  Just nameIndex ->+    case getName (classAttributeMapNameMap classAttributeMap) nameIndex of+      Nothing -> Left ("could not get name for index " <> show nameIndex)+      Just name -> Right (Just name)++lookupObjectName :: ClassAttributeMap -> Word32le -> Either String Str+lookupObjectName classAttributeMap objectId =+  case getObjectName (classAttributeMapObjectMap classAttributeMap) objectId of+    Nothing -> Left ("could not get object name for id " <> show objectId)+    Just objectName -> Right objectName++lookupClassName :: Str -> Either String Str+lookupClassName objectName = case getClassName objectName of+  Nothing -> Left ("could not get class name for object " <> show objectName)+  Just className -> Right className
+ source/library/Rattletrap/Decode/StatEventAttribute.hs view
@@ -0,0 +1,12 @@+module Rattletrap.Decode.StatEventAttribute+  ( decodeStatEventAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Int32le+import Rattletrap.Type.StatEventAttribute++decodeStatEventAttributeBits :: DecodeBits StatEventAttribute+decodeStatEventAttributeBits =+  StatEventAttribute <$> getBool <*> decodeInt32leBits
+ source/library/Rattletrap/Decode/Str.hs view
@@ -0,0 +1,42 @@+module Rattletrap.Decode.Str+  ( decodeStr+  , decodeStrBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Int32le+import Rattletrap.Type.Int32le+import Rattletrap.Type.Str+import Rattletrap.Utility.Bytes++import qualified Data.ByteString as Bytes+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text++decodeStr :: Decode Str+decodeStr = do+  rawSize <- decodeInt32le+  bytes <- getByteString (normalizeTextSize rawSize)+  pure (Str (dropNull (getTextDecoder rawSize bytes)))++decodeStrBits :: DecodeBits Str+decodeStrBits = do+  rawSize <- decodeInt32leBits+  bytes <- getByteStringBits (normalizeTextSize rawSize)+  pure (Str (dropNull (getTextDecoder rawSize (reverseBytes bytes))))++normalizeTextSize :: Integral a => Int32le -> a+normalizeTextSize size = case int32leValue size of+  0x05000000 -> 8+  x -> if x < 0 then (-2 * fromIntegral x) else fromIntegral x++getTextDecoder :: Int32le -> Bytes.ByteString -> Text.Text+getTextDecoder size bytes =+  let+    decode =+      if size < Int32le 0 then Text.decodeUtf16LE else Text.decodeLatin1+  in decode bytes++dropNull :: Text.Text -> Text.Text+dropNull = Text.dropWhileEnd (== '\x00')
+ source/library/Rattletrap/Decode/StringAttribute.hs view
@@ -0,0 +1,11 @@+module Rattletrap.Decode.StringAttribute+  ( decodeStringAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Str+import Rattletrap.Type.StringAttribute++decodeStringAttributeBits :: DecodeBits StringAttribute+decodeStringAttributeBits = StringAttribute <$> decodeStrBits
+ source/library/Rattletrap/Decode/TeamPaintAttribute.hs view
@@ -0,0 +1,18 @@+module Rattletrap.Decode.TeamPaintAttribute+  ( decodeTeamPaintAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Word32le+import Rattletrap.Decode.Word8le+import Rattletrap.Type.TeamPaintAttribute++decodeTeamPaintAttributeBits :: DecodeBits TeamPaintAttribute+decodeTeamPaintAttributeBits =+  TeamPaintAttribute+    <$> decodeWord8leBits+    <*> decodeWord8leBits+    <*> decodeWord8leBits+    <*> decodeWord32leBits+    <*> decodeWord32leBits
+ source/library/Rattletrap/Decode/TitleAttribute.hs view
@@ -0,0 +1,20 @@+module Rattletrap.Decode.TitleAttribute+  ( decodeTitleAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Word32le+import Rattletrap.Type.TitleAttribute++decodeTitleAttributeBits :: DecodeBits TitleAttribute+decodeTitleAttributeBits =+  TitleAttribute+    <$> getBool+    <*> getBool+    <*> decodeWord32leBits+    <*> decodeWord32leBits+    <*> decodeWord32leBits+    <*> decodeWord32leBits+    <*> decodeWord32leBits+    <*> getBool
+ source/library/Rattletrap/Decode/UniqueIdAttribute.hs view
@@ -0,0 +1,16 @@+module Rattletrap.Decode.UniqueIdAttribute+  ( decodeUniqueIdAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.RemoteId+import Rattletrap.Decode.Word8le+import Rattletrap.Type.UniqueIdAttribute++decodeUniqueIdAttributeBits :: (Int, Int, Int) -> DecodeBits UniqueIdAttribute+decodeUniqueIdAttributeBits version = do+  systemId <- decodeWord8leBits+  UniqueIdAttribute systemId+    <$> decodeRemoteIdBits version systemId+    <*> decodeWord8leBits
+ source/library/Rattletrap/Decode/UpdatedReplication.hs view
@@ -0,0 +1,22 @@+module Rattletrap.Decode.UpdatedReplication+  ( decodeUpdatedReplicationBits+  )+where++import Rattletrap.Decode.Attribute+import Rattletrap.Decode.Common+import Rattletrap.Type.ClassAttributeMap+import Rattletrap.Type.CompressedWord+import Rattletrap.Type.UpdatedReplication+import Rattletrap.Type.Word32le++import qualified Data.Map as Map++decodeUpdatedReplicationBits+  :: (Int, Int, Int)+  -> ClassAttributeMap+  -> Map.Map CompressedWord Word32le+  -> CompressedWord+  -> DecodeBits UpdatedReplication+decodeUpdatedReplicationBits version classes actors actor =+  UpdatedReplication <$> decodeAttributesBits version classes actors actor
+ source/library/Rattletrap/Decode/Vector.hs view
@@ -0,0 +1,29 @@+module Rattletrap.Decode.Vector+  ( decodeVectorBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.CompressedWord+import Rattletrap.Type.CompressedWord+import Rattletrap.Type.Vector++decodeVectorBits :: (Int, Int, Int) -> DecodeBits Vector+decodeVectorBits version = do+  size <- decodeCompressedWordBits (if version >= (868, 22, 7) then 21 else 19)+  let+    limit = getLimit size+    bias = getBias size+  Vector size bias+    <$> fmap (fromDelta bias) (decodeCompressedWordBits limit)+    <*> fmap (fromDelta bias) (decodeCompressedWordBits limit)+    <*> fmap (fromDelta bias) (decodeCompressedWordBits limit)++getLimit :: CompressedWord -> Word+getLimit = (2 ^) . (+ 2) . compressedWordValue++getBias :: CompressedWord -> Word+getBias = (2 ^) . (+ 1) . compressedWordValue++fromDelta :: Word -> CompressedWord -> Int+fromDelta bias x = fromIntegral (compressedWordValue x) - fromIntegral bias
+ source/library/Rattletrap/Decode/WeldedInfoAttribute.hs view
@@ -0,0 +1,21 @@+module Rattletrap.Decode.WeldedInfoAttribute+  ( decodeWeldedInfoAttributeBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Decode.Float32le+import Rattletrap.Decode.Int32le+import Rattletrap.Decode.Int8Vector+import Rattletrap.Decode.Vector+import Rattletrap.Type.WeldedInfoAttribute++decodeWeldedInfoAttributeBits+  :: (Int, Int, Int) -> DecodeBits WeldedInfoAttribute+decodeWeldedInfoAttributeBits version =+  WeldedInfoAttribute+    <$> getBool+    <*> decodeInt32leBits+    <*> decodeVectorBits version+    <*> decodeFloat32leBits+    <*> decodeInt8VectorBits
+ source/library/Rattletrap/Decode/Word32le.hs view
@@ -0,0 +1,14 @@+module Rattletrap.Decode.Word32le+  ( decodeWord32le+  , decodeWord32leBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Type.Word32le++decodeWord32le :: Decode Word32le+decodeWord32le = Word32le <$> getWord32le++decodeWord32leBits :: DecodeBits Word32le+decodeWord32leBits = toBits decodeWord32le 4
+ source/library/Rattletrap/Decode/Word64le.hs view
@@ -0,0 +1,14 @@+module Rattletrap.Decode.Word64le+  ( decodeWord64le+  , decodeWord64leBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Type.Word64le++decodeWord64le :: Decode Word64le+decodeWord64le = Word64le <$> getWord64le++decodeWord64leBits :: DecodeBits Word64le+decodeWord64leBits = toBits decodeWord64le 8
+ source/library/Rattletrap/Decode/Word8le.hs view
@@ -0,0 +1,14 @@+module Rattletrap.Decode.Word8le+  ( decodeWord8le+  , decodeWord8leBits+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Type.Word8le++decodeWord8le :: Decode Word8le+decodeWord8le = Word8le <$> getWord8++decodeWord8leBits :: DecodeBits Word8le+decodeWord8leBits = toBits decodeWord8le 1
+ source/library/Rattletrap/Encode/AppliedDamageAttribute.hs view
@@ -0,0 +1,18 @@+module Rattletrap.Encode.AppliedDamageAttribute+  ( putAppliedDamageAttribute+  )+where++import Rattletrap.Encode.Int32le+import Rattletrap.Encode.Vector+import Rattletrap.Encode.Word8le+import Rattletrap.Type.AppliedDamageAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putAppliedDamageAttribute :: AppliedDamageAttribute -> BinaryBits.BitPut ()+putAppliedDamageAttribute appliedDamageAttribute = do+  putWord8Bits (appliedDamageAttributeUnknown1 appliedDamageAttribute)+  putVector (appliedDamageAttributeLocation appliedDamageAttribute)+  putInt32Bits (appliedDamageAttributeUnknown3 appliedDamageAttribute)+  putInt32Bits (appliedDamageAttributeUnknown4 appliedDamageAttribute)
+ source/library/Rattletrap/Encode/Attribute.hs view
@@ -0,0 +1,26 @@+module Rattletrap.Encode.Attribute+  ( putAttributes+  )+where++import Rattletrap.Encode.AttributeValue+import Rattletrap.Encode.CompressedWord+import Rattletrap.Type.Attribute++import qualified Data.Binary.Bits.Put as BinaryBits++putAttributes :: [Attribute] -> BinaryBits.BitPut ()+putAttributes attributes = case attributes of+  [] -> BinaryBits.putBool False+  [attribute] -> do+    putAttribute attribute+    BinaryBits.putBool False+  first : rest -> do+    putAttribute first+    putAttributes rest++putAttribute :: Attribute -> BinaryBits.BitPut ()+putAttribute attribute = do+  BinaryBits.putBool True+  putCompressedWord (attributeId attribute)+  putAttributeValue (attributeValue attribute)
+ source/library/Rattletrap/Encode/AttributeMapping.hs view
@@ -0,0 +1,14 @@+module Rattletrap.Encode.AttributeMapping+  ( putAttributeMapping+  )+where++import Rattletrap.Encode.Word32le+import Rattletrap.Type.AttributeMapping++import qualified Data.Binary as Binary++putAttributeMapping :: AttributeMapping -> Binary.Put+putAttributeMapping attributeMapping = do+  putWord32 (attributeMappingObjectId attributeMapping)+  putWord32 (attributeMappingStreamId attributeMapping)
+ source/library/Rattletrap/Encode/AttributeValue.hs view
@@ -0,0 +1,83 @@+module Rattletrap.Encode.AttributeValue+  ( putAttributeValue+  )+where++import Rattletrap.Encode.AppliedDamageAttribute+import Rattletrap.Encode.BooleanAttribute+import Rattletrap.Encode.ByteAttribute+import Rattletrap.Encode.CamSettingsAttribute+import Rattletrap.Encode.ClubColorsAttribute+import Rattletrap.Encode.DamageStateAttribute+import Rattletrap.Encode.DemolishAttribute+import Rattletrap.Encode.EnumAttribute+import Rattletrap.Encode.ExplosionAttribute+import Rattletrap.Encode.ExtendedExplosionAttribute+import Rattletrap.Encode.FlaggedIntAttribute+import Rattletrap.Encode.FlaggedByteAttribute+import Rattletrap.Encode.FloatAttribute+import Rattletrap.Encode.GameModeAttribute+import Rattletrap.Encode.Int64Attribute+import Rattletrap.Encode.IntAttribute+import Rattletrap.Encode.LoadoutAttribute+import Rattletrap.Encode.LoadoutOnlineAttribute+import Rattletrap.Encode.LoadoutsAttribute+import Rattletrap.Encode.LoadoutsOnlineAttribute+import Rattletrap.Encode.LocationAttribute+import Rattletrap.Encode.MusicStingerAttribute+import Rattletrap.Encode.PartyLeaderAttribute+import Rattletrap.Encode.PickupAttribute+import Rattletrap.Encode.PickupAttributeNew+import Rattletrap.Encode.PlayerHistoryKeyAttribute+import Rattletrap.Encode.PrivateMatchSettingsAttribute+import Rattletrap.Encode.QWordAttribute+import Rattletrap.Encode.ReservationAttribute+import Rattletrap.Encode.RigidBodyStateAttribute+import Rattletrap.Encode.StatEventAttribute+import Rattletrap.Encode.StringAttribute+import Rattletrap.Encode.TeamPaintAttribute+import Rattletrap.Encode.TitleAttribute+import Rattletrap.Encode.UniqueIdAttribute+import Rattletrap.Encode.WeldedInfoAttribute+import Rattletrap.Type.AttributeValue++import qualified Data.Binary.Bits.Put as BinaryBits++putAttributeValue :: AttributeValue -> BinaryBits.BitPut ()+putAttributeValue value = case value of+  AttributeValueAppliedDamage x -> putAppliedDamageAttribute x+  AttributeValueBoolean x -> putBooleanAttribute x+  AttributeValueByte x -> putByteAttribute x+  AttributeValueCamSettings x -> putCamSettingsAttribute x+  AttributeValueClubColors x -> putClubColorsAttribute x+  AttributeValueDamageState x -> putDamageStateAttribute x+  AttributeValueDemolish x -> putDemolishAttribute x+  AttributeValueEnum x -> putEnumAttribute x+  AttributeValueExplosion x -> putExplosionAttribute x+  AttributeValueExtendedExplosion x -> putExtendedExplosionAttribute x+  AttributeValueFlaggedInt x -> putFlaggedIntAttribute x+  AttributeValueFlaggedByte x -> putFlaggedByteAttribute x+  AttributeValueFloat x -> putFloatAttribute x+  AttributeValueGameMode x -> putGameModeAttribute x+  AttributeValueInt x -> putIntAttribute x+  AttributeValueInt64 x -> putInt64Attribute x+  AttributeValueLoadout x -> putLoadoutAttribute x+  AttributeValueLoadoutOnline x -> putLoadoutOnlineAttribute x+  AttributeValueLoadouts x -> putLoadoutsAttribute x+  AttributeValueLoadoutsOnline x -> putLoadoutsOnlineAttribute x+  AttributeValueLocation x -> putLocationAttribute x+  AttributeValueMusicStinger x -> putMusicStingerAttribute x+  AttributeValuePartyLeader x -> putPartyLeaderAttribute x+  AttributeValuePickup x -> putPickupAttribute x+  AttributeValuePickupNew x -> putPickupAttributeNew x+  AttributeValuePlayerHistoryKey x -> putPlayerHistoryKeyAttribute x+  AttributeValuePrivateMatchSettings x -> putPrivateMatchSettingsAttribute x+  AttributeValueQWord x -> putQWordAttribute x+  AttributeValueReservation x -> putReservationAttribute x+  AttributeValueRigidBodyState x -> putRigidBodyStateAttribute x+  AttributeValueStatEvent x -> putStatEventAttribute x+  AttributeValueString x -> putStringAttribute x+  AttributeValueTeamPaint x -> putTeamPaintAttribute x+  AttributeValueTitle x -> putTitleAttribute x+  AttributeValueUniqueId x -> putUniqueIdAttribute x+  AttributeValueWeldedInfo x -> putWeldedInfoAttribute x
+ source/library/Rattletrap/Encode/BooleanAttribute.hs view
@@ -0,0 +1,12 @@+module Rattletrap.Encode.BooleanAttribute+  ( putBooleanAttribute+  )+where++import Rattletrap.Type.BooleanAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putBooleanAttribute :: BooleanAttribute -> BinaryBits.BitPut ()+putBooleanAttribute booleanAttribute =+  BinaryBits.putBool (booleanAttributeValue booleanAttribute)
+ source/library/Rattletrap/Encode/ByteAttribute.hs view
@@ -0,0 +1,13 @@+module Rattletrap.Encode.ByteAttribute+  ( putByteAttribute+  )+where++import Rattletrap.Encode.Word8le+import Rattletrap.Type.ByteAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putByteAttribute :: ByteAttribute -> BinaryBits.BitPut ()+putByteAttribute byteAttribute =+  putWord8Bits (byteAttributeValue byteAttribute)
+ source/library/Rattletrap/Encode/Cache.hs view
@@ -0,0 +1,18 @@+module Rattletrap.Encode.Cache+  ( putCache+  )+where++import Rattletrap.Encode.AttributeMapping+import Rattletrap.Encode.List+import Rattletrap.Encode.Word32le+import Rattletrap.Type.Cache++import qualified Data.Binary as Binary++putCache :: Cache -> Binary.Put+putCache cache = do+  putWord32 (cacheClassId cache)+  putWord32 (cacheParentCacheId cache)+  putWord32 (cacheCacheId cache)+  putList putAttributeMapping (cacheAttributeMappings cache)
+ source/library/Rattletrap/Encode/CamSettingsAttribute.hs view
@@ -0,0 +1,21 @@+module Rattletrap.Encode.CamSettingsAttribute+  ( putCamSettingsAttribute+  )+where++import Rattletrap.Encode.Float32le+import Rattletrap.Type.CamSettingsAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putCamSettingsAttribute :: CamSettingsAttribute -> BinaryBits.BitPut ()+putCamSettingsAttribute camSettingsAttribute = do+  putFloat32Bits (camSettingsAttributeFov camSettingsAttribute)+  putFloat32Bits (camSettingsAttributeHeight camSettingsAttribute)+  putFloat32Bits (camSettingsAttributeAngle camSettingsAttribute)+  putFloat32Bits (camSettingsAttributeDistance camSettingsAttribute)+  putFloat32Bits (camSettingsAttributeStiffness camSettingsAttribute)+  putFloat32Bits (camSettingsAttributeSwivelSpeed camSettingsAttribute)+  case camSettingsAttributeTransitionSpeed camSettingsAttribute of+    Nothing -> pure ()+    Just transitionSpeed -> putFloat32Bits transitionSpeed
+ source/library/Rattletrap/Encode/ClassMapping.hs view
@@ -0,0 +1,15 @@+module Rattletrap.Encode.ClassMapping+  ( putClassMapping+  )+where++import Rattletrap.Encode.Str+import Rattletrap.Encode.Word32le+import Rattletrap.Type.ClassMapping++import qualified Data.Binary as Binary++putClassMapping :: ClassMapping -> Binary.Put+putClassMapping classMapping = do+  putText (classMappingName classMapping)+  putWord32 (classMappingStreamId classMapping)
+ source/library/Rattletrap/Encode/ClubColorsAttribute.hs view
@@ -0,0 +1,16 @@+module Rattletrap.Encode.ClubColorsAttribute+  ( putClubColorsAttribute+  )+where++import Rattletrap.Encode.Word8le+import Rattletrap.Type.ClubColorsAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putClubColorsAttribute :: ClubColorsAttribute -> BinaryBits.BitPut ()+putClubColorsAttribute clubColorsAttribute = do+  BinaryBits.putBool (clubColorsAttributeBlueFlag clubColorsAttribute)+  putWord8Bits (clubColorsAttributeBlueColor clubColorsAttribute)+  BinaryBits.putBool (clubColorsAttributeOrangeFlag clubColorsAttribute)+  putWord8Bits (clubColorsAttributeOrangeColor clubColorsAttribute)
+ source/library/Rattletrap/Encode/Common.hs view
@@ -0,0 +1,10 @@+module Rattletrap.Encode.Common+  ( putBitsLE+  )+where++import qualified Data.Binary.Bits.Put as BinaryBits+import qualified Data.Bits as Bits++putBitsLE :: Bits.Bits a => Int -> a -> BinaryBits.BitPut ()+putBitsLE size x = mapM_ (BinaryBits.putBool . Bits.testBit x) [0 .. size - 1]
+ source/library/Rattletrap/Encode/CompressedWord.hs view
@@ -0,0 +1,44 @@+module Rattletrap.Encode.CompressedWord+  ( putCompressedWord+  )+where++import Rattletrap.Type.CompressedWord++import qualified Data.Binary.Bits.Put as BinaryBits+import qualified Data.Bits as Bits++putCompressedWord :: CompressedWord -> BinaryBits.BitPut ()+putCompressedWord compressedWord =+  let+    limit = compressedWordLimit compressedWord+    value = compressedWordValue compressedWord+    maxBits = getMaxBits limit+  in putCompressedWordStep limit value maxBits 0 0++putCompressedWordStep+  :: Word -> Word -> Int -> Int -> Word -> BinaryBits.BitPut ()+putCompressedWordStep limit value maxBits position soFar =+  if position < maxBits+    then do+      let x = Bits.shiftL 1 position :: Word+      if maxBits > 1 && position == maxBits - 1 && soFar + x > limit+        then pure ()+        else do+          let bit = Bits.testBit value position+          BinaryBits.putBool bit+          let delta = if bit then x else 0+          putCompressedWordStep+            limit+            value+            maxBits+            (position + 1)+            (soFar + delta)+    else pure ()++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
+ source/library/Rattletrap/Encode/CompressedWordVector.hs view
@@ -0,0 +1,15 @@+module Rattletrap.Encode.CompressedWordVector+  ( putCompressedWordVector+  )+where++import Rattletrap.Encode.CompressedWord+import Rattletrap.Type.CompressedWordVector++import qualified Data.Binary.Bits.Put as BinaryBits++putCompressedWordVector :: CompressedWordVector -> BinaryBits.BitPut ()+putCompressedWordVector compressedWordVector = do+  putCompressedWord (compressedWordVectorX compressedWordVector)+  putCompressedWord (compressedWordVectorY compressedWordVector)+  putCompressedWord (compressedWordVectorZ compressedWordVector)
+ source/library/Rattletrap/Encode/Content.hs view
@@ -0,0 +1,43 @@+module Rattletrap.Encode.Content+  ( putContent+  )+where++import Rattletrap.Encode.Cache+import Rattletrap.Encode.ClassMapping+import Rattletrap.Encode.Frame+import Rattletrap.Encode.KeyFrame+import Rattletrap.Encode.List+import Rattletrap.Encode.Mark+import Rattletrap.Encode.Message+import Rattletrap.Encode.Str+import Rattletrap.Encode.Word32le+import Rattletrap.Type.Content+import Rattletrap.Type.Word32le+import Rattletrap.Utility.Bytes++import qualified Data.Binary as Binary+import qualified Data.Binary.Bits.Put as BinaryBits+import qualified Data.Binary.Put as Binary+import qualified Data.ByteString.Lazy as LazyBytes++putContent :: Content -> Binary.Put+putContent content = do+  putList putText (contentLevels content)+  putList putKeyFrame (contentKeyFrames content)+  let streamSize = contentStreamSize content+  putWord32 streamSize+  let+    stream = LazyBytes.toStrict+      (Binary.runPut (BinaryBits.runBitPut (putFrames (contentFrames content)))+      )+  Binary.putByteString+    (reverseBytes (padBytes (word32leValue streamSize) stream))+  putList putMessage (contentMessages content)+  putList putMark (contentMarks content)+  putList putText (contentPackages content)+  putList putText (contentObjects content)+  putList putText (contentNames content)+  putList putClassMapping (contentClassMappings content)+  putList putCache (contentCaches content)+  mapM_ Binary.putWord8 (contentUnknown content)
+ source/library/Rattletrap/Encode/DamageStateAttribute.hs view
@@ -0,0 +1,20 @@+module Rattletrap.Encode.DamageStateAttribute+  ( putDamageStateAttribute+  )+where++import Rattletrap.Encode.Int32le+import Rattletrap.Encode.Vector+import Rattletrap.Encode.Word8le+import Rattletrap.Type.DamageStateAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putDamageStateAttribute :: DamageStateAttribute -> BinaryBits.BitPut ()+putDamageStateAttribute damageStateAttribute = do+  putWord8Bits (damageStateAttributeUnknown1 damageStateAttribute)+  BinaryBits.putBool (damageStateAttributeUnknown2 damageStateAttribute)+  putInt32Bits (damageStateAttributeUnknown3 damageStateAttribute)+  putVector (damageStateAttributeUnknown4 damageStateAttribute)+  BinaryBits.putBool (damageStateAttributeUnknown5 damageStateAttribute)+  BinaryBits.putBool (damageStateAttributeUnknown6 damageStateAttribute)
+ source/library/Rattletrap/Encode/DemolishAttribute.hs view
@@ -0,0 +1,19 @@+module Rattletrap.Encode.DemolishAttribute+  ( putDemolishAttribute+  )+where++import Rattletrap.Encode.Vector+import Rattletrap.Encode.Word32le+import Rattletrap.Type.DemolishAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putDemolishAttribute :: DemolishAttribute -> BinaryBits.BitPut ()+putDemolishAttribute demolishAttribute = do+  BinaryBits.putBool (demolishAttributeAttackerFlag demolishAttribute)+  putWord32Bits (demolishAttributeAttackerActorId demolishAttribute)+  BinaryBits.putBool (demolishAttributeVictimFlag demolishAttribute)+  putWord32Bits (demolishAttributeVictimActorId demolishAttribute)+  putVector (demolishAttributeAttackerVelocity demolishAttribute)+  putVector (demolishAttributeVictimVelocity demolishAttribute)
+ source/library/Rattletrap/Encode/DestroyedReplication.hs view
@@ -0,0 +1,11 @@+module Rattletrap.Encode.DestroyedReplication+  ( putDestroyedReplication+  )+where++import Rattletrap.Type.DestroyedReplication++import qualified Data.Binary.Bits.Put as BinaryBits++putDestroyedReplication :: DestroyedReplication -> BinaryBits.BitPut ()+putDestroyedReplication _ = pure ()
+ source/library/Rattletrap/Encode/Dictionary.hs view
@@ -0,0 +1,17 @@+module Rattletrap.Encode.Dictionary+  ( putDictionary+  )+where++import Rattletrap.Encode.Str+import Rattletrap.Type.Dictionary++import qualified Data.Binary as Binary++putDictionary :: (a -> Binary.Put) -> Dictionary a -> Binary.Put+putDictionary f x = case x of+  DictionaryElement k v y -> do+    putText k+    f v+    putDictionary f y+  DictionaryEnd y -> putText y
+ source/library/Rattletrap/Encode/EnumAttribute.hs view
@@ -0,0 +1,13 @@+module Rattletrap.Encode.EnumAttribute+  ( putEnumAttribute+  )+where++import Rattletrap.Encode.Common+import Rattletrap.Type.EnumAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putEnumAttribute :: EnumAttribute -> BinaryBits.BitPut ()+putEnumAttribute enumAttribute =+  putBitsLE 11 (enumAttributeValue enumAttribute)
+ source/library/Rattletrap/Encode/ExplosionAttribute.hs view
@@ -0,0 +1,16 @@+module Rattletrap.Encode.ExplosionAttribute+  ( putExplosionAttribute+  )+where++import Rattletrap.Encode.Int32le+import Rattletrap.Encode.Vector+import Rattletrap.Type.ExplosionAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putExplosionAttribute :: ExplosionAttribute -> BinaryBits.BitPut ()+putExplosionAttribute explosionAttribute = do+  BinaryBits.putBool False+  putInt32Bits (explosionAttributeActorId explosionAttribute)+  putVector (explosionAttributeLocation explosionAttribute)
+ source/library/Rattletrap/Encode/ExtendedExplosionAttribute.hs view
@@ -0,0 +1,16 @@+module Rattletrap.Encode.ExtendedExplosionAttribute+  ( putExtendedExplosionAttribute+  )+where++import Rattletrap.Encode.ExplosionAttribute+import Rattletrap.Encode.FlaggedIntAttribute+import Rattletrap.Type.ExtendedExplosionAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putExtendedExplosionAttribute+  :: ExtendedExplosionAttribute -> BinaryBits.BitPut ()+putExtendedExplosionAttribute x = do+  putExplosionAttribute (extendedExplosionAttributeExplosion x)+  putFlaggedIntAttribute (extendedExplosionAttributeUnknown x)
+ source/library/Rattletrap/Encode/FlaggedByteAttribute.hs view
@@ -0,0 +1,14 @@+module Rattletrap.Encode.FlaggedByteAttribute+  ( putFlaggedByteAttribute+  )+where++import Rattletrap.Encode.Word8le+import Rattletrap.Type.FlaggedByteAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putFlaggedByteAttribute :: FlaggedByteAttribute -> BinaryBits.BitPut ()+putFlaggedByteAttribute flaggedByteAttribute = do+  BinaryBits.putBool (flaggedByteAttributeFlag flaggedByteAttribute)+  putWord8Bits (flaggedByteAttributeByte flaggedByteAttribute)
+ source/library/Rattletrap/Encode/FlaggedIntAttribute.hs view
@@ -0,0 +1,14 @@+module Rattletrap.Encode.FlaggedIntAttribute+  ( putFlaggedIntAttribute+  )+where++import Rattletrap.Encode.Int32le+import Rattletrap.Type.FlaggedIntAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putFlaggedIntAttribute :: FlaggedIntAttribute -> BinaryBits.BitPut ()+putFlaggedIntAttribute flaggedIntAttribute = do+  BinaryBits.putBool (flaggedIntAttributeFlag flaggedIntAttribute)+  putInt32Bits (flaggedIntAttributeInt flaggedIntAttribute)
+ source/library/Rattletrap/Encode/Float32le.hs view
@@ -0,0 +1,21 @@+module Rattletrap.Encode.Float32le+  ( putFloat32+  , putFloat32Bits+  )+where++import Rattletrap.Type.Float32le+import Rattletrap.Utility.Bytes++import qualified Data.Binary as Binary+import qualified Data.Binary.Bits.Put as BinaryBits+import qualified Data.Binary.Put as Binary+import qualified Data.ByteString.Lazy as LazyBytes++putFloat32 :: Float32le -> Binary.Put+putFloat32 = Binary.putFloatle . float32leValue++putFloat32Bits :: Float32le -> BinaryBits.BitPut ()+putFloat32Bits float32 = do+  let bytes = LazyBytes.toStrict (Binary.runPut (putFloat32 float32))+  BinaryBits.putByteString (reverseBytes bytes)
+ source/library/Rattletrap/Encode/FloatAttribute.hs view
@@ -0,0 +1,13 @@+module Rattletrap.Encode.FloatAttribute+  ( putFloatAttribute+  )+where++import Rattletrap.Encode.Float32le+import Rattletrap.Type.FloatAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putFloatAttribute :: FloatAttribute -> BinaryBits.BitPut ()+putFloatAttribute floatAttribute =+  putFloat32Bits (floatAttributeValue floatAttribute)
+ source/library/Rattletrap/Encode/Frame.hs view
@@ -0,0 +1,24 @@+module Rattletrap.Encode.Frame+  ( putFrames+  )+where++import Rattletrap.Encode.Float32le+import Rattletrap.Encode.Replication+import Rattletrap.Type.Frame++import qualified Data.Binary.Bits.Put as BinaryBits++putFrames :: [Frame] -> BinaryBits.BitPut ()+putFrames frames = case frames of+  [] -> pure ()+  [frame] -> putFrame frame+  first : rest -> do+    putFrame first+    putFrames rest++putFrame :: Frame -> BinaryBits.BitPut ()+putFrame frame = do+  putFloat32Bits (frameTime frame)+  putFloat32Bits (frameDelta frame)+  putReplications (frameReplications frame)
+ source/library/Rattletrap/Encode/GameModeAttribute.hs view
@@ -0,0 +1,14 @@+module Rattletrap.Encode.GameModeAttribute+  ( putGameModeAttribute+  )+where++import Rattletrap.Type.GameModeAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putGameModeAttribute :: GameModeAttribute -> BinaryBits.BitPut ()+putGameModeAttribute gameModeAttribute = do+  let numBits = gameModeAttributeNumBits gameModeAttribute+  let word = gameModeAttributeWord gameModeAttribute+  BinaryBits.putWord8 numBits word
+ source/library/Rattletrap/Encode/Header.hs view
@@ -0,0 +1,22 @@+module Rattletrap.Encode.Header+  ( putHeader+  )+where++import Rattletrap.Encode.Dictionary+import Rattletrap.Encode.Property+import Rattletrap.Encode.Str+import Rattletrap.Encode.Word32le+import Rattletrap.Type.Header++import qualified Data.Binary as Binary++putHeader :: Header -> Binary.Put+putHeader header = do+  putWord32 (headerEngineVersion header)+  putWord32 (headerLicenseeVersion header)+  case headerPatchVersion header of+    Nothing -> pure ()+    Just patchVersion -> putWord32 patchVersion+  putText (headerLabel header)+  putDictionary putProperty (headerProperties header)
+ source/library/Rattletrap/Encode/Initialization.hs view
@@ -0,0 +1,19 @@+module Rattletrap.Encode.Initialization+  ( putInitialization+  )+where++import Rattletrap.Encode.Int8Vector+import Rattletrap.Encode.Vector+import Rattletrap.Type.Initialization++import qualified Data.Binary.Bits.Put as BinaryBits++putInitialization :: Initialization -> BinaryBits.BitPut ()+putInitialization initialization = do+  case initializationLocation initialization of+    Nothing -> pure ()+    Just location -> putVector location+  case initializationRotation initialization of+    Nothing -> pure ()+    Just rotation -> putInt8Vector rotation
+ source/library/Rattletrap/Encode/Int32le.hs view
@@ -0,0 +1,21 @@+module Rattletrap.Encode.Int32le+  ( putInt32+  , putInt32Bits+  )+where++import Rattletrap.Type.Int32le+import Rattletrap.Utility.Bytes++import qualified Data.Binary as Binary+import qualified Data.Binary.Bits.Put as BinaryBits+import qualified Data.Binary.Put as Binary+import qualified Data.ByteString.Lazy as LazyBytes++putInt32 :: Int32le -> Binary.Put+putInt32 int32 = Binary.putInt32le (int32leValue int32)++putInt32Bits :: Int32le -> BinaryBits.BitPut ()+putInt32Bits int32 = do+  let bytes = LazyBytes.toStrict (Binary.runPut (putInt32 int32))+  BinaryBits.putByteString (reverseBytes bytes)
+ source/library/Rattletrap/Encode/Int64Attribute.hs view
@@ -0,0 +1,13 @@+module Rattletrap.Encode.Int64Attribute+  ( putInt64Attribute+  )+where++import Rattletrap.Encode.Int64le+import Rattletrap.Type.Int64Attribute++import qualified Data.Binary.Bits.Put as BinaryBits++putInt64Attribute :: Int64Attribute -> BinaryBits.BitPut ()+putInt64Attribute int64Attribute =+  putInt64Bits (int64AttributeValue int64Attribute)
+ source/library/Rattletrap/Encode/Int64le.hs view
@@ -0,0 +1,20 @@+module Rattletrap.Encode.Int64le+  ( putInt64Bits+  )+where++import Rattletrap.Type.Int64le+import Rattletrap.Utility.Bytes++import qualified Data.Binary as Binary+import qualified Data.Binary.Bits.Put as BinaryBits+import qualified Data.Binary.Put as Binary+import qualified Data.ByteString.Lazy as LazyBytes++putInt64 :: Int64le -> Binary.Put+putInt64 int64 = Binary.putInt64le (int64leValue int64)++putInt64Bits :: Int64le -> BinaryBits.BitPut ()+putInt64Bits int64 = do+  let bytes = LazyBytes.toStrict (Binary.runPut (putInt64 int64))+  BinaryBits.putByteString (reverseBytes bytes)
+ source/library/Rattletrap/Encode/Int8Vector.hs view
@@ -0,0 +1,23 @@+module Rattletrap.Encode.Int8Vector+  ( putInt8Vector+  )+where++import Rattletrap.Encode.Int8le+import Rattletrap.Type.Int8Vector+import Rattletrap.Type.Int8le++import qualified Data.Binary.Bits.Put as BinaryBits++putInt8Vector :: Int8Vector -> BinaryBits.BitPut ()+putInt8Vector int8Vector = do+  putInt8VectorField (int8VectorX int8Vector)+  putInt8VectorField (int8VectorY int8Vector)+  putInt8VectorField (int8VectorZ int8Vector)++putInt8VectorField :: Maybe Int8le -> BinaryBits.BitPut ()+putInt8VectorField maybeField = case maybeField of+  Nothing -> BinaryBits.putBool False+  Just field -> do+    BinaryBits.putBool True+    putInt8Bits field
+ source/library/Rattletrap/Encode/Int8le.hs view
@@ -0,0 +1,19 @@+module Rattletrap.Encode.Int8le+  ( putInt8Bits+  )+where++import Rattletrap.Type.Int8le+import Rattletrap.Utility.Bytes++import qualified Data.Binary.Bits.Put as BinaryBits+import qualified Data.Binary.Put as Binary+import qualified Data.ByteString.Lazy as LazyBytes++putInt8 :: Int8le -> Binary.Put+putInt8 int8 = Binary.putInt8 (int8leValue int8)++putInt8Bits :: Int8le -> BinaryBits.BitPut ()+putInt8Bits int8 = do+  let bytes = LazyBytes.toStrict (Binary.runPut (putInt8 int8))+  BinaryBits.putByteString (reverseBytes bytes)
+ source/library/Rattletrap/Encode/IntAttribute.hs view
@@ -0,0 +1,12 @@+module Rattletrap.Encode.IntAttribute+  ( putIntAttribute+  )+where++import Rattletrap.Encode.Int32le+import Rattletrap.Type.IntAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putIntAttribute :: IntAttribute -> BinaryBits.BitPut ()+putIntAttribute intAttribute = putInt32Bits (intAttributeValue intAttribute)
+ source/library/Rattletrap/Encode/KeyFrame.hs view
@@ -0,0 +1,16 @@+module Rattletrap.Encode.KeyFrame+  ( putKeyFrame+  )+where++import Rattletrap.Encode.Float32le+import Rattletrap.Encode.Word32le+import Rattletrap.Type.KeyFrame++import qualified Data.Binary as Binary++putKeyFrame :: KeyFrame -> Binary.Put+putKeyFrame keyFrame = do+  putFloat32 (keyFrameTime keyFrame)+  putWord32 (keyFrameFrame keyFrame)+  putWord32 (keyFramePosition keyFrame)
+ source/library/Rattletrap/Encode/List.hs view
@@ -0,0 +1,16 @@+module Rattletrap.Encode.List+  ( putList+  )+where++import Rattletrap.Encode.Word32le+import Rattletrap.Type.List+import Rattletrap.Type.Word32le++import qualified Data.Binary as Binary++putList :: (a -> Binary.Put) -> List a -> Binary.Put+putList putElement list = do+  let elements = listValue list+  putWord32 (Word32le (fromIntegral (length elements)))+  mapM_ putElement elements
+ source/library/Rattletrap/Encode/LoadoutAttribute.hs view
@@ -0,0 +1,35 @@+module Rattletrap.Encode.LoadoutAttribute+  ( putLoadoutAttribute+  )+where++import Rattletrap.Encode.Word32le+import Rattletrap.Encode.Word8le+import Rattletrap.Type.LoadoutAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putLoadoutAttribute :: LoadoutAttribute -> BinaryBits.BitPut ()+putLoadoutAttribute loadoutAttribute = do+  putWord8Bits (loadoutAttributeVersion loadoutAttribute)+  putWord32Bits (loadoutAttributeBody loadoutAttribute)+  putWord32Bits (loadoutAttributeDecal loadoutAttribute)+  putWord32Bits (loadoutAttributeWheels loadoutAttribute)+  putWord32Bits (loadoutAttributeRocketTrail loadoutAttribute)+  putWord32Bits (loadoutAttributeAntenna loadoutAttribute)+  putWord32Bits (loadoutAttributeTopper loadoutAttribute)+  putWord32Bits (loadoutAttributeUnknown1 loadoutAttribute)+  putOptional (loadoutAttributeUnknown2 loadoutAttribute) putWord32Bits+  putOptional (loadoutAttributeEngineAudio loadoutAttribute) putWord32Bits+  putOptional (loadoutAttributeTrail loadoutAttribute) putWord32Bits+  putOptional (loadoutAttributeGoalExplosion loadoutAttribute) putWord32Bits+  putOptional (loadoutAttributeBanner loadoutAttribute) putWord32Bits+  putOptional (loadoutAttributeUnknown3 loadoutAttribute) putWord32Bits+  putOptional (loadoutAttributeUnknown4 loadoutAttribute) putWord32Bits+  putOptional (loadoutAttributeUnknown5 loadoutAttribute) putWord32Bits+  putOptional (loadoutAttributeUnknown6 loadoutAttribute) putWord32Bits++putOptional :: Maybe a -> (a -> BinaryBits.BitPut ()) -> BinaryBits.BitPut ()+putOptional m f = case m of+  Just x -> f x+  Nothing -> pure ()
+ source/library/Rattletrap/Encode/LoadoutOnlineAttribute.hs view
@@ -0,0 +1,17 @@+module Rattletrap.Encode.LoadoutOnlineAttribute+  ( putLoadoutOnlineAttribute+  )+where++import Rattletrap.Encode.ProductAttribute+import Rattletrap.Encode.Word8le+import Rattletrap.Type.LoadoutOnlineAttribute+import Rattletrap.Type.Word8le++import qualified Data.Binary.Bits.Put as BinaryBits++putLoadoutOnlineAttribute :: LoadoutOnlineAttribute -> BinaryBits.BitPut ()+putLoadoutOnlineAttribute loadoutAttribute = do+  let attributes = loadoutAttributeValue loadoutAttribute+  putWord8Bits (Word8le (fromIntegral (length attributes)))+  mapM_ putProductAttributes attributes
+ source/library/Rattletrap/Encode/LoadoutsAttribute.hs view
@@ -0,0 +1,14 @@+module Rattletrap.Encode.LoadoutsAttribute+  ( putLoadoutsAttribute+  )+where++import Rattletrap.Encode.LoadoutAttribute+import Rattletrap.Type.LoadoutsAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putLoadoutsAttribute :: LoadoutsAttribute -> BinaryBits.BitPut ()+putLoadoutsAttribute loadoutsAttribute = do+  putLoadoutAttribute (loadoutsAttributeBlue loadoutsAttribute)+  putLoadoutAttribute (loadoutsAttributeOrange loadoutsAttribute)
+ source/library/Rattletrap/Encode/LoadoutsOnlineAttribute.hs view
@@ -0,0 +1,18 @@+module Rattletrap.Encode.LoadoutsOnlineAttribute+  ( putLoadoutsOnlineAttribute+  )+where++import Rattletrap.Encode.LoadoutOnlineAttribute+import Rattletrap.Type.LoadoutsOnlineAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putLoadoutsOnlineAttribute :: LoadoutsOnlineAttribute -> BinaryBits.BitPut ()+putLoadoutsOnlineAttribute loadoutsOnlineAttribute = do+  putLoadoutOnlineAttribute+    (loadoutsOnlineAttributeBlue loadoutsOnlineAttribute)+  putLoadoutOnlineAttribute+    (loadoutsOnlineAttributeOrange loadoutsOnlineAttribute)+  BinaryBits.putBool (loadoutsOnlineAttributeUnknown1 loadoutsOnlineAttribute)+  BinaryBits.putBool (loadoutsOnlineAttributeUnknown2 loadoutsOnlineAttribute)
+ source/library/Rattletrap/Encode/LocationAttribute.hs view
@@ -0,0 +1,13 @@+module Rattletrap.Encode.LocationAttribute+  ( putLocationAttribute+  )+where++import Rattletrap.Encode.Vector+import Rattletrap.Type.LocationAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putLocationAttribute :: LocationAttribute -> BinaryBits.BitPut ()+putLocationAttribute locationAttribute =+  putVector (locationAttributeValue locationAttribute)
+ source/library/Rattletrap/Encode/Mark.hs view
@@ -0,0 +1,15 @@+module Rattletrap.Encode.Mark+  ( putMark+  )+where++import Rattletrap.Encode.Str+import Rattletrap.Encode.Word32le+import Rattletrap.Type.Mark++import qualified Data.Binary as Binary++putMark :: Mark -> Binary.Put+putMark mark = do+  putText (markValue mark)+  putWord32 (markFrame mark)
+ source/library/Rattletrap/Encode/Message.hs view
@@ -0,0 +1,16 @@+module Rattletrap.Encode.Message+  ( putMessage+  )+where++import Rattletrap.Encode.Str+import Rattletrap.Encode.Word32le+import Rattletrap.Type.Message++import qualified Data.Binary as Binary++putMessage :: Message -> Binary.Put+putMessage message = do+  putWord32 (messageFrame message)+  putText (messageName message)+  putText (messageValue message)
+ source/library/Rattletrap/Encode/MusicStingerAttribute.hs view
@@ -0,0 +1,16 @@+module Rattletrap.Encode.MusicStingerAttribute+  ( putMusicStingerAttribute+  )+where++import Rattletrap.Encode.Word32le+import Rattletrap.Encode.Word8le+import Rattletrap.Type.MusicStingerAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putMusicStingerAttribute :: MusicStingerAttribute -> BinaryBits.BitPut ()+putMusicStingerAttribute musicStingerAttribute = do+  BinaryBits.putBool (musicStingerAttributeFlag musicStingerAttribute)+  putWord32Bits (musicStingerAttributeCue musicStingerAttribute)+  putWord8Bits (musicStingerAttributeTrigger musicStingerAttribute)
+ source/library/Rattletrap/Encode/PartyLeaderAttribute.hs view
@@ -0,0 +1,19 @@+module Rattletrap.Encode.PartyLeaderAttribute+  ( putPartyLeaderAttribute+  )+where++import Rattletrap.Encode.RemoteId+import Rattletrap.Encode.Word8le+import Rattletrap.Type.PartyLeaderAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putPartyLeaderAttribute :: PartyLeaderAttribute -> BinaryBits.BitPut ()+putPartyLeaderAttribute partyLeaderAttribute = do+  putWord8Bits (partyLeaderAttributeSystemId partyLeaderAttribute)+  case partyLeaderAttributeId partyLeaderAttribute of+    Nothing -> pure ()+    Just (remoteId, localId) -> do+      putRemoteId remoteId+      putWord8Bits localId
+ source/library/Rattletrap/Encode/PickupAttribute.hs view
@@ -0,0 +1,18 @@+module Rattletrap.Encode.PickupAttribute+  ( putPickupAttribute+  )+where++import Rattletrap.Encode.Word32le+import Rattletrap.Type.PickupAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putPickupAttribute :: PickupAttribute -> BinaryBits.BitPut ()+putPickupAttribute pickupAttribute = do+  case pickupAttributeInstigatorId pickupAttribute of+    Nothing -> BinaryBits.putBool False+    Just instigatorId -> do+      BinaryBits.putBool True+      putWord32Bits instigatorId+  BinaryBits.putBool (pickupAttributePickedUp pickupAttribute)
+ source/library/Rattletrap/Encode/PickupAttributeNew.hs view
@@ -0,0 +1,19 @@+module Rattletrap.Encode.PickupAttributeNew+  ( putPickupAttributeNew+  )+where++import Rattletrap.Encode.Word32le+import Rattletrap.Encode.Word8le+import Rattletrap.Type.PickupAttributeNew++import qualified Data.Binary.Bits.Put as BinaryBits++putPickupAttributeNew :: PickupAttributeNew -> BinaryBits.BitPut ()+putPickupAttributeNew pickupAttributeNew = do+  case pickupAttributeNewInstigatorId pickupAttributeNew of+    Nothing -> BinaryBits.putBool False+    Just instigatorId -> do+      BinaryBits.putBool True+      putWord32Bits instigatorId+  putWord8Bits (pickupAttributeNewPickedUp pickupAttributeNew)
+ source/library/Rattletrap/Encode/PlayerHistoryKeyAttribute.hs view
@@ -0,0 +1,13 @@+module Rattletrap.Encode.PlayerHistoryKeyAttribute+  ( putPlayerHistoryKeyAttribute+  )+where++import Rattletrap.Encode.Common+import Rattletrap.Type.PlayerHistoryKeyAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putPlayerHistoryKeyAttribute+  :: PlayerHistoryKeyAttribute -> BinaryBits.BitPut ()+putPlayerHistoryKeyAttribute = putBitsLE 14 . playerHistoryKeyAttributeUnknown
+ source/library/Rattletrap/Encode/PrivateMatchSettingsAttribute.hs view
@@ -0,0 +1,26 @@+module Rattletrap.Encode.PrivateMatchSettingsAttribute+  ( putPrivateMatchSettingsAttribute+  )+where++import Rattletrap.Encode.Str+import Rattletrap.Encode.Word32le+import Rattletrap.Type.PrivateMatchSettingsAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putPrivateMatchSettingsAttribute+  :: PrivateMatchSettingsAttribute -> BinaryBits.BitPut ()+putPrivateMatchSettingsAttribute privateMatchSettingsAttribute = do+  putTextBits+    (privateMatchSettingsAttributeMutators privateMatchSettingsAttribute)+  putWord32Bits+    (privateMatchSettingsAttributeJoinableBy privateMatchSettingsAttribute)+  putWord32Bits+    (privateMatchSettingsAttributeMaxPlayers privateMatchSettingsAttribute)+  putTextBits+    (privateMatchSettingsAttributeGameName privateMatchSettingsAttribute)+  putTextBits+    (privateMatchSettingsAttributePassword privateMatchSettingsAttribute)+  BinaryBits.putBool+    (privateMatchSettingsAttributeFlag privateMatchSettingsAttribute)
+ source/library/Rattletrap/Encode/ProductAttribute.hs view
@@ -0,0 +1,37 @@+module Rattletrap.Encode.ProductAttribute+  ( putProductAttributes+  )+where++import Rattletrap.Encode.Common+import Rattletrap.Encode.CompressedWord+import Rattletrap.Encode.Word32le+import Rattletrap.Encode.Word8le+import Rattletrap.Encode.Str+import Rattletrap.Type.ProductAttribute+import Rattletrap.Type.Word8le++import qualified Data.Binary.Bits.Put as BinaryBits++putProductAttributes :: [ProductAttribute] -> BinaryBits.BitPut ()+putProductAttributes attributes = do+  putWord8Bits (Word8le (fromIntegral (length attributes)))+  mapM_ putProductAttribute attributes++putProductAttribute :: ProductAttribute -> BinaryBits.BitPut ()+putProductAttribute attribute = do+  BinaryBits.putBool (productAttributeUnknown attribute)+  putWord32Bits (productAttributeObjectId attribute)+  case productAttributeValue attribute of+    ProductAttributeValuePaintedOld x -> putCompressedWord x+    ProductAttributeValuePaintedNew x -> putBitsLE 31 x+    ProductAttributeValueTeamEditionOld x -> putCompressedWord x+    ProductAttributeValueTeamEditionNew x -> putBitsLE 31 x+    ProductAttributeValueSpecialEdition x -> putBitsLE 31 x+    ProductAttributeValueUserColorOld x -> case x of+      Nothing -> BinaryBits.putBool False+      Just y -> do+        BinaryBits.putBool True+        putBitsLE 31 y+    ProductAttributeValueUserColorNew x -> putWord32Bits x+    ProductAttributeValueTitleId x -> putTextBits x
+ source/library/Rattletrap/Encode/Property.hs view
@@ -0,0 +1,17 @@+module Rattletrap.Encode.Property+  ( putProperty+  )+where++import Rattletrap.Encode.PropertyValue+import Rattletrap.Encode.Str+import Rattletrap.Encode.Word64le+import Rattletrap.Type.Property++import qualified Data.Binary as Binary++putProperty :: Property -> Binary.Put+putProperty property = do+  putText (propertyKind property)+  putWord64 (propertySize property)+  putPropertyValue putProperty (propertyValue property)
+ source/library/Rattletrap/Encode/PropertyValue.hs view
@@ -0,0 +1,30 @@+module Rattletrap.Encode.PropertyValue+  ( putPropertyValue+  )+where++import Rattletrap.Encode.Dictionary+import Rattletrap.Encode.Float32le+import Rattletrap.Encode.Int32le+import Rattletrap.Encode.List+import Rattletrap.Encode.Str+import Rattletrap.Encode.Word64le+import Rattletrap.Encode.Word8le+import Rattletrap.Type.PropertyValue++import qualified Data.Binary as Binary++putPropertyValue :: (a -> Binary.Put) -> PropertyValue a -> Binary.Put+putPropertyValue putProperty value = case value of+  PropertyValueArray list -> putList (putDictionary putProperty) list+  PropertyValueBool word8 -> putWord8 word8+  PropertyValueByte k mv -> do+    putText k+    case mv of+      Nothing -> pure ()+      Just v -> putText v+  PropertyValueFloat float32 -> putFloat32 float32+  PropertyValueInt int32 -> putInt32 int32+  PropertyValueName text -> putText text+  PropertyValueQWord word64 -> putWord64 word64+  PropertyValueStr text -> putText text
+ source/library/Rattletrap/Encode/QWordAttribute.hs view
@@ -0,0 +1,13 @@+module Rattletrap.Encode.QWordAttribute+  ( putQWordAttribute+  )+where++import Rattletrap.Encode.Word64le+import Rattletrap.Type.QWordAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putQWordAttribute :: QWordAttribute -> BinaryBits.BitPut ()+putQWordAttribute qWordAttribute =+  putWord64Bits (qWordAttributeValue qWordAttribute)
+ source/library/Rattletrap/Encode/Quaternion.hs view
@@ -0,0 +1,41 @@+module Rattletrap.Encode.Quaternion+  ( putQuaternion+  )+where++import Rattletrap.Encode.CompressedWord+import Rattletrap.Type.CompressedWord+import Rattletrap.Type.Quaternion++import qualified Data.Binary.Bits.Put as BinaryBits++putQuaternion :: Quaternion -> BinaryBits.BitPut ()+putQuaternion q = do+  let c = maxComponent q+  putComponent c+  case c of+    ComponentX -> putParts (quaternionY q) (quaternionZ q) (quaternionW q)+    ComponentY -> putParts (quaternionX q) (quaternionZ q) (quaternionW q)+    ComponentZ -> putParts (quaternionX q) (quaternionY q) (quaternionW q)+    ComponentW -> putParts (quaternionX q) (quaternionY q) (quaternionZ q)++putComponent :: Component -> BinaryBits.BitPut ()+putComponent component = putCompressedWord+  (CompressedWord+    3+    (case component of+      ComponentX -> 0+      ComponentY -> 1+      ComponentZ -> 2+      ComponentW -> 3+    )+  )++putParts :: Double -> Double -> Double -> BinaryBits.BitPut ()+putParts a b c = do+  putPart a+  putPart b+  putPart c++putPart :: Double -> BinaryBits.BitPut ()+putPart = putCompressedWord . compressPart
+ source/library/Rattletrap/Encode/RemoteId.hs view
@@ -0,0 +1,35 @@+module Rattletrap.Encode.RemoteId+  ( putRemoteId+  )+where++import Rattletrap.Encode.Common+import Rattletrap.Encode.Word64le+import Rattletrap.Type.RemoteId+import Rattletrap.Type.Word64le+import Rattletrap.Utility.Bytes++import qualified Data.Binary.Bits.Put as BinaryBits+import qualified Data.ByteString as Bytes++putRemoteId :: RemoteId -> BinaryBits.BitPut ()+putRemoteId remoteId = case remoteId of+  RemoteIdPlayStation name bytes -> do+    let rawName = reverseBytes (padBytes (16 :: Int) (encodeLatin1 name))+    BinaryBits.putByteString rawName+    BinaryBits.putByteString (Bytes.pack bytes)+  RemoteIdPsyNet e -> case e of+    Left l -> putWord64Bits l+    Right (a, b, c, d) -> putWord256 a b c d+  RemoteIdSplitscreen word24 -> putBitsLE 24 word24+  RemoteIdSteam word64 -> putWord64Bits word64+  RemoteIdSwitch a b c d -> putWord256 a b c d+  RemoteIdXbox word64 -> putWord64Bits word64++putWord256+  :: Word64le -> Word64le -> Word64le -> Word64le -> BinaryBits.BitPut ()+putWord256 a b c d = do+  putWord64Bits a+  putWord64Bits b+  putWord64Bits c+  putWord64Bits d
+ source/library/Rattletrap/Encode/Replay.hs view
@@ -0,0 +1,21 @@+module Rattletrap.Encode.Replay+  ( putReplay+  )+where++import Rattletrap.Encode.Content+import Rattletrap.Encode.Header+import Rattletrap.Encode.Section+import Rattletrap.Type.Replay++import qualified Data.Binary as Binary++-- | Generates a raw replay. Use this with 'Data.Binary.Put.runPut'.+--+-- @+-- let bytes = 'Data.Binary.Put.runPut' ('putReplay' replay)+-- @+putReplay :: Replay -> Binary.Put+putReplay replay = do+  putSection putHeader (replayHeader replay)+  putSection putContent (replayContent replay)
+ source/library/Rattletrap/Encode/Replication.hs view
@@ -0,0 +1,26 @@+module Rattletrap.Encode.Replication+  ( putReplications+  )+where++import Rattletrap.Encode.CompressedWord+import Rattletrap.Encode.ReplicationValue+import Rattletrap.Type.Replication++import qualified Data.Binary.Bits.Put as BinaryBits++putReplications :: [Replication] -> BinaryBits.BitPut ()+putReplications replications = case replications of+  [] -> BinaryBits.putBool False+  [replication] -> do+    putReplication replication+    BinaryBits.putBool False+  first : rest -> do+    putReplication first+    putReplications rest++putReplication :: Replication -> BinaryBits.BitPut ()+putReplication replication = do+  BinaryBits.putBool True+  putCompressedWord (replicationActorId replication)+  putReplicationValue (replicationValue replication)
+ source/library/Rattletrap/Encode/ReplicationValue.hs view
@@ -0,0 +1,25 @@+module Rattletrap.Encode.ReplicationValue+  ( putReplicationValue+  )+where++import Rattletrap.Encode.DestroyedReplication+import Rattletrap.Encode.SpawnedReplication+import Rattletrap.Encode.UpdatedReplication+import Rattletrap.Type.ReplicationValue++import qualified Data.Binary.Bits.Put as BinaryBits++putReplicationValue :: ReplicationValue -> BinaryBits.BitPut ()+putReplicationValue value = case value of+  ReplicationValueSpawned x -> do+    BinaryBits.putBool True+    BinaryBits.putBool True+    putSpawnedReplication x+  ReplicationValueUpdated x -> do+    BinaryBits.putBool True+    BinaryBits.putBool False+    putUpdatedReplication x+  ReplicationValueDestroyed x -> do+    BinaryBits.putBool False+    putDestroyedReplication x
+ source/library/Rattletrap/Encode/ReservationAttribute.hs view
@@ -0,0 +1,24 @@+module Rattletrap.Encode.ReservationAttribute+  ( putReservationAttribute+  )+where++import Rattletrap.Encode.CompressedWord+import Rattletrap.Encode.Str+import Rattletrap.Encode.UniqueIdAttribute+import Rattletrap.Type.ReservationAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putReservationAttribute :: ReservationAttribute -> BinaryBits.BitPut ()+putReservationAttribute reservationAttribute = do+  putCompressedWord (reservationAttributeNumber reservationAttribute)+  putUniqueIdAttribute (reservationAttributeUniqueId reservationAttribute)+  case reservationAttributeName reservationAttribute of+    Nothing -> pure ()+    Just name -> putTextBits name+  BinaryBits.putBool (reservationAttributeUnknown1 reservationAttribute)+  BinaryBits.putBool (reservationAttributeUnknown2 reservationAttribute)+  case reservationAttributeUnknown3 reservationAttribute of+    Nothing -> pure ()+    Just c -> BinaryBits.putWord8 6 c
+ source/library/Rattletrap/Encode/RigidBodyStateAttribute.hs view
@@ -0,0 +1,22 @@+module Rattletrap.Encode.RigidBodyStateAttribute+  ( putRigidBodyStateAttribute+  )+where++import Rattletrap.Encode.Rotation+import Rattletrap.Encode.Vector+import Rattletrap.Type.RigidBodyStateAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putRigidBodyStateAttribute :: RigidBodyStateAttribute -> BinaryBits.BitPut ()+putRigidBodyStateAttribute rigidBodyStateAttribute = do+  BinaryBits.putBool (rigidBodyStateAttributeSleeping rigidBodyStateAttribute)+  putVector (rigidBodyStateAttributeLocation rigidBodyStateAttribute)+  putRotation (rigidBodyStateAttributeRotation rigidBodyStateAttribute)+  case rigidBodyStateAttributeLinearVelocity rigidBodyStateAttribute of+    Nothing -> pure ()+    Just linearVelocity -> putVector linearVelocity+  case rigidBodyStateAttributeAngularVelocity rigidBodyStateAttribute of+    Nothing -> pure ()+    Just angularVelocity -> putVector angularVelocity
+ source/library/Rattletrap/Encode/Rotation.hs view
@@ -0,0 +1,15 @@+module Rattletrap.Encode.Rotation+  ( putRotation+  )+where++import Rattletrap.Encode.CompressedWordVector+import Rattletrap.Encode.Quaternion+import Rattletrap.Type.Rotation++import qualified Data.Binary.Bits.Put as BinaryBits++putRotation :: Rotation -> BinaryBits.BitPut ()+putRotation r = case r of+  RotationCompressedWordVector cwv -> putCompressedWordVector cwv+  RotationQuaternion q -> putQuaternion q
+ source/library/Rattletrap/Encode/Section.hs view
@@ -0,0 +1,31 @@+module Rattletrap.Encode.Section+  ( putSection+  )+where++import Rattletrap.Encode.Word32le+import Rattletrap.Type.Section+import Rattletrap.Type.Word32le+import Rattletrap.Utility.Crc++import qualified Data.Binary as Binary+import qualified Data.Binary.Put as Binary+import qualified Data.ByteString as Bytes+import qualified Data.ByteString.Lazy as LazyBytes++-- | Given a way to put the 'sectionBody', puts a section. This will also put+-- the size and CRC.+--+-- @+-- let bytes = 'Data.Binary.Put.runPut' ('putSection' 'Rattletrap.Content.putContent' content)+-- @+putSection :: (a -> Binary.Put) -> Section a -> Binary.Put+putSection putBody section = do+  let+    rawBody =+      LazyBytes.toStrict (Binary.runPut (putBody (sectionBody section)))+  let size = Bytes.length rawBody+  let crc = getCrc32 rawBody+  putWord32 (Word32le (fromIntegral size))+  putWord32 (Word32le crc)+  Binary.putByteString rawBody
+ source/library/Rattletrap/Encode/SpawnedReplication.hs view
@@ -0,0 +1,19 @@+module Rattletrap.Encode.SpawnedReplication+  ( putSpawnedReplication+  )+where++import Rattletrap.Encode.Initialization+import Rattletrap.Encode.Word32le+import Rattletrap.Type.SpawnedReplication++import qualified Data.Binary.Bits.Put as BinaryBits++putSpawnedReplication :: SpawnedReplication -> BinaryBits.BitPut ()+putSpawnedReplication spawnedReplication = do+  BinaryBits.putBool (spawnedReplicationFlag spawnedReplication)+  case spawnedReplicationNameIndex spawnedReplication of+    Nothing -> pure ()+    Just nameIndex -> putWord32Bits nameIndex+  putWord32Bits (spawnedReplicationObjectId spawnedReplication)+  putInitialization (spawnedReplicationInitialization spawnedReplication)
+ source/library/Rattletrap/Encode/StatEventAttribute.hs view
@@ -0,0 +1,14 @@+module Rattletrap.Encode.StatEventAttribute+  ( putStatEventAttribute+  )+where++import Rattletrap.Encode.Int32le+import Rattletrap.Type.StatEventAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putStatEventAttribute :: StatEventAttribute -> BinaryBits.BitPut ()+putStatEventAttribute statEventAttribute = do+  BinaryBits.putBool (statEventAttributeUnknown statEventAttribute)+  putInt32Bits (statEventAttributeObjectId statEventAttribute)
+ source/library/Rattletrap/Encode/Str.hs view
@@ -0,0 +1,53 @@+module Rattletrap.Encode.Str+  ( putText+  , putTextBits+  )+where++import Rattletrap.Encode.Int32le+import Rattletrap.Type.Common+import Rattletrap.Type.Int32le+import Rattletrap.Type.Str+import Rattletrap.Utility.Bytes++import qualified Data.Binary as Binary+import qualified Data.Binary.Bits.Put as BinaryBits+import qualified Data.Binary.Put as Binary+import qualified Data.ByteString as Bytes+import qualified Data.Char as Char+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text++putText :: Str -> Binary.Put+putText text = do+  let size = getTextSize text+  let encode = getTextEncoder size+  putInt32 size+  Binary.putByteString (encode (addNull (strValue text)))++putTextBits :: Str -> BinaryBits.BitPut ()+putTextBits text = do+  let size = getTextSize text+  let encode = getTextEncoder size+  putInt32Bits size+  BinaryBits.putByteString (reverseBytes (encode (addNull (strValue text))))++getTextSize :: Str -> Int32le+getTextSize text =+  let+    value = strValue text+    scale = if Text.all Char.isLatin1 value then 1 else -1 :: Int32+    rawSize = if Text.null value+      then 0+      else fromIntegral (Text.length value) + 1 :: Int32+    size = if value == Text.pack "\x00\x00\x00None"+      then 0x05000000+      else scale * rawSize :: Int32+  in Int32le size++getTextEncoder :: Int32le -> Text.Text -> Bytes.ByteString+getTextEncoder size text =+  if size < Int32le 0 then Text.encodeUtf16LE text else encodeLatin1 text++addNull :: Text.Text -> Text.Text+addNull text = if Text.null text then text else Text.snoc text '\x00'
+ source/library/Rattletrap/Encode/StringAttribute.hs view
@@ -0,0 +1,13 @@+module Rattletrap.Encode.StringAttribute+  ( putStringAttribute+  )+where++import Rattletrap.Encode.Str+import Rattletrap.Type.StringAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putStringAttribute :: StringAttribute -> BinaryBits.BitPut ()+putStringAttribute stringAttribute =+  putTextBits (stringAttributeValue stringAttribute)
+ source/library/Rattletrap/Encode/TeamPaintAttribute.hs view
@@ -0,0 +1,18 @@+module Rattletrap.Encode.TeamPaintAttribute+  ( putTeamPaintAttribute+  )+where++import Rattletrap.Encode.Word32le+import Rattletrap.Encode.Word8le+import Rattletrap.Type.TeamPaintAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putTeamPaintAttribute :: TeamPaintAttribute -> BinaryBits.BitPut ()+putTeamPaintAttribute teamPaintAttribute = do+  putWord8Bits (teamPaintAttributeTeam teamPaintAttribute)+  putWord8Bits (teamPaintAttributePrimaryColor teamPaintAttribute)+  putWord8Bits (teamPaintAttributeAccentColor teamPaintAttribute)+  putWord32Bits (teamPaintAttributePrimaryFinish teamPaintAttribute)+  putWord32Bits (teamPaintAttributeAccentFinish teamPaintAttribute)
+ source/library/Rattletrap/Encode/TitleAttribute.hs view
@@ -0,0 +1,20 @@+module Rattletrap.Encode.TitleAttribute+  ( putTitleAttribute+  )+where++import Rattletrap.Encode.Word32le+import Rattletrap.Type.TitleAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putTitleAttribute :: TitleAttribute -> BinaryBits.BitPut ()+putTitleAttribute titleAttribute = do+  BinaryBits.putBool (titleAttributeUnknown1 titleAttribute)+  BinaryBits.putBool (titleAttributeUnknown2 titleAttribute)+  putWord32Bits (titleAttributeUnknown3 titleAttribute)+  putWord32Bits (titleAttributeUnknown4 titleAttribute)+  putWord32Bits (titleAttributeUnknown5 titleAttribute)+  putWord32Bits (titleAttributeUnknown6 titleAttribute)+  putWord32Bits (titleAttributeUnknown7 titleAttribute)+  BinaryBits.putBool (titleAttributeUnknown8 titleAttribute)
+ source/library/Rattletrap/Encode/UniqueIdAttribute.hs view
@@ -0,0 +1,16 @@+module Rattletrap.Encode.UniqueIdAttribute+  ( putUniqueIdAttribute+  )+where++import Rattletrap.Encode.RemoteId+import Rattletrap.Encode.Word8le+import Rattletrap.Type.UniqueIdAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putUniqueIdAttribute :: UniqueIdAttribute -> BinaryBits.BitPut ()+putUniqueIdAttribute uniqueIdAttribute = do+  putWord8Bits (uniqueIdAttributeSystemId uniqueIdAttribute)+  putRemoteId (uniqueIdAttributeRemoteId uniqueIdAttribute)+  putWord8Bits (uniqueIdAttributeLocalId uniqueIdAttribute)
+ source/library/Rattletrap/Encode/UpdatedReplication.hs view
@@ -0,0 +1,13 @@+module Rattletrap.Encode.UpdatedReplication+  ( putUpdatedReplication+  )+where++import Rattletrap.Encode.Attribute+import Rattletrap.Type.UpdatedReplication++import qualified Data.Binary.Bits.Put as BinaryBits++putUpdatedReplication :: UpdatedReplication -> BinaryBits.BitPut ()+putUpdatedReplication updatedReplication =+  putAttributes (updatedReplicationAttributes updatedReplication)
+ source/library/Rattletrap/Encode/Vector.hs view
@@ -0,0 +1,27 @@+module Rattletrap.Encode.Vector+  ( putVector+  )+where++import Rattletrap.Encode.CompressedWord+import Rattletrap.Type.CompressedWord+import Rattletrap.Type.Vector++import qualified Data.Binary.Bits.Put as BinaryBits++putVector :: Vector -> BinaryBits.BitPut ()+putVector vector = do+  let+    bitSize =+      round (logBase (2 :: Float) (fromIntegral (vectorBias vector))) - 1 :: Word+    dx =+      fromIntegral (vectorX vector + fromIntegral (vectorBias vector)) :: Word+    dy =+      fromIntegral (vectorY vector + fromIntegral (vectorBias vector)) :: Word+    dz =+      fromIntegral (vectorZ vector + fromIntegral (vectorBias vector)) :: Word+    limit = 2 ^ (bitSize + 2) :: Word+  putCompressedWord (vectorSize vector)+  putCompressedWord (CompressedWord limit dx)+  putCompressedWord (CompressedWord limit dy)+  putCompressedWord (CompressedWord limit dz)
+ source/library/Rattletrap/Encode/WeldedInfoAttribute.hs view
@@ -0,0 +1,20 @@+module Rattletrap.Encode.WeldedInfoAttribute+  ( putWeldedInfoAttribute+  )+where++import Rattletrap.Encode.Float32le+import Rattletrap.Encode.Int32le+import Rattletrap.Encode.Int8Vector+import Rattletrap.Encode.Vector+import Rattletrap.Type.WeldedInfoAttribute++import qualified Data.Binary.Bits.Put as BinaryBits++putWeldedInfoAttribute :: WeldedInfoAttribute -> BinaryBits.BitPut ()+putWeldedInfoAttribute weldedInfoAttribute = do+  BinaryBits.putBool (weldedInfoAttributeActive weldedInfoAttribute)+  putInt32Bits (weldedInfoAttributeActorId weldedInfoAttribute)+  putVector (weldedInfoAttributeOffset weldedInfoAttribute)+  putFloat32Bits (weldedInfoAttributeMass weldedInfoAttribute)+  putInt8Vector (weldedInfoAttributeRotation weldedInfoAttribute)
+ source/library/Rattletrap/Encode/Word32le.hs view
@@ -0,0 +1,21 @@+module Rattletrap.Encode.Word32le+  ( putWord32+  , putWord32Bits+  )+where++import Rattletrap.Type.Word32le+import Rattletrap.Utility.Bytes++import qualified Data.Binary as Binary+import qualified Data.Binary.Bits.Put as BinaryBits+import qualified Data.Binary.Put as Binary+import qualified Data.ByteString.Lazy as LazyBytes++putWord32 :: Word32le -> Binary.Put+putWord32 word32 = Binary.putWord32le (word32leValue word32)++putWord32Bits :: Word32le -> BinaryBits.BitPut ()+putWord32Bits word32 = do+  let bytes = LazyBytes.toStrict (Binary.runPut (putWord32 word32))+  BinaryBits.putByteString (reverseBytes bytes)
+ source/library/Rattletrap/Encode/Word64le.hs view
@@ -0,0 +1,21 @@+module Rattletrap.Encode.Word64le+  ( putWord64+  , putWord64Bits+  )+where++import Rattletrap.Type.Word64le+import Rattletrap.Utility.Bytes++import qualified Data.Binary as Binary+import qualified Data.Binary.Bits.Put as BinaryBits+import qualified Data.Binary.Put as Binary+import qualified Data.ByteString.Lazy as LazyBytes++putWord64 :: Word64le -> Binary.Put+putWord64 word64 = Binary.putWord64le (word64leValue word64)++putWord64Bits :: Word64le -> BinaryBits.BitPut ()+putWord64Bits word64 = do+  let bytes = LazyBytes.toStrict (Binary.runPut (putWord64 word64))+  BinaryBits.putByteString (reverseBytes bytes)
+ source/library/Rattletrap/Encode/Word8le.hs view
@@ -0,0 +1,21 @@+module Rattletrap.Encode.Word8le+  ( putWord8+  , putWord8Bits+  )+where++import Rattletrap.Type.Word8le+import Rattletrap.Utility.Bytes++import qualified Data.Binary as Binary+import qualified Data.Binary.Bits.Put as BinaryBits+import qualified Data.Binary.Put as Binary+import qualified Data.ByteString.Lazy as LazyBytes++putWord8 :: Word8le -> Binary.Put+putWord8 word8 = Binary.putWord8 (word8leValue word8)++putWord8Bits :: Word8le -> BinaryBits.BitPut ()+putWord8Bits word8 = do+  let bytes = LazyBytes.toStrict (Binary.runPut (putWord8 word8))+  BinaryBits.putByteString (reverseBytes bytes)
+ source/library/Rattletrap/Type/AppliedDamageAttribute.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.AppliedDamageAttribute+  ( AppliedDamageAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Int32le+import Rattletrap.Type.Vector+import Rattletrap.Type.Word8le++data AppliedDamageAttribute = AppliedDamageAttribute+  { appliedDamageAttributeUnknown1 :: Word8le+  , appliedDamageAttributeLocation :: Vector+  , appliedDamageAttributeUnknown3 :: Int32le+  , appliedDamageAttributeUnknown4 :: Int32le+  } deriving (Eq, Ord, Show)++$(deriveJson ''AppliedDamageAttribute)
+ source/library/Rattletrap/Type/Attribute.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Attribute+  ( Attribute(..)+  )+where++import Rattletrap.Type.AttributeValue+import Rattletrap.Type.Common+import Rattletrap.Type.CompressedWord+import Rattletrap.Type.Str++data Attribute = Attribute+  { attributeId :: CompressedWord+  , attributeName :: Str+  -- ^ Read-only! Changing an attribute's name requires editing the class+  -- attribute map.+  , attributeValue :: AttributeValue+  } deriving (Eq, Ord, Show)++$(deriveJson ''Attribute)
+ source/library/Rattletrap/Type/AttributeMapping.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.AttributeMapping+  ( AttributeMapping(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Word32le++data AttributeMapping = AttributeMapping+  { attributeMappingObjectId :: Word32le+  , attributeMappingStreamId :: Word32le+  } deriving (Eq, Ord, Show)++$(deriveJson ''AttributeMapping)
+ source/library/Rattletrap/Type/AttributeType.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.AttributeType+  ( AttributeType(..)+  )+where++import Rattletrap.Type.Common++data AttributeType+  = AttributeTypeAppliedDamage+  | AttributeTypeBoolean+  | AttributeTypeByte+  | AttributeTypeCamSettings+  | AttributeTypeClubColors+  | AttributeTypeDamageState+  | AttributeTypeDemolish+  | AttributeTypeEnum+  | AttributeTypeExplosion+  | AttributeTypeExtendedExplosion+  | AttributeTypeFlaggedInt+  | AttributeTypeFlaggedByte+  | AttributeTypeFloat+  | AttributeTypeGameMode+  | AttributeTypeInt+  | AttributeTypeInt64+  | AttributeTypeLoadout+  | AttributeTypeLoadoutOnline+  | AttributeTypeLoadouts+  | AttributeTypeLoadoutsOnline+  | AttributeTypeLocation+  | AttributeTypeMusicStinger+  | AttributeTypePartyLeader+  | AttributeTypePickup+  | AttributeTypePickupNew+  | AttributeTypePlayerHistoryKey+  | AttributeTypePrivateMatchSettings+  | AttributeTypeQWord+  | AttributeTypeReservation+  | AttributeTypeRigidBodyState+  | AttributeTypeStatEvent+  | AttributeTypeString+  | AttributeTypeTeamPaint+  | AttributeTypeTitle+  | AttributeTypeUniqueId+  | AttributeTypeWeldedInfo+  deriving (Eq, Ord, Show)++$(deriveJson ''AttributeType)
+ source/library/Rattletrap/Type/AttributeValue.hs view
@@ -0,0 +1,85 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.AttributeValue+  ( AttributeValue(..)+  )+where++import Rattletrap.Type.AppliedDamageAttribute+import Rattletrap.Type.BooleanAttribute+import Rattletrap.Type.ByteAttribute+import Rattletrap.Type.CamSettingsAttribute+import Rattletrap.Type.ClubColorsAttribute+import Rattletrap.Type.Common+import Rattletrap.Type.DamageStateAttribute+import Rattletrap.Type.DemolishAttribute+import Rattletrap.Type.EnumAttribute+import Rattletrap.Type.ExplosionAttribute+import Rattletrap.Type.ExtendedExplosionAttribute+import Rattletrap.Type.FlaggedIntAttribute+import Rattletrap.Type.FlaggedByteAttribute+import Rattletrap.Type.FloatAttribute+import Rattletrap.Type.GameModeAttribute+import Rattletrap.Type.Int64Attribute+import Rattletrap.Type.IntAttribute+import Rattletrap.Type.LoadoutAttribute+import Rattletrap.Type.LoadoutOnlineAttribute+import Rattletrap.Type.LoadoutsAttribute+import Rattletrap.Type.LoadoutsOnlineAttribute+import Rattletrap.Type.LocationAttribute+import Rattletrap.Type.MusicStingerAttribute+import Rattletrap.Type.PartyLeaderAttribute+import Rattletrap.Type.PickupAttribute+import Rattletrap.Type.PickupAttributeNew+import Rattletrap.Type.PlayerHistoryKeyAttribute+import Rattletrap.Type.PrivateMatchSettingsAttribute+import Rattletrap.Type.QWordAttribute+import Rattletrap.Type.ReservationAttribute+import Rattletrap.Type.RigidBodyStateAttribute+import Rattletrap.Type.StatEventAttribute+import Rattletrap.Type.StringAttribute+import Rattletrap.Type.TeamPaintAttribute+import Rattletrap.Type.TitleAttribute+import Rattletrap.Type.UniqueIdAttribute+import Rattletrap.Type.WeldedInfoAttribute++data AttributeValue+  = AttributeValueAppliedDamage AppliedDamageAttribute+  | AttributeValueBoolean BooleanAttribute+  | AttributeValueByte ByteAttribute+  | AttributeValueCamSettings CamSettingsAttribute+  | AttributeValueClubColors ClubColorsAttribute+  | AttributeValueDamageState DamageStateAttribute+  | AttributeValueDemolish DemolishAttribute+  | AttributeValueEnum EnumAttribute+  | AttributeValueExplosion ExplosionAttribute+  | AttributeValueExtendedExplosion ExtendedExplosionAttribute+  | AttributeValueFlaggedInt FlaggedIntAttribute+  | AttributeValueFlaggedByte FlaggedByteAttribute+  | AttributeValueFloat FloatAttribute+  | AttributeValueGameMode GameModeAttribute+  | AttributeValueInt IntAttribute+  | AttributeValueInt64 Int64Attribute+  | AttributeValueLoadout LoadoutAttribute+  | AttributeValueLoadoutOnline LoadoutOnlineAttribute+  | AttributeValueLoadouts LoadoutsAttribute+  | AttributeValueLoadoutsOnline LoadoutsOnlineAttribute+  | AttributeValueLocation LocationAttribute+  | AttributeValueMusicStinger MusicStingerAttribute+  | AttributeValuePartyLeader PartyLeaderAttribute+  | AttributeValuePickup PickupAttribute+  | AttributeValuePickupNew PickupAttributeNew+  | AttributeValuePlayerHistoryKey PlayerHistoryKeyAttribute+  | AttributeValuePrivateMatchSettings PrivateMatchSettingsAttribute+  | AttributeValueQWord QWordAttribute+  | AttributeValueReservation ReservationAttribute+  | AttributeValueRigidBodyState RigidBodyStateAttribute+  | AttributeValueStatEvent StatEventAttribute+  | AttributeValueString StringAttribute+  | AttributeValueTeamPaint TeamPaintAttribute+  | AttributeValueTitle TitleAttribute+  | AttributeValueUniqueId UniqueIdAttribute+  | AttributeValueWeldedInfo WeldedInfoAttribute+  deriving (Eq, Ord, Show)++$(deriveJson ''AttributeValue)
+ source/library/Rattletrap/Type/BooleanAttribute.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.BooleanAttribute+  ( BooleanAttribute(..)+  )+where++import Rattletrap.Type.Common++newtype BooleanAttribute = BooleanAttribute+  { booleanAttributeValue :: Bool+  } deriving (Eq, Ord, Show)++$(deriveJson ''BooleanAttribute)
+ source/library/Rattletrap/Type/ByteAttribute.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.ByteAttribute+  ( ByteAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Word8le++newtype ByteAttribute = ByteAttribute+  { byteAttributeValue :: Word8le+  } deriving (Eq, Ord, Show)++$(deriveJson ''ByteAttribute)
+ source/library/Rattletrap/Type/Cache.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Cache+  ( Cache(..)+  )+where++import Rattletrap.Type.AttributeMapping+import Rattletrap.Type.Common+import Rattletrap.Type.List+import Rattletrap.Type.Word32le++data Cache = Cache+  { cacheClassId :: Word32le+  , cacheParentCacheId :: Word32le+  , cacheCacheId :: Word32le+  , cacheAttributeMappings :: List AttributeMapping+  } deriving (Eq, Ord, Show)++$(deriveJson ''Cache)
+ source/library/Rattletrap/Type/CamSettingsAttribute.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.CamSettingsAttribute+  ( CamSettingsAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Float32le++data CamSettingsAttribute = CamSettingsAttribute+  { camSettingsAttributeFov :: Float32le+  , camSettingsAttributeHeight :: Float32le+  , camSettingsAttributeAngle :: Float32le+  , camSettingsAttributeDistance :: Float32le+  , camSettingsAttributeStiffness :: Float32le+  , camSettingsAttributeSwivelSpeed :: Float32le+  , camSettingsAttributeTransitionSpeed :: Maybe Float32le+  } deriving (Eq, Ord, Show)++$(deriveJson ''CamSettingsAttribute)
+ source/library/Rattletrap/Type/ClassAttributeMap.hs view
@@ -0,0 +1,324 @@+module Rattletrap.Type.ClassAttributeMap+  ( ClassAttributeMap(..)+  , classHasLocation+  , classHasRotation+  , getAttributeIdLimit+  , getAttributeMap+  , getAttributeName+  , getClassName+  , getName+  , getObjectName+  , makeClassAttributeMap+  )+where++import Rattletrap.Data+import Rattletrap.Type.AttributeMapping+import Rattletrap.Type.Cache+import Rattletrap.Type.ClassMapping+import Rattletrap.Type.Common+import Rattletrap.Type.CompressedWord+import Rattletrap.Type.List+import Rattletrap.Type.Str+import Rattletrap.Type.Word32le++import qualified Data.IntMap as IntMap+import qualified Data.List as List+import qualified Data.Map as Map+import qualified Data.Maybe as Maybe+import qualified Data.Set as Set+import qualified Data.Text as Text+import qualified Data.Tuple as Tuple++-- | This data structure holds all the information about classes, objects, and+-- attributes in the replay. The class hierarchy is not fixed; it is encoded+-- in the 'Rattletrap.Content.Content'. Similarly, the attributes that belong+-- to each class are not fixed either. Converting the raw data into a usable+-- structure is tedious; see 'makeClassAttributeMap'.+data ClassAttributeMap = ClassAttributeMap+  { classAttributeMapObjectMap :: Map Word32le Str+  -- ^ A map from object IDs to their names.+  , classAttributeMapObjectClassMap :: Map Word32le Word32le+  -- ^ A map from object IDs to their class IDs.+    , classAttributeMapValue :: Map Word32le (Map Word32le Word32le)+  -- ^ A map from class IDs to a map from attribute stream IDs to attribute+  -- IDs.+  , classAttributeMapNameMap :: IntMap.IntMap Str+  } deriving (Eq, Ord, Show)++type Bimap l r = (Map l r, Map r l)++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 k = Map.lookup k . fst++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'.+makeClassAttributeMap+  :: List Str+  -- ^ From 'Rattletrap.Content.contentObjects'.+  -> List ClassMapping+  -- ^ From 'Rattletrap.Content.contentClassMappings'.+  -> List Cache+  -- ^ From 'Rattletrap.Content.contentCaches'.+  -> List Str+  -- ^ From 'Rattletrap.Content.contentNames'.+  -> ClassAttributeMap+makeClassAttributeMap 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++makeNameMap :: List Str -> IntMap.IntMap Str+makeNameMap names = IntMap.fromDistinctAscList (zip [0 ..] (listValue names))++getName :: IntMap.IntMap Str -> Word32le -> Maybe Str+getName nameMap nameIndex =+  IntMap.lookup (fromIntegral (word32leValue nameIndex)) nameMap++makeObjectClassMap+  :: Map Word32le Str -> Bimap Word32le Str -> Map Word32le Word32le+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+  Map.fromList pairs++getClassId+  :: Map Word32le Str -> Bimap Word32le Str -> Word32le -> Maybe Word32le+getClassId objectMap classMap objectId = do+  objectName <- getObjectName objectMap objectId+  className <- getClassName objectName+  lookupR className classMap++makeClassCache+  :: Bimap Word32le Str+  -> List Cache+  -> [(Maybe Str, Word32le, Word32le, Word32le)]+makeClassCache classMap caches = fmap+  (\cache ->+    let classId = cacheClassId cache+    in+      ( lookupL classId classMap+      , classId+      , cacheCacheId cache+      , cacheParentCacheId cache+      )+  )+  (listValue caches)++makeClassMap :: List ClassMapping -> Bimap Word32le Str+makeClassMap classMappings = bimap+  (fmap+    (\classMapping ->+      (classMappingStreamId classMapping, classMappingName classMapping)+    )+    (listValue classMappings)+  )++makeAttributeMap :: List Cache -> Map Word32le (Map Word32le Word32le)+makeAttributeMap caches = Map.fromList+  (fmap+    (\cache ->+      ( cacheClassId cache+      , Map.fromList+        (fmap+          (\attributeMapping ->+            ( attributeMappingStreamId attributeMapping+            , attributeMappingObjectId attributeMapping+            )+          )+          (listValue (cacheAttributeMappings cache))+        )+      )+    )+    (listValue caches)+  )++makeShallowParentMap+  :: [(Maybe Str, Word32le, Word32le, Word32le)] -> Map Word32le Word32le+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))+  )++makeParentMap+  :: [(Maybe Str, Word32le, Word32le, Word32le)] -> Map Word32le [Word32le]+makeParentMap classCache =+  let shallowParentMap = makeShallowParentMap classCache+  in+    Map.mapWithKey+      (\classId _ -> getParentClasses shallowParentMap classId)+      shallowParentMap++getParentClasses :: Map Word32le Word32le -> Word32le -> [Word32le]+getParentClasses shallowParentMap classId =+  case Map.lookup classId shallowParentMap of+    Nothing -> []+    Just parentClassId ->+      parentClassId : getParentClasses shallowParentMap parentClassId++getParentClass+  :: Maybe Str+  -> Word32le+  -> [(Maybe Str, Word32le, Word32le, Word32le)]+  -> Maybe Word32le+getParentClass maybeClassName parentCacheId xs = case maybeClassName of+  Nothing -> getParentClassById parentCacheId xs+  Just className -> getParentClassByName className parentCacheId xs++getParentClassById+  :: Word32le -> [(Maybe Str, Word32le, Word32le, Word32le)] -> Maybe Word32le+getParentClassById parentCacheId xs =+  case dropWhile (\(_, _, cacheId, _) -> cacheId /= parentCacheId) xs of+    [] -> if parentCacheId == Word32le 0+      then Nothing+      else getParentClassById (Word32le (word32leValue parentCacheId - 1)) xs+    (_, parentClassId, _, _) : _ -> Just parentClassId++getParentClassByName+  :: Str+  -> Word32le+  -> [(Maybe Str, Word32le, Word32le, Word32le)]+  -> Maybe Word32le+getParentClassByName className parentCacheId xs =+  case Map.lookup className 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, _, _, _) ->+                maybeClassName == Just parentClassName+              )+              xs+            )+          )+        )+      )++parentClasses :: Map Str Str+parentClasses =+  Map.map toStr (Map.mapKeys toStr (Map.fromList rawParentClasses))++makeObjectMap :: List Str -> Map Word32le Str+makeObjectMap objects =+  Map.fromAscList (zip (fmap Word32le [0 ..]) (listValue objects))++getObjectName :: Map Word32le Str -> Word32le -> Maybe Str+getObjectName objectMap objectId = Map.lookup objectId objectMap++getClassName :: Str -> Maybe Str+getClassName rawObjectName =+  Map.lookup (normalizeObjectName rawObjectName) objectClasses++normalizeObjectName :: Str -> Str+normalizeObjectName objectName =+  let+    name = strValue 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 crowdActor+    else if Text.isInfixOf crowdManager name+      then Str crowdManager+      else if Text.isInfixOf boostPickup name+        then Str boostPickup+        else if Text.isInfixOf mapScoreboard name+          then Str mapScoreboard+          else if Text.isInfixOf breakout name+            then Str breakout+            else objectName++objectClasses :: Map Str Str+objectClasses =+  Map.map toStr (Map.mapKeys toStr (Map.fromList rawObjectClasses))++classHasLocation :: Str -> Bool+classHasLocation className = Set.member className classesWithLocation++classesWithLocation :: Set.Set Str+classesWithLocation = Set.fromList (fmap toStr rawClassesWithLocation)++classHasRotation :: Str -> Bool+classHasRotation className = Set.member className classesWithRotation++classesWithRotation :: Set.Set Str+classesWithRotation = Set.fromList (fmap toStr rawClassesWithRotation)++getAttributeIdLimit :: Map Word32le Word32le -> Maybe Word+getAttributeIdLimit attributeMap = do+  ((streamId, _), _) <- Map.maxViewWithKey attributeMap+  pure (fromIntegral (word32leValue streamId))++getAttributeName+  :: ClassAttributeMap -> Map Word32le Word32le -> CompressedWord -> Maybe Str+getAttributeName classAttributeMap attributeMap streamId = do+  let key = Word32le (fromIntegral (compressedWordValue streamId))+  attributeId <- Map.lookup key attributeMap+  let objectMap = classAttributeMapObjectMap classAttributeMap+  Map.lookup attributeId objectMap++getAttributeMap+  :: ClassAttributeMap+  -> Map CompressedWord Word32le+  -> CompressedWord+  -> Maybe (Map Word32le Word32le)+getAttributeMap classAttributeMap actorMap actorId = do+  objectId <- Map.lookup actorId actorMap+  let objectClassMap = classAttributeMapObjectClassMap classAttributeMap+  classId <- Map.lookup objectId objectClassMap+  let value = classAttributeMapValue classAttributeMap+  Map.lookup classId value
+ source/library/Rattletrap/Type/ClassMapping.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.ClassMapping+  ( ClassMapping(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Str+import Rattletrap.Type.Word32le++data ClassMapping = ClassMapping+  { classMappingName :: Str+  , classMappingStreamId :: Word32le+  } deriving (Eq, Ord, Show)++$(deriveJson ''ClassMapping)
+ source/library/Rattletrap/Type/ClubColorsAttribute.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.ClubColorsAttribute+  ( ClubColorsAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Word8le++data ClubColorsAttribute = ClubColorsAttribute+  { clubColorsAttributeBlueFlag :: Bool+  , clubColorsAttributeBlueColor :: Word8le+  , clubColorsAttributeOrangeFlag :: Bool+  , clubColorsAttributeOrangeColor :: Word8le+  } deriving (Eq, Ord, Show)++$(deriveJson ''ClubColorsAttribute)
+ source/library/Rattletrap/Type/Common.hs view
@@ -0,0 +1,56 @@+module Rattletrap.Type.Common+  ( Int.Int8+  , Int.Int32+  , Int.Int64+  , Map.Map+  , Text.Text+  , Word.Word8+  , Word.Word16+  , Word.Word32+  , Word.Word64+  , deriveJson+  )+where++import qualified Data.Aeson as Json+import qualified Data.Aeson.TH as Json+import qualified Data.Char as Char+import qualified Data.Int as Int+import qualified Data.Map as Map+import qualified Data.Maybe as Maybe+import qualified Data.Text as Text+import qualified Data.Word as Word+import qualified Language.Haskell.TH as TH++deriveJson :: TH.Name -> TH.Q [TH.Dec]+deriveJson name = Json.deriveJSON (jsonOptions (TH.nameBase name)) name++jsonOptions :: String -> Json.Options+jsonOptions prefix = Json.defaultOptions+  { Json.constructorTagModifier = toSnakeCase . partialDropPrefix prefix+  , Json.fieldLabelModifier = toSnakeCase+    . partialDropPrefix (lowerFirst prefix)+  , Json.omitNothingFields = True+  , Json.sumEncoding = Json.ObjectWithSingleField+  , Json.unwrapUnaryRecords = True+  }++lowerFirst :: String -> String+lowerFirst string = case string of+  "" -> string+  first : rest -> Char.toLower first : rest++toSnakeCase :: String -> String+toSnakeCase = Json.camelTo2 '_'++partialDropPrefix :: (Eq a, Show a) => [a] -> [a] -> [a]+partialDropPrefix prefix list = Maybe.fromMaybe+  (error (unwords [show prefix, "is not a prefix of", show list]))+  (dropPrefix prefix list)++dropPrefix :: Eq a => [a] -> [a] -> Maybe [a]+dropPrefix prefix list = case prefix of+  [] -> Just list+  ph : pt -> case list of+    [] -> Nothing+    lh : lt -> if ph == lh then dropPrefix pt lt else Nothing
+ source/library/Rattletrap/Type/CompressedWord.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.CompressedWord+  ( CompressedWord(..)+  )+where++import Rattletrap.Type.Common++-- | Although there's no guarantee that these values will not overflow, it's+-- exceptionally unlikely. Most 'CompressedWord's are very small.+data CompressedWord = CompressedWord+  { compressedWordLimit :: Word+  , compressedWordValue :: Word+  } deriving (Eq, Ord, Show)++$(deriveJson ''CompressedWord)
+ source/library/Rattletrap/Type/CompressedWordVector.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.CompressedWordVector+  ( CompressedWordVector(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.CompressedWord++data CompressedWordVector = CompressedWordVector+  { compressedWordVectorX :: CompressedWord+  , compressedWordVectorY :: CompressedWord+  , compressedWordVectorZ :: CompressedWord+  } deriving (Eq, Ord, Show)++$(deriveJson ''CompressedWordVector)
+ source/library/Rattletrap/Type/Content.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Content+  ( Content(..)+  , defaultContent+  )+where++import Rattletrap.Type.Cache+import Rattletrap.Type.ClassMapping+import Rattletrap.Type.Common+import Rattletrap.Type.Frame+import Rattletrap.Type.KeyFrame+import Rattletrap.Type.List+import Rattletrap.Type.Mark+import Rattletrap.Type.Message+import Rattletrap.Type.Str+import Rattletrap.Type.Word32le++-- | Contains low-level game data about a 'Rattletrap.Replay.Replay'.+data Content = Content+  { contentLevels :: List Str+  -- ^ This typically only has one element, like @stadium_oob_audio_map@.+  , contentKeyFrames :: List 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.+  , contentStreamSize :: Word32le+  -- ^ The size of the stream in bytes. This is only really necessary because+  -- the stream has some arbitrary amount of padding at the end.+  , contentFrames :: [Frame]+  -- ^ The actual game data. This is where all the interesting information is.+  , contentMessages :: List Message+  -- ^ Debugging messages. In newer replays, this is always empty.+  , contentMarks :: List Mark+  -- ^ Tick marks shown on the scrubber when watching a replay.+  , contentPackages :: List Str+  -- ^ A list of @.upk@ files to load, like+  -- @..\\..\\TAGame\\CookedPCConsole\\Stadium_P.upk@.+  , contentObjects :: List Str+  -- ^ Objects in the stream. Used for the+  -- 'Rattletrap.Type.ClassAttributeMap.ClassAttributeMap'.+  , contentNames :: List Str+  -- ^ It's not clear what these are used for. This list is usually not empty,+  -- but appears unused otherwise.+  , contentClassMappings :: List ClassMapping+  -- ^ A mapping between classes and their ID in the stream. Used for the+  -- 'Rattletrap.Type.ClassAttributeMap.ClassAttributeMap'.+  , contentCaches :: List Cache+  -- ^ A list of classes along with their parent classes and attributes. Used+  -- for the 'Rattletrap.Type.ClassAttributeMap.ClassAttributeMap'.+  , contentUnknown :: [Word8]+  } deriving (Eq, Ord, Show)++$(deriveJson ''Content)++defaultContent :: Content+defaultContent = Content+  { contentLevels = List []+  , contentKeyFrames = List []+  , contentStreamSize = Word32le 0+  , contentFrames = []+  , contentMessages = List []+  , contentMarks = List []+  , contentPackages = List []+  , contentObjects = List []+  , contentNames = List []+  , contentClassMappings = List []+  , contentCaches = List []+  , contentUnknown = []+  }
+ source/library/Rattletrap/Type/DamageStateAttribute.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.DamageStateAttribute+  ( DamageStateAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Int32le+import Rattletrap.Type.Vector+import Rattletrap.Type.Word8le++data DamageStateAttribute = DamageStateAttribute+  { damageStateAttributeUnknown1 :: Word8le+  , damageStateAttributeUnknown2 :: Bool+  , damageStateAttributeUnknown3 :: Int32le+  , damageStateAttributeUnknown4 :: Vector+  , damageStateAttributeUnknown5 :: Bool+  , damageStateAttributeUnknown6 :: Bool+  } deriving (Eq, Ord, Show)++$(deriveJson ''DamageStateAttribute)
+ source/library/Rattletrap/Type/DemolishAttribute.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.DemolishAttribute+  ( DemolishAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Vector+import Rattletrap.Type.Word32le++data DemolishAttribute = DemolishAttribute+  { demolishAttributeAttackerFlag :: Bool+  , demolishAttributeAttackerActorId :: Word32le+  , demolishAttributeVictimFlag :: Bool+  , demolishAttributeVictimActorId :: Word32le+  , demolishAttributeAttackerVelocity :: Vector+  , demolishAttributeVictimVelocity :: Vector+  } deriving (Eq, Ord, Show)++$(deriveJson ''DemolishAttribute)
+ source/library/Rattletrap/Type/DestroyedReplication.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.DestroyedReplication+  ( DestroyedReplication(..)+  )+where++import Rattletrap.Type.Common++-- | Destroyed replications don't actually contain any extra information. All+-- you need to know is the actor's ID, which is given by the+-- 'Rattletrap.Replication.Replication'.+data DestroyedReplication = DestroyedReplication+  deriving (Eq, Ord, Show)++$(deriveJson ''DestroyedReplication)
+ source/library/Rattletrap/Type/Dictionary.hs view
@@ -0,0 +1,69 @@+module Rattletrap.Type.Dictionary+  ( Dictionary(..)+  , dictionaryLookup+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Str++import qualified Control.Monad as Monad+import qualified Data.Aeson as Json+import qualified Data.Aeson.Types as Json+import qualified Data.Map as Map+import qualified Data.Text as Text++data Dictionary a+  = DictionaryElement Str a (Dictionary a)+  | DictionaryEnd Str+  deriving (Eq, Ord, Show)++instance Json.FromJSON a => Json.FromJSON (Dictionary a) where+  parseJSON = Json.withObject+    "Dictionary"+    (\o -> do+      keys <- get o "keys"+      lastKey <- get o "last_key"+      value <- get o "value"+      Monad.foldM+        (\d k -> case Map.lookup k value of+          Nothing -> fail (unwords ["missing key", show k])+          Just v -> pure (DictionaryElement (Str k) v d)+        )+        (DictionaryEnd lastKey)+        (reverse keys)+    )++instance Json.ToJSON a => Json.ToJSON (Dictionary a) where+  toJSON d = Json.object+    [ pair "keys" (dictionaryKeys d)+    , pair "last_key" (dictionaryLastKey d)+    , pair "value" (dictionaryValue d)+    ]++dictionaryKeys :: Dictionary a -> [Str]+dictionaryKeys = fmap fst . toList++dictionaryLastKey :: Dictionary a -> Str+dictionaryLastKey x = case x of+  DictionaryElement _ _ y -> dictionaryLastKey y+  DictionaryEnd y -> y++dictionaryLookup :: Str -> Dictionary a -> Maybe a+dictionaryLookup k x = case x of+  DictionaryElement j v y -> if k == j then Just v else dictionaryLookup k y+  DictionaryEnd _ -> Nothing++dictionaryValue :: Dictionary a -> Map Text a+dictionaryValue = Map.mapKeys strValue . Map.fromList . toList++get :: Json.FromJSON a => Json.Object -> String -> Json.Parser a+get o k = o Json..: Text.pack k++pair :: Json.ToJSON a => String -> a -> (Text, Json.Value)+pair k v = (Text.pack k, Json.toJSON v)++toList :: Dictionary a -> [(Str, a)]+toList x = case x of+  DictionaryElement k v y -> (k, v) : toList y+  DictionaryEnd _ -> []
+ source/library/Rattletrap/Type/EnumAttribute.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.EnumAttribute+  ( EnumAttribute(..)+  )+where++import Rattletrap.Type.Common++newtype EnumAttribute = EnumAttribute+  { enumAttributeValue :: Word16+  } deriving (Eq, Ord, Show)++$(deriveJson ''EnumAttribute)
+ source/library/Rattletrap/Type/ExplosionAttribute.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.ExplosionAttribute+  ( ExplosionAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Int32le+import Rattletrap.Type.Vector++data ExplosionAttribute = ExplosionAttribute+  { explosionAttributeFlag :: Bool+  , explosionAttributeActorId :: Int32le+  , explosionAttributeLocation :: Vector+  } deriving (Eq, Ord, Show)++$(deriveJson ''ExplosionAttribute)
+ source/library/Rattletrap/Type/ExtendedExplosionAttribute.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.ExtendedExplosionAttribute+  ( ExtendedExplosionAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.ExplosionAttribute+import Rattletrap.Type.FlaggedIntAttribute++data ExtendedExplosionAttribute = ExtendedExplosionAttribute+  { extendedExplosionAttributeExplosion :: ExplosionAttribute+  , extendedExplosionAttributeUnknown :: FlaggedIntAttribute+  } deriving (Eq, Ord, Show)++$(deriveJson ''ExtendedExplosionAttribute)
+ source/library/Rattletrap/Type/FlaggedByteAttribute.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.FlaggedByteAttribute+  ( FlaggedByteAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Word8le++data FlaggedByteAttribute = FlaggedByteAttribute+  { flaggedByteAttributeFlag :: Bool+  , flaggedByteAttributeByte :: Word8le+  } deriving (Eq, Ord, Show)++$(deriveJson ''FlaggedByteAttribute)
+ source/library/Rattletrap/Type/FlaggedIntAttribute.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.FlaggedIntAttribute+  ( FlaggedIntAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Int32le++data FlaggedIntAttribute = FlaggedIntAttribute+  { flaggedIntAttributeFlag :: Bool+  , flaggedIntAttributeInt :: Int32le+  } deriving (Eq, Ord, Show)++$(deriveJson ''FlaggedIntAttribute)
+ source/library/Rattletrap/Type/Float32le.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Float32le+  ( Float32le(..)+  )+where++import Rattletrap.Type.Common++newtype Float32le = Float32le+  { float32leValue :: Float+  } deriving (Eq, Ord, Show)++$(deriveJson ''Float32le)
+ source/library/Rattletrap/Type/FloatAttribute.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.FloatAttribute+  ( FloatAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Float32le++newtype FloatAttribute = FloatAttribute+  { floatAttributeValue :: Float32le+  } deriving (Eq, Ord, Show)++$(deriveJson ''FloatAttribute)
+ source/library/Rattletrap/Type/Frame.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Frame+  ( Frame(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Float32le+import Rattletrap.Type.Replication++data Frame = Frame+  { frameTime :: Float32le+  -- ^ Time in seconds since the beginning of the match.+  , frameDelta :: Float32le+  -- ^ Time in seconds since the last frame. Usually about 0.03 since there+  -- are 30 frames per second.+  , frameReplications :: [Replication]+  } deriving (Eq, Ord, Show)++$(deriveJson ''Frame)
+ source/library/Rattletrap/Type/GameModeAttribute.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.GameModeAttribute+  ( GameModeAttribute(..)+  )+where++import Rattletrap.Type.Common++data GameModeAttribute = GameModeAttribute+  { gameModeAttributeNumBits :: 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.+  , gameModeAttributeWord :: Word8+  } deriving (Eq, Ord, Show)++$(deriveJson ''GameModeAttribute)
+ source/library/Rattletrap/Type/Header.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Header+  ( Header(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Dictionary+import Rattletrap.Type.Property+import Rattletrap.Type.Str+import Rattletrap.Type.Word32le++-- | Contains high-level metadata about a 'Rattletrap.Replay.Replay'.+data Header = Header+  { headerEngineVersion :: Word32le+  -- ^ The "major" ("engine") version number.+  , headerLicenseeVersion :: Word32le+  -- ^ The "minor" ("licensee") version number.+  , headerPatchVersion :: Maybe Word32le+  -- ^ The "patch" ("net") version number.+  , headerLabel :: Str+  -- ^ Always @TAGame.Replay_Soccar_TA@.+  , headerProperties :: Dictionary 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@.+  } deriving (Eq, Ord, Show)++$(deriveJson ''Header)
+ source/library/Rattletrap/Type/Initialization.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Initialization+  ( Initialization(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Int8Vector+import Rattletrap.Type.Vector++data Initialization = Initialization+  { initializationLocation :: Maybe Vector+  -- ^ Not every class has an initial location. See+  -- 'Rattletrap.Data.rawClassesWithLocation'.+  , initializationRotation :: Maybe Int8Vector+  -- ^ Only classes with location can have rotation, but not every one does.+  -- See 'Rattletrap.Data.rawClassesWithRotation'.+  } deriving (Eq, Ord, Show)++$(deriveJson ''Initialization)
+ source/library/Rattletrap/Type/Int32le.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Int32le+  ( Int32le(..)+  )+where++import Rattletrap.Type.Common++newtype Int32le = Int32le+  { int32leValue :: Int32+  } deriving (Eq, Ord, Show)++$(deriveJson ''Int32le)
+ source/library/Rattletrap/Type/Int64Attribute.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Int64Attribute+  ( Int64Attribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Int64le++newtype Int64Attribute = Int64Attribute+  { int64AttributeValue :: Int64le+  } deriving (Eq, Ord, Show)++$(deriveJson ''Int64Attribute)
+ source/library/Rattletrap/Type/Int64le.hs view
@@ -0,0 +1,28 @@+module Rattletrap.Type.Int64le+  ( Int64le(..)+  )+where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.Types as Aeson+import qualified Data.Int as Int+import qualified Data.Scientific as Scientific+import qualified Data.Text as Text+import qualified Text.Read as Read++newtype Int64le = Int64le+  { int64leValue :: Int.Int64+  } deriving (Eq, Ord, Show)++instance Aeson.FromJSON Int64le where+  parseJSON value = case value of+    Aeson.String text -> case Read.readEither $ Text.unpack text of+      Left _ -> Aeson.typeMismatch "Int64le" value+      Right int64 -> pure $ Int64le int64+    Aeson.Number number -> case Scientific.toBoundedInteger number of+      Nothing -> Aeson.typeMismatch "Int64le" value+      Just int64 -> pure $ Int64le int64+    _ -> Aeson.typeMismatch "Int64le" value++instance Aeson.ToJSON Int64le where+  toJSON = Aeson.toJSON . show . int64leValue
+ source/library/Rattletrap/Type/Int8Vector.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Int8Vector+  ( Int8Vector(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Int8le++data Int8Vector = Int8Vector+  { int8VectorX :: Maybe Int8le+  , int8VectorY :: Maybe Int8le+  , int8VectorZ :: Maybe Int8le+  } deriving (Eq, Ord, Show)++$(deriveJson ''Int8Vector)
+ source/library/Rattletrap/Type/Int8le.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Int8le+  ( Int8le(..)+  )+where++import Rattletrap.Type.Common++newtype Int8le = Int8le+  { int8leValue :: Int8+  } deriving (Eq, Ord, Show)++$(deriveJson ''Int8le)
+ source/library/Rattletrap/Type/IntAttribute.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.IntAttribute+  ( IntAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Int32le++newtype IntAttribute = IntAttribute+  { intAttributeValue :: Int32le+  } deriving (Eq, Ord, Show)++$(deriveJson ''IntAttribute)
+ source/library/Rattletrap/Type/KeyFrame.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.KeyFrame+  ( KeyFrame(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Float32le+import Rattletrap.Type.Word32le++data KeyFrame = KeyFrame+  { keyFrameTime :: Float32le+  -- ^ When this key frame occurs, in seconds.+  , keyFrameFrame :: Word32le+  -- ^ The frame number of this key frame, starting from 0.+  , keyFramePosition :: Word32le+  -- ^ The bit position of this key frame in the stream.+  } deriving (Eq, Ord, Show)++$(deriveJson ''KeyFrame)
+ source/library/Rattletrap/Type/List.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.List+  ( List(..)+  )+where++import Rattletrap.Type.Common++newtype List a = List+  { listValue :: [a]+  } deriving (Eq, Ord, Show)++$(deriveJson ''List)
+ source/library/Rattletrap/Type/LoadoutAttribute.hs view
@@ -0,0 +1,33 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.LoadoutAttribute+  ( LoadoutAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Word32le+import Rattletrap.Type.Word8le++data LoadoutAttribute = LoadoutAttribute+  { loadoutAttributeVersion :: Word8le+  , loadoutAttributeBody :: Word32le+  , loadoutAttributeDecal :: Word32le+  , loadoutAttributeWheels :: Word32le+  , loadoutAttributeRocketTrail :: Word32le+  -- ^ Now known as "rocket boost".+  , loadoutAttributeAntenna :: Word32le+  , loadoutAttributeTopper :: Word32le+  , loadoutAttributeUnknown1 :: Word32le+  , loadoutAttributeUnknown2 :: Maybe Word32le+  , loadoutAttributeEngineAudio :: Maybe Word32le+  , loadoutAttributeTrail :: Maybe Word32le+  , loadoutAttributeGoalExplosion :: Maybe Word32le+  , loadoutAttributeBanner :: Maybe Word32le+  , loadoutAttributeUnknown3 :: Maybe Word32le+  , loadoutAttributeUnknown4 :: Maybe Word32le+  , loadoutAttributeUnknown5 :: Maybe Word32le+  , loadoutAttributeUnknown6 :: Maybe Word32le+  } deriving (Eq, Ord, Show)++$(deriveJson ''LoadoutAttribute)
+ source/library/Rattletrap/Type/LoadoutOnlineAttribute.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.LoadoutOnlineAttribute+  ( LoadoutOnlineAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.ProductAttribute++newtype LoadoutOnlineAttribute = LoadoutOnlineAttribute+  { loadoutAttributeValue :: [[ProductAttribute]]+  } deriving (Eq, Ord, Show)++$(deriveJson ''LoadoutOnlineAttribute)
+ source/library/Rattletrap/Type/LoadoutsAttribute.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.LoadoutsAttribute+  ( LoadoutsAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.LoadoutAttribute++data LoadoutsAttribute = LoadoutsAttribute+  { loadoutsAttributeBlue :: LoadoutAttribute+  , loadoutsAttributeOrange :: LoadoutAttribute+  } deriving (Eq, Ord, Show)++$(deriveJson ''LoadoutsAttribute)
+ source/library/Rattletrap/Type/LoadoutsOnlineAttribute.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.LoadoutsOnlineAttribute+  ( LoadoutsOnlineAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.LoadoutOnlineAttribute++data LoadoutsOnlineAttribute = LoadoutsOnlineAttribute+  { loadoutsOnlineAttributeBlue :: LoadoutOnlineAttribute+  , loadoutsOnlineAttributeOrange :: LoadoutOnlineAttribute+  , loadoutsOnlineAttributeUnknown1 :: Bool+  , loadoutsOnlineAttributeUnknown2 :: Bool+  } deriving (Eq, Ord, Show)++$(deriveJson ''LoadoutsOnlineAttribute)
+ source/library/Rattletrap/Type/LocationAttribute.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.LocationAttribute+  ( LocationAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Vector++newtype LocationAttribute = LocationAttribute+  { locationAttributeValue :: Vector+  } deriving (Eq, Ord, Show)++$(deriveJson ''LocationAttribute)
+ source/library/Rattletrap/Type/Mark.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Mark+  ( Mark(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Str+import Rattletrap.Type.Word32le++data Mark = Mark+  { markValue :: Str+  -- ^ Which type of mark this is, like @Team0Goal@.+  , markFrame :: Word32le+  -- ^ Which frame this mark belongs to, starting from 0.+  } deriving (Eq, Ord, Show)++$(deriveJson ''Mark)
+ source/library/Rattletrap/Type/Message.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Message+  ( Message(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Str+import Rattletrap.Type.Word32le++data Message = Message+  { messageFrame :: Word32le+  -- ^ Which frame this message belongs to, starting from 0.+  , messageName :: Str+  -- ^ The primary player's name.+  , messageValue :: Str+  -- ^ The content of the message.+  } deriving (Eq, Ord, Show)++$(deriveJson ''Message)
+ source/library/Rattletrap/Type/MusicStingerAttribute.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.MusicStingerAttribute+  ( MusicStingerAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Word32le+import Rattletrap.Type.Word8le++data MusicStingerAttribute = MusicStingerAttribute+  { musicStingerAttributeFlag :: Bool+  , musicStingerAttributeCue :: Word32le+  , musicStingerAttributeTrigger :: Word8le+  } deriving (Eq, Ord, Show)++$(deriveJson ''MusicStingerAttribute)
+ source/library/Rattletrap/Type/PartyLeaderAttribute.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.PartyLeaderAttribute+  ( PartyLeaderAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.RemoteId+import Rattletrap.Type.Word8le++data PartyLeaderAttribute = PartyLeaderAttribute+  { partyLeaderAttributeSystemId :: Word8le+  , partyLeaderAttributeId :: Maybe (RemoteId, Word8le)+  } deriving (Eq, Ord, Show)++$(deriveJson ''PartyLeaderAttribute)
+ source/library/Rattletrap/Type/PickupAttribute.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.PickupAttribute+  ( PickupAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Word32le++data PickupAttribute = PickupAttribute+  { pickupAttributeInstigatorId :: Maybe Word32le+  , pickupAttributePickedUp :: Bool+  } deriving (Eq, Ord, Show)++$(deriveJson ''PickupAttribute)
+ source/library/Rattletrap/Type/PickupAttributeNew.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.PickupAttributeNew+  ( PickupAttributeNew(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Word8le+import Rattletrap.Type.Word32le++data PickupAttributeNew = PickupAttributeNew+  { pickupAttributeNewInstigatorId :: Maybe Word32le+  , pickupAttributeNewPickedUp :: Word8le+  } deriving (Eq, Ord, Show)++$(deriveJson ''PickupAttributeNew)
+ source/library/Rattletrap/Type/PlayerHistoryKeyAttribute.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.PlayerHistoryKeyAttribute+  ( PlayerHistoryKeyAttribute(..)+  )+where++import Rattletrap.Type.Common++newtype PlayerHistoryKeyAttribute = PlayerHistoryKeyAttribute+  { playerHistoryKeyAttributeUnknown :: Word16+  } deriving (Eq, Ord, Show)++$(deriveJson ''PlayerHistoryKeyAttribute)
+ source/library/Rattletrap/Type/PrivateMatchSettingsAttribute.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.PrivateMatchSettingsAttribute+  ( PrivateMatchSettingsAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Str+import Rattletrap.Type.Word32le++data PrivateMatchSettingsAttribute = PrivateMatchSettingsAttribute+  { privateMatchSettingsAttributeMutators :: Str+  , privateMatchSettingsAttributeJoinableBy :: Word32le+  , privateMatchSettingsAttributeMaxPlayers :: Word32le+  , privateMatchSettingsAttributeGameName :: Str+  , privateMatchSettingsAttributePassword :: Str+  , privateMatchSettingsAttributeFlag :: Bool+  } deriving (Eq, Ord, Show)++$(deriveJson ''PrivateMatchSettingsAttribute)
+ source/library/Rattletrap/Type/ProductAttribute.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.ProductAttribute+  ( ProductAttribute(..)+  , ProductAttributeValue(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.CompressedWord+import Rattletrap.Type.Str+import Rattletrap.Type.Word32le++data ProductAttributeValue+  = ProductAttributeValuePaintedOld CompressedWord+  | ProductAttributeValuePaintedNew Word32+  | ProductAttributeValueTeamEditionOld CompressedWord+  | ProductAttributeValueTeamEditionNew Word32+  | ProductAttributeValueSpecialEdition Word32+  | ProductAttributeValueUserColorOld (Maybe Word32)+  | ProductAttributeValueUserColorNew Word32le+  | ProductAttributeValueTitleId Str+  deriving (Eq, Ord, Show)++$(deriveJson ''ProductAttributeValue)++data ProductAttribute = ProductAttribute+  { productAttributeUnknown :: Bool+  , productAttributeObjectId :: Word32le+  , productAttributeObjectName :: Maybe Str+  -- ^ read-only+  , productAttributeValue :: ProductAttributeValue+  } deriving (Eq, Ord, Show)++$(deriveJson ''ProductAttribute)
+ source/library/Rattletrap/Type/Property.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Property+  ( Property(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.PropertyValue+import Rattletrap.Type.Str+import Rattletrap.Type.Word64le++data Property = Property+  { propertyKind :: Str+  , propertySize :: Word64le+  -- ^ Not used.+  , propertyValue :: PropertyValue Property+  } deriving (Eq, Ord, Show)++$(deriveJson ''Property)
+ source/library/Rattletrap/Type/PropertyValue.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.PropertyValue+  ( PropertyValue(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Dictionary+import Rattletrap.Type.Float32le+import Rattletrap.Type.Int32le+import Rattletrap.Type.List+import Rattletrap.Type.Str+import Rattletrap.Type.Word64le+import Rattletrap.Type.Word8le++data PropertyValue a+  = PropertyValueArray (List (Dictionary a))+  -- ^ Yes, a list of dictionaries. No, it doesn't make sense. These usually+  -- only have one element.+  | PropertyValueBool Word8le+  | PropertyValueByte Str (Maybe Str)+  -- ^ This is a strange name for essentially a key-value pair.+  | PropertyValueFloat Float32le+  | PropertyValueInt Int32le+  | PropertyValueName Str+  -- ^ It's unclear how exactly this is different than a 'StrProperty'.+  | PropertyValueQWord Word64le+  | PropertyValueStr Str+  deriving (Eq, Ord, Show)++$(deriveJson ''PropertyValue)
+ source/library/Rattletrap/Type/QWordAttribute.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.QWordAttribute+  ( QWordAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Word64le++newtype QWordAttribute = QWordAttribute+  { qWordAttributeValue :: Word64le+  } deriving (Eq, Ord, Show)++$(deriveJson ''QWordAttribute)
+ source/library/Rattletrap/Type/Quaternion.hs view
@@ -0,0 +1,99 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Quaternion+  ( Quaternion(..)+  , Component(..)+  , toQuaternion+  , compressPart+  , decompressPart+  , maxComponent+  , maxCompressedValue+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.CompressedWord++import qualified Data.Maybe as Maybe++data Quaternion = Quaternion+  { quaternionX :: Double+  , quaternionY :: Double+  , quaternionZ :: Double+  , quaternionW :: Double+  } deriving (Eq, Ord, Show)++$(deriveJson ''Quaternion)++data Component+  = ComponentX+  | ComponentY+  | ComponentZ+  | ComponentW+  deriving (Eq, Ord, Show)++toQuaternion :: Component -> Double -> Double -> Double -> Quaternion+toQuaternion component a b c =+  let d = toPart a b c+  in+    case component of+      ComponentX -> Quaternion d a b c+      ComponentY -> Quaternion a d b c+      ComponentZ -> Quaternion a b d c+      ComponentW -> Quaternion a b c d++toPart :: Double -> Double -> Double -> Double+toPart a b c = sqrt (1 - (a * a) - (b * b) - (c * c))++compressPart :: Double -> CompressedWord+compressPart =+  CompressedWord maxCompressedValue+    . round+    . (* wordToDouble maxCompressedValue)+    . (+ 0.5)+    . (/ 2.0)+    . (/ maxValue)++decompressPart :: CompressedWord -> Double+decompressPart x =+  (* maxValue)+    . (* 2.0)+    . subtract 0.5+    . (/ wordToDouble (compressedWordLimit x))+    . wordToDouble+    $ compressedWordValue x++maxComponent :: Quaternion -> Component+maxComponent quaternion =+  let+    x = quaternionX quaternion+    y = quaternionY quaternion+    z = quaternionZ quaternion+    w = quaternionW quaternion+    parts =+      [(x, ComponentX), (y, ComponentY), (z, ComponentZ), (w, ComponentW)]+    biggestPart = maximum parts+    roundTrip = decompressPart . compressPart+    computedPart = Maybe.fromMaybe+      biggestPart+      (Maybe.listToMaybe+        (filter (\(value, _) -> value /= roundTrip value) parts)+      )+  in snd+    (if (biggestPart == computedPart)+        || (abs (fst biggestPart - fst computedPart) > 0.00001)+      then biggestPart+      else computedPart+    )++numBits :: Word+numBits = 18++wordToDouble :: Word -> Double+wordToDouble = fromIntegral++maxCompressedValue :: Word+maxCompressedValue = (2 ^ numBits) - 1++maxValue :: Double+maxValue = 1.0 / sqrt 2.0
+ source/library/Rattletrap/Type/RemoteId.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.RemoteId+  ( RemoteId(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Word64le++data RemoteId+  = RemoteIdPlayStation Text [Word8]+  | RemoteIdPsyNet (Either Word64le (Word64le, Word64le, Word64le, Word64le))+  | RemoteIdSplitscreen Word32+  -- ^ Really only 24 bits.+  | RemoteIdSteam Word64le+  | RemoteIdSwitch Word64le Word64le Word64le Word64le+  | RemoteIdXbox Word64le+  deriving (Eq, Ord, Show)++$(deriveJson ''RemoteId)
+ source/library/Rattletrap/Type/Replay.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Replay+  ( Replay(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Content+import Rattletrap.Type.Header+import Rattletrap.Type.Section++-- | A Rocket League replay.+data Replay = Replay+  { replayHeader :: Section Header+  -- ^ This has most of the high-level metadata.+  , replayContent :: Section Content+  -- ^ This has most of the low-level game data.+  } deriving (Eq, Ord, Show)++$(deriveJson ''Replay)
+ source/library/Rattletrap/Type/Replication.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Replication+  ( Replication(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.CompressedWord+import Rattletrap.Type.ReplicationValue++data Replication = Replication+  { replicationActorId :: CompressedWord+  , replicationValue :: ReplicationValue+  } deriving (Eq, Ord, Show)++$(deriveJson ''Replication)
+ source/library/Rattletrap/Type/ReplicationValue.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.ReplicationValue+  ( ReplicationValue(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.DestroyedReplication+import Rattletrap.Type.SpawnedReplication+import Rattletrap.Type.UpdatedReplication++data ReplicationValue+  = ReplicationValueSpawned SpawnedReplication+  -- ^ Creates a new actor.+  | ReplicationValueUpdated UpdatedReplication+  -- ^ Updates an existing actor.+  | ReplicationValueDestroyed DestroyedReplication+  -- ^ Destroys an existing actor.+  deriving (Eq, Ord, Show)++$(deriveJson ''ReplicationValue)
+ source/library/Rattletrap/Type/ReservationAttribute.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.ReservationAttribute+  ( ReservationAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.CompressedWord+import Rattletrap.Type.Str+import Rattletrap.Type.UniqueIdAttribute++data ReservationAttribute = ReservationAttribute+  { reservationAttributeNumber :: CompressedWord+  , reservationAttributeUniqueId :: UniqueIdAttribute+  , reservationAttributeName :: Maybe Str+  , reservationAttributeUnknown1 :: Bool+  , reservationAttributeUnknown2 :: Bool+  , reservationAttributeUnknown3 :: Maybe Word8+  } deriving (Eq, Ord, Show)++$(deriveJson ''ReservationAttribute)
+ source/library/Rattletrap/Type/RigidBodyStateAttribute.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.RigidBodyStateAttribute+  ( RigidBodyStateAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Rotation+import Rattletrap.Type.Vector++data RigidBodyStateAttribute = RigidBodyStateAttribute+  { rigidBodyStateAttributeSleeping :: Bool+  , rigidBodyStateAttributeLocation :: Vector+  , rigidBodyStateAttributeRotation :: Rotation+  , rigidBodyStateAttributeLinearVelocity :: Maybe Vector+  , rigidBodyStateAttributeAngularVelocity :: Maybe Vector+  } deriving (Eq, Ord, Show)++$(deriveJson ''RigidBodyStateAttribute)
+ source/library/Rattletrap/Type/Rotation.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Rotation+  ( Rotation(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Quaternion+import Rattletrap.Type.CompressedWordVector++data Rotation+  = RotationCompressedWordVector CompressedWordVector+  | RotationQuaternion Quaternion+  deriving (Eq, Ord, Show)++$(deriveJson ''Rotation)
+ source/library/Rattletrap/Type/Section.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Section+  ( Section(..)+  , toSection+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Word32le+import Rattletrap.Utility.Crc++import qualified Data.Binary as Binary+import qualified Data.Binary.Put as Binary+import qualified Data.ByteString as Bytes+import qualified Data.ByteString.Lazy as LazyBytes++-- | A section is a large piece of a 'Rattletrap.Replay.Replay'. It has a+-- 32-bit size (in bytes), a 32-bit CRC (see "Rattletrap.Utility.Crc"), and then a+-- 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+  { sectionSize :: Word32le+  -- ^ read only+  , sectionCrc :: Word32le+  -- ^ read only+  , sectionBody :: a+  -- ^ The actual content in the section.+  } deriving (Eq, Ord, Show)++$(deriveJson ''Section)++toSection :: (a -> Binary.Put) -> a -> Section a+toSection encode body =+  let bytes = LazyBytes.toStrict . Binary.runPut $ encode body+  in+    Section+      { sectionSize = Word32le . fromIntegral $ Bytes.length bytes+      , sectionCrc = Word32le $ getCrc32 bytes+      , sectionBody = body+      }
+ source/library/Rattletrap/Type/SpawnedReplication.hs view
@@ -0,0 +1,30 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.SpawnedReplication+  ( SpawnedReplication(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Initialization+import Rattletrap.Type.Str+import Rattletrap.Type.Word32le++data SpawnedReplication = SpawnedReplication+  { spawnedReplicationFlag :: Bool+  -- ^ Unclear what this is.+  , spawnedReplicationNameIndex :: Maybe Word32le+  , spawnedReplicationName :: Maybe Str+  -- ^ Read-only! Changing a replication's name requires editing the+  -- 'spawnedReplicationNameIndex' and maybe the class attribute map.+  , spawnedReplicationObjectId :: Word32le+  , spawnedReplicationObjectName :: Str+  -- ^ Read-only! Changing a replication's object requires editing the class+  -- attribute map.+  , spawnedReplicationClassName :: Str+  -- ^ Read-only! Changing a replication's class requires editing the class+  -- attribute map.+  , spawnedReplicationInitialization :: Initialization+  } deriving (Eq, Ord, Show)++$(deriveJson ''SpawnedReplication)
+ source/library/Rattletrap/Type/StatEventAttribute.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.StatEventAttribute+  ( StatEventAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Int32le++data StatEventAttribute = StatEventAttribute+  { statEventAttributeUnknown :: Bool+  , statEventAttributeObjectId :: Int32le+  } deriving (Eq, Ord, Show)++$(deriveJson ''StatEventAttribute)
+ source/library/Rattletrap/Type/Str.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Str+  ( Str(..)+  , toStr+  , fromStr+  )+where++import Rattletrap.Type.Common++import qualified Data.Text as Text++newtype Str = Str+  { strValue :: Text+  } deriving (Eq, Ord, Show)++$(deriveJson ''Str)++toStr :: String -> Str+toStr string = Str (Text.pack string)++fromStr :: Str -> String+fromStr text = Text.unpack (strValue text)
+ source/library/Rattletrap/Type/StringAttribute.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.StringAttribute+  ( StringAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Str++newtype StringAttribute = StringAttribute+  { stringAttributeValue :: Str+  } deriving (Eq, Ord, Show)++$(deriveJson ''StringAttribute)
+ source/library/Rattletrap/Type/TeamPaintAttribute.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.TeamPaintAttribute+  ( TeamPaintAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Word32le+import Rattletrap.Type.Word8le++data TeamPaintAttribute = TeamPaintAttribute+  { teamPaintAttributeTeam :: Word8le+  , teamPaintAttributePrimaryColor :: Word8le+  , teamPaintAttributeAccentColor :: Word8le+  , teamPaintAttributePrimaryFinish :: Word32le+  , teamPaintAttributeAccentFinish :: Word32le+  } deriving (Eq, Ord, Show)++$(deriveJson ''TeamPaintAttribute)
+ source/library/Rattletrap/Type/TitleAttribute.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.TitleAttribute+  ( TitleAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Word32le++data TitleAttribute = TitleAttribute+  { titleAttributeUnknown1 :: Bool+  , titleAttributeUnknown2 :: Bool+  , titleAttributeUnknown3 :: Word32le+  , titleAttributeUnknown4 :: Word32le+  , titleAttributeUnknown5 :: Word32le+  , titleAttributeUnknown6 :: Word32le+  , titleAttributeUnknown7 :: Word32le+  , titleAttributeUnknown8 :: Bool+  } deriving (Eq, Ord, Show)++$(deriveJson ''TitleAttribute)
+ source/library/Rattletrap/Type/UniqueIdAttribute.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.UniqueIdAttribute+  ( UniqueIdAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.RemoteId+import Rattletrap.Type.Word8le++data UniqueIdAttribute = UniqueIdAttribute+  { uniqueIdAttributeSystemId :: Word8le+  , uniqueIdAttributeRemoteId :: RemoteId+  , uniqueIdAttributeLocalId :: Word8le+  } deriving (Eq, Ord, Show)++$(deriveJson ''UniqueIdAttribute)
+ source/library/Rattletrap/Type/UpdatedReplication.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.UpdatedReplication+  ( UpdatedReplication(..)+  )+where++import Rattletrap.Type.Attribute+import Rattletrap.Type.Common++newtype UpdatedReplication = UpdatedReplication+  { updatedReplicationAttributes :: [Attribute]+  } deriving (Eq, Ord, Show)++$(deriveJson ''UpdatedReplication)
+ source/library/Rattletrap/Type/Vector.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Vector+  ( Vector(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.CompressedWord++data Vector = Vector+  { vectorSize :: CompressedWord+  , vectorBias :: 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.+  , vectorX :: Int+  -- ^ See 'vectorBias'.+  , vectorY :: Int+  -- ^ See 'vectorBias'.+  , vectorZ :: Int+  -- ^ See 'vectorBias'.+  } deriving (Eq, Ord, Show)++$(deriveJson ''Vector)
+ source/library/Rattletrap/Type/WeldedInfoAttribute.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.WeldedInfoAttribute+  ( WeldedInfoAttribute(..)+  )+where++import Rattletrap.Type.Common+import Rattletrap.Type.Float32le+import Rattletrap.Type.Int32le+import Rattletrap.Type.Int8Vector+import Rattletrap.Type.Vector++data WeldedInfoAttribute = WeldedInfoAttribute+  { weldedInfoAttributeActive :: Bool+  , weldedInfoAttributeActorId :: Int32le+  , weldedInfoAttributeOffset :: Vector+  , weldedInfoAttributeMass :: Float32le+  , weldedInfoAttributeRotation :: Int8Vector+  } deriving (Eq, Ord, Show)++$(deriveJson ''WeldedInfoAttribute)
+ source/library/Rattletrap/Type/Word32le.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Word32le+  ( Word32le(..)+  )+where++import Rattletrap.Type.Common++newtype Word32le = Word32le+  { word32leValue :: Word32+  } deriving (Eq, Ord, Show)++$(deriveJson ''Word32le)
+ source/library/Rattletrap/Type/Word64le.hs view
@@ -0,0 +1,28 @@+module Rattletrap.Type.Word64le+  ( Word64le(..)+  )+where++import qualified Data.Aeson as Aeson+import qualified Data.Aeson.Types as Aeson+import qualified Data.Scientific as Scientific+import qualified Data.Text as Text+import qualified Data.Word as Word+import qualified Text.Read as Read++newtype Word64le = Word64le+  { word64leValue :: Word.Word64+  } deriving (Eq, Ord, Show)++instance Aeson.FromJSON Word64le where+  parseJSON value = case value of+    Aeson.String text -> case Read.readEither $ Text.unpack text of+      Left _ -> Aeson.typeMismatch "Word64le" value+      Right word64 -> pure $ Word64le word64+    Aeson.Number number -> case Scientific.toBoundedInteger number of+      Nothing -> Aeson.typeMismatch "Word64le" value+      Just word64 -> pure $ Word64le word64+    _ -> Aeson.typeMismatch "Word64le" value++instance Aeson.ToJSON Word64le where+  toJSON = Aeson.toJSON . show . word64leValue
+ source/library/Rattletrap/Type/Word8le.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE TemplateHaskell #-}++module Rattletrap.Type.Word8le+  ( Word8le(..)+  )+where++import Rattletrap.Type.Common++newtype Word8le = Word8le+  { word8leValue :: Word8+  } deriving (Eq, Ord, Show)++$(deriveJson ''Word8le)
+ source/library/Rattletrap/Utility/Bytes.hs view
@@ -0,0 +1,33 @@+module Rattletrap.Utility.Bytes+  ( encodeLatin1+  , padBytes+  , reverseBytes+  )+where++import qualified Data.Bits as Bits+import qualified Data.ByteString as Bytes+import qualified Data.ByteString.Char8 as Bytes8+import qualified Data.Text as Text+import qualified Data.Word as Word++encodeLatin1 :: Text.Text -> Bytes.ByteString+encodeLatin1 text = Bytes8.pack (Text.unpack text)++padBytes :: Integral a => a -> Bytes.ByteString -> Bytes.ByteString+padBytes size bytes =+  bytes <> Bytes.replicate (fromIntegral size - Bytes.length bytes) 0x00++reverseByte :: Word.Word8 -> Word.Word8+reverseByte byte =+  Bits.shiftR (byte Bits..&. Bits.bit 7) 7+    + Bits.shiftR (byte Bits..&. Bits.bit 6) 5+    + Bits.shiftR (byte Bits..&. Bits.bit 5) 3+    + Bits.shiftR (byte Bits..&. Bits.bit 4) 1+    + Bits.shiftL (byte Bits..&. Bits.bit 3) 1+    + Bits.shiftL (byte Bits..&. Bits.bit 2) 3+    + Bits.shiftL (byte Bits..&. Bits.bit 1) 5+    + Bits.shiftL (byte Bits..&. Bits.bit 0) 7++reverseBytes :: Bytes.ByteString -> Bytes.ByteString+reverseBytes = Bytes.map reverseByte
+ source/library/Rattletrap/Utility/Crc.hs view
@@ -0,0 +1,47 @@+module Rattletrap.Utility.Crc+  ( getCrc32+  )+where++import Rattletrap.Data++import qualified Data.Bits as Bits+import qualified Data.ByteString as Bytes+import qualified Data.IntMap as IntMap+import qualified Data.Word as Word++-- | Computes the CRC32 of some bytes. This is done to ensure that the bytes+-- are valid before trying to parse them.+--+-- @+-- getCrc32 ('Data.ByteString.Lazy.pack' [0x00])+-- @+--+-- This CRC uses an initial value of @0xefcbf201@ and a polynomial of+-- @0x04c11db7@.+getCrc32 :: Bytes.ByteString -> Word.Word32+getCrc32 bytes = do+  let+    update = crc32Update crc32Table+    initial = Bits.complement crc32Initial+    crc = Bytes.foldl update initial bytes+  Bits.complement crc++crc32Update+  :: IntMap.IntMap Word.Word32 -> Word.Word32 -> Word.Word8 -> Word.Word32+crc32Update table crc byte = do+  let+    toWord8 :: (Integral a) => a -> Word.Word8+    toWord8 = fromIntegral+    toInt :: (Integral a) => a -> Int+    toInt = fromIntegral+    index = toInt (Bits.xor byte (toWord8 (Bits.shiftR crc 24)))+    left = table IntMap.! index+    right = Bits.shiftL crc 8+  Bits.xor left right++crc32Initial :: Word.Word32+crc32Initial = 0xefcbf201++crc32Table :: IntMap.IntMap Word.Word32+crc32Table = IntMap.fromDistinctAscList (zip [0 ..] rawCrc32Table)
+ source/library/Rattletrap/Utility/Helper.hs view
@@ -0,0 +1,46 @@+-- | This module provides helper functions for converting replays to and from+-- both their binary format and JSON.+module Rattletrap.Utility.Helper+  ( decodeReplayFile+  , encodeReplayJson+  , decodeReplayJson+  , encodeReplayFile+  )+where++import Rattletrap.Decode.Common+import Rattletrap.Encode.Content+import Rattletrap.Decode.Replay+import Rattletrap.Encode.Replay+import Rattletrap.Type.Replay+import Rattletrap.Type.Section+import Rattletrap.Type.Content++import qualified Data.Aeson as Json+import qualified Data.Aeson.Encode.Pretty as Json+import qualified Data.Binary.Put as Binary+import qualified Data.ByteString as Bytes+import qualified Data.ByteString.Lazy as LazyBytes++-- | Parses a raw replay.+decodeReplayFile :: Bool -> Bytes.ByteString -> Either String Replay+decodeReplayFile fast = runDecode $ decodeReplay fast++-- | Encodes a replay as JSON.+encodeReplayJson :: Replay -> Bytes.ByteString+encodeReplayJson = LazyBytes.toStrict . Json.encodePretty' Json.defConfig+  { Json.confCompare = compare+  , Json.confIndent = Json.Spaces 2+  , Json.confTrailingNewline = True+  }++-- | Parses a JSON replay.+decodeReplayJson :: Bytes.ByteString -> Either String Replay+decodeReplayJson = Json.eitherDecodeStrict'++-- | Encodes a raw replay.+encodeReplayFile :: Bool -> Replay -> Bytes.ByteString+encodeReplayFile fast replay =+  LazyBytes.toStrict . Binary.runPut . putReplay $ if fast+    then replay { replayContent = toSection putContent defaultContent }+    else replay
+ source/test-suite/Main.hs view
@@ -0,0 +1,187 @@+module Main+  ( main+  )+where++import qualified Control.Monad as Monad+import qualified Data.ByteString.Lazy as Bytes+import qualified Data.Int as Int+import qualified Data.Word as Word+import qualified GHC.Clock as Clock+import qualified Rattletrap+import qualified System.Exit as Exit+import qualified System.FilePath as Path+import qualified System.IO.Temp as Temp+import qualified System.Mem as Mem+import qualified Test.HUnit as Test+import qualified Text.Printf as Printf++main :: IO ()+main = Temp.withSystemTempDirectory "rattletrap-" (runTests . toTests)++runTests :: Test.Test -> IO ()+runTests test = do+  result <- Test.runTestTT test+  Monad.when+    (Test.errors result > 0 || Test.failures result > 0)+    Exit.exitFailure++toTests :: FilePath -> Test.Test+toTests directory = Test.TestList (fmap (toTest directory) replays)++toTest :: FilePath -> (String, String) -> Test.Test+toTest directory (uuid, name) = Test.TestLabel+  (toLabel uuid name)+  (Test.TestCase (toAssertion directory uuid))++toLabel :: String -> String -> String+toLabel uuid name = uuid <> ": " <> name++toAssertion :: FilePath -> String -> Test.Assertion+toAssertion directory uuid = do+  let+    inputFile = Path.joinPath ["replays", Path.addExtension uuid ".replay"]+    jsonFile = Path.joinPath [directory, Path.addExtension uuid ".json"]+    outputFile = Path.joinPath [directory, Path.addExtension uuid ".replay"]+  input <- Bytes.readFile inputFile+  putStrLn ("\t" <> uuid)+  do+    (((), allocated), elapsed) <- withElapsed+      (withAllocations (decode inputFile jsonFile))+    put "decoding" (Bytes.length input) elapsed allocated+  do+    (((), allocated), elapsed) <- withElapsed+      (withAllocations (encode jsonFile outputFile))+    put "encoding" (Bytes.length input) elapsed allocated+  output <- Bytes.readFile outputFile+  Monad.unless+    (output == input)+    (Test.assertFailure "output does not match input")++put :: String -> Int.Int64 -> Word.Word64 -> Int.Int64 -> IO ()+put label size elapsed allocated = Printf.printf+  "%s %d byte%s took %d nanosecond%s (%.3f MB/s) and allocated %d byte%s (%d x)\n"+  label+  size+  (if size == 1 then "" else "s")+  elapsed+  (if elapsed == 1 then "" else "s")+  ((1e9 * fromIntegral size) / (1048576 * fromIntegral elapsed) :: Double)+  allocated+  (if allocated == 1 then "" else "s")+  (div allocated size)++decode :: FilePath -> FilePath -> IO ()+decode input output =+  Rattletrap.rattletrap "" ["--compact", "--input", input, "--output", output]++encode :: FilePath -> FilePath -> IO ()+encode input output =+  Rattletrap.rattletrap "" ["--input", input, "--output", output]++withAllocations :: IO a -> IO (a, Int.Int64)+withAllocations action = do+  before <- Mem.getAllocationCounter+  result <- action+  after <- Mem.getAllocationCounter+  pure (result, before - after)++withElapsed :: IO a -> IO (a, Word.Word64)+withElapsed action = do+  before <- Clock.getMonotonicTimeNSec+  result <- action+  after <- Clock.getMonotonicTimeNSec+  pure (result, after - before)++replays :: [(String, String)]+replays =+  [ ("d1d5", "v1.68")+  , ("21a8", "v1.66")+  , ("0008", "a flip time")+  , ("000b", "nintendo switch")+  , ("07e9", "a game mode before Neo Tokyo")+  , ("0ad2", "some Latin-1 text")+  , ("1205", "rumble mode")+  , ("160c", "a dedicated server IP")+  , ("16d5", "new property types")+  , ("18d6", "an online loadout attribute")+  , ("1a12", "overtime")+  , ("1ae4", "a game time")+  , ("1bc2", "no padding after the frames")+  , ("1d1d", "a camera pitch")+  , ("1ec9", "a V1.63 match")+  , ("1ef9", "a private hoops match")+  , ("1f37", "splitscreen players")+  , ("2114", "a match save")+  , ("2266", "dropshot")+  , ("22ba", "a vote to forfeit")+  , ("27b6", "some UTF-16 text")+  , ("29f5", "frames")+  , ("2cfe", "a new playstation id")+  , ("3381", "patch 1.37")+  , ("372d", "a camera yaw attribute")+  , ("383e", "older unknown content field")+  , ("387f", "a frozen attribute")+  , ("3abd", "rlcs")+  , ("3ea1", "a custom team name")+  , ("4126", "a game mode after Neo Tokyo")+  , ("419a", "a club match")+  , ("42f0", "reservations after Neo Tokyo")+  , ("4bc3", "with timed out attribute")+  , ("504e", "some messages")+  , ("520e", "no pickup attribute")+  , ("524f", "quat edge case")+  , ("52aa", "a match-ending attribute")+  , ("540d", "a demolish attribute")+  , ("551c", "private match settings")+  , ("5a06", "esports items")+  , ("6210", "different player history key")+  , ("6320", "a forfeit attribute")+  , ("6688", "a malformed byte property")+  , ("6b0d", "patch 1.37")+  , ("6d1b", "a flip right")+  , ("6f7c", "a map with numbers")+  , ("7083", "weird basketball capitalization")+  , ("7109", "a boost modifier")+  , ("7256", "special edition")+  , ("75ce", "primary and secondary titles")+  , ("7bf6", "an online loadouts attribute")+  , ("89cb", "remote user data")+  , ("8ae5", "new painted items")+  , ("92a6", "with server performance state")+  , ("946f", "patch 1.43")+  , ("9704", "a batarang")+  , ("98e5", "a player using behind view")+  , ("9eaa", "newer replay without trailing bytes")+  , ("a09e", "a tournament")+  , ("a128", "a round count down")+  , ("a52f", "some more mutators")+  , ("a558", "extended explosion data")+  , ("a671", "a waiting player")+  , ("a676", "new user color")+  , ("a7f0", "a ready attribute")+  , ("a9df", "salty shores patch 1.45")+  , ("aa70", "patch 1.50 - TitleID attribute")+  , ("afb1", "patch 1.37")+  , ("b9f9", "a party leader")+  , ("c14f", "some mutators")+  , ("c23b", "new psynet id")+  , ("c837", "a spectator")+  , ("cc4c", "after Starbase ARC")+  , ("d044", "hoops mutators")+  , ("d236", "rlcs s2")+  , ("d428", "a private hockey match")+  , ("d52e", "psynet system id")+  , ("d7fb", "an explosion attribute")+  , ("db70", "new lag indicator")+  , ("dcb3", "a pawn type attribute")+  , ("de56", "a problematic product attribute")+  , ("e80d", "unlimited time")+  , ("eae3", "an actor/object ID collision")+  , ("eae8", "custom team colors")+  , ("edbb", "remote role")+  , ("f299", "a location attribute")+  , ("f7b9", "a hockey game event")+  , ("f811", "no frames")+  , ("fdc7", "an MVP")+  ]
− stack.yaml
@@ -1,1 +0,0 @@-resolver: nightly-2019-05-27
− tests/Main.hs
@@ -1,186 +0,0 @@-module Main-  ( main-  )-where--import qualified Control.Monad as Monad-import qualified Data.ByteString.Lazy as Bytes-import qualified Data.Int as Int-import qualified Data.Word as Word-import qualified GHC.Clock as Clock-import qualified Rattletrap-import qualified System.Exit as Exit-import qualified System.FilePath as Path-import qualified System.IO.Temp as Temp-import qualified System.Mem as Mem-import qualified Test.HUnit as Test-import qualified Text.Printf as Printf--main :: IO ()-main = Temp.withSystemTempDirectory "rattletrap-" (runTests . toTests)--runTests :: Test.Test -> IO ()-runTests test = do-  result <- Test.runTestTT test-  Monad.when-    (Test.errors result > 0 || Test.failures result > 0)-    Exit.exitFailure--toTests :: FilePath -> Test.Test-toTests directory = Test.TestList (fmap (toTest directory) replays)--toTest :: FilePath -> (String, String) -> Test.Test-toTest directory (uuid, name) = Test.TestLabel-  (toLabel uuid name)-  (Test.TestCase (toAssertion directory uuid))--toLabel :: String -> String -> String-toLabel uuid name = uuid <> ": " <> name--toAssertion :: FilePath -> String -> Test.Assertion-toAssertion directory uuid = do-  let-    inputFile = Path.joinPath ["replays", Path.addExtension uuid ".replay"]-    jsonFile = Path.joinPath [directory, Path.addExtension uuid ".json"]-    outputFile = Path.joinPath [directory, Path.addExtension uuid ".replay"]-  input <- Bytes.readFile inputFile-  putStrLn ("\t" <> uuid)-  do-    (((), allocated), elapsed) <- withElapsed-      (withAllocations (decode inputFile jsonFile))-    put "decoding" (Bytes.length input) elapsed allocated-  do-    (((), allocated), elapsed) <- withElapsed-      (withAllocations (encode jsonFile outputFile))-    put "encoding" (Bytes.length input) elapsed allocated-  output <- Bytes.readFile outputFile-  Monad.unless-    (output == input)-    (Test.assertFailure "output does not match input")--put :: String -> Int.Int64 -> Word.Word64 -> Int.Int64 -> IO ()-put label size elapsed allocated = Printf.printf-  "%s %d byte%s took %d nanosecond%s (%.3f MB/s) and allocated %d byte%s (%d x)\n"-  label-  size-  (if size == 1 then "" else "s")-  elapsed-  (if elapsed == 1 then "" else "s")-  ((1e9 * fromIntegral size) / (1048576 * fromIntegral elapsed) :: Double)-  allocated-  (if allocated == 1 then "" else "s")-  (div allocated size)--decode :: FilePath -> FilePath -> IO ()-decode input output =-  Rattletrap.rattletrap "" ["--compact", "--input", input, "--output", output]--encode :: FilePath -> FilePath -> IO ()-encode input output =-  Rattletrap.rattletrap "" ["--input", input, "--output", output]--withAllocations :: IO a -> IO (a, Int.Int64)-withAllocations action = do-  before <- Mem.getAllocationCounter-  result <- action-  after <- Mem.getAllocationCounter-  pure (result, before - after)--withElapsed :: IO a -> IO (a, Word.Word64)-withElapsed action = do-  before <- Clock.getMonotonicTimeNSec-  result <- action-  after <- Clock.getMonotonicTimeNSec-  pure (result, after - before)--replays :: [(String, String)]-replays =-  [ ("21a8", "v1.66")-  , ("0008", "a flip time")-  , ("000b", "nintendo switch")-  , ("07e9", "a game mode before Neo Tokyo")-  , ("0ad2", "some Latin-1 text")-  , ("1205", "rumble mode")-  , ("160c", "a dedicated server IP")-  , ("16d5", "new property types")-  , ("18d6", "an online loadout attribute")-  , ("1a12", "overtime")-  , ("1ae4", "a game time")-  , ("1bc2", "no padding after the frames")-  , ("1d1d", "a camera pitch")-  , ("1ec9", "a V1.63 match")-  , ("1ef9", "a private hoops match")-  , ("1f37", "splitscreen players")-  , ("2114", "a match save")-  , ("2266", "dropshot")-  , ("22ba", "a vote to forfeit")-  , ("27b6", "some UTF-16 text")-  , ("29f5", "frames")-  , ("2cfe", "a new playstation id")-  , ("3381", "patch 1.37")-  , ("372d", "a camera yaw attribute")-  , ("383e", "older unknown content field")-  , ("387f", "a frozen attribute")-  , ("3abd", "rlcs")-  , ("3ea1", "a custom team name")-  , ("4126", "a game mode after Neo Tokyo")-  , ("419a", "a club match")-  , ("42f0", "reservations after Neo Tokyo")-  , ("4bc3", "with timed out attribute")-  , ("504e", "some messages")-  , ("520e", "no pickup attribute")-  , ("524f", "quat edge case")-  , ("52aa", "a match-ending attribute")-  , ("540d", "a demolish attribute")-  , ("551c", "private match settings")-  , ("5a06", "esports items")-  , ("6210", "different player history key")-  , ("6320", "a forfeit attribute")-  , ("6688", "a malformed byte property")-  , ("6b0d", "patch 1.37")-  , ("6d1b", "a flip right")-  , ("6f7c", "a map with numbers")-  , ("7083", "weird basketball capitalization")-  , ("7109", "a boost modifier")-  , ("7256", "special edition")-  , ("75ce", "primary and secondary titles")-  , ("7bf6", "an online loadouts attribute")-  , ("89cb", "remote user data")-  , ("8ae5", "new painted items")-  , ("92a6", "with server performance state")-  , ("946f", "patch 1.43")-  , ("9704", "a batarang")-  , ("98e5", "a player using behind view")-  , ("9eaa", "newer replay without trailing bytes")-  , ("a09e", "a tournament")-  , ("a128", "a round count down")-  , ("a52f", "some more mutators")-  , ("a558", "extended explosion data")-  , ("a671", "a waiting player")-  , ("a676", "new user color")-  , ("a7f0", "a ready attribute")-  , ("a9df", "salty shores patch 1.45")-  , ("aa70", "patch 1.50 - TitleID attribute")-  , ("afb1", "patch 1.37")-  , ("b9f9", "a party leader")-  , ("c14f", "some mutators")-  , ("c23b", "new psynet id")-  , ("c837", "a spectator")-  , ("cc4c", "after Starbase ARC")-  , ("d044", "hoops mutators")-  , ("d236", "rlcs s2")-  , ("d428", "a private hockey match")-  , ("d52e", "psynet system id")-  , ("d7fb", "an explosion attribute")-  , ("db70", "new lag indicator")-  , ("dcb3", "a pawn type attribute")-  , ("de56", "a problematic product attribute")-  , ("e80d", "unlimited time")-  , ("eae3", "an actor/object ID collision")-  , ("eae8", "custom team colors")-  , ("edbb", "remote role")-  , ("f299", "a location attribute")-  , ("f7b9", "a hockey game event")-  , ("f811", "no frames")-  , ("fdc7", "an MVP")-  ]