sc2-lowlevel-0.1.0.0: src/Network/SC2/LowLevel/Requests.hs
{-#LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
{-#LANGUAGE OverloadedLabels #-}
{-# LANGUAGE FlexibleContexts #-}
module Network.SC2.LowLevel.Requests
( module Network.SC2.LowLevel.Types
, Ping(..)
, PingResponse(..)
, Fog(..)
, Realtime(..)
, Seed(..)
, CreateGame(..)
, JoinGame(..)
, RestartGame(..)
-- , StartReplay(..)
, LeaveGame(..)
, QuickSave(..)
, QuickLoad(..)
, QuitGame(..)
, GameInfo(..)
, GameInfoResponse(..)
, Step(..)
, AvailableMaps(..)
) where
import qualified Proto.S2clientprotocol.Common as C
import qualified Proto.S2clientprotocol.Sc2api as A
import qualified Proto.S2clientprotocol.Raw as R
import qualified Proto.S2clientprotocol.Raw_Fields as R
import Control.Lens
import Control.Monad
import Data.Default.Class
import qualified Data.Text as T
import Data.Void
import Network.SC2.LowLevel.Requestable
import Network.SC2.LowLevel.Types
import Network.SC2.LowLevel.Convert
import Lens.Labels.Unwrapped ()
import Data.ProtoLens (defMessage)
data Ping = Ping
deriving (Show, Eq)
data PingResponse =
PingResponse
{ gameVersion :: T.Text
, dataVersion :: T.Text
, dataBuild :: Int
, baseBuild :: Int
} deriving (Show, Eq)
instance Requestable Ping where
type ResponseOf Ping = PingResponse
toRequest _ = defMessage& #ping .~ defMessage
fromResponse _ = extractResponse (view #maybe'ping >=> convert)
where convert r = PingResponse <$> r^. #maybe'gameVersion <*> r^. #maybe'dataVersion <*> (fromIntegral <$> r^. #maybe'dataBuild ) <*> (fromIntegral <$> r^. #maybe'baseBuild)
data Fog = Fog | NoFog
deriving (Show, Eq, Enum)
data Realtime = Stepped | Realtime
deriving (Show, Eq, Enum)
data Seed = Seed Int | RandomSeed
deriving (Show, Eq)
data CreateGame = CreateGame Map [Player Race]
| CreateGameFull Map [Player Race] Fog Seed Realtime
deriving (Show, Eq)
instance Requestable CreateGame where
type ResponseOf CreateGame = ()
toRequest (CreateGame map players) = toRequest (CreateGameFull map players Fog RandomSeed Stepped)
toRequest (CreateGameFull map players fog seed rt) = defMessage& #createGame .~ mods defMessage
where
mods = mapmod map . playermod . fogmod . seedmod seed . rtmod
fogmod :: A.RequestCreateGame -> A.RequestCreateGame
fogmod = #disableFog .~ (fog == NoFog)
seedmod :: Seed -> A.RequestCreateGame -> A.RequestCreateGame
seedmod RandomSeed = id
seedmod (Seed s) = #randomSeed .~ fromIntegral s
rtmod :: A.RequestCreateGame -> A.RequestCreateGame
rtmod = #realtime .~ (rt == Realtime)
mapmod :: Map -> A.RequestCreateGame -> A.RequestCreateGame
mapmod (BattlenetMap m) = #battlenetMapName .~ m
mapmod (LocalMap m d) = #localMap .~ (defMessage & #mapPath .~ m & #maybe'mapData .~ d)
playermod :: A.RequestCreateGame -> A.RequestCreateGame
playermod = #playerSetup .~ fmap convertPlayer players
fromResponse _ = void . extractResponseErr (view #maybe'createGame) Just (view #maybe'errorDetails)
-- FIXME as observer? ports? render / featurelayer interface?
data JoinGame = JoinGame Race [Interface Void]
deriving (Show, Eq)
instance Requestable JoinGame where
type ResponseOf JoinGame = PlayerID
toRequest (JoinGame r ifaces) = defMessage& #joinGame .~ mod defMessage
where
mod = racemod . foldr (.) id (fmap ifacemod ifaces)
racemod :: A.RequestJoinGame -> A.RequestJoinGame
racemod = #race .~ convertRace r
ifacemod :: Interface Void -> A.RequestJoinGame -> A.RequestJoinGame
ifacemod Raw = #options . #raw .~ True
ifacemod Score = #options . #score .~ True
fromResponse _ = fmap (PlayerID . fromIntegral) . extractResponseErr (view #maybe'joinGame) (view #maybe'playerId) (view #maybe'errorDetails)
data RestartGame = RestartGame
deriving (Show, Eq)
instance Requestable RestartGame where
type ResponseOf RestartGame = ()
toRequest _ = defMessage& #restartGame .~ defMessage
fromResponse _ = void . extractResponseErr (view #maybe'restartGame) Just (view #maybe'errorDetails)
-- StartReplay
data LeaveGame = LeaveGame
deriving (Show, Eq)
instance Requestable LeaveGame where
type ResponseOf LeaveGame = ()
toRequest _ = defMessage& #leaveGame .~ defMessage
fromResponse _ = void . extractResponse (view #maybe'leaveGame)
data QuickSave = QuickSave
deriving (Show, Eq)
instance Requestable QuickSave where
type ResponseOf QuickSave = ()
toRequest _ = defMessage& #quickSave .~ defMessage
fromResponse _ = void . extractResponse (view #maybe'quickSave)
data QuickLoad = QuickLoad
deriving (Show, Eq)
instance Requestable QuickLoad where
type ResponseOf QuickLoad = ()
toRequest _ = defMessage& #quickLoad .~ defMessage
fromResponse _ = void . extractResponse (view #maybe'quickLoad)
data QuitGame = QuitGame
deriving (Show, Eq)
instance Requestable QuitGame where
type ResponseOf QuitGame = ()
toRequest _ = defMessage& #quit .~ defMessage
fromResponse _ = void . extractResponse (view #maybe'quit)
instance Requestable GameInfo where
type ResponseOf GameInfo = GameInfoResponse
toRequest _ = defMessage& #gameInfo .~ defMessage
fromResponse _ = extractResponse (view #maybe'gameInfo >=> convert)
where
convert gi = do
mname <- gi^. #maybe'mapName
let mods = gi^. #modNames
localpath <- T.unpack <$> (gi ^. #maybe'localMapPath)
players <- traverse convertPlayer (gi^. #playerInfo) -- TODO: Lensify this wholefunction
let raw = convertRaw =<< gi ^. #maybe'startRaw
let ifaces = (snd . iface #maybe'raw id Raw . iface #maybe'score id Score . iface #maybe'featureLayer (const True) (FeatureLayer ()) . iface #maybe'render (const True) (Render ())) (gi, [])
return (GameInfoResponse mname mods localpath players raw ifaces)
iface :: Lens' A.InterfaceOptions (Maybe b) -> (b -> Bool) -> a -> (A.ResponseGameInfo, [a]) -> (A.ResponseGameInfo, [a])
iface l t x (gi, xs) = case gi ^. #options . l of
Just b | t b -> (gi, x : xs)
_ -> (gi, xs)
convertPlayer p = do
pid <- PlayerID . fromIntegral <$> (p ^. #maybe'playerId)
typ <- p ^. #maybe'type'
ourtyp <- case typ of
A.Observer -> return Observer
A.Participant -> do
race <- convertRace p
return (Participant race)
A.Computer -> do
race <- convertRace p
diff <- p ^. #maybe'difficulty
return (Computer race diff)
return (pid, ourtyp)
convertRace p = do
req <- p ^. #maybe'raceRequested
let act = p ^. #maybe'raceActual
return (convertRaceBack req (flip convertRaceBack (error "convertRace") <$> act))
convertRaw :: R.StartRaw -> Maybe StartRaw
convertRaw r = do
msize <- convertFrom =<< (r^. #maybe'mapSize)
pagrid <- convertFrom =<< (r^. #maybe'pathingGrid)
theight <- convertFrom =<< (r^. #maybe'terrainHeight)
plgrid <- convertFrom =<< (r^. #maybe'placementGrid)
parea <- convertFrom =<< (r^. #maybe'playableArea)
starts <- traverse convertFrom (r^. #startLocations)
return (StartRaw msize pagrid theight plgrid parea starts)
-- FIXME RequestObservation
-- FIXME RequestAction
data Step = Step
| StepMany Word
instance Requestable Step where
type ResponseOf Step = ()
toRequest Step = toRequest (StepMany 1)
toRequest (StepMany i) = defMessage& #step . #count .~ fromIntegral i
fromResponse _ = void . extractResponse (view #maybe'step)
data AvailableMaps = AvailableMaps
deriving (Show, Eq)
instance Requestable AvailableMaps where
type ResponseOf AvailableMaps = [Map]
toRequest _ = defMessage& #availableMaps .~ defMessage
fromResponse _ = extractResponse (fmap makeMaps . view #maybe'availableMaps) -- TODO: Lensify fmap
where makeMaps :: A.ResponseAvailableMaps -> [Map]
makeMaps m = (LocalMap <$> m ^. #localMapPaths <*> pure Nothing)
++ (BattlenetMap <$> m ^. #battlenetMapNames)