module DarkPlaces.Demo (
getDemoMessage,
getDemoMessages,
iterDemoMessages,
demoFileMessages,
demoFilePackets
) where
import Control.Applicative
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString as B
import Data.Binary.Get
import DarkPlaces.Types
import DarkPlaces.Binary
import DarkPlaces.PacketParser
getDemoMessage :: Get (QVector, BL.ByteString)
getDemoMessage = do
size <- fromIntegral <$> getWord32le
angls <- getQVector
msg <- getLazyByteString size
return (angls, msg)
getDemoMessages :: Get [(QVector, BL.ByteString)]
getDemoMessages = do
empty <- isEmpty
if empty
then return []
else (:) <$> getDemoMessage <*> getDemoMessages
iterDemoMessages :: BL.ByteString -> [Either ErrorInfo (QVector, BL.ByteString)]
iterDemoMessages demo_data = go decoder $ BL.toChunks demo_data
where
decoder = runGetIncremental getDemoMessage
go (Fail _ offset msg) _ = [Left (offset, msg)]
go (Partial k) [] = go (k Nothing) []
go (Partial k) (x:xs) = go (k $ Just x) xs
go (Done left _ res) xs = Right res : if empty then [] else go decoder xs'
where
empty = B.null left && null xs
xs' = left:xs
demoFileMessages :: BL.ByteString -> [Either ErrorInfo (QVector, BL.ByteString)]
demoFileMessages file_data = either (\l -> [Left l]) iterDemoMessages either_demo
where
either_demo = skipTrack file_data
demoFilePackets :: BL.ByteString -> [Either ErrorInfo PacketOrError]
demoFilePackets file_data = parse (demoFileMessages file_data) defaultDemoState
where
parse (x:xs) s = case x of
Left l -> [Left l]
Right (_, ps) -> case listPackets ps s of
Left l -> [Left l]
Right (pls, s') -> (Right <$> pls) ++ parse xs s'
parse [] _ = []