diff --git a/library/Rattletrap/Data.hs b/library/Rattletrap/Data.hs
--- a/library/Rattletrap/Data.hs
+++ b/library/Rattletrap/Data.hs
@@ -1,4 +1,11 @@
-module Rattletrap.Data where
+module Rattletrap.Data
+  ( rawParentClasses
+  , rawClassesWithLocation
+  , rawClassesWithRotation
+  , rawObjectClasses
+  , rawAttributeTypes
+  , rawCrc32Table
+  ) where
 
 import Rattletrap.Type.AttributeType
 
@@ -123,6 +130,7 @@
   , ("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")
diff --git a/library/Rattletrap/Decode/CompressedWordVector.hs b/library/Rattletrap/Decode/CompressedWordVector.hs
--- a/library/Rattletrap/Decode/CompressedWordVector.hs
+++ b/library/Rattletrap/Decode/CompressedWordVector.hs
@@ -6,12 +6,12 @@
 import Rattletrap.Decode.CompressedWord
 import Rattletrap.Type.CompressedWordVector
 
-decodeCompressedWordVectorBits :: (Int, Int, Int) -> DecodeBits CompressedWordVector
-decodeCompressedWordVectorBits version =
+decodeCompressedWordVectorBits :: DecodeBits CompressedWordVector
+decodeCompressedWordVectorBits =
   CompressedWordVector
-    <$> decodeCompressedWordBits (limit version)
-    <*> decodeCompressedWordBits (limit version)
-    <*> decodeCompressedWordBits (limit version)
+    <$> decodeCompressedWordBits limit
+    <*> decodeCompressedWordBits limit
+    <*> decodeCompressedWordBits limit
 
-limit :: (Int, Int, Int) -> Word
-limit version = if version >= (868, 22, 7) then 262144 else 65536
+limit :: Word
+limit = 65536
diff --git a/library/Rattletrap/Decode/Quaternion.hs b/library/Rattletrap/Decode/Quaternion.hs
new file mode 100644
--- /dev/null
+++ b/library/Rattletrap/Decode/Quaternion.hs
@@ -0,0 +1,26 @@
+module Rattletrap.Decode.Quaternion
+  ( decodeQuaternionBits
+  )
+where
+
+import Rattletrap.Decode.Common
+import Rattletrap.Decode.CompressedWord
+import Rattletrap.Type.CompressedWord
+import Rattletrap.Type.Quaternion
+
+decodeQuaternionBits :: DecodeBits Quaternion
+decodeQuaternionBits =
+  toQuaternion <$> decodeComponent <*> decodePart <*> decodePart <*> decodePart
+
+decodeComponent :: DecodeBits Component
+decodeComponent = do
+  x <- decodeCompressedWordBits 3
+  case compressedWordValue x of
+    0 -> pure ComponentX
+    1 -> pure ComponentY
+    2 -> pure ComponentZ
+    3 -> pure ComponentW
+    y -> fail ("invalid component: " <> show y)
+
+decodePart :: DecodeBits Double
+decodePart = decompressPart <$> decodeCompressedWordBits maxCompressedValue
diff --git a/library/Rattletrap/Decode/Replay.hs b/library/Rattletrap/Decode/Replay.hs
--- a/library/Rattletrap/Decode/Replay.hs
+++ b/library/Rattletrap/Decode/Replay.hs
@@ -30,8 +30,19 @@
 getVersion header =
   ( fromIntegral (word32leValue (headerEngineVersion header))
   , fromIntegral (word32leValue (headerLicenseeVersion header))
-  , maybe 0 (fromIntegral . word32leValue) (headerPatchVersion header)
+  , getPatchVersion header
   )
+
+getPatchVersion :: Header -> Int
+getPatchVersion header = case headerPatchVersion header of
+  Just version -> fromIntegral (word32leValue version)
+  Nothing ->
+    case dictionaryLookup (toStr "MatchType") (headerProperties header) of
+      -- This is an ugly, ugly hack to handle replays from season 2 of RLCS.
+      -- See `decodeSpawnedReplicationBits` and #85.
+      Just Property { propertyValue = PropertyValueName str }
+        | fromStr str == "Lan" -> -1
+      _ -> 0
 
 getNumFrames :: Header -> Int
 getNumFrames header =
diff --git a/library/Rattletrap/Decode/RigidBodyStateAttribute.hs b/library/Rattletrap/Decode/RigidBodyStateAttribute.hs
--- a/library/Rattletrap/Decode/RigidBodyStateAttribute.hs
+++ b/library/Rattletrap/Decode/RigidBodyStateAttribute.hs
@@ -3,7 +3,7 @@
   ) where
 
 import Rattletrap.Decode.Common
-import Rattletrap.Decode.CompressedWordVector
+import Rattletrap.Decode.Rotation
 import Rattletrap.Decode.Vector
 import Rattletrap.Type.RigidBodyStateAttribute
 
@@ -12,8 +12,6 @@
   sleeping <- getBool
   RigidBodyStateAttribute sleeping
     <$> decodeVectorBits version
-    <*> decodeWhen (version >= (868, 22, 7)) getBool
-    <*> decodeCompressedWordVectorBits version
-    <*> decodeWhen (version >= (868, 22, 7)) getBool
+    <*> decodeRotationBits version
     <*> decodeWhen (not sleeping) (decodeVectorBits version)
     <*> decodeWhen (not sleeping) (decodeVectorBits version)
diff --git a/library/Rattletrap/Decode/Rotation.hs b/library/Rattletrap/Decode/Rotation.hs
new file mode 100644
--- /dev/null
+++ b/library/Rattletrap/Decode/Rotation.hs
@@ -0,0 +1,14 @@
+module Rattletrap.Decode.Rotation
+  ( decodeRotationBits
+  )
+where
+
+import Rattletrap.Decode.Common
+import Rattletrap.Decode.CompressedWordVector
+import Rattletrap.Decode.Quaternion
+import Rattletrap.Type.Rotation
+
+decodeRotationBits :: (Int, Int, Int) -> DecodeBits Rotation
+decodeRotationBits version = if version >= (868, 22, 7)
+  then RotationQuaternion <$> decodeQuaternionBits
+  else RotationCompressedWordVector <$> decodeCompressedWordVectorBits
diff --git a/library/Rattletrap/Encode/Quaternion.hs b/library/Rattletrap/Encode/Quaternion.hs
new file mode 100644
--- /dev/null
+++ b/library/Rattletrap/Encode/Quaternion.hs
@@ -0,0 +1,41 @@
+module Rattletrap.Encode.Quaternion
+  ( putQuaternion
+  )
+where
+
+import Rattletrap.Encode.CompressedWord
+import Rattletrap.Type.CompressedWord
+import Rattletrap.Type.Quaternion
+
+import qualified Data.Binary.Bits.Put as BinaryBits
+
+putQuaternion :: Quaternion -> BinaryBits.BitPut ()
+putQuaternion q = do
+  let c = maxComponent q
+  putComponent c
+  case c of
+    ComponentX -> putParts (quaternionY q) (quaternionZ q) (quaternionW q)
+    ComponentY -> putParts (quaternionX q) (quaternionZ q) (quaternionW q)
+    ComponentZ -> putParts (quaternionX q) (quaternionY q) (quaternionW q)
+    ComponentW -> putParts (quaternionX q) (quaternionY q) (quaternionZ q)
+
+putComponent :: Component -> BinaryBits.BitPut ()
+putComponent component = putCompressedWord
+  (CompressedWord
+    3
+    (case component of
+      ComponentX -> 0
+      ComponentY -> 1
+      ComponentZ -> 2
+      ComponentW -> 3
+    )
+  )
+
+putParts :: Double -> Double -> Double -> BinaryBits.BitPut ()
+putParts a b c = do
+  putPart a
+  putPart b
+  putPart c
+
+putPart :: Double -> BinaryBits.BitPut ()
+putPart = putCompressedWord . compressPart
diff --git a/library/Rattletrap/Encode/RigidBodyStateAttribute.hs b/library/Rattletrap/Encode/RigidBodyStateAttribute.hs
--- a/library/Rattletrap/Encode/RigidBodyStateAttribute.hs
+++ b/library/Rattletrap/Encode/RigidBodyStateAttribute.hs
@@ -2,7 +2,7 @@
   ( putRigidBodyStateAttribute
   ) where
 
-import Rattletrap.Encode.CompressedWordVector
+import Rattletrap.Encode.Rotation
 import Rattletrap.Encode.Vector
 import Rattletrap.Type.RigidBodyStateAttribute
 
@@ -12,10 +12,8 @@
 putRigidBodyStateAttribute rigidBodyStateAttribute = do
   BinaryBits.putBool (rigidBodyStateAttributeSleeping rigidBodyStateAttribute)
   putVector (rigidBodyStateAttributeLocation rigidBodyStateAttribute)
-  maybe (pure ()) BinaryBits.putBool (rigidBodyStateAttributeUnknown1 rigidBodyStateAttribute)
-  putCompressedWordVector
+  putRotation
     (rigidBodyStateAttributeRotation rigidBodyStateAttribute)
-  maybe (pure ()) BinaryBits.putBool (rigidBodyStateAttributeUnknown2 rigidBodyStateAttribute)
   case rigidBodyStateAttributeLinearVelocity rigidBodyStateAttribute of
     Nothing -> pure ()
     Just linearVelocity -> putVector linearVelocity
diff --git a/library/Rattletrap/Encode/Rotation.hs b/library/Rattletrap/Encode/Rotation.hs
new file mode 100644
--- /dev/null
+++ b/library/Rattletrap/Encode/Rotation.hs
@@ -0,0 +1,15 @@
+module Rattletrap.Encode.Rotation
+  ( putRotation
+  )
+where
+
+import Rattletrap.Encode.CompressedWordVector
+import Rattletrap.Encode.Quaternion
+import Rattletrap.Type.Rotation
+
+import qualified Data.Binary.Bits.Put as BinaryBits
+
+putRotation :: Rotation -> BinaryBits.BitPut ()
+putRotation r = case r of
+  RotationCompressedWordVector cwv -> putCompressedWordVector cwv
+  RotationQuaternion q -> putQuaternion q
diff --git a/library/Rattletrap/Type/Quaternion.hs b/library/Rattletrap/Type/Quaternion.hs
new file mode 100644
--- /dev/null
+++ b/library/Rattletrap/Type/Quaternion.hs
@@ -0,0 +1,100 @@
+{-# LANGUAGE TemplateHaskell #-}
+
+module Rattletrap.Type.Quaternion
+  ( Quaternion(..)
+  , Component(..)
+  , toQuaternion
+  , toPart
+  , compressPart
+  , decompressPart
+  , maxComponent
+  , maxCompressedValue
+  )
+where
+
+import Rattletrap.Type.Common
+import Rattletrap.Type.CompressedWord
+
+import qualified Data.Maybe as Maybe
+
+data Quaternion = Quaternion
+  { quaternionX :: Double
+  , quaternionY :: Double
+  , quaternionZ :: Double
+  , quaternionW :: Double
+  } deriving (Eq, Ord, Show)
+
+$(deriveJson ''Quaternion)
+
+data Component
+  = ComponentX
+  | ComponentY
+  | ComponentZ
+  | ComponentW
+  deriving (Eq, Ord, Show)
+
+toQuaternion :: Component -> Double -> Double -> Double -> Quaternion
+toQuaternion component a b c =
+  let d = toPart a b c
+  in
+    case component of
+      ComponentX -> Quaternion d a b c
+      ComponentY -> Quaternion a d b c
+      ComponentZ -> Quaternion a b d c
+      ComponentW -> Quaternion a b c d
+
+toPart :: Double -> Double -> Double -> Double
+toPart a b c = sqrt (1 - (a * a) - (b * b) - (c * c))
+
+compressPart :: Double -> CompressedWord
+compressPart =
+  CompressedWord maxCompressedValue
+    . round
+    . (* wordToDouble maxCompressedValue)
+    . (+ 0.5)
+    . (/ 2.0)
+    . (/ maxValue)
+
+decompressPart :: CompressedWord -> Double
+decompressPart x =
+  (* maxValue)
+    . (* 2.0)
+    . subtract 0.5
+    . (/ wordToDouble (compressedWordLimit x))
+    . wordToDouble
+    $ compressedWordValue x
+
+maxComponent :: Quaternion -> Component
+maxComponent quaternion
+  = let
+      x = quaternionX quaternion
+      y = quaternionY quaternion
+      z = quaternionZ quaternion
+      w = quaternionW quaternion
+      parts =
+        [(x, ComponentX), (y, ComponentY), (z, ComponentZ), (w, ComponentW)]
+      biggestPart = maximum parts
+      roundTrip = decompressPart . compressPart
+      computedPart = Maybe.fromMaybe
+        biggestPart
+        (Maybe.listToMaybe
+          (filter (\(value, _) -> value /= roundTrip value) parts)
+        )
+    in snd
+      (if (biggestPart == computedPart)
+          || (abs (fst biggestPart - fst computedPart) > 0.00001)
+        then biggestPart
+        else computedPart
+      )
+
+numBits :: Word
+numBits = 18
+
+wordToDouble :: Word -> Double
+wordToDouble = fromIntegral
+
+maxCompressedValue :: Word
+maxCompressedValue = (2 ^ numBits) - 1
+
+maxValue :: Double
+maxValue = 1.0 / sqrt 2.0
diff --git a/library/Rattletrap/Type/RigidBodyStateAttribute.hs b/library/Rattletrap/Type/RigidBodyStateAttribute.hs
--- a/library/Rattletrap/Type/RigidBodyStateAttribute.hs
+++ b/library/Rattletrap/Type/RigidBodyStateAttribute.hs
@@ -5,15 +5,13 @@
   ) where
 
 import Rattletrap.Type.Common
-import Rattletrap.Type.CompressedWordVector
+import Rattletrap.Type.Rotation
 import Rattletrap.Type.Vector
 
 data RigidBodyStateAttribute = RigidBodyStateAttribute
   { rigidBodyStateAttributeSleeping :: Bool
   , rigidBodyStateAttributeLocation :: Vector
-  , rigidBodyStateAttributeUnknown1 :: Maybe Bool
-  , rigidBodyStateAttributeRotation :: CompressedWordVector
-  , rigidBodyStateAttributeUnknown2 :: Maybe Bool
+  , rigidBodyStateAttributeRotation :: Rotation
   , rigidBodyStateAttributeLinearVelocity :: Maybe Vector
   , rigidBodyStateAttributeAngularVelocity :: Maybe Vector
   } deriving (Eq, Ord, Show)
diff --git a/library/Rattletrap/Type/Rotation.hs b/library/Rattletrap/Type/Rotation.hs
new file mode 100644
--- /dev/null
+++ b/library/Rattletrap/Type/Rotation.hs
@@ -0,0 +1,17 @@
+{-# LANGUAGE TemplateHaskell #-}
+
+module Rattletrap.Type.Rotation
+  ( Rotation(..)
+  )
+where
+
+import Rattletrap.Type.Common
+import Rattletrap.Type.Quaternion
+import Rattletrap.Type.CompressedWordVector
+
+data Rotation
+  = RotationCompressedWordVector CompressedWordVector
+  | RotationQuaternion Quaternion
+  deriving (Eq, Ord, Show)
+
+$(deriveJson ''Rotation)
diff --git a/library/Rattletrap/Utility/Bytes.hs b/library/Rattletrap/Utility/Bytes.hs
--- a/library/Rattletrap/Utility/Bytes.hs
+++ b/library/Rattletrap/Utility/Bytes.hs
@@ -1,4 +1,9 @@
-module Rattletrap.Utility.Bytes where
+module Rattletrap.Utility.Bytes
+  ( encodeLatin1
+  , padBytes
+  , reverseByte
+  , reverseBytes
+  ) where
 
 import qualified Data.Bits as Bits
 import qualified Data.ByteString.Lazy as LazyBytes
diff --git a/package.yaml b/package.yaml
--- a/package.yaml
+++ b/package.yaml
@@ -1,5 +1,5 @@
 name: rattletrap
-version: 4.1.2
+version: 5.0.0
 
 category: Game
 description: Rattletrap parses and generates Rocket League replays.
@@ -31,7 +31,9 @@
 ghc-options:
   - -optP -Wno-nonportable-include-path # https://github.com/haskell/cabal/issues/4739
   - -Weverything
+  - -Wno-all-missed-specialisations
   - -Wno-implicit-prelude
+  - -Wno-missing-exported-signatures # https://ghc.haskell.org/trac/ghc/ticket/14794
   - -Wno-missing-import-lists
   - -Wno-safe
   - -Wno-unsafe
diff --git a/rattletrap.cabal b/rattletrap.cabal
--- a/rattletrap.cabal
+++ b/rattletrap.cabal
@@ -2,10 +2,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: f97575be8798337622664b2f229d5417b0e7e29fefe6a61109a65cb02abb3208
+-- hash: 9ba2a9aa65fbdd16f1e3edc2524f922e6ffb9e794cd408c41397f03c5cb37ad8
 
 name:           rattletrap
-version:        4.1.2
+version:        5.0.0
 synopsis:       Parse and generate Rocket League replays.
 description:    Rattletrap parses and generates Rocket League replays.
 category:       Game
@@ -85,6 +85,7 @@
       Rattletrap.Decode.ProductAttribute
       Rattletrap.Decode.Property
       Rattletrap.Decode.PropertyValue
+      Rattletrap.Decode.Quaternion
       Rattletrap.Decode.QWordAttribute
       Rattletrap.Decode.RemoteId
       Rattletrap.Decode.Replay
@@ -92,6 +93,7 @@
       Rattletrap.Decode.ReplicationValue
       Rattletrap.Decode.ReservationAttribute
       Rattletrap.Decode.RigidBodyStateAttribute
+      Rattletrap.Decode.Rotation
       Rattletrap.Decode.Section
       Rattletrap.Decode.SpawnedReplication
       Rattletrap.Decode.StatEventAttribute
@@ -155,6 +157,7 @@
       Rattletrap.Encode.ProductAttribute
       Rattletrap.Encode.Property
       Rattletrap.Encode.PropertyValue
+      Rattletrap.Encode.Quaternion
       Rattletrap.Encode.QWordAttribute
       Rattletrap.Encode.RemoteId
       Rattletrap.Encode.Replay
@@ -162,6 +165,7 @@
       Rattletrap.Encode.ReplicationValue
       Rattletrap.Encode.ReservationAttribute
       Rattletrap.Encode.RigidBodyStateAttribute
+      Rattletrap.Encode.Rotation
       Rattletrap.Encode.Section
       Rattletrap.Encode.SpawnedReplication
       Rattletrap.Encode.StatEventAttribute
@@ -228,6 +232,7 @@
       Rattletrap.Type.ProductAttribute
       Rattletrap.Type.Property
       Rattletrap.Type.PropertyValue
+      Rattletrap.Type.Quaternion
       Rattletrap.Type.QWordAttribute
       Rattletrap.Type.RemoteId
       Rattletrap.Type.Replay
@@ -235,6 +240,7 @@
       Rattletrap.Type.ReplicationValue
       Rattletrap.Type.ReservationAttribute
       Rattletrap.Type.RigidBodyStateAttribute
+      Rattletrap.Type.Rotation
       Rattletrap.Type.Section
       Rattletrap.Type.SpawnedReplication
       Rattletrap.Type.StatEventAttribute
@@ -256,7 +262,7 @@
       Paths_rattletrap
   hs-source-dirs:
       library
-  ghc-options: -optP -Wno-nonportable-include-path -Weverything -Wno-implicit-prelude -Wno-missing-import-lists -Wno-safe -Wno-unsafe
+  ghc-options: -optP -Wno-nonportable-include-path -Weverything -Wno-all-missed-specialisations -Wno-implicit-prelude -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-safe -Wno-unsafe
   build-depends:
       aeson >=1.2.4 && <1.5
     , aeson-pretty >=0.8.5 && <0.9
@@ -279,7 +285,7 @@
       Paths_rattletrap
   hs-source-dirs:
       executables
-  ghc-options: -optP -Wno-nonportable-include-path -Weverything -Wno-implicit-prelude -Wno-missing-import-lists -Wno-safe -Wno-unsafe -rtsopts -threaded
+  ghc-options: -optP -Wno-nonportable-include-path -Weverything -Wno-all-missed-specialisations -Wno-implicit-prelude -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-safe -Wno-unsafe -rtsopts -threaded
   build-depends:
       aeson >=1.2.4 && <1.5
     , aeson-pretty >=0.8.5 && <0.9
@@ -306,7 +312,7 @@
       Paths_rattletrap
   hs-source-dirs:
       tests
-  ghc-options: -optP -Wno-nonportable-include-path -Weverything -Wno-implicit-prelude -Wno-missing-import-lists -Wno-safe -Wno-unsafe -rtsopts -threaded
+  ghc-options: -optP -Wno-nonportable-include-path -Weverything -Wno-all-missed-specialisations -Wno-implicit-prelude -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-safe -Wno-unsafe -rtsopts -threaded
   build-depends:
       HUnit >=1.6.0 && <1.7
     , aeson >=1.2.4 && <1.5
diff --git a/tests/Main.hs b/tests/Main.hs
--- a/tests/Main.hs
+++ b/tests/Main.hs
@@ -1,17 +1,26 @@
-import Control.Exception (displayException, try)
-import Control.Monad (unless)
-import Data.ByteString.Lazy (readFile)
-import Prelude hiding (readFile)
-import Rattletrap.Console.Main (rattletrap)
-import System.FilePath (addExtension, joinPath)
-import System.IO.Temp (withSystemTempDirectory)
-import Text.Printf (printf)
+module Main
+  ( main
+  )
+where
 
+import qualified Control.Monad as Monad
+import qualified Data.ByteString.Lazy as Bytes
+import qualified Rattletrap.Console.Main as Rattletrap
+import qualified System.Exit as Exit
+import qualified System.FilePath as Path
+import qualified System.IO.Temp as Temp
 import qualified Test.HUnit as Test
 
-main :: IO Test.Counts
-main = withSystemTempDirectory "rattletrap-" (Test.runTestTT . toTests)
+main :: IO ()
+main = Temp.withSystemTempDirectory "rattletrap-" (runTests . toTests)
 
+runTests :: Test.Test -> IO ()
+runTests test = do
+  result <- Test.runTestTT test
+  Monad.when
+    (Test.errors result > 0 || Test.failures result > 0)
+    Exit.exitFailure
+
 toTests :: FilePath -> Test.Test
 toTests directory = Test.TestList (fmap (toTest directory) replays)
 
@@ -21,23 +30,23 @@
   (Test.TestCase (toAssertion directory uuid))
 
 toLabel :: String -> String -> String
-toLabel = printf "%s: %s"
+toLabel uuid name = uuid <> ": " <> name
 
 toAssertion :: FilePath -> String -> Test.Assertion
 toAssertion directory uuid = do
-  let inputFile = joinPath ["replays", addExtension uuid ".replay"]
-  result <- try (readFile inputFile)
-  case result of
-    Left problem -> putStrLn (displayException (problem :: IOError))
-    Right input -> do
-      let jsonFile = joinPath [directory, addExtension uuid ".json"]
-      rattletrap "" ["--compact", "--input", inputFile, "--output", jsonFile]
-      let outputFile = joinPath [directory, addExtension uuid ".replay"]
-      rattletrap "" ["--input", jsonFile, "--output", outputFile]
-      output <- readFile outputFile
-      unless
-        (output == input)
-        (Test.assertFailure "output does not match input")
+  let
+    inputFile = Path.joinPath ["replays", Path.addExtension uuid ".replay"]
+    jsonFile = Path.joinPath [directory, Path.addExtension uuid ".json"]
+    outputFile = Path.joinPath [directory, Path.addExtension uuid ".replay"]
+  input <- Bytes.readFile inputFile
+  Rattletrap.rattletrap
+    ""
+    ["--compact", "--input", inputFile, "--output", jsonFile]
+  Rattletrap.rattletrap "" ["--input", jsonFile, "--output", outputFile]
+  output <- Bytes.readFile outputFile
+  Monad.unless
+    (output == input)
+    (Test.assertFailure "output does not match input")
 
 replays :: [(String, String)]
 replays =
@@ -64,11 +73,13 @@
   , ("3381", "patch 1.37")
   , ("372d", "a camera yaw attribute")
   , ("387f", "a frozen attribute")
+  , ("3abd", "rlcs")
   , ("3ea1", "a custom team name")
   , ("4126", "a game mode after Neo Tokyo")
   , ("42f0", "reservations after Neo Tokyo")
   , ("504e", "some messages")
   , ("520e", "no pickup attribute")
+  , ("524f", "quat edge case")
   , ("52aa", "a match-ending attribute")
   , ("540d", "a demolish attribute")
   , ("551c", "private match settings")
@@ -101,6 +112,7 @@
   , ("c837", "a spectator")
   , ("cc4c", "after Starbase ARC")
   , ("d044", "hoops mutators")
+  , ("d236", "rlcs s2")
   , ("d428", "a private hockey match")
   , ("d7fb", "an explosion attribute")
   , ("db70", "new lag indicator")
