gameServer/Actions.hs
branchwebgl
changeset 9521 8054d9d775fd
parent 9197 e4e366013e9a
parent 9448 04e0acfa7c2c
child 9950 2759212a27de
equal deleted inserted replaced
9282:92af50454cf2 9521:8054d9d775fd
    15 import Control.Monad.State.Strict
    15 import Control.Monad.State.Strict
    16 import qualified Data.ByteString.Char8 as B
    16 import qualified Data.ByteString.Char8 as B
    17 import Control.DeepSeq
    17 import Control.DeepSeq
    18 import Data.Unique
    18 import Data.Unique
    19 import Control.Arrow
    19 import Control.Arrow
    20 import Control.Exception
    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 -----------------------------
    24 -----------------------------
    25 #if defined(OFFICIAL_SERVER)
    25 #if defined(OFFICIAL_SERVER)
   344     mapM_ processAction [
   344     mapM_ processAction [
   345         AnswerClients chans ["EM", rmTeamMsg],
   345         AnswerClients chans ["EM", rmTeamMsg],
   346         ModifyRoom (\r -> r{
   346         ModifyRoom (\r -> r{
   347                 gameInfo = liftM (\g -> g{
   347                 gameInfo = liftM (\g -> g{
   348                     teamsInGameNumber = teamsInGameNumber g - 1
   348                     teamsInGameNumber = teamsInGameNumber g - 1
   349                     , roundMsgs = rmTeamMsg : roundMsgs g
   349                     , roundMsgs = (if isJust $ lastFilteredTimedMsg g then (:) (fromJust $ lastFilteredTimedMsg g) else id) 
       
   350                       $ rmTeamMsg : roundMsgs g
   350                 }) $ gameInfo r
   351                 }) $ gameInfo r
   351             })
   352             })
   352         ]
   353         ]
   353 
   354 
   354     rnc <- gets roomsClients
   355     rnc <- gets roomsClients
   418     return ()
   419     return ()
   419 
   420 
   420 
   421 
   421 processAction (ProcessAccountInfo info) = do
   422 processAction (ProcessAccountInfo info) = do
   422     case info of
   423     case info of
   423         HasAccount passwd isAdmin -> do
   424         HasAccount passwd isAdmin isContr -> do
   424             b <- isBanned
   425             b <- isBanned
   425             c <- client's isChecker
   426             c <- client's isChecker
   426             when (not b) $ (if c then checkerLogin else playerLogin) passwd isAdmin
   427             when (not b) $ (if c then checkerLogin else playerLogin) passwd isAdmin isContr
   427         Guest -> do
   428         Guest -> do
   428             b <- isBanned
   429             b <- isBanned
   429             c <- client's isChecker
   430             c <- client's isChecker
   430             when (not b) $
   431             when (not b) $
   431                 if c then
   432                 if c then
   432                     checkerLogin "" False
   433                     checkerLogin "" False False
   433                     else
   434                     else
   434                     processAction JoinLobby
   435                     processAction JoinLobby
   435         Admin -> do
   436         Admin -> do
   436             mapM_ processAction [ModifyClient (\cl -> cl{isAdministrator = True}), JoinLobby]
   437             mapM_ processAction [ModifyClient (\cl -> cl{isAdministrator = True}), JoinLobby]
   437             chan <- client's sendChan
   438             chan <- client's sendChan
   438             processAction $ AnswerClients [chan] ["ADMIN_ACCESS"]
   439             processAction $ AnswerClients [chan] ["ADMIN_ACCESS"]
       
   440         ReplayName fn -> processAction $ ShowReplay fn
   439     where
   441     where
   440     isBanned = do
   442     isBanned = do
   441         processAction $ CheckBanned False
   443         processAction $ CheckBanned False
   442         liftM B.null $ client's nick
   444         liftM B.null $ client's nick
   443     checkerLogin _ False = processAction $ ByeClient $ loc "No checker rights"
   445     checkerLogin _ False _ = processAction $ ByeClient $ loc "No checker rights"
   444     checkerLogin p True = do
   446     checkerLogin p True _ = do
   445         wp <- client's webPassword
   447         wp <- client's webPassword
   446         processAction $
   448         processAction $
   447             if wp == p then ModifyClient $ \c -> c{logonPassed = True} else ByeClient $ loc "Authentication failed"
   449             if wp == p then ModifyClient $ \c -> c{logonPassed = True} else ByeClient $ loc "Authentication failed"
   448     playerLogin p a = do
   450     playerLogin p a contr = do
   449         chan <- client's sendChan
   451         chan <- client's sendChan
   450         mapM_ processAction [AnswerClients [chan] ["ASKPASSWORD"], ModifyClient (\c -> c{webPassword = p, isAdministrator = a})]
   452         mapM_ processAction [
       
   453             AnswerClients [chan] ["ASKPASSWORD"]
       
   454             , ModifyClient (\c -> c{webPassword = p, isAdministrator = a, isContributor = contr})
       
   455             ]
   451 
   456 
   452 processAction JoinLobby = do
   457 processAction JoinLobby = do
   453     chan <- client's sendChan
   458     chan <- client's sendChan
   454     clientNick <- client's nick
   459     clientNick <- client's nick
   455     isAuthenticated <- liftM (not . B.null) $ client's webPassword
   460     isAuthenticated <- liftM (not . B.null) $ client's webPassword
   456     isAdmin <- client's isAdministrator
   461     isAdmin <- client's isAdministrator
       
   462     isContr <- client's isContributor
   457     loggedInClients <- liftM (Prelude.filter isVisible) $! allClientsS
   463     loggedInClients <- liftM (Prelude.filter isVisible) $! allClientsS
   458     let (lobbyNicks, clientsChans) = unzip . L.map (nick &&& sendChan) $ loggedInClients
   464     let (lobbyNicks, clientsChans) = unzip . L.map (nick &&& sendChan) $ loggedInClients
   459     let authenticatedNicks = L.map nick . L.filter (not . B.null . webPassword) $ loggedInClients
   465     let authenticatedNicks = L.map nick . L.filter (not . B.null . webPassword) $ loggedInClients
   460     let adminsNicks = L.map nick . L.filter isAdministrator $ loggedInClients
   466     let adminsNicks = L.map nick . L.filter isAdministrator $ loggedInClients
   461     let clFlags = B.concat . L.concat $ [["u" | isAuthenticated], ["a" | isAdmin]]
   467     let contrNicks = L.map nick . L.filter isContributor $ loggedInClients
       
   468     let clFlags = B.concat . L.concat $ [["u" | isAuthenticated], ["a" | isAdmin], ["c" | isContr]]
   462     mapM_ processAction . concat $ [
   469     mapM_ processAction . concat $ [
   463         [AnswerClients clientsChans ["LOBBY:JOINED", clientNick]]
   470         [AnswerClients clientsChans ["LOBBY:JOINED", clientNick]]
   464         , [AnswerClients [chan] ("LOBBY:JOINED" : clientNick : lobbyNicks)]
   471         , [AnswerClients [chan] ("LOBBY:JOINED" : clientNick : lobbyNicks)]
   465         , [AnswerClients [chan] ("CLIENT_FLAGS" : "+u" : authenticatedNicks) | not $ null authenticatedNicks]
   472         , [AnswerClients [chan] ("CLIENT_FLAGS" : "+u" : authenticatedNicks) | not $ null authenticatedNicks]
   466         , [AnswerClients [chan] ("CLIENT_FLAGS" : "+a" : adminsNicks) | not $ null adminsNicks]
   473         , [AnswerClients [chan] ("CLIENT_FLAGS" : "+a" : adminsNicks) | not $ null adminsNicks]
       
   474         , [AnswerClients [chan] ("CLIENT_FLAGS" : "+c" : contrNicks) | not $ null contrNicks]
   467         , [AnswerClients (chan : clientsChans) ["CLIENT_FLAGS",  B.concat["+" , clFlags], clientNick] | not $ B.null clFlags]
   475         , [AnswerClients (chan : clientsChans) ["CLIENT_FLAGS",  B.concat["+" , clFlags], clientNick] | not $ B.null clFlags]
   468         , [ModifyClient (\cl -> cl{logonPassed = True, isVisible = True})]
   476         , [ModifyClient (\cl -> cl{logonPassed = True, isVisible = True})]
   469         , [SendServerMessage]
   477         , [SendServerMessage]
   470         ]
   478         ]
   471 
   479 
   607         rnc <- gets roomsClients
   615         rnc <- gets roomsClients
   608         (roomsNum, clientsNum) <- io $ withRoomsAndClients rnc st
   616         (roomsNum, clientsNum) <- io $ withRoomsAndClients rnc st
   609         io $ writeChan (dbQueries si) $ SendStats clientsNum (roomsNum - 1)
   617         io $ writeChan (dbQueries si) $ SendStats clientsNum (roomsNum - 1)
   610     where
   618     where
   611           st irnc = (length $ allRooms irnc, length $ allClients irnc)
   619           st irnc = (length $ allRooms irnc, length $ allClients irnc)
       
   620 
   612 
   621 
   613 processAction RestartServer = do
   622 processAction RestartServer = do
   614     sp <- gets (shutdownPending . serverInfo)
   623     sp <- gets (shutdownPending . serverInfo)
   615     when (not sp) $ do
   624     when (not sp) $ do
   616         sock <- gets (fromJust . serverSocket . serverInfo)
   625         sock <- gets (fromJust . serverSocket . serverInfo)
   620             sClose sock
   629             sClose sock
   621             noticeM "Core" "Spawning new server"
   630             noticeM "Core" "Spawning new server"
   622             _ <- createProcess (proc "./hedgewars-server" args)
   631             _ <- createProcess (proc "./hedgewars-server" args)
   623             return ()
   632             return ()
   624         processAction $ ModifyServerInfo (\s -> s{shutdownPending = True})
   633         processAction $ ModifyServerInfo (\s -> s{shutdownPending = True})
       
   634 
   625 
   635 
   626 processAction Stats = do
   636 processAction Stats = do
   627     cls <- allClientsS
   637     cls <- allClientsS
   628     rms <- allRoomsS
   638     rms <- allRoomsS
   629     let clientsMap = Map.fromListWith (+) . map (\c -> (clientProto c, 1 :: Int)) $ cls
   639     let clientsMap = Map.fromListWith (+) . map (\c -> (clientProto c, 1 :: Int)) $ cls
   648 #if defined(OFFICIAL_SERVER)
   658 #if defined(OFFICIAL_SERVER)
   649 processAction SaveReplay = do
   659 processAction SaveReplay = do
   650     ri <- clientRoomA
   660     ri <- clientRoomA
   651     rnc <- gets roomsClients
   661     rnc <- gets roomsClients
   652 
   662 
   653     io $ do
   663     readyCheckersIds <- io $ do
   654         r <- room'sM rnc id ri
   664         r <- room'sM rnc id ri
   655         saveReplay r
   665         saveReplay r
       
   666         allci <- allClientsM rnc
       
   667         filterM (client'sM rnc isReadyChecker) allci
       
   668 
       
   669     when (not $ null readyCheckersIds) $ do
       
   670         oldci <- gets clientIndex
       
   671         withStateT (\s -> s{clientIndex = Just $ head readyCheckersIds})
       
   672             $ processAction CheckRecord
       
   673         modify (\s -> s{clientIndex = oldci})
       
   674     where
       
   675         isReadyChecker cl = isChecker cl && isReady cl
   656 
   676 
   657 
   677 
   658 processAction CheckRecord = do
   678 processAction CheckRecord = do
   659     p <- client's clientProto
   679     p <- client's clientProto
   660     c <- client's sendChan
   680     c <- client's sendChan
   661     (cinfo, l) <- io $ loadReplay (fromIntegral p)
   681     (cinfo, l) <- io $ loadReplay (fromIntegral p)
   662     when (not . null $ l) $
   682     when (not . null $ l) $
   663         mapM_ processAction [
   683         mapM_ processAction [
   664             AnswerClients [c] ("REPLAY" : l)
   684             AnswerClients [c] ("REPLAY" : l)
   665             , ModifyClient $ \c -> c{checkInfo = cinfo}
   685             , ModifyClient $ \c -> c{checkInfo = cinfo, isReady = False}
   666             ]
   686             ]
       
   687 
   667 
   688 
   668 processAction (CheckFailed msg) = do
   689 processAction (CheckFailed msg) = do
   669     Just (CheckInfo fileName _) <- client's checkInfo
   690     Just (CheckInfo fileName _) <- client's checkInfo
   670     io $ moveFailedRecord fileName
   691     io $ moveFailedRecord fileName
   671 
   692 
       
   693 
   672 processAction (CheckSuccess info) = do
   694 processAction (CheckSuccess info) = do
   673     Just (CheckInfo fileName _) <- client's checkInfo
   695     Just (CheckInfo fileName teams) <- client's checkInfo
       
   696     si <- gets serverInfo
       
   697     io $ writeChan (dbQueries si) $ StoreAchievements (B.pack fileName) (map toPair teams) info
   674     io $ moveCheckedRecord fileName
   698     io $ moveCheckedRecord fileName
       
   699     where
       
   700         toPair t = (teamname t, teamowner t)
       
   701 
       
   702 processAction (QueryReplay name) = do
       
   703     (Just ci) <- gets clientIndex
       
   704     si <- gets serverInfo
       
   705     uid <- client's clUID
       
   706     io $ writeChan (dbQueries si) $ GetReplayName ci (hashUnique uid) name
   675 
   707 
   676 #else
   708 #else
   677 processAction SaveReplay = return ()
   709 processAction SaveReplay = return ()
   678 processAction CheckRecord = return ()
   710 processAction CheckRecord = return ()
   679 processAction (CheckFailed _) = return ()
   711 processAction (CheckFailed _) = return ()
   680 processAction (CheckSuccess _) = return ()
   712 processAction (CheckSuccess _) = return ()
       
   713 processAction (QueryReplay _) = return ()
   681 #endif
   714 #endif
       
   715 
       
   716 processAction (ShowReplay name) = do
       
   717     c <- client's sendChan
       
   718     cl <- client's id
       
   719 
       
   720     let fileName = B.concat ["checked/", if B.isPrefixOf "replays/" name then B.drop 8 name else name]
       
   721 
       
   722     checkInfo <- liftIO $ E.handle (\(e :: SomeException) ->
       
   723                     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)
       
   725             return $ Just (t, Map.fromList p1, Map.fromList p2, reverse msgs)
       
   726 
       
   727     let (teams, params1, params2, roundMsgs) = fromJust checkInfo
       
   728 
       
   729     when (isJust checkInfo) $ do
       
   730         mapM_ processAction $ concat [
       
   731             [AnswerClients [c] ["JOINED", nick cl]]
       
   732             , answerFullConfigParams cl params1 params2
       
   733             , answerAllTeams cl teams
       
   734             , [AnswerClients [c]  ["RUN_GAME"]]
       
   735             , [AnswerClients [c] $ "EM" : roundMsgs]
       
   736             , [AnswerClients [c] ["KICKED"]]
       
   737             ]