gameServer/Actions.hs
changeset 1804 4e78ad846fb6
child 1811 1b9e33623b7e
--- /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)
+