packages feed

octane 0.4.18 → 0.4.19

raw patch · 13 files changed

+251/−124 lines, 13 filesdep ~autoexporterdep ~base

Dependency ranges changed: autoexporter, base

Files

+ CHANGELOG.markdown view
@@ -0,0 +1,7 @@+# Change log++Octane uses [Semantic Versioning][].+The change log is available through the [releases on GitHub][].++[Semantic Versioning]: http://semver.org/spec/v2.0.0.html+[releases on GitHub]: https://github.com/tfausak/octane/releases
− CHANGELOG.md
@@ -1,7 +0,0 @@-# Change log--Octane uses [Semantic Versioning][].-The change log is available through the [releases on GitHub][].--[Semantic Versioning]: http://semver.org/spec/v2.0.0.html-[releases on GitHub]: https://github.com/tfausak/octane/releases
− LICENSE.md
@@ -1,23 +0,0 @@-[The MIT License (MIT)][]--Copyright (c) 2016 Taylor Fausak <taylor@fausak.me>--Permission is hereby granted, free of charge, to any person obtaining a copy of-this software and associated documentation files (the "Software"), to deal in-the Software without restriction, including without limitation the rights to-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies-of the Software, and to permit persons to whom the Software is furnished to do-so, subject to the following conditions:--The above copyright notice and this permission notice shall be included in all-copies or substantial portions of the Software.--THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE-SOFTWARE.--[The MIT License (MIT)]: http://opensource.org/licenses/MIT
+ README.markdown view
@@ -0,0 +1,24 @@+# [Octane][]++[![Version badge][]][version]+[![Windows build badge][]][windows build]+[![Build badge][]][build]++Octane parses [Rocket League][] replays.++To use Octane, first download and unpack the [latest release][] for your+operating system. Then run `octane path-to/the.replay`.++The [Rocket League Replays wiki][] has links to other Rocket League replay+parsers.++[Octane]: https://github.com/tfausak/octane+[Version badge]: https://www.stackage.org/package/octane/badge/nightly?label=version+[version]: https://www.stackage.org/package/octane+[Windows build badge]: https://ci.appveyor.com/api/projects/status/github/tfausak/octane?branch=main&svg=true+[windows build]: https://ci.appveyor.com/project/TaylorFausak/octane+[Build badge]: https://travis-ci.org/tfausak/octane.svg?branch=main+[build]: https://travis-ci.org/tfausak/octane+[Rocket League]: http://www.rocketleaguegame.com+[latest release]: https://github.com/tfausak/octane/releases/latest+[Rocket League Replays wiki]: https://github.com/rocket-league-replays/rocket-league-replays/wiki/Rocket-League-Replay-Parsers
− README.md
@@ -1,11 +0,0 @@-## The Haskell Tool Stack--[![Build Status](https://travis-ci.org/commercialhaskell/stack.svg?branch=master)](https://travis-ci.org/commercialhaskell/stack)-[![Windows build status](https://ci.appveyor.com/api/projects/status/c1c7uvmw6x1dupcl?svg=true)](https://ci.appveyor.com/project/snoyberg/stack)-[![Release](https://img.shields.io/github/release/commercialhaskell/stack.svg)](https://github.com/commercialhaskell/stack/releases)--`stack` is a cross-platform program for developing Haskell projects. It is aimed-at Haskellers both new and experienced.--See [haskellstack.org](http://haskellstack.org) or the `doc` directory for more-information.
library/Octane/Parser.hs view
@@ -7,36 +7,125 @@ import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BSL import Data.Function ((&))+import qualified Data.IntMap as IntMap+import qualified Data.Maybe as Maybe+import qualified Data.Text as Text import qualified Octane.Type as Type  parseFrames :: Type.Replay -> [Type.Frame] parseFrames replay =-    Binary.runGet-        (replay & extractContext & getFrames & Bits.runBitGet)-        (replay & Type.replayStream & Newtype.unpack & BSL.fromStrict)+    let get = replay & extractContext & getFrames & Bits.runBitGet+        stream = replay & Type.replayStream & Newtype.unpack & BSL.fromStrict+    in Binary.runGet get stream --- TODO: This will need at least the actors and cache items.+type ObjectMap = IntMap.IntMap Text.Text++buildObjectMap :: Type.Replay -> ObjectMap+buildObjectMap replay =+    replay & Type.replayObjects & Newtype.unpack & map Newtype.unpack &+    zip [0 ..] &+    IntMap.fromAscList++type ClassMap = IntMap.IntMap Text.Text++buildClassMap :: Type.Replay -> ClassMap+buildClassMap replay =+    replay & Type.replayActors & Newtype.unpack &+    map+        (\x ->+              ( x & Type.actorTag & Newtype.unpack & fromIntegral+              , x & Type.actorName & Newtype.unpack)) &+    IntMap.fromList++type Cache = IntMap.IntMap Type.CacheItem++buildCache :: Type.Replay -> Cache+buildCache replay =+    replay & Type.replayCacheItems & Newtype.unpack &+    map+        (\x ->+              (x & Type.cacheItemTag & Newtype.unpack & fromIntegral, x)) &+    IntMap.fromList++type PropertyMap = IntMap.IntMap Text.Text++buildPropertyMap :: ObjectMap -> Cache -> Int -> PropertyMap+buildPropertyMap objectMap cache key =+    case IntMap.lookup key cache of+        Nothing -> IntMap.empty+        Just cacheItem ->+            let parentId =+                    cacheItem & Type.cacheItemStart & Newtype.unpack &+                    fromIntegral+                properties =+                    cacheItem & Type.cacheItemCacheProperties & Newtype.unpack &+                    map+                        (\x ->+                              ( x & Type.cachePropertyIndex & Newtype.unpack &+                                fromIntegral+                              , x & Type.cachePropertyTag & Newtype.unpack &+                                fromIntegral)) &+                    Maybe.mapMaybe+                        (\(k,v) ->+                              case IntMap.lookup v objectMap of+                                  Nothing -> Nothing+                                  Just name -> Just (k, name)) &+                    IntMap.fromList+            in if key == parentId+                   then properties+                   else IntMap.union+                            properties+                            (buildPropertyMap objectMap cache parentId)++type ClassPropertyMap = IntMap.IntMap (IntMap.IntMap Text.Text)++buildClassPropertyMap :: Type.Replay -> ClassPropertyMap+buildClassPropertyMap replay =+    let objectMap = buildObjectMap replay+        classMap = buildClassMap replay+        cache = buildCache replay+        f k _ m =+            case IntMap.lookup k cache of+                Nothing -> m+                Just cacheItem ->+                    let x =+                            cacheItem & Type.cacheItemTag & Newtype.unpack &+                            fromIntegral+                        v = buildPropertyMap objectMap cache x+                    in IntMap.insert k v m+    in IntMap.foldrWithKey f IntMap.empty classMap++getClass :: ObjectMap -> Int -> Maybe (Int, Text.Text)+getClass objectMap objectId =+    case IntMap.lookup objectId objectMap of+        Nothing -> Nothing+        Just name ->+            if name == Text.pack "TAGame.Default__PRI_TA" ||+               Text.isInfixOf (Text.pack "Archetype") name+                then getClass objectMap (objectId - 1)+                else Just (objectId, name)+ data Context = Context-    {+    { contextObjectMap :: ObjectMap     }  extractContext :: Type.Replay -> Context-extractContext _replay =+extractContext replay =     Context-    {+    { contextObjectMap = buildObjectMap replay     }  getFrames :: Context -> Bits.BitGet [Type.Frame] getFrames context = do-    maybeFrame <- getFrame context+    maybeFrame <- getMaybeFrame context     case maybeFrame of         Nothing -> return []         Just frame -> do             frames <- getFrames context             return (frame : frames) -getFrame :: Context -> Bits.BitGet (Maybe Type.Frame)-getFrame context = do+getMaybeFrame :: Context -> Bits.BitGet (Maybe Type.Frame)+getMaybeFrame context = do     -- TODO: Convert time bytes into a float.     time <- Bits.getByteString 32     -- TODO: Convert delta bytes into a float.@@ -44,72 +133,110 @@     if BS.all (== 0) time && BS.all (== 0) delta         then return Nothing         else do-            replications <- getReplications context-            let frame =-                    Type.Frame-                    { Type.frameTime = time-                    , Type.frameDelta = delta-                    , Type.frameReplications = replications-                    }+            frame <- getFrame context time delta             return (Just frame) +type Time = BS.ByteString++type Delta = BS.ByteString++getFrame :: Context -> Time -> Delta -> Bits.BitGet Type.Frame+getFrame context time delta = do+    replications <- getReplications context+    let frame =+            Type.Frame+            { Type.frameTime = time+            , Type.frameDelta = delta+            , Type.frameReplications = replications+            }+    return frame+ getReplications :: Context -> Bits.BitGet [Type.Replication] getReplications context = do-    (context',maybeReplication) <- getReplication context+    (context',maybeReplication) <- getMaybeReplication context     case maybeReplication of         Nothing -> return []         Just replication -> do             replications <- getReplications context'             return (replication : replications) -getReplication :: Context -> Bits.BitGet (Context, Maybe Type.Replication)-getReplication context = do+getMaybeReplication :: Context -> Bits.BitGet (Context, Maybe Type.Replication)+getMaybeReplication context = do     hasReplication <- Bits.getBool     if not hasReplication         then return (context, Nothing)         else do-            -- TODO: Convert actor ID into an integer.-            actorId <- Bits.getByteString (bitSize maxChannels)-            isOpen <- Bits.getBool+            (newContext,replication) <- getReplication context+            return (newContext, Just replication)++getReplication :: Context -> Bits.BitGet (Context, Type.Replication)+getReplication context = do+    actorId <- getInt maxChannels+    isOpen <- Bits.getBool+    let go =             if isOpen-                then do-                    isNew <- Bits.getBool-                    if isNew-                        then do-                            _unknownFlag <- Bits.getBool-                            _objectId <- getInt 32-                            -- TODO: Parse new actor.-                            return-                                ( context-                                , Just-                                      (Type.Replication-                                       { Type.replicationActorId = actorId-                                       , Type.replicationIsOpen = isOpen-                                       , Type.replicationIsNew = Just isNew-                                       }))-                        else do-                            let maybeClassId = getClassId context actorId-                            case maybeClassId of-                                Nothing -> fail "TODO: Could not get class ID."-                                Just _classId ->-                                    -- TODO: Parse existing actor.-                                    return-                                        ( context-                                        , Just-                                              (Type.Replication-                                               { Type.replicationActorId = actorId-                                               , Type.replicationIsOpen = isOpen-                                               , Type.replicationIsNew = Just isNew-                                               }))-                else return-                         ( context-                         , Just-                               (Type.Replication-                                { Type.replicationActorId = actorId-                                , Type.replicationIsOpen = isOpen-                                , Type.replicationIsNew = Nothing-                                }))+                then getOpenReplication+                else getClosedReplication+    go context actorId +type ActorId = Int++getOpenReplication :: Context+                   -> ActorId+                   -> Bits.BitGet (Context, Type.Replication)+getOpenReplication context actorId = do+    isNew <- Bits.getBool+    let go =+            if isNew+                then getNewReplication+                else getExistingReplication+    go context actorId++getNewReplication :: Context+                  -> ActorId+                  -> Bits.BitGet (Context, Type.Replication)+getNewReplication context actorId = do+    _unknownFlag <- Bits.getBool+    _objectId <- getInt 32+    -- TODO: Parse new actor.+    return+        ( context+        , Type.Replication+          { Type.replicationActorId = actorId+          , Type.replicationIsOpen = True+          , Type.replicationIsNew = Just True+          })++getExistingReplication :: Context+                       -> ActorId+                       -> Bits.BitGet (Context, Type.Replication)+getExistingReplication context actorId = do+    let maybeClass = getClass (contextObjectMap context) actorId+    case maybeClass of+        Nothing ->+            fail ("TODO: Could not get class for object " ++ show actorId)+        Just (_classId,_className) ->+            -- TODO: Parse existing actor.+            return+                ( context+                , Type.Replication+                  { Type.replicationActorId = actorId+                  , Type.replicationIsOpen = True+                  , Type.replicationIsNew = Just True+                  })++getClosedReplication :: Context+                     -> ActorId+                     -> Bits.BitGet (Context, Type.Replication)+getClosedReplication context actorId = do+    return+        ( context+        , Type.Replication+          { Type.replicationActorId = actorId+          , Type.replicationIsOpen = False+          , Type.replicationIsNew = Nothing+          })+ maxChannels     :: (Integral a)     => a@@ -145,7 +272,3 @@                     go (i + 1) newValue                 else return value     go 0 0---- TODO: Actually implement this.-getClassId :: Context -> BS.ByteString -> Maybe ()-getClassId _context _actorId = Nothing
library/Octane/Type/Replication.hs view
@@ -3,11 +3,10 @@ module Octane.Type.Replication (Replication(..)) where  import qualified Control.DeepSeq as DeepSeq-import qualified Data.ByteString as BS import qualified GHC.Generics as Generics  data Replication = Replication-    { replicationActorId :: BS.ByteString+    { replicationActorId :: Int     , replicationIsOpen :: Bool     , replicationIsNew :: Maybe Bool     } deriving (Eq,Generics.Generic,Show)
library/Octane/Version.hs view
@@ -1,3 +1,7 @@-module Octane.Version (module Paths_octane) where+module Octane.Version where -import Paths_octane (version)+import qualified Data.Version as Version+import qualified Paths_octane as This++version :: Version.Version+version = This.version
octane.cabal view
@@ -3,7 +3,7 @@ -- see: https://github.com/sol/hpack  name:           octane-version:        0.4.18+version:        0.4.19 synopsis:       Parse Rocket League replays. description:    Octane parses Rocket League replays. category:       Game@@ -16,10 +16,9 @@ cabal-version:  >= 1.10  extra-source-files:-    CHANGELOG.md-    LICENSE.md+    CHANGELOG.markdown     package.yaml-    README.md+    README.markdown     stack.yaml  source-repository head@@ -33,8 +32,8 @@   build-depends:       aeson ==0.11.*     , aeson-pretty ==0.7.*-    , autoexporter >=0.1 && <0.3-    , base >=4.8 && <4.10+    , autoexporter ==0.2.*+    , base ==4.*     , binary ==0.7.*     , binary-bits ==0.5.*     , bytestring ==0.10.*@@ -116,6 +115,7 @@       Octane.Type.PropertySpec       Octane.Type.ReplaySpec       Octane.TypeSpec+      Octane.VersionSpec       OctaneSpec   default-language: Haskell2010 
package.yaml view
@@ -27,10 +27,9 @@     main: Executable.hs     source-dirs: executable extra-source-files:-- CHANGELOG.md-- LICENSE.md+- CHANGELOG.markdown - package.yaml-- README.md+- README.markdown - stack.yaml ghc-options: -Wall github: tfausak/octane@@ -38,8 +37,8 @@   dependencies:   - aeson ==0.11.*   - aeson-pretty ==0.7.*-  - autoexporter >=0.1 && <0.3-  - base >=4.8 && <4.10+  - autoexporter ==0.2.*+  - base ==4.*   - binary ==0.7.*   - binary-bits ==0.5.*   - bytestring ==0.10.*@@ -51,6 +50,7 @@   other-modules: Paths_octane   source-dirs: library license: MIT+license-file: LICENSE.markdown maintainer: Taylor Fausak name: octane synopsis: Parse Rocket League replays.@@ -70,4 +70,4 @@     - -with-rtsopts=-N     main: TestSuite.hs     source-dirs: test-suite-version: '0.4.18'+version: '0.4.19'
stack.yaml view
@@ -1,3 +1,1 @@-install-ghc: true-require-stack-version: ! '>=1.0.4'-resolver: nightly-2016-04-14+resolver: nightly-2016-05-02
+ test-suite/Octane/VersionSpec.hs view
@@ -0,0 +1,11 @@+module Octane.VersionSpec (spec) where++import Octane+import Test.Tasty.Hspec++import qualified Data.Version as Version++spec :: Spec+spec = describe "Version" $ do+    it "has some parts" $ do+        shouldBe (null (Version.versionBranch version)) False
test-suite/OctaneSpec.hs view
@@ -4,8 +4,10 @@  import qualified Octane.MainSpec import qualified Octane.TypeSpec+import qualified Octane.VersionSpec  spec :: Spec spec = describe "Octane" $ do     Octane.MainSpec.spec     Octane.TypeSpec.spec+    Octane.VersionSpec.spec