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