wizard-wipeout/src-server/Server/Communication/Handler.hs

144 lines
5.4 KiB
Haskell
Raw Permalink Normal View History

2024-05-01 21:52:49 +00:00
module Server.Communication.Handler where
2024-11-03 14:22:28 +00:00
import Control.Concurrent (threadDelay)
2024-05-01 21:52:49 +00:00
import qualified Control.Concurrent.STM as STM
import Control.Monad
import Control.Monad.Reader
import Control.Monad.State
import Data.List
import Data.Maybe
import Data.Time
import Data.UUID.V4
import Library.Types
import Server.Communication.Send
2024-11-04 05:53:58 +00:00
import Server.Log
2024-05-01 21:52:49 +00:00
import Server.Types
import Server.Util
2024-11-25 02:58:31 +00:00
import System.Random (randomRIO)
2024-05-01 21:52:49 +00:00
-- | function for translating 'ClientMessage's into server actions
handleMessage
:: StateContainer
-> ReaderContainer
-> ClientMessage
-> IO ()
handleMessage stateContainer readerContainer msg = do
2024-11-03 10:19:19 +00:00
let socketList = scClientSockets stateContainer
queueList = scClientQueues stateContainer
2024-11-04 05:53:58 +00:00
curLevel = rcLogLevel readerContainer
2024-11-03 10:19:19 +00:00
socks <- liftIO $ STM.atomically $ STM.readTMVar socketList
queues <- liftIO $ STM.atomically $ STM.readTMVar queueList
2024-11-04 05:53:58 +00:00
logPrintIO curLevel Verbose $ "Handling: " <> show msg
2024-05-01 21:52:49 +00:00
case msg of
IdRequest -> do
clientId <- nextRandom
2024-11-03 14:22:28 +00:00
threadDelay 1000
2024-11-03 10:19:19 +00:00
let clientIdx = findIndex (isNothing . csUUID) socks
sock = socks !! fromJust clientIdx
queue = queues !! fromJust clientIdx
if csUUID sock == cqUUID queue
then do
let otherSocks = delete sock socks
newSocks = sock
{ csUUID = Just clientId
} : otherSocks
otherQueues = delete queue queues
newQueues = queue
{ cqUUID = Just clientId
} : otherQueues
liftIO $ STM.atomically $ do
void $ STM.swapTMVar socketList newSocks
void $ STM.swapTMVar queueList newQueues
2024-11-04 05:53:58 +00:00
logPrintIO curLevel Info $ "Accepted Client with UUID: " <> show clientId
queueMessage curLevel (AcceptClient clientId) clientId queueList
2024-11-03 10:19:19 +00:00
else
2024-11-04 05:53:58 +00:00
logPrintIO curLevel Error $ "Unable to assign ID to socket and queue: " <> show clientId
2024-05-01 21:52:49 +00:00
ClientMessage clientId payload ->
case payload of
ClientQuit -> do
2024-11-03 15:21:03 +00:00
currentPlayers <- STM.atomically $ STM.readTMVar (scPlayers stateContainer)
let newPlayers = filter (\p -> playerId p /= clientId) currentPlayers
void $ STM.atomically $ STM.swapTMVar (scPlayers stateContainer) newPlayers
2024-11-04 08:41:22 +00:00
let mclient = find (\a -> csUUID a == Just clientId) socks
maybe
(logPrintIO curLevel Warning $ "unknown client: " <> show clientId)
(dropClient curLevel socketList queueList . csSocket)
mclient
2024-11-04 05:53:58 +00:00
logPrintIO curLevel Info $ "client has quit the game: " <> show clientId
2024-05-01 21:52:49 +00:00
ClientRequestWizard -> do
let arena = rcMap readerContainer
initPos <- rollInitPosition arena
2024-11-25 02:58:31 +00:00
initRot <- randomRIO (0, 2 * pi)
2024-05-01 21:52:49 +00:00
now <- liftIO getCurrentTime
uuid <- nextRandom
2024-11-25 02:58:31 +00:00
let freshWizard = newWizard initPos initRot
2024-05-01 21:52:49 +00:00
STM.atomically $ do
currentPlayers <- STM.readTMVar (scPlayers stateContainer)
void $ STM.swapTMVar (scPlayers stateContainer) $
Player clientId freshWizard False (now, uuid) : currentPlayers
2024-11-04 05:53:58 +00:00
queueMessage curLevel (ProvideInitialWizard freshWizard) clientId queueList
logPrintIO curLevel Info $ "initialized new wizard for: " <> show clientId
2024-05-01 21:52:49 +00:00
ClientReady -> do
now <- getCurrentTime
STM.atomically $ do
currentPlayers <- STM.readTMVar (scPlayers stateContainer)
let (thisPlayers, otherPlayers) =
partition (\p -> playerId p == clientId) currentPlayers
unless (null thisPlayers) $
void $ STM.swapTMVar (scPlayers stateContainer) $
(head thisPlayers)
{ playerReady = True
, playerLastPong = (now, snd (playerLastPong $ head thisPlayers))
}
: otherPlayers
2024-11-04 05:53:58 +00:00
logPrintIO curLevel Info $ "client ready: " <> show clientId
2024-11-03 03:40:46 +00:00
Pong pongUuid -> do
2024-11-03 10:19:19 +00:00
let mclient = find (\c -> csUUID c == Just clientId) socks
2024-11-03 03:40:46 +00:00
players <- STM.atomically $ STM.readTMVar (scPlayers stateContainer)
2024-05-01 21:52:49 +00:00
maybe
2024-11-04 05:53:58 +00:00
(logPrintIO curLevel Warning $ "Unknown client: " <> show clientId)
2024-11-03 03:40:46 +00:00
(const $ do
2024-05-01 21:52:49 +00:00
mPlayer <- STM.atomically $ do
pure $ find (\p -> playerId p == clientId) players
maybe
(pure ())
(\player ->
2024-11-03 03:40:46 +00:00
if snd (playerLastPong player) /= pongUuid
2024-05-01 21:52:49 +00:00
then
2024-11-04 05:53:58 +00:00
logPrintIO curLevel Warning $ "Pong ID mismatch from: " <> show clientId
2024-05-01 21:52:49 +00:00
else do
now <- getCurrentTime
STM.atomically$ do
let otherPlayers = filter (\a -> playerId a /= playerId player) players
modPlayer = player
2024-11-03 03:40:46 +00:00
{ playerLastPong = (now, pongUuid)
2024-05-01 21:52:49 +00:00
}
void $ STM.swapTMVar (scPlayers stateContainer) (modPlayer : otherPlayers)
2024-11-04 05:53:58 +00:00
sendUpdate curLevel stateContainer (rcMap readerContainer) player
2024-05-01 21:52:49 +00:00
)
mPlayer
)
mclient
-- | handle received messages
handleMessages :: Game ()
handleMessages = do
queue <- gets scMessageQueue
serverState <- get
readerContainer <- ask
liftIO $ do
2024-10-31 18:19:13 +00:00
msgs <- STM.atomically $
STM.flushTQueue queue
2024-10-31 20:01:53 +00:00
mapM_
(handleMessage serverState readerContainer)
msgs