octane 0.6.0 → 0.6.1
raw patch · 5 files changed
+227/−7 lines, 5 files
Files
- library/Octane.hs +13/−1
- library/Octane/Analyzer.hs +203/−0
- library/Octane/Parser.hs +8/−4
- octane.cabal +2/−1
- package.yaml +1/−1
library/Octane.hs view
@@ -1,1 +1,13 @@-{-# OPTIONS_GHC -F -pgmF autoexporter #-}+module Octane+ ( module Octane.Data+ , module Octane.Main+ , module Octane.Parser+ , module Octane.Type+ , module Octane.Version+ ) where++import Octane.Data+import Octane.Main+import Octane.Parser+import Octane.Type+import Octane.Version
+ library/Octane/Analyzer.hs view
@@ -0,0 +1,203 @@+module Octane.Analyzer where++import Data.Function ((&))++import qualified Data.Binary as Binary+import qualified Data.Map.Strict as Map+import qualified Data.Maybe as Maybe+import qualified Data.Text as Text+import qualified Octane.Parser as Parser+import qualified System.Environment as Environment++type Point = (Int, Int, Int)+type Points = [Point]+type Frames = [Parser.Frame]+type ActorId = Int++find :: (a -> Bool) -> [a] -> Maybe a+find p xs = xs & filter p & Maybe.listToMaybe++getActorId :: (Parser.Replication -> Bool) -> (Parser.Replication -> ActorId) -> Frames -> Maybe ActorId+getActorId p f frames = frames+ & Maybe.mapMaybe (\ frame -> frame+ & Parser.frameReplications+ & find p+ & fmap f)+ & Maybe.listToMaybe++getBallActorId :: Frames -> Maybe ActorId+getBallActorId frames = getActorId+ (\ replication -> replication+ & Parser.replicationClassName+ & (== ballClassName))+ Parser.replicationActorId+ frames++getPlayerActorIds :: Frames -> Map.Map ActorId Text.Text+getPlayerActorIds frames = frames+ & concatMap Parser.frameReplications+ & filter (\ replication -> replication+ & Parser.replicationClassName+ & (== playerClassName))+ & Maybe.mapMaybe (\ replication -> let+ actorId = replication+ & Parser.replicationActorId+ maybeProperty = replication+ & Parser.replicationProperties+ & Map.lookup playerNamePropertyName+ in case maybeProperty of+ Nothing -> Nothing+ Just property -> case property of+ Parser.PString name -> Just (actorId, name)+ _ -> Nothing)+ & Map.fromList++getRigidBodyStatesForActorId :: ActorId -> Frames -> [(Parser.Time, Point)]+getRigidBodyStatesForActorId actorId frames = frames+ & concatMap (\ frame -> let+ time = Parser.frameTime frame+ in frame+ & Parser.frameReplications+ & filter (\ replication -> replication+ & Parser.replicationActorId+ & (== actorId))+ & map Parser.replicationProperties+ & Maybe.mapMaybe (\ properties -> properties+ & Map.lookup rbsPropertyName)+ & Maybe.mapMaybe (\ property -> case property of+ Parser.PRigidBodyState _ location _ _ _ -> Just location+ _ -> Nothing)+ & map (\ (Parser.Vector x y z) -> (x, y, z))+ & map (\ point -> (time, point)))++getBallLocations :: Frames -> Points+getBallLocations frames = let+ ballActorId = frames+ & getBallActorId+ & Maybe.fromJust+ rigidBodyStates = frames+ & getRigidBodyStatesForActorId ballActorId+ in rigidBodyStates+ & map snd++ballClassName :: Text.Text+ballClassName = Text.pack "TAGame.Ball_TA"++playerClassName :: Text.Text+playerClassName = Text.pack "TAGame.PRI_TA"++rbsPropertyName :: Text.Text+rbsPropertyName = Text.pack "TAGame.RBActor_TA:ReplicatedRBState"++playerNamePropertyName :: Text.Text+playerNamePropertyName = Text.pack "Engine.PlayerReplicationInfo:PlayerName"++getDistance :: Point -> Point -> Float+getDistance (x1, y1, z1) (x2, y2, z2) = let+ dx = fromIntegral (x2 - x1)+ dy = fromIntegral (y2 - y1)+ dz = fromIntegral (z2 - z1)+ in sqrt (dx ** 2 + dy ** 2 + dz ** 2)++getBallDistances :: Points -> [Float]+getBallDistances points = points+ & zip (drop 1 points)+ & map (\ (p2, p1) -> getDistance p1 p2)++getBallDistance :: Points -> Float+getBallDistance points = points+ & getBallDistances+ & sum++getBallSpeeds :: Points -> [Float]+getBallSpeeds points = points+ & getBallDistances+ & map (\ distance -> distance / 0.04 {- the average delta -})++getHisto :: (a -> Int) -> Int -> Int -> [a] -> (Int, Int, Int)+getHisto fromPoint bottom top points = let+ range = abs (top - bottom)+ third = quot range 3+ values = map fromPoint points+ in foldr+ ((\ value (low, mid, high) ->+ if value > top - third then (low, mid, high + 1)+ else if value < bottom + third then (low + 1, mid, high)+ else (low, mid + 1, high)))+ (0, 0, 0)+ values++getXHisto :: Points -> (Int, Int, Int) -- not sure of the direction... left to right?+getXHisto points = getHisto (\ (x, _, _) -> x) (-4500) 4500 points++getYHisto :: Points -> (Int, Int, Int) -- not sure of the direction... orange to blue?+getYHisto points = getHisto (\ (_, y, _) -> y) (-5200) 5200 points++getZHisto :: Points -> (Int, Int, Int) -- bottom to top+getZHisto points = getHisto (\ (_, _, z) -> z) 0 2000 points++getSpeedHisto :: [Float] -> (Int, Int, Int) -- slow to fast+getSpeedHisto speeds = getHisto round 0 2000 speeds++analyze :: FilePath -> IO ()+analyze file = do+ replay <- Binary.decodeFile file+ let frames = Parser.parseFrames replay++ putStr "Number of frames: "+ print (length frames)++ let ballLocations = getBallLocations frames+ putStr "Number of ball replications: "+ print (length ballLocations) -- 7702++ let ballDistance = getBallDistance ballLocations+ putStr "Total distance traveled by the ball: "+ print ballDistance -- 323759.94++ let (xs, ys, zs) = unzip3 ballLocations+ let minX = minimum xs+ let maxX = maximum xs+ putStr "(Minimum X value, maximum X value): "+ print (minX, maxX) -- (-4004,4003) [wasteland (-4451,4458)]++ let minY = minimum ys+ let maxY = maximum ys+ putStr "(Minimum Y value, maximum Y value): "+ print (minY, maxY) -- (-5215,5214)++ let minZ = minimum zs+ let maxZ = maximum zs+ putStr "(Minimum Z value, maximum Z value): "+ print (minZ, maxZ) -- (88,1943)++ let xHisto = getXHisto ballLocations+ putStr "(Left, middle, right): "+ print xHisto -- (2241,2237,3224)++ let yHisto = getYHisto ballLocations+ putStr "(Orange, middle, blue): "+ print yHisto -- (3731,1504,2467)++ let zHisto = getZHisto ballLocations+ putStr "(Bottom, middle, top): "+ print zHisto -- (6967,507,228)++ let ballSpeeds = getBallSpeeds ballLocations+ let minSpeed = minimum ballSpeeds+ let maxSpeed = maximum ballSpeeds+ putStr "(Minimum speed, maximum speed): "+ print (minSpeed, maxSpeed) -- (0.0,130894.555)++ let speedHisto = getSpeedHisto ballSpeeds+ putStr "(Slow, medium, fast): "+ print speedHisto -- (2250,3630,1821)++ let playerActorIds = getPlayerActorIds frames+ putStrLn "Players:"+ playerActorIds & Map.toList & mapM_ print++main :: IO ()+main = do+ args <- Environment.getArgs+ mapM_ analyze args
library/Octane/Parser.hs view
@@ -148,7 +148,8 @@ return ( newContext , Replication- { replicationObjectName = objectName+ { replicationActorId = actorId+ , replicationObjectName = objectName , replicationClassName = className , replicationState = RSOpening , replicationInitialization = Just classInit@@ -164,7 +165,8 @@ Just x -> x props <- getProps context thing return (context, Replication- { replicationObjectName = thingObjectName thing+ { replicationActorId = actorId+ , replicationObjectName = thingObjectName thing , replicationClassName = thingClassName thing , replicationState = RSExisting , replicationInitialization = Nothing@@ -183,7 +185,8 @@ return ( newContext , Replication- { replicationObjectName = thingObjectName thing+ { replicationActorId = actorId+ , replicationObjectName = thingObjectName thing , replicationClassName = thingClassName thing , replicationState = RSClosing , replicationInitialization = Nothing@@ -604,7 +607,8 @@ -- | Replication information about an actor in the net stream. data Replication = Replication- { replicationObjectName :: !Text.Text+ { replicationActorId :: !Int+ , replicationObjectName :: !Text.Text , replicationClassName :: !Text.Text , replicationState :: !ReplicationState , replicationInitialization :: !(Maybe ClassInit)
octane.cabal view
@@ -3,7 +3,7 @@ -- see: https://github.com/sol/hpack name: octane-version: 0.6.0+version: 0.6.1 synopsis: Parse Rocket League replays. description: Octane parses Rocket League replays. category: Game@@ -42,6 +42,7 @@ , text ==1.2.* exposed-modules: Octane+ Octane.Analyzer Octane.Data Octane.Json Octane.Main
package.yaml view
@@ -68,4 +68,4 @@ - -with-rtsopts=-N main: TestSuite.hs source-dirs: test-suite-version: '0.6.0'+version: '0.6.1'