gameServer/Actions.hs
branchwebgl
changeset 9950 2759212a27de
parent 9521 8054d9d775fd
parent 9868 53d1b92db6ce
child 10015 4feced261c68
equal deleted inserted replaced
9521:8054d9d775fd 9950:2759212a27de
    19 import Control.Arrow
    19 import Control.Arrow
    20 import Control.Exception as E
    20 import Control.Exception as E
    21 import System.Process
    21 import System.Process
    22 import Network.Socket
    22 import Network.Socket
    23 import System.Random
    23 import System.Random
       
    24 import qualified Data.Traversable as DT
    24 -----------------------------
    25 -----------------------------
    25 #if defined(OFFICIAL_SERVER)
    26 #if defined(OFFICIAL_SERVER)
    26 import OfficialServer.GameReplayStore
    27 import OfficialServer.GameReplayStore
    27 #endif
    28 #endif
    28 import CoreTypes
    29 import CoreTypes
   185 processAction (MoveToLobby msg) = do
   186 processAction (MoveToLobby msg) = do
   186     (Just ci) <- gets clientIndex
   187     (Just ci) <- gets clientIndex
   187     ri <- clientRoomA
   188     ri <- clientRoomA
   188     rnc <- gets roomsClients
   189     rnc <- gets roomsClients
   189     playersNum <- io $ room'sM rnc playersIn ri
   190     playersNum <- io $ room'sM rnc playersIn ri
       
   191     specialRoom <- io $ room'sM rnc isSpecial ri
   190     master <- client's isMaster
   192     master <- client's isMaster
   191 --    client <- client's id
   193 --    client <- client's id
   192     clNick <- client's nick
   194     clNick <- client's nick
   193     chans <- othersChans
   195     chans <- othersChans
   194 
   196 
   195     if master then
   197     if master then
   196         if playersNum > 1 then
   198         if (playersNum > 1) || specialRoom then
   197             mapM_ processAction [ChangeMaster Nothing, NoticeMessage AdminLeft, RemoveClientTeams, AnswerClients chans ["LEFT", clNick, msg]]
   199             mapM_ processAction [ChangeMaster Nothing, NoticeMessage AdminLeft, RemoveClientTeams, AnswerClients chans ["LEFT", clNick, msg]]
   198             else
   200             else
   199             processAction RemoveRoom
   201             processAction RemoveRoom
   200         else
   202         else
   201         mapM_ processAction [RemoveClientTeams, AnswerClients chans ["LEFT", clNick, msg]]
   203         mapM_ processAction [RemoveClientTeams, AnswerClients chans ["LEFT", clNick, msg]]
   203     allClientsChans <- liftM (Prelude.map sendChan . Prelude.filter isVisible) $! allClientsS
   205     allClientsChans <- liftM (Prelude.map sendChan . Prelude.filter isVisible) $! allClientsS
   204     processAction $ AnswerClients allClientsChans ["CLIENT_FLAGS", "-i", clNick]
   206     processAction $ AnswerClients allClientsChans ["CLIENT_FLAGS", "-i", clNick]
   205 
   207 
   206     -- when not removing room
   208     -- when not removing room
   207     ready <- client's isReady
   209     ready <- client's isReady
   208     when (not master || playersNum > 1) . io $ do
   210     when (not master || playersNum > 1 || specialRoom) . io $ do
   209         modifyRoom rnc (\r -> r{
   211         modifyRoom rnc (\r -> r{
   210                 playersIn = playersIn r - 1,
   212                 playersIn = playersIn r - 1,
   211                 readyPlayers = if ready then readyPlayers r - 1 else readyPlayers r
   213                 readyPlayers = if ready then readyPlayers r - 1 else readyPlayers r
   212                 }) ri
   214                 }) ri
   213         moveClientToLobby rnc ci
   215         moveClientToLobby rnc ci
   216 processAction (ChangeMaster delegateId)= do
   218 processAction (ChangeMaster delegateId)= do
   217     (Just ci) <- gets clientIndex
   219     (Just ci) <- gets clientIndex
   218     proto <- client's clientProto
   220     proto <- client's clientProto
   219     ri <- clientRoomA
   221     ri <- clientRoomA
   220     rnc <- gets roomsClients
   222     rnc <- gets roomsClients
   221     newMasterId <- liftM (\ids -> fromMaybe (last . filter (/= ci) $ ids) delegateId) . io $ roomClientsIndicesM rnc ri
   223     specialRoom <- io $ room'sM rnc isSpecial ri
   222     newMaster <- io $ client'sM rnc id newMasterId
   224     newMasterId <- liftM (\ids -> fromMaybe (listToMaybe . reverse . filter (/= ci) $ ids) $ liftM Just delegateId) . io $ roomClientsIndicesM rnc ri
       
   225     newMaster <- io $ client'sM rnc id `DT.mapM` newMasterId
   223     oldMasterId <- io $ room'sM rnc masterID ri
   226     oldMasterId <- io $ room'sM rnc masterID ri
   224     oldMaster <- io $ client'sM rnc id oldMasterId
       
   225     oldRoomName <- io $ room'sM rnc name ri
   227     oldRoomName <- io $ room'sM rnc name ri
   226     kicked <- client's isKickedFromServer
   228     kicked <- client's isKickedFromServer
   227     thisRoomChans <- liftM (map sendChan) $ roomClientsS ri
   229     thisRoomChans <- liftM (map sendChan) $ roomClientsS ri
   228     let newRoomName = if (proto < 42) || kicked then nick newMaster else oldRoomName
   230     let newRoomName = if ((proto < 42) || kicked) && (not specialRoom) then maybeNick newMaster else oldRoomName
   229     mapM_ processAction [
   231 
       
   232     when (isJust oldMasterId) $ do
       
   233         oldMasterNick <- io $ client'sM rnc nick (fromJust oldMasterId)
       
   234         mapM_ processAction [
       
   235             ModifyClient2 (fromJust oldMasterId) (\c -> c{isMaster = False})
       
   236             , AnswerClients thisRoomChans ["CLIENT_FLAGS", "-h", oldMasterNick]
       
   237             ]
       
   238 
       
   239     when (isJust newMasterId) $
       
   240         mapM_ processAction [
       
   241           ModifyClient2 (fromJust newMasterId) (\c -> c{isMaster = True})
       
   242         , AnswerClients [sendChan $ fromJust newMaster] ["ROOM_CONTROL_ACCESS", "1"]
       
   243         , AnswerClients thisRoomChans ["CLIENT_FLAGS", "+h", nick $ fromJust newMaster]
       
   244         ]
       
   245 
       
   246     processAction $
   230         ModifyRoom (\r -> r{masterID = newMasterId
   247         ModifyRoom (\r -> r{masterID = newMasterId
   231                 , name = newRoomName
   248                 , name = newRoomName
   232                 , isRestrictedJoins = False
   249                 , isRestrictedJoins = False
   233                 , isRestrictedTeams = False
   250                 , isRestrictedTeams = False
   234                 , isRegisteredOnly = False}
   251                 , isRegisteredOnly = isSpecial r}
   235                 )
   252                 )
   236         , ModifyClient2 newMasterId (\c -> c{isMaster = True})
       
   237         , ModifyClient2 oldMasterId (\c -> c{isMaster = False})
       
   238         , AnswerClients [sendChan newMaster] ["ROOM_CONTROL_ACCESS", "1"]
       
   239         , AnswerClients thisRoomChans ["CLIENT_FLAGS", "-h", nick oldMaster]
       
   240         , AnswerClients thisRoomChans ["CLIENT_FLAGS", "+h", nick newMaster]
       
   241         ]
       
   242 
   253 
   243     newRoom' <- io $ room'sM rnc id ri
   254     newRoom' <- io $ room'sM rnc id ri
   244     chans <- liftM (map sendChan) $! sameProtoClientsS proto
   255     chans <- liftM (map sendChan) $! sameProtoClientsS proto
   245     processAction $ AnswerClients chans ("ROOM" : "UPD" : oldRoomName : roomInfo (nick newMaster) newRoom')
   256     processAction $ AnswerClients chans ("ROOM" : "UPD" : oldRoomName : roomInfo proto (maybeNick newMaster) newRoom')
   246 
   257 
   247 
   258 
   248 processAction (AddRoom roomName roomPassword) = do
   259 processAction (AddRoom roomName roomPassword) = do
   249     Just clId <- gets clientIndex
   260     Just clId <- gets clientIndex
   250     rnc <- gets roomsClients
   261     rnc <- gets roomsClients
   251     proto <- client's clientProto
   262     proto <- client's clientProto
   252     n <- client's nick
   263     n <- client's nick
   253 
   264 
   254     let rm = newRoom{
   265     let rm = newRoom{
   255             masterID = clId,
   266             masterID = Just clId,
   256             name = roomName,
   267             name = roomName,
   257             password = roomPassword,
   268             password = roomPassword,
   258             roomProto = proto
   269             roomProto = proto
   259             }
   270             }
   260 
   271 
   263     processAction $ MoveToRoom rId
   274     processAction $ MoveToRoom rId
   264 
   275 
   265     chans <- liftM (map sendChan) $! sameProtoClientsS proto
   276     chans <- liftM (map sendChan) $! sameProtoClientsS proto
   266 
   277 
   267     mapM_ processAction [
   278     mapM_ processAction [
   268       AnswerClients chans ("ROOM" : "ADD" : roomInfo n rm{playersIn = 1})
   279       AnswerClients chans ("ROOM" : "ADD" : roomInfo proto n rm{playersIn = 1})
   269         ]
   280         ]
   270 
   281 
   271 
   282 
   272 processAction RemoveRoom = do
   283 processAction RemoveRoom = do
   273     Just clId <- gets clientIndex
   284     Just clId <- gets clientIndex
   290     Just clId <- gets clientIndex
   301     Just clId <- gets clientIndex
   291     proto <- client's clientProto
   302     proto <- client's clientProto
   292     rnc <- gets roomsClients
   303     rnc <- gets roomsClients
   293     ri <- io $ clientRoomM rnc clId
   304     ri <- io $ clientRoomM rnc clId
   294     rm <- io $ room'sM rnc id ri
   305     rm <- io $ room'sM rnc id ri
   295     n <- io $ client'sM rnc nick (masterID rm)
   306     masterCl <- io $ client'sM rnc id `DT.mapM` (masterID rm)
   296     chans <- liftM (map sendChan) $! sameProtoClientsS proto
   307     chans <- liftM (map sendChan) $! sameProtoClientsS proto
   297     processAction $ AnswerClients chans ("ROOM" : "UPD" : name rm : roomInfo n rm)
   308     processAction $ AnswerClients chans ("ROOM" : "UPD" : name rm : roomInfo proto (maybeNick masterCl) rm)
   298 
   309 
   299 
   310 
   300 processAction UnreadyRoomClients = do
   311 processAction UnreadyRoomClients = do
   301     ri <- clientRoomA
   312     ri <- clientRoomA
   302     roomPlayers <- roomClientsS ri
   313     roomPlayers <- roomClientsS ri
   431             when (not b) $
   442             when (not b) $
   432                 if c then
   443                 if c then
   433                     checkerLogin "" False False
   444                     checkerLogin "" False False
   434                     else
   445                     else
   435                     processAction JoinLobby
   446                     processAction JoinLobby
   436         Admin -> do
   447         Admin ->
   437             mapM_ processAction [ModifyClient (\cl -> cl{isAdministrator = True}), JoinLobby]
   448             mapM_ processAction [ModifyClient (\cl -> cl{isAdministrator = True}), JoinLobby]
   438             chan <- client's sendChan
       
   439             processAction $ AnswerClients [chan] ["ADMIN_ACCESS"]
       
   440         ReplayName fn -> processAction $ ShowReplay fn
   449         ReplayName fn -> processAction $ ShowReplay fn
   441     where
   450     where
   442     isBanned = do
   451     isBanned = do
   443         processAction $ CheckBanned False
   452         processAction $ CheckBanned False
   444         liftM B.null $ client's nick
   453         liftM B.null $ client's nick
   454             , ModifyClient (\c -> c{webPassword = p, isAdministrator = a, isContributor = contr})
   463             , ModifyClient (\c -> c{webPassword = p, isAdministrator = a, isContributor = contr})
   455             ]
   464             ]
   456 
   465 
   457 processAction JoinLobby = do
   466 processAction JoinLobby = do
   458     chan <- client's sendChan
   467     chan <- client's sendChan
       
   468     rnc <- gets roomsClients
   459     clientNick <- client's nick
   469     clientNick <- client's nick
   460     isAuthenticated <- liftM (not . B.null) $ client's webPassword
   470     isAuthenticated <- liftM (not . B.null) $ client's webPassword
   461     isAdmin <- client's isAdministrator
   471     isAdmin <- client's isAdministrator
   462     isContr <- client's isContributor
   472     isContr <- client's isContributor
   463     loggedInClients <- liftM (Prelude.filter isVisible) $! allClientsS
   473     loggedInClients <- liftM (Prelude.filter isVisible) $! allClientsS
   464     let (lobbyNicks, clientsChans) = unzip . L.map (nick &&& sendChan) $ loggedInClients
   474     let (lobbyNicks, clientsChans) = unzip . L.map (nick &&& sendChan) $ loggedInClients
   465     let authenticatedNicks = L.map nick . L.filter (not . B.null . webPassword) $ loggedInClients
   475     let authenticatedNicks = L.map nick . L.filter (not . B.null . webPassword) $ loggedInClients
   466     let adminsNicks = L.map nick . L.filter isAdministrator $ loggedInClients
   476     let adminsNicks = L.map nick . L.filter isAdministrator $ loggedInClients
   467     let contrNicks = L.map nick . L.filter isContributor $ loggedInClients
   477     let contrNicks = L.map nick . L.filter isContributor $ loggedInClients
       
   478     inRoomNicks <- io $
       
   479         allClientsM rnc
       
   480         >>= filterM (liftM ((/=) lobbyId) . clientRoomM rnc)
       
   481         >>= mapM (client'sM rnc nick)
   468     let clFlags = B.concat . L.concat $ [["u" | isAuthenticated], ["a" | isAdmin], ["c" | isContr]]
   482     let clFlags = B.concat . L.concat $ [["u" | isAuthenticated], ["a" | isAdmin], ["c" | isContr]]
   469     mapM_ processAction . concat $ [
   483     mapM_ processAction . concat $ [
   470         [AnswerClients clientsChans ["LOBBY:JOINED", clientNick]]
   484         [AnswerClients clientsChans ["LOBBY:JOINED", clientNick]]
   471         , [AnswerClients [chan] ("LOBBY:JOINED" : clientNick : lobbyNicks)]
   485         , [AnswerClients [chan] ("LOBBY:JOINED" : clientNick : lobbyNicks)]
   472         , [AnswerClients [chan] ("CLIENT_FLAGS" : "+u" : authenticatedNicks) | not $ null authenticatedNicks]
   486         , [AnswerClients [chan] ("CLIENT_FLAGS" : "+u" : authenticatedNicks) | not $ null authenticatedNicks]
   473         , [AnswerClients [chan] ("CLIENT_FLAGS" : "+a" : adminsNicks) | not $ null adminsNicks]
   487         , [AnswerClients [chan] ("CLIENT_FLAGS" : "+a" : adminsNicks) | not $ null adminsNicks]
   474         , [AnswerClients [chan] ("CLIENT_FLAGS" : "+c" : contrNicks) | not $ null contrNicks]
   488         , [AnswerClients [chan] ("CLIENT_FLAGS" : "+c" : contrNicks) | not $ null contrNicks]
       
   489         , [AnswerClients [chan] ("CLIENT_FLAGS" : "+i" : inRoomNicks) | not $ null inRoomNicks]
   475         , [AnswerClients (chan : clientsChans) ["CLIENT_FLAGS",  B.concat["+" , clFlags], clientNick] | not $ B.null clFlags]
   490         , [AnswerClients (chan : clientsChans) ["CLIENT_FLAGS",  B.concat["+" , clFlags], clientNick] | not $ B.null clFlags]
   476         , [ModifyClient (\cl -> cl{logonPassed = True, isVisible = True})]
   491         , [ModifyClient (\cl -> cl{logonPassed = True, isVisible = True})]
   477         , [SendServerMessage]
   492         , [SendServerMessage]
   478         ]
   493         ]
   479 
   494 
   676 
   691 
   677 
   692 
   678 processAction CheckRecord = do
   693 processAction CheckRecord = do
   679     p <- client's clientProto
   694     p <- client's clientProto
   680     c <- client's sendChan
   695     c <- client's sendChan
   681     (cinfo, l) <- io $ loadReplay (fromIntegral p)
   696     ri <- clientRoomA
       
   697     rnc <- gets roomsClients
       
   698 
       
   699     blackList <- liftM (map (recordFileName . fromJust . checkInfo) . filter (isJust . checkInfo)) allClientsS
       
   700 
       
   701     readyCheckersIds <- io $ do
       
   702         allci <- allClientsM rnc
       
   703         filterM (client'sM rnc (isJust . checkInfo)) allci
       
   704 
       
   705     (cinfo, l) <- io $ loadReplay (fromIntegral p) blackList
   682     when (not . null $ l) $
   706     when (not . null $ l) $
   683         mapM_ processAction [
   707         mapM_ processAction [
   684             AnswerClients [c] ("REPLAY" : l)
   708             AnswerClients [c] ("REPLAY" : l)
   685             , ModifyClient $ \c -> c{checkInfo = cinfo, isReady = False}
   709             , ModifyClient $ \c -> c{checkInfo = cinfo, isReady = False}
   686             ]
   710             ]
   691     io $ moveFailedRecord fileName
   715     io $ moveFailedRecord fileName
   692 
   716 
   693 
   717 
   694 processAction (CheckSuccess info) = do
   718 processAction (CheckSuccess info) = do
   695     Just (CheckInfo fileName teams) <- client's checkInfo
   719     Just (CheckInfo fileName teams) <- client's checkInfo
       
   720     p <- client's clientProto
   696     si <- gets serverInfo
   721     si <- gets serverInfo
   697     io $ writeChan (dbQueries si) $ StoreAchievements (B.pack fileName) (map toPair teams) info
   722     io $ writeChan (dbQueries si) $ StoreAchievements p (B.pack fileName) (map toPair teams) info
   698     io $ moveCheckedRecord fileName
   723     io $ moveCheckedRecord fileName
   699     where
   724     where
   700         toPair t = (teamname t, teamowner t)
   725         toPair t = (teamname t, teamowner t)
   701 
   726 
   702 processAction (QueryReplay name) = do
   727 processAction (QueryReplay rname) = do
   703     (Just ci) <- gets clientIndex
   728     (Just ci) <- gets clientIndex
   704     si <- gets serverInfo
   729     si <- gets serverInfo
   705     uid <- client's clUID
   730     uid <- client's clUID
   706     io $ writeChan (dbQueries si) $ GetReplayName ci (hashUnique uid) name
   731     io $ writeChan (dbQueries si) $ GetReplayName ci (hashUnique uid) rname
   707 
   732 
   708 #else
   733 #else
   709 processAction SaveReplay = return ()
   734 processAction SaveReplay = return ()
   710 processAction CheckRecord = return ()
   735 processAction CheckRecord = return ()
   711 processAction (CheckFailed _) = return ()
   736 processAction (CheckFailed _) = return ()
   712 processAction (CheckSuccess _) = return ()
   737 processAction (CheckSuccess _) = return ()
   713 processAction (QueryReplay _) = return ()
   738 processAction (QueryReplay _) = return ()
   714 #endif
   739 #endif
   715 
   740 
   716 processAction (ShowReplay name) = do
   741 processAction (ShowReplay rname) = do
   717     c <- client's sendChan
   742     c <- client's sendChan
   718     cl <- client's id
   743     cl <- client's id
   719 
   744 
   720     let fileName = B.concat ["checked/", if B.isPrefixOf "replays/" name then B.drop 8 name else name]
   745     let fileName = B.concat ["checked/", if B.isPrefixOf "replays/" rname then B.drop 8 rname else rname]
   721 
   746 
   722     checkInfo <- liftIO $ E.handle (\(e :: SomeException) ->
   747     cInfo <- liftIO $ E.handle (\(e :: SomeException) ->
   723                     warningM "REPLAYS" (B.unpack $ B.concat ["Problems reading ", fileName, ": ", B.pack $ show e]) >> return Nothing) $ do
   748                     warningM "REPLAYS" (B.unpack $ B.concat ["Problems reading ", fileName, ": ", B.pack $ show e]) >> return Nothing) $ do
   724             (t, p1, p2, msgs) <- liftM read $ readFile (B.unpack fileName)
   749             (t, p1, p2, msgs) <- liftM read $ readFile (B.unpack fileName)
   725             return $ Just (t, Map.fromList p1, Map.fromList p2, reverse msgs)
   750             return $ Just (t, Map.fromList p1, Map.fromList p2, reverse msgs)
   726 
   751 
   727     let (teams, params1, params2, roundMsgs) = fromJust checkInfo
   752     let (teams', params1, params2, roundMsgs') = fromJust cInfo
   728 
   753 
   729     when (isJust checkInfo) $ do
   754     when (isJust cInfo) $ do
   730         mapM_ processAction $ concat [
   755         mapM_ processAction $ concat [
   731             [AnswerClients [c] ["JOINED", nick cl]]
   756             [AnswerClients [c] ["JOINED", nick cl]]
   732             , answerFullConfigParams cl params1 params2
   757             , answerFullConfigParams cl params1 params2
   733             , answerAllTeams cl teams
   758             , answerAllTeams cl teams'
   734             , [AnswerClients [c]  ["RUN_GAME"]]
   759             , [AnswerClients [c]  ["RUN_GAME"]]
   735             , [AnswerClients [c] $ "EM" : roundMsgs]
   760             , [AnswerClients [c] $ "EM" : roundMsgs']
   736             , [AnswerClients [c] ["KICKED"]]
   761             , [AnswerClients [c] ["KICKED"]]
   737             ]
   762             ]