nearing the solution

This commit is contained in:
nek0 2024-11-03 04:40:46 +01:00
parent 473d9dea6e
commit e8bdc8a1f7
10 changed files with 181 additions and 161 deletions

View file

@ -2,6 +2,6 @@ setSocketPath : "/tmp/wizard.sock"
setMapRows : 40 setMapRows : 40
setMapColumns : 40 setMapColumns : 40
setSpawnerProbability : 0.01 setSpawnerProbability : 0.01
setFPS : 30 setFPS : 1
setClientMaxTimeout : 5 setClientMaxTimeout : 5
setFramesPerPing : 120 setFramesPerPing : 120

View file

@ -15,7 +15,7 @@ import qualified Data.Matrix as M
import Graphics.Vty import Graphics.Vty
import Graphics.Vty.CrossPlatform import Graphics.Vty.CrossPlatform
import Network.Socket (close) import Network.Socket (Socket, close)
import Options.Applicative import Options.Applicative
@ -44,8 +44,7 @@ main = do
mockClientState <- STM.newTMVarIO (ClientState undefined False) mockClientState <- STM.newTMVarIO (ClientState undefined False)
let mockState = StateContainer undefined mockClientState undefined undefined let mockState = StateContainer undefined mockClientState undefined undefined
sendMessage IdRequest sock sendMessage IdRequest sock
receiveMessage sock messageQueue mockState awaitResponse sock messageQueue mockState 0
awaitResponse messageQueue 1
clientIdMsg <- head <$> STM.atomically (STM.flushTQueue messageQueue) clientIdMsg <- head <$> STM.atomically (STM.flushTQueue messageQueue)
let clientId = acClientUUID clientIdMsg let clientId = acClientUUID clientIdMsg
putStrLn $ "received client UUID: " <> show clientId putStrLn $ "received client UUID: " <> show clientId
@ -57,8 +56,7 @@ main = do
sendMessage (ClientMessage clientId ClientRequestWizard) sock sendMessage (ClientMessage clientId ClientRequestWizard) sock
-- threadDelay $ 1 * 10 ^ 6 -- threadDelay $ 1 * 10 ^ 6
receiveMessage sock messageQueue mockState awaitResponse sock messageQueue mockState 1
awaitResponse messageQueue 1
playerWizard <- head <$> STM.atomically (STM.flushTQueue messageQueue) playerWizard <- head <$> STM.atomically (STM.flushTQueue messageQueue)
putStrLn $ "received wizard: " <> show (initWizard playerWizard) putStrLn $ "received wizard: " <> show (initWizard playerWizard)
@ -85,7 +83,7 @@ main = do
putStrLn "Shutting down client…" putStrLn "Shutting down client…"
showCursor (outputIface vty) showCursor (outputIface vty)
shutdown vty shutdown vty
threadDelay (10 ^ 6) threadDelay (10 ^ 3)
putStrLn "Closing connection to server…" putStrLn "Closing connection to server…"
close sock close sock
putStrLn "bye bye" putStrLn "bye bye"
@ -112,14 +110,17 @@ welcomeText = mconcat $ map (<> "\n")
] ]
awaitResponse awaitResponse
:: STM.TQueue ServerMessage :: Socket
-> STM.TQueue ServerMessage
-> StateContainer
-> Int -> Int
-> IO () -> IO ()
awaitResponse _ 10 = error "Tries to communicate with server exceeded" awaitResponsea _ _ _ 10 = error "Tries to communicate with server exceeded"
awaitResponse messageQueue numTries = do awaitResponse sock messageQueue mockState numTries = do
receiveMessage sock messageQueue mockState
responsePresent <- not <$> STM.atomically (STM.isEmptyTQueue messageQueue) responsePresent <- not <$> STM.atomically (STM.isEmptyTQueue messageQueue)
if responsePresent if responsePresent
then pure () then pure ()
else do else do
threadDelay $ 10 ^ 6 threadDelay $ 10 ^ 6
awaitResponse messageQueue (succ numTries) awaitResponse sock messageQueue mockState (succ numTries)

View file

@ -54,6 +54,7 @@ main = do
putStrLn "starting game…" putStrLn "starting game…"
now <- getCurrentTime now <- getCurrentTime
sockList <- STM.newTMVarIO [] sockList <- STM.newTMVarIO []
queueList <- STM.newTMVarIO []
messageQueue <- STM.newTQueueIO messageQueue <- STM.newTQueueIO
serverState <- STM.newTMVarIO (ServerState False False) serverState <- STM.newTMVarIO (ServerState False False)
emptyPLayers <- STM.newTMVarIO [] emptyPLayers <- STM.newTMVarIO []
@ -63,7 +64,7 @@ main = do
setFramesPerPing setFramesPerPing
setClientMaxTimeout setClientMaxTimeout
sock sock
initState = StateContainer (arenaSpawners arena) emptyPLayers serverState now sockList messageQueue initState = StateContainer (arenaSpawners arena) emptyPLayers serverState now sockList queueList messageQueue
(finalState, finalWrite) <- execRWST (finalState, finalWrite) <- execRWST
(do (do
terminateGameOnSigint terminateGameOnSigint

View file

@ -16,6 +16,10 @@ import Control.Monad.IO.Class
import Control.Monad.RWS.Strict import Control.Monad.RWS.Strict
import Data.List (find)
import Data.Maybe (fromJust)
import Network.Socket as Net import Network.Socket as Net
import System.Posix.Signals import System.Posix.Signals
@ -51,12 +55,13 @@ terminateGameOnSigint = do
sock <- asks rcMainSocket sock <- asks rcMainSocket
serverState <- gets scServerState serverState <- gets scServerState
clientList <- gets scClientSockets clientList <- gets scClientSockets
queueList <- gets scClientQueues
void $ liftIO $ installHandler void $ liftIO $ installHandler
sigINT sigINT
(CatchOnce $ do (CatchOnce $ do
putStrLn "SIGINT caught, terminating…" putStrLn "SIGINT caught, terminating…"
clients <- liftIO $ STM.atomically $ STM.readTMVar clientList queues <- liftIO $ STM.atomically $ STM.readTMVar queueList
disconnectClients clientList clients disconnectClients clientList queues
threadDelay (10 ^ 6) threadDelay (10 ^ 6)
close sock close sock
st <- STM.atomically $ STM.readTMVar serverState st <- STM.atomically $ STM.readTMVar serverState
@ -68,62 +73,72 @@ terminateGameOnSigint = do
-- | Disconnect all connected clients gracefully by announcing the server quitting -- | Disconnect all connected clients gracefully by announcing the server quitting
disconnectClients disconnectClients
:: STM.TMVar [ClientComms] :: STM.TMVar [ClientSocket]
-> [ClientComms] -> [ClientQueue]
-> IO () -> IO ()
disconnectClients clientList clients = do disconnectClients clientSockets queues = do
putStrLn "server shutting down. Notifying all clients…" putStrLn "server shutting down. Notifying all clients…"
mapM_ mapM_
(\client -> do (\queue -> do
maybe maybe
(pure ()) (pure ())
(\uuid -> do (\uuid -> do
putStrLn $ "notifying client: " <> show uuid putStrLn $ "notifying client: " <> show uuid
queueMessage ServerQuit uuid clientList queueMessage ServerQuit uuid queues
dropClient clientList (ccSocket client) sock <- do
socketList <- STM.atomically $ STM.readTMVar clientSockets
pure $ fromJust $ find (\s -> csUUID s == Just uuid) socketList
dropClient clientSockets (csSocket sock)
) )
(ccUUID client) (cqUUID queue)
) )
clients queues
-- | Process incoming connection requests -- | Process incoming connection requests
processRequests :: Game () processRequests :: Game ()
processRequests = do processRequests = do
mainSocket <- asks rcMainSocket mainSocket <- asks rcMainSocket
queue <- gets scMessageQueue serverQueue <- gets scMessageQueue
socketList <- gets scClientSockets socketList <- gets scClientSockets
queueList <- gets scClientQueues
st <- gets scServerState st <- gets scServerState
void $ liftIO $ forkIO $ acceptConnection mainSocket socketList queue st void $ liftIO $ forkIO $ acceptConnection mainSocket socketList queueList serverQueue st
where where
acceptConnection mainSocket socketList queue st = do acceptConnection mainSocket socketList queueList serverQueue st = do
putStrLn "Ready for new connection requests…" putStrLn "Ready for new connection requests…"
eSock <- try $ accept mainSocket eSock <- try $ accept mainSocket
case eSock of case eSock of
Left (_ :: SomeException) -> Left (_ :: SomeException) ->
putStrLn "Main socket vanished!" putStrLn "Main socket vanished!"
Right (clientSock, _) -> do Right (clientSock, _) -> do
messageQueue <- STM.newTQueueIO clientQueue <- STM.newTQueueIO
sockContainer <- STM.newTMVarIO clientSock sockContainer <- STM.newTMVarIO clientSock
clientWriteThreadId <- liftIO $ forkIO $ forever $ do receiverThreadId <- liftIO $ forkIO $ forever $ do
receiveMessage sockContainer queue socketList receiveMessage sockContainer serverQueue
clientListenThreadId <- liftIO $ forkIO $ forever $ do senderThreadId <- liftIO $ forkIO $ forever $ do
sendMessageQueue sockContainer messageQueue sendMessageQueue sockContainer clientQueue
print clientSock print clientSock
liftIO $ STM.atomically $ do liftIO $ STM.atomically $ do
list <- STM.takeTMVar socketList slist <- STM.takeTMVar socketList
STM.putTMVar STM.putTMVar
socketList socketList
(ClientComms (ClientSocket
Nothing Nothing
clientSock clientSock
messageQueue receiverThreadId
clientWriteThreadId senderThreadId
clientListenThreadId : slist
: list )
qlist <- STM.takeTMVar queueList
STM.putTMVar queueList
(ClientQueue
Nothing
clientQueue
: qlist
) )
putStrLn "accepted new connection" putStrLn "accepted new connection"
-- abortCondition <- serverStop <$> STM.atomically (STM.readTMVar st) -- abortCondition <- serverStop <$> STM.atomically (STM.readTMVar st)
-- unless abortCondition $ -- unless abortCondition $
-- acceptConnection mainSocket socketList queue st -- acceptConnection mainSocket socketList queue st
acceptConnection mainSocket socketList queue st acceptConnection mainSocket socketList queueList serverQueue st

View file

@ -29,19 +29,20 @@ handleMessage
-> IO () -> IO ()
handleMessage stateContainer readerContainer msg = do handleMessage stateContainer readerContainer msg = do
let clientList = scClientSockets stateContainer let clientList = scClientSockets stateContainer
queueList <- STM.atomically $ STM.readTMVar $ scClientQueues stateContainer
clients <- liftIO $ STM.atomically $ STM.readTMVar clientList clients <- liftIO $ STM.atomically $ STM.readTMVar clientList
-- putStrLn $ "Handling: " <> show msg -- putStrLn $ "Handling: " <> show msg
case msg of case msg of
IdRequest -> do IdRequest -> do
clientId <- nextRandom clientId <- nextRandom
let clientIdx = findIndex (isNothing . ccUUID) clients let clientIdx = findIndex (isNothing . csUUID) clients
clientSock = ccSocket $ clients !! fromJust clientIdx clientSock = csSocket $ clients !! fromJust clientIdx
newClients = map newClients = map
(\old@(ClientComms mUUID oldClientSock _ _ _) -> (\old@(ClientSocket mUUID oldClientSock _ _) ->
if oldClientSock == clientSock && isNothing mUUID if oldClientSock == clientSock && isNothing mUUID
then then
old old
{ ccUUID = Just clientId { csUUID = Just clientId
} }
else else
old old
@ -49,13 +50,13 @@ handleMessage stateContainer readerContainer msg = do
clients clients
void $ liftIO $ STM.atomically $ STM.swapTMVar clientList newClients void $ liftIO $ STM.atomically $ STM.swapTMVar clientList newClients
putStrLn $ "Accepted Client with UUID " <> show clientId putStrLn $ "Accepted Client with UUID " <> show clientId
queueMessage (AcceptClient clientId) clientId clientList queueMessage (AcceptClient clientId) clientId queueList
ClientMessage clientId payload -> ClientMessage clientId payload ->
case payload of case payload of
ClientQuit -> do ClientQuit -> do
putStrLn $ "client has quit the game: " <> show clientId putStrLn $ "client has quit the game: " <> show clientId
let client = find (\a -> ccUUID a == Just clientId) clients let client = find (\a -> csUUID a == Just clientId) clients
dropClient clientList (ccSocket $ fromJust client) dropClient clientList (csSocket $ fromJust client)
ClientRequestWizard -> do ClientRequestWizard -> do
putStrLn "initializing new wizard" putStrLn "initializing new wizard"
let arena = rcMap readerContainer let arena = rcMap readerContainer
@ -67,9 +68,8 @@ handleMessage stateContainer readerContainer msg = do
currentPlayers <- STM.readTMVar (scPlayers stateContainer) currentPlayers <- STM.readTMVar (scPlayers stateContainer)
void $ STM.swapTMVar (scPlayers stateContainer) $ void $ STM.swapTMVar (scPlayers stateContainer) $
Player clientId freshWizard False (now, uuid) : currentPlayers Player clientId freshWizard False (now, uuid) : currentPlayers
queueMessage (ProvideInitialWizard freshWizard) clientId clientList queueMessage (ProvideInitialWizard freshWizard) clientId queueList
ClientReady -> do ClientReady -> do
putStrLn $ "client " <> show clientId <> " is ready!"
now <- getCurrentTime now <- getCurrentTime
STM.atomically $ do STM.atomically $ do
currentPlayers <- STM.readTMVar (scPlayers stateContainer) currentPlayers <- STM.readTMVar (scPlayers stateContainer)
@ -82,27 +82,27 @@ handleMessage stateContainer readerContainer msg = do
, playerLastPong = (now, snd (playerLastPong $ head thisPlayers)) , playerLastPong = (now, snd (playerLastPong $ head thisPlayers))
} }
: otherPlayers : otherPlayers
Pong uuid -> do putStrLn $ "client ready: " <> show clientId
let mclient = find (\c -> ccUUID c == Just clientId) clients Pong pongUuid -> do
let mclient = find (\c -> csUUID c == Just clientId) clients
players <- STM.atomically $ STM.readTMVar (scPlayers stateContainer)
maybe maybe
(putStrLn $ "Who is " <> show uuid <> "?") (putStrLn $ "Unknown client: " <> show clientId)
(\_ -> do (const $ do
mPlayer <- STM.atomically $ do mPlayer <- STM.atomically $ do
players <- STM.readTMVar (scPlayers stateContainer)
pure $ find (\p -> playerId p == clientId) players pure $ find (\p -> playerId p == clientId) players
maybe maybe
(pure ()) (pure ())
(\player -> (\player ->
if snd (playerLastPong player) /= uuid if snd (playerLastPong player) /= pongUuid
then then
putStrLn $ "Pong ID mismatch from " <> show clientId putStrLn $ "Pong ID mismatch from: " <> show clientId
else do else do
now <- getCurrentTime now <- getCurrentTime
STM.atomically$ do STM.atomically$ do
players <- STM.readTMVar (scPlayers stateContainer)
let otherPlayers = filter (\a -> playerId a /= playerId player) players let otherPlayers = filter (\a -> playerId a /= playerId player) players
modPlayer = player modPlayer = player
{ playerLastPong = (now, uuid) { playerLastPong = (now, pongUuid)
} }
void $ STM.swapTMVar (scPlayers stateContainer) (modPlayer : otherPlayers) void $ STM.swapTMVar (scPlayers stateContainer) (modPlayer : otherPlayers)
sendUpdate stateContainer (rcMap readerContainer) player sendUpdate stateContainer (rcMap readerContainer) player

View file

@ -1,3 +1,4 @@
{-# LANGUAGE OverloadedStrings #-}
module Server.Communication.Receive where module Server.Communication.Receive where
import Control.Concurrent (threadDelay) import Control.Concurrent (threadDelay)
@ -30,43 +31,38 @@ import Server.Types
receiveMessage receiveMessage
:: STM.TMVar Socket :: STM.TMVar Socket
-> STM.TQueue ClientMessage -> STM.TQueue ClientMessage
-> STM.TMVar [ClientComms]
-> IO () -> IO ()
receiveMessage sockContainer queue clientList = do receiveMessage sockContainer queue = do
randSleep <- randomRIO (1, 1000) randSleep <- randomRIO (1, 1000)
threadDelay randSleep threadDelay randSleep
msock <- STM.atomically $ STM.tryTakeTMVar sockContainer sock <- STM.atomically $ STM.readTMVar sockContainer
let maxBufferLength = 4096 let maxBufferLength = 4096
putStrLn "read socket container for receiving"
mMsg <- do
ptr <- mallocArray maxBufferLength
putStrLn "receiving data"
eBufferLength <-
try $ recvBuf sock ptr maxBufferLength
bufferLength <- case eBufferLength of
Left (e :: IOException) -> do
-- putStrLn ("Socket vanished, cleaning up after " <> show e)
-- dropClient clientList sock
pure 0
Right len -> pure len
free ptr
msg <- B.pack <$> peekArray bufferLength ptr
putStrLn $ "received data: " <> show msg
if bufferLength > 0 && msg /= ""
then do
putStrLn $ "received message: " <> show msg
pure (A.decode' $ B8.fromStrict msg :: Maybe ClientMessage)
else
pure Nothing
maybe maybe
(pure ()) (pure ())
(\sock -> do (\msg -> do
putStrLn "took socket container for receiving" print msg
mMsg <- do liftIO $ STM.atomically $ STM.writeTQueue queue msg
ptr <- mallocArray maxBufferLength -- when (msg == IdRequest) (threadDelay $ 10 ^ 3)
eBufferLength <-
try $ recvBuf sock ptr maxBufferLength
bufferLength <- case eBufferLength of
Left (e :: IOException) -> do
-- putStrLn ("Socket vanished, cleaning up after " <> show e)
-- dropClient clientList sock
pure 0
Right len -> pure len
msg <- B.pack <$> peekArray bufferLength ptr
let mJsonMsg = A.decode' $ B8.fromStrict msg :: Maybe ClientMessage
free ptr
if bufferLength > 0
then
pure mJsonMsg
else
pure Nothing
maybe
(pure ())
(\msg -> do
print msg
liftIO $ STM.atomically $ STM.writeTQueue queue msg
-- when (msg == IdRequest) (threadDelay $ 10 ^ 3)
)
mMsg
STM.atomically $ STM.putTMVar sockContainer sock
) )
msock mMsg

View file

@ -47,50 +47,44 @@ import Server.Types
queueMessage queueMessage
:: ServerMessage :: ServerMessage
-> UUID -> UUID
-> STM.TMVar [ClientComms] -> [ClientQueue]
-> IO () -> IO ()
queueMessage msg uuid clientList = do queueMessage msg uuid queueList = do
clients <- STM.atomically $ STM.readTMVar clientList putStrLn $ "queueing message \"" <> show msg <> "\" for client " <> show uuid <> ""
let mQueue = ccQueue <$> find (\client -> ccUUID client == Just uuid) clients let mQueue = cqQueue <$> find (\client -> cqUUID client == Just uuid) queueList
maybe maybe
(putStrLn $ "unknown client UUID: " <> show uuid) (putStrLn $ "no queue found for client: " <> show uuid)
(\queue -> (\queue ->
STM.atomically $ STM.writeTQueue queue msg STM.atomically $ STM.writeTQueue queue msg
) )
mQueue mQueue
putStrLn "message queued!"
sendMessageQueue sendMessageQueue
:: STM.TMVar Socket :: STM.TMVar Socket
-> STM.TQueue ServerMessage -> STM.TQueue ServerMessage
-> IO () -> IO ()
sendMessageQueue sockContainer queue = do sendMessageQueue sockContainer queue = do
randSleep <- randomRIO (1, 1000) msgs <- STM.atomically $ STM.flushTQueue queue
threadDelay randSleep mapM_
msock <- STM.atomically $ STM.tryTakeTMVar sockContainer (\msg -> do
maybe sock <- STM.atomically $ STM.readTMVar sockContainer
(pure ()) putStrLn "read socket container for sending"
(\sock -> do putStrLn $ "sending message: " <> show msg
putStrLn "took socket container for sending" let msgJson = A.encode msg
msgs <- STM.atomically $ STM.flushTQueue queue msgVector = VS.fromList $ B.unpack $ B.toStrict ('<' `B8.cons` (msgJson `B8.snoc` '>'))
mapM_ VS.unsafeWith
(\msg -> do msgVector
let msgJson = A.encode msg (\ptr -> do
msgVector = VS.fromList $ B.unpack $ B.toStrict ('<' `B8.cons` (msgJson `B8.snoc` '>')) eResult <- try $ void $ sendBuf sock ptr (VS.length msgVector)
VS.unsafeWith case eResult of
msgVector Left (e :: IOException) ->
(\ptr -> do putStrLn $ "can't reach client after " <> show e
eResult <- try $ void $ sendBuf sock ptr (VS.length msgVector) Right _ ->
case eResult of pure ()
Left (e :: IOException) ->
putStrLn $ "can't reach client after " <> show e
Right _ ->
pure ()
)
) )
msgs
STM.atomically $ STM.putTMVar sockContainer sock
) )
msock msgs
sendPings :: Game () sendPings :: Game ()
sendPings = do sendPings = do
@ -100,54 +94,59 @@ sendPings = do
fps <- asks rcFPS fps <- asks rcFPS
stateContainer <- get stateContainer <- get
players <- liftIO $ STM.atomically $ STM.readTMVar (scPlayers stateContainer) players <- liftIO $ STM.atomically $ STM.readTMVar (scPlayers stateContainer)
sockets <- liftIO $ STM.atomically $ STM.readTMVar (scClientSockets stateContainer) -- sockets <- liftIO $ STM.atomically $ STM.readTMVar (scClientSockets stateContainer)
mapM_ mapM_
(\player@(Player plId (Wizard {}) readiness (lastPongTime, _)) -> do (\player@(Player plId (Wizard {}) readiness (lastPongTime, _)) -> do
let timeDiff = realToFrac $ diffUTCTime now lastPongTime :: Float let timeDiff = realToFrac $ diffUTCTime now lastPongTime :: Float
when (readiness && timeDiff > (fromIntegral framesPerPing * recip (fromIntegral fps))) $ do when (readiness && timeDiff > (fromIntegral framesPerPing * recip (fromIntegral fps))) $ do
let clientSock = ccSocket <$> find (\c -> ccUUID c == Just plId) sockets -- let clientSock = ccSocket <$> find (\c -> ccUUID c == Just plId) sockets
when (isJust clientSock) $ -- when (isJust clientSock) $
if timeDiff > realToFrac maxTimeout -- if timeDiff > realToFrac maxTimeout
then do -- then do
liftIO $ do -- liftIO $ do
putStrLn $ "dropping client because of timeout: " <> show plId -- putStrLn $ "dropping client because of timeout: " <> show plId
dropClient (scClientSockets stateContainer) (fromJust clientSock) -- dropClient (scClientSockets stateContainer) (fromJust clientSock)
put stateContainer -- put stateContainer
else do -- else do
random <- liftIO nextRandom random <- liftIO nextRandom
let newPong = (now, random) let newPong = (now, random)
liftIO $ queueMessage liftIO $ do
( Ping random queues <- STM.atomically $ STM.readTMVar (scClientQueues stateContainer)
) queueMessage
plId ( Ping random
(scClientSockets stateContainer) )
plId
queues
let newPlayer = player let newPlayer = player
{ playerLastPong = newPong { playerLastPong = newPong
} }
otherPlayers = filter (\a -> playerId a /= plId) players otherPlayers = filter (\a -> playerId a /= plId) players
liftIO $ void $ STM.atomically $ liftIO $ do
STM.swapTMVar (scPlayers stateContainer) (newPlayer : otherPlayers) void $ STM.atomically $
STM.swapTMVar (scPlayers stateContainer) (newPlayer : otherPlayers)
putStrLn "ping!"
) )
players players
put stateContainer put stateContainer
-- | Drops the client from internal management and closes its socket, if still present. -- | Drops the client from internal management and closes its socket, if still present.
dropClient dropClient
:: STM.TMVar [ClientComms] :: STM.TMVar [ClientSocket]
-> Socket -> Socket
-> IO () -> IO ()
dropClient clientList sock = do dropClient clientList sock = do
mClient <- STM.atomically $ do mClient <- STM.atomically $ do
clients <- STM.readTMVar clientList clients <- STM.readTMVar clientList
let mclient = find (\client -> ccSocket client == sock) clients let mclient = find (\client -> csSocket client == sock) clients
let reducedClients = filter (\client -> ccSocket client /= sock) clients let reducedClients = filter (\client -> csSocket client /= sock) clients
void $ STM.swapTMVar clientList reducedClients void $ STM.swapTMVar clientList reducedClients
pure mclient pure mclient
maybe maybe
(putStrLn $ "closing unknown socket: " <> show sock) (putStrLn $ "closing unknown socket: " <> show sock)
(\client -> do (\client -> do
putStrLn $ "dropping client because of closed socket: " <> show (fromJust $ ccUUID client) putStrLn $ "dropping client because of closed socket: " <> show (fromJust $ csUUID client)
killThread (ccListener client) killThread (csSender client)
killThread (csReceiver client)
) )
mClient mClient
close sock close sock
@ -158,11 +157,11 @@ sendUpdate
-> Player -> Player
-> IO () -> IO ()
sendUpdate stateContainer tileMap player = do sendUpdate stateContainer tileMap player = do
slice <- buildSlice player let slice = buildSlice player
sendSlice slice player sendSlice slice player
where where
buildSlice :: Player -> IO MapSlice buildSlice :: Player -> MapSlice
buildSlice (Player _ (Wizard {..}) _ _) = do buildSlice (Player _ (Wizard {..}) _ _) =
let V2 wr wc = wizardPos let V2 wr wc = wizardPos
subCoords = (,) <$> [floor wr - 4 .. floor wr + 4] <*> [floor wc - 4 .. floor wc + 4] subCoords = (,) <$> [floor wr - 4 .. floor wr + 4] <*> [floor wc - 4 .. floor wc + 4]
leftBound = wizardRot + (pi / 4) leftBound = wizardRot + (pi / 4)
@ -185,9 +184,12 @@ sendUpdate stateContainer tileMap player = do
Nothing Nothing
) )
subCoords subCoords
pure (MapSlice initViewMatrix []) in
MapSlice initViewMatrix []
sendSlice :: MapSlice -> Player -> IO () sendSlice :: MapSlice -> Player -> IO ()
sendSlice slice (Player playerId wizard _ _) = do sendSlice slice (Player playerId wizard _ _) = do
let msg = TickUpdate slice wizard let msg = TickUpdate slice wizard
-- print slice -- print slice
liftIO $ queueMessage msg playerId (scClientSockets stateContainer) liftIO $ do
queues <- STM.atomically $ STM.readTMVar $ scClientQueues stateContainer
queueMessage msg playerId queues

View file

@ -36,13 +36,13 @@ runGame = do
let delta = realToFrac $ diffUTCTime now before let delta = realToFrac $ diffUTCTime now before
-- liftIO $ B8.hPutStr stdout $ "tick: " <> fromString (show delta) <> " \r" -- liftIO $ B8.hPutStr stdout $ "tick: " <> fromString (show delta) <> " \r"
handleMessages handleMessages
updateSpawners delta -- updateSpawners delta
updateWizards delta -- updateWizards delta
modify' -- modify'
(\s -> s -- (\s -> s
{ scServerLastTick = now -- { scServerLastTick = now
} -- }
) -- )
fps <- asks rcFPS fps <- asks rcFPS
sendPings sendPings
let remainingTime = recip (fromIntegral fps) - delta let remainingTime = recip (fromIntegral fps) - delta
@ -50,4 +50,3 @@ runGame = do
liftIO $ threadDelay $ floor $ remainingTime * 10 ^ 6 liftIO $ threadDelay $ floor $ remainingTime * 10 ^ 6
) )
liftIO $ threadDelay (10 ^ 6) liftIO $ threadDelay (10 ^ 6)
-- liftIO $ killThread recvThread

View file

@ -16,7 +16,7 @@ import Server.Types
updateSpawners :: Float -> Game () updateSpawners :: Float -> Game ()
updateSpawners dt = updateSpawners dt =
modify' (\sc@(StateContainer spawners _ _ _ _ _) -> modify' (\sc@(StateContainer spawners _ _ _ _ _ _) ->
let newSpawners = map let newSpawners = map
(\spawner -> do (\spawner -> do
let newTTL = spawnerReloadTTL spawner - dt let newTTL = spawnerReloadTTL spawner - dt

View file

@ -63,16 +63,22 @@ data StateContainer = StateContainer
, scPlayers :: STM.TMVar [Player] , scPlayers :: STM.TMVar [Player]
, scServerState :: STM.TMVar ServerState , scServerState :: STM.TMVar ServerState
, scServerLastTick :: UTCTime , scServerLastTick :: UTCTime
, scClientSockets :: STM.TMVar [ClientComms] , scClientSockets :: STM.TMVar [ClientSocket]
, scClientQueues :: STM.TMVar [ClientQueue]
, scMessageQueue :: STM.TQueue ClientMessage , scMessageQueue :: STM.TQueue ClientMessage
} }
data ClientComms = ClientComms data ClientSocket = ClientSocket
{ ccUUID :: Maybe UUID { csUUID :: Maybe UUID
, ccSocket :: Socket , csSocket :: Socket
, ccQueue :: STM.TQueue ServerMessage , csSender :: ThreadId
, ccWriter :: ThreadId , csReceiver :: ThreadId
, ccListener :: ThreadId }
deriving (Eq)
data ClientQueue = ClientQueue
{ cqUUID :: Maybe UUID
, cqQueue :: STM.TQueue ServerMessage
} }
deriving (Eq) deriving (Eq)