diff -r 95efe37482e3 -r 4e78ad846fb6 gameServer/Actions.hs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gameServer/Actions.hs Wed Feb 18 15:04:40 2009 +0000 @@ -0,0 +1,197 @@ +module Actions where + +import Control.Concurrent.STM +import Control.Concurrent.Chan +import Data.IntMap +import qualified Data.IntSet as IntSet +import Monad +----------------------------- +import CoreTypes + +data Action = + AnswerThisClient [String] + | AnswerAll [String] + | AnswerAllOthers [String] + | AnswerThisRoom [String] + | AnswerOthersInRoom [String] + | AnswerLobby [String] + | RoomAddThisClient Int -- roomID + | RoomRemoveThisClient + | RemoveRoom + | ProtocolError String + | Warning String + | ByeClient String + | ModifyClient (ClientInfo -> ClientInfo) + | ModifyRoom (RoomInfo -> RoomInfo) + | AddRoom String String + | Dump + +type CmdHandler = Int -> Clients -> Rooms -> [String] -> [Action] + + +processAction :: (Int, ServerInfo, Clients, Rooms) -> Action -> IO (Int, ServerInfo, Clients, Rooms) + + +processAction (clID, serverInfo, clients, rooms) (AnswerThisClient msg) = do + writeChan (sendChan $ clients ! clID) msg + return (clID, serverInfo, clients, rooms) + + +processAction (clID, serverInfo, clients, rooms) (AnswerAll msg) = do + mapM_ (\id -> writeChan (sendChan $ clients ! id) msg) (keys clients) + return (clID, serverInfo, clients, rooms) + + +processAction (clID, serverInfo, clients, rooms) (AnswerAllOthers msg) = do + mapM_ (\id -> writeChan (sendChan $ clients ! id) msg) $ Prelude.filter (/= clID) (keys clients) + return (clID, serverInfo, clients, rooms) + + +processAction (clID, serverInfo, clients, rooms) (AnswerThisRoom msg) = do + mapM_ (\id -> writeChan (sendChan $ clients ! id) msg) roomClients + return (clID, serverInfo, clients, rooms) + where + roomClients = IntSet.elems $ playersIDs room + room = rooms ! rID + rID = roomID client + client = clients ! clID + + +processAction (clID, serverInfo, clients, rooms) (AnswerOthersInRoom msg) = do + mapM_ (\id -> writeChan (sendChan $ clients ! id) msg) $ Prelude.filter (/= clID) roomClients + return (clID, serverInfo, clients, rooms) + where + roomClients = IntSet.elems $ playersIDs room + room = rooms ! rID + rID = roomID client + client = clients ! clID + + +processAction (clID, serverInfo, clients, rooms) (AnswerLobby msg) = do + mapM_ (\id -> writeChan (sendChan $ clients ! id) msg) roomClients + return (clID, serverInfo, clients, rooms) + where + roomClients = IntSet.elems $ playersIDs room + room = rooms ! 0 + + +processAction (clID, serverInfo, clients, rooms) (ProtocolError msg) = do + writeChan (sendChan $ clients ! clID) ["ERROR", msg] + return (clID, serverInfo, clients, rooms) + + +processAction (clID, serverInfo, clients, rooms) (Warning msg) = do + writeChan (sendChan $ clients ! clID) ["WARNING", msg] + return (clID, serverInfo, clients, rooms) + + +processAction (clID, serverInfo, clients, rooms) (ByeClient msg) = do + mapM_ (processAction (clID, serverInfo, clients, rooms)) $ answerOthersQuit ++ answerInformRoom + writeChan (sendChan $ clients ! clID) ["BYE"] + return ( + 0, + serverInfo, + delete clID clients, + adjust (\r -> r{playersIDs = IntSet.delete clID (playersIDs r), playersIn = (playersIn r) - 1}) rID rooms + ) + where + client = clients ! clID + rID = roomID client + clientNick = nick client + answerInformRoom = + if roomID client /= 0 then + if not $ Prelude.null msg then + [AnswerThisRoom ["LEFT", clientNick, msg]] + else + [AnswerThisRoom ["LEFT", clientNick]] + else + [] + answerOthersQuit = + if not $ Prelude.null clientNick then + if not $ Prelude.null msg then + [AnswerAll ["LOBBY:LEFT", clientNick, msg]] + else + [AnswerAll ["LOBBY:LEFT", clientNick]] + else + [] + + +processAction (clID, serverInfo, clients, rooms) (ModifyClient func) = do + return (clID, serverInfo, adjust func clID clients, rooms) + + +processAction (clID, serverInfo, clients, rooms) (ModifyRoom func) = do + return (clID, serverInfo, clients, adjust func rID rooms) + where + rID = roomID $ clients ! clID + + +processAction (clID, serverInfo, clients, rooms) (RoomAddThisClient rID) = do + processAction ( + clID, + serverInfo, + adjust (\cl -> cl{roomID = rID}) clID clients, + adjust (\r -> r{playersIDs = IntSet.insert clID (playersIDs r), playersIn = (playersIn r) + 1}) rID $ + adjust (\r -> r{playersIDs = IntSet.delete clID (playersIDs r)}) 0 rooms + ) joinMsg + where + client = clients ! clID + joinMsg = if rID == 0 then + AnswerAllOthers ["LOBBY:JOINED", nick client] + else + AnswerThisRoom ["JOINED", nick client] + + +processAction (clID, serverInfo, clients, rooms) (RoomRemoveThisClient) = do + when (rID /= 0) $ (processAction (clID, serverInfo, clients, rooms) $ AnswerOthersInRoom ["LEFT", nick client, "part"]) >> return () + return ( + clID, + serverInfo, + adjust (\cl -> cl{roomID = 0}) clID clients, + adjust (\r -> r{playersIDs = IntSet.delete clID (playersIDs r), playersIn = (playersIn r) - 1}) rID $ + adjust (\r -> r{playersIDs = IntSet.insert clID (playersIDs r)}) 0 rooms + ) + where + rID = roomID client + client = clients ! clID + + +processAction (clID, serverInfo, clients, rooms) (AddRoom roomName roomPassword) = do + let newServerInfo = serverInfo {nextRoomID = newID} + let room = newRoom{ + roomUID = newID, + name = roomName, + password = roomPassword, + roomProto = (clientProto client) + } + + processAction (clID, serverInfo, clients, rooms) $ AnswerLobby ["ROOM", "ADD", roomName] + + processAction ( + clID, + newServerInfo, + adjust (\cl -> cl{isMaster = True}) clID clients, + insert newID room rooms + ) $ RoomAddThisClient newID + where + newID = (nextRoomID serverInfo) - 1 + client = clients ! clID + + +processAction (clID, serverInfo, clients, rooms) (RemoveRoom) = do + processAction (clID, serverInfo, clients, rooms) $ AnswerLobby ["ROOM", "DEL", name clRoom] + processAction (clID, serverInfo, clients, rooms) $ AnswerOthersInRoom ["ROOMABANDONED", name clRoom] + return (clID, + serverInfo, + Data.IntMap.map (\cl -> if roomID cl == rID then cl{roomID = 0, isMaster = False} else cl) clients, + delete rID $ adjust (\r -> r{playersIDs = IntSet.union (playersIDs clRoom) (playersIDs r)}) 0 rooms + ) + where + clRoom = rooms ! rID + rID = roomID client + client = clients ! clID + +processAction (clID, serverInfo, clients, rooms) (Dump) = do + writeChan (sendChan $ clients ! clID) ["DUMP", show serverInfo, showTree clients, showTree rooms] + return (clID, serverInfo, clients, rooms) +