Skip to content

Instantly share code, notes, and snippets.

@tfausak
Last active July 8, 2018 21:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tfausak/c39fce5768727305e21a19e8e2ed9f6a to your computer and use it in GitHub Desktop.
Save tfausak/c39fce5768727305e21a19e8e2ed9f6a to your computer and use it in GitHub Desktop.
Changes every car in a Rocket League replay to be Octane with the striped decal. Uses Rattletrap: https://github.com/tfausak/rattletrap
#!/usr/bin/env stack
-- stack --resolver nightly-2018-06-01 script --compile
-- To run this, first install Stack: <https://haskellstack.org>.
-- Then run this from the command line: `stack edit-replay.hs input.replay output.replay`
module Main ( main ) where
import qualified Data.ByteString.Lazy as L
import qualified Data.Map as M
import qualified Data.Word as W
import qualified Rattletrap as R
import qualified Rattletrap.Type.Str as R
import qualified System.Directory as D
import qualified System.Environment as E
import qualified System.FilePath as F
data Team = Blue | Orange deriving (Eq, Ord)
replacements :: M.Map Team (M.Map W.Word32 W.Word32)
replacements = M.fromList
[ (Blue, M.fromList
[ (23, 306) -- For the blue team, body 23 (Octane) should end up with decal 306 (Stripes).
, (403, 508) -- Add more replacements to the blue team like this.
])
, (Orange, M.fromList
[ (23, 305) -- For the orange team, body 23 (Octane) should end up with decal 305 (Stars).
, (403, 510) -- Add more replacements to the orange team like this.
])
]
-- This code is hideous. Don't judge me.
main :: IO ()
main = do
[inputDirectory, outputDirectory] <- E.getArgs
inputFiles <- D.listDirectory inputDirectory
flip mapM_ inputFiles $ \ inputFile -> do
let inputPath = F.combine inputDirectory inputFile
let outputPath = F.combine outputDirectory inputFile
putStrLn $ unwords [ inputPath, "=>", outputPath ]
inputBytes <- L.readFile inputPath
inputReplay <- either fail pure $ R.decodeReplayFile inputBytes
let outputReplay = editReplay inputReplay
let outputBytes = R.encodeReplayFile outputReplay
L.writeFile outputPath outputBytes
editReplay :: R.Replay -> R.Replay
editReplay replay = replay
{ R.replayHeader = let section = R.replayHeader replay in section
{ R.sectionBody = let header = R.sectionBody section in header
{ R.headerProperties = let
properties = R.headerProperties header
editDictionary k f dictionary = case dictionary of
R.DictionaryElement k2 v e -> R.DictionaryElement
k2
(if R.toStr k == k2 then f v else v)
(editDictionary k f e)
R.DictionaryEnd l -> R.DictionaryEnd l
editProperty property = property
{ R.propertyValue = case R.propertyValue property of
R.PropertyValueStr str -> R.PropertyValueStr (R.toStr (R.fromStr str ++ " [edit]"))
value -> value
}
in editDictionary "ReplayName" editProperty properties
}
}
, R.replayContent = let section = R.replayContent replay in section
{ R.sectionBody = let content = R.sectionBody section in content
{ R.contentFrames = let
editFrame frame = frame
{ R.frameReplications = let
editReplication replication = replication
{ R.replicationValue = case R.replicationValue replication of
R.ReplicationValueUpdated updated -> R.ReplicationValueUpdated updated
{ R.updatedReplicationAttributes = let
editAttribute attribute = attribute
{ R.attributeValue = case R.attributeValue attribute of
R.AttributeValueLoadouts loadouts -> let
editLoadout team loadout = case M.lookup team replacements of
Nothing -> loadout
Just teamReplacements -> case M.lookup (R.word32leValue (R.loadoutAttributeBody loadout)) teamReplacements of
Nothing -> loadout
Just decal -> loadout { R.loadoutAttributeDecal = R.Word32le decal }
in R.AttributeValueLoadouts loadouts
{ R.loadoutsAttributeBlue = editLoadout Blue (R.loadoutsAttributeBlue loadouts)
, R.loadoutsAttributeOrange = editLoadout Orange (R.loadoutsAttributeOrange loadouts)
}
value -> value
}
in map editAttribute (R.updatedReplicationAttributes updated)
}
value -> value
}
in map editReplication (R.frameReplications frame)
}
in map editFrame (R.contentFrames content)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment