Merge
authorMitchell Kember <mk12360@gmail.com>
Wed, 05 Dec 2012 17:25:48 -0500
changeset 8249 9ffb156902f6
parent 8234 d2207f22c5f2 (current diff)
parent 8247 d7cf4a9ce685 (diff)
child 8254 eeaf3e1773c6
Merge
--- a/doc/protocol.txt	Wed Dec 05 13:45:18 2012 -0500
+++ b/doc/protocol.txt	Wed Dec 05 17:25:48 2012 -0500
@@ -1,34 +1,35 @@
-	'?'             ping?
-	'!'             pong!
-	'l','L'         срабатывание команд     -left, +left
-	'r','R'                                 -right, +right
-	'u','U'                                 -up, +up
-	'd','D'                                 -down, +down
-	'z', 'Z'                                -precise, +precise
-	'N'             срабатывание команды /nextturn
-	'S'                                  /switch
-	's' + <текст>   /say
-	'+'             пустой пакет для постоянности лага
-	'1'..'5'        /timer 1..5
-	chr(128+№)     /slot №
-	'w'             /setweap
-	'p'             /put
-	'j'             /ljump
-	'J'             /hjump
-	'E' + <текст>   сообщение об ошибке
-	','             /skip
-	'K'             вывести сообщение из KB
-	'Q'             выход через команду /quit
-	'q'             выход по причине окончания игры
-	't' + №        /taunt №
-	'F' + <team>    команда team вылетела в сетевой игре
+    '?'             ping?
+    '!'             pong!
+    'l','L'         срабатывание команд     -left, +left
+    'r','R'                                 -right, +right
+    'u','U'                                 -up, +up
+    'd','D'                                 -down, +down
+    'z', 'Z'                                -precise, +precise
+    'N'             срабатывание команды /nextturn
+    'S'                                  /switch
+    's' + <текст>   /say
+    '+'             пустой пакет для постоянности лага
+    '1'..'5'        /timer 1..5
+    chr(128+№)     /slot №
+    'w'             /setweap
+    'p'             /put
+    'j'             /ljump
+    'J'             /hjump
+    'E' + <текст>   сообщение об ошибке
+    ','             /skip
+    't' + №         /taunt №
 
 фронтенд клиенту:
-	'e' + <команда> выполнить "/<команда>"
-	'T' + {L,N,D}   тип игры (локальная, сетевая, просмотр демо)
-	'W' + <текст>   сообщение о нефатальной ошибке
+    'e' + <команда> выполнить "/<команда>"
+    'T' + {L,N,D}   тип игры (локальная, сетевая, просмотр демо)
+    'W' + <текст>   сообщение о нефатальной ошибке
+    'F' + <team>    команда team вылетела в сетевой игре
+    'o'             stop syncing, game over!
 
 Клиент фронтенду:
-	'C'             запрос текущего конфига игры
-	'q'             выход по причине окончания демки
-	'i'             статистика
+    'C'             запрос текущего конфига игры
+    'q'             выход по причине окончания демки
+    'i'             статистика
+    'K'             вывести сообщение из KB
+    'Q'             выход через команду /quit
+    'q'             выход по причине окончания игры
--- a/gameServer/Actions.hs	Wed Dec 05 13:45:18 2012 -0500
+++ b/gameServer/Actions.hs	Wed Dec 05 17:25:48 2012 -0500
@@ -55,7 +55,7 @@
     | BanNick B.ByteString NominalDiffTime B.ByteString
     | BanList
     | Unban B.ByteString
-    | ChangeMaster
+    | ChangeMaster (Maybe ClientIndex)
     | RemoveClientTeams ClientIndex
     | ModifyClient (ClientInfo -> ClientInfo)
     | ModifyClient2 ClientIndex (ClientInfo -> ClientInfo)
@@ -74,7 +74,7 @@
     | RestartServer
     | AddNick2Bans B.ByteString B.ByteString UTCTime
     | AddIP2Bans B.ByteString B.ByteString UTCTime
-    | CheckBanned
+    | CheckBanned Bool
     | SaveReplay
 
 
@@ -235,7 +235,7 @@
 
     if master then
         if playersNum > 1 then
-            mapM_ processAction [ChangeMaster, NoticeMessage AdminLeft, RemoveClientTeams ci, AnswerClients chans ["LEFT", clNick, msg]]
+            mapM_ processAction [ChangeMaster Nothing, NoticeMessage AdminLeft, RemoveClientTeams ci, AnswerClients chans ["LEFT", clNick, msg]]
             else
             processAction RemoveRoom
         else
@@ -251,26 +251,27 @@
         moveClientToLobby rnc ci
 
 
-processAction ChangeMaster = do
+processAction (ChangeMaster delegateId)= do
     (Just ci) <- gets clientIndex
     proto <- client's clientProto
     ri <- clientRoomA
     rnc <- gets roomsClients
-    newMasterId <- liftM (last . filter (/= ci)) . io $ roomClientsIndicesM rnc ri
+    newMasterId <- liftM (\ids -> fromMaybe (last . filter (/= ci) $ ids) delegateId) . io $ roomClientsIndicesM rnc ri
     newMaster <- io $ client'sM rnc id newMasterId
     oldRoomName <- io $ room'sM rnc name ri
     oldMaster <- client's nick
+    kicked <- client's isKickedFromServer
     thisRoomChans <- liftM (map sendChan) $ roomClientsS ri
-    let newRoomName = if proto < 42 then nick newMaster else oldRoomName
+    let newRoomName = if (proto < 42) || kicked then nick newMaster else oldRoomName
     mapM_ processAction [
         ModifyRoom (\r -> r{masterID = newMasterId
                 , name = newRoomName
                 , isRestrictedJoins = False
                 , isRestrictedTeams = False
+                , isRegisteredOnly = False
                 , readyPlayers = if isReady newMaster then readyPlayers r else readyPlayers r + 1})
         , ModifyClient2 newMasterId (\c -> c{isMaster = True, isReady = True})
         , AnswerClients [sendChan newMaster] ["ROOM_CONTROL_ACCESS", "1"]
-        , AnswerClients thisRoomChans ["WARNING", "New room admin is " `B.append` nick newMaster]
         , AnswerClients thisRoomChans ["CLIENT_FLAGS", "-h", oldMaster]
         , AnswerClients thisRoomChans ["CLIENT_FLAGS", "+hr", nick newMaster]
         ]
@@ -362,6 +363,7 @@
             )
         : UnreadyRoomClients
         : SendUpdateOnThisRoom
+        : AnswerClients thisRoomChans ["ROUND_FINISHED"]
         : answerRemovedTeams
 
 
@@ -423,17 +425,14 @@
     haveSameNick <- liftM (not . null . tail . filter (\c -> caseInsensitiveCompare (nick c) n)) allClientsS
     if haveSameNick then
         if p < 38 then
-            mapM_ processAction [ByeClient "Nickname is already in use", removeNick]
+            processAction $ ByeClient "Nickname is already in use"
             else
-            mapM_ processAction [NoticeMessage NickAlreadyInUse, removeNick]
+            processAction $ NoticeMessage NickAlreadyInUse
         else
         do
         db <- gets (dbQueries . serverInfo)
         io $ writeChan db $ CheckAccount ci (hashUnique uid) n h
         return ()
-   where
-       removeNick = ModifyClient (\c -> c{nick = ""})
-
 
 processAction ClearAccountsCache = do
     dbq <- gets (dbQueries . serverInfo)
@@ -458,7 +457,7 @@
             processAction $ AnswerClients [chan] ["ADMIN_ACCESS"]
     where
     isBanned = do
-        processAction CheckBanned
+        processAction $ CheckBanned False
         liftM B.null $ client's nick
 
 
@@ -488,8 +487,9 @@
     clHost <- client's host
     currentTime <- io getCurrentTime
     mapM_ processAction [
-        AddIP2Bans clHost "60 seconds cooldown after kick" (addUTCTime 60 currentTime),
-        ByeClient "Kicked"
+        AddIP2Bans clHost "60 seconds cooldown after kick" (addUTCTime 60 currentTime)
+        , ModifyClient (\c -> c{isKickedFromServer = True})
+        , ByeClient "Kicked"
         ]
 
 
@@ -503,12 +503,14 @@
         , KickClient banId
         ]
 
+
 processAction (BanIP ip seconds reason) = do
     currentTime <- io getCurrentTime
     let msg = B.concat ["Ban for ", B.pack . show $ seconds, " (", reason, ")"]
     processAction $
         AddIP2Bans ip msg (addUTCTime seconds currentTime)
 
+
 processAction (BanNick n seconds reason) = do
     currentTime <- io getCurrentTime
     let msg = 
@@ -519,6 +521,7 @@
     processAction $
         AddNick2Bans n msg (addUTCTime seconds currentTime)
 
+
 processAction BanList = do
     time <- io $ getCurrentTime
     ch <- client's sendChan
@@ -529,12 +532,14 @@
         ban2Str time (BanByIP b r t) = ["I", b, r, B.pack . show $ t `diffUTCTime` time]
         ban2Str time (BanByNick b r t) = ["N", b, r, B.pack . show $ t `diffUTCTime` time]
 
+
 processAction (Unban entry) = do
     processAction $ ModifyServerInfo (\s -> s{bans = filter (not . f) $ bans s})
     where
         f (BanByIP bip _ _) = bip == entry
         f (BanByNick bn _ _) = bn == entry
 
+
 processAction (KickRoomClient kickId) = do
     modify (\s -> s{clientIndex = Just kickId})
     ch <- client's sendChan
@@ -556,7 +561,7 @@
     mapM_ processAction
         [
             AnswerClients [sendChan cl] ["CONNECTED", "Hedgewars server http://www.hedgewars.org/", serverVersion]
-            , CheckBanned
+            , CheckBanned True
             , AddIP2Bans (host cl) "Reconnected too fast" (addUTCTime 10 $ connectTime cl)
         ]
 
@@ -570,21 +575,22 @@
     when (not $ ci `Set.member` rc)
         $ processAction $ ModifyServerInfo (\s -> s{bans = BanByIP ip reason expiring : bans s})
 
-processAction CheckBanned = do
+processAction (CheckBanned byIP) = do
     clTime <- client's connectTime
     clNick <- client's nick
     clHost <- client's host
     si <- gets serverInfo
     let validBans = filter (checkNotExpired clTime) $ bans si
-    let ban = L.find (checkBan clHost clNick) $ validBans
+    let ban = L.find (checkBan byIP clHost clNick) $ validBans
     mapM_ processAction $
         ModifyServerInfo (\s -> s{bans = validBans})
         : [ByeClient (getBanReason $ fromJust ban) | isJust ban]
     where
         checkNotExpired testTime (BanByIP _ _ time) = testTime `diffUTCTime` time <= 0
         checkNotExpired testTime (BanByNick _ _ time) = testTime `diffUTCTime` time <= 0
-        checkBan ip _ (BanByIP bip _ _) = bip `B.isPrefixOf` ip
-        checkBan _ n (BanByNick bn _ _) = caseInsensitiveCompare bn n
+        checkBan True ip _ (BanByIP bip _ _) = bip `B.isPrefixOf` ip
+        checkBan False _ n (BanByNick bn _ _) = caseInsensitiveCompare bn n
+        checkBan _ _ _ _ = False
         getBanReason (BanByIP _ msg _) = msg
         getBanReason (BanByNick _ msg _) = msg
 
--- a/gameServer/CoreTypes.hs	Wed Dec 05 13:45:18 2012 -0500
+++ b/gameServer/CoreTypes.hs	Wed Dec 05 17:25:48 2012 -0500
@@ -36,6 +36,7 @@
         isReady :: !Bool,
         isInGame :: Bool,
         isAdministrator :: Bool,
+        isKickedFromServer :: Bool,
         clientClan :: Maybe B.ByteString,
         teamsInGame :: Word
     }
@@ -100,6 +101,7 @@
         readyPlayers :: !Int,
         isRestrictedJoins :: Bool,
         isRestrictedTeams :: Bool,
+        isRegisteredOnly :: Bool,
         roomBansList :: ![B.ByteString],
         mapParams :: Map.Map B.ByteString B.ByteString,
         params :: Map.Map B.ByteString [B.ByteString]
@@ -118,6 +120,7 @@
         0
         False
         False
+        False
         []
         (
             Map.fromList $ Prelude.zipWith (,)
--- a/gameServer/HWProtoInRoomState.hs	Wed Dec 05 13:45:18 2012 -0500
+++ b/gameServer/HWProtoInRoomState.hs	Wed Dec 05 17:25:48 2012 -0500
@@ -264,6 +264,14 @@
             [ModifyRoom (\r -> r{isRestrictedTeams = not $ isRestrictedTeams r})]
 
 
+handleCmd_inRoom ["TOGGLE_REGISTERED_ONLY"] = do
+    cl <- thisClient
+    return $
+        if not $ isMaster cl then
+            [ProtocolError "Not room master"]
+        else
+            [ModifyRoom (\r -> r{isRegisteredOnly = not $ isRegisteredOnly r})]
+
 handleCmd_inRoom ["ROOM_NAME", newName] = do
     cl <- thisClient
     rs <- allRoomInfos
@@ -293,6 +301,16 @@
         [KickRoomClient kickId | master && isJust maybeClientId && (kickId /= thisClientId) && sameRoom]
 
 
+handleCmd_inRoom ["DELEGATE", newAdmin] = do
+    (thisClientId, rnc) <- ask
+    maybeClientId <- clientByNick newAdmin
+    master <- liftM isMaster thisClient
+    let newAdminId = fromJust maybeClientId
+    let sameRoom = clientRoom rnc thisClientId == clientRoom rnc newAdminId
+    return
+        [ChangeMaster (Just newAdminId) | master && isJust maybeClientId && (newAdminId /= thisClientId) && sameRoom]
+
+
 handleCmd_inRoom ["TEAMCHAT", msg] = do
     cl <- thisClient
     chans <- roomSameClanChans
--- a/gameServer/HWProtoLobbyState.hs	Wed Dec 05 13:45:18 2012 -0500
+++ b/gameServer/HWProtoLobbyState.hs	Wed Dec 05 17:25:48 2012 -0500
@@ -80,6 +80,8 @@
             [Warning "No such room"]
             else if isRestrictedJoins jRoom then
             [Warning "Joining restricted"]
+            else if isRegisteredOnly jRoom then
+            [Warning "Registered users only"]
             else if isBanned then
             [Warning "You are banned in this room"]
             else if roomPassword /= password jRoom then
@@ -89,20 +91,21 @@
                 MoveToRoom jRI
                 , AnswerClients [sendChan cl] $ "JOINED" : nicks
                 , AnswerClients chans ["CLIENT_FLAGS", "-r", nick cl]
-                , AnswerClients [sendChan cl] $ ["WARNING", "Room admin is " `B.append` ownerNick]
                 , AnswerClients [sendChan cl] $ ["CLIENT_FLAGS", "+h", ownerNick]
             ]
-            ++ map (readynessMessage cl) jRoomClients
+            ++ (if clientProto cl < 38 then map (readynessMessage cl) jRoomClients else [sendStateFlags cl jRoomClients])
             ++ answerFullConfig cl (mapParams jRoom) (params jRoom)
             ++ answerTeams cl jRoom
-            ++ watchRound cl jRoom
+            ++ watchRound cl jRoom chans
 
         where
-        readynessMessage cl c = AnswerClients [sendChan cl] $
-                if clientProto cl < 38 then
-                    [if isReady c then "READY" else "NOT_READY", nick c]
-                    else
-                    ["CLIENT_FLAGS", if isReady c then "+r" else "-r", nick c]
+        readynessMessage cl c = AnswerClients [sendChan cl] [if isReady c then "READY" else "NOT_READY", nick c]
+        sendStateFlags cl clients = AnswerClients [sendChan cl] . concat . intersperse [""] . filter (not . null) . concat $
+                [f "+r" ready, f "-r" unready, f "+g" ingame, f "-g" inroomlobby]
+            where
+            (ready, unready) = partition isReady clients
+            (ingame, inroomlobby) = partition isInGame clients
+            f fl lst = ["CLIENT_FLAGS" : fl : map nick lst | not $ null lst]
 
         toAnswer cl (paramName, paramStrs) = AnswerClients [sendChan cl] $ "CFG" : paramName : paramStrs
 
@@ -119,11 +122,13 @@
 
         answerTeams cl jRoom = let f = if isJust $ gameInfo jRoom then teamsAtStart . fromJust . gameInfo else teams in answerAllTeams cl $ f jRoom
 
-        watchRound cl jRoom = if isNothing $ gameInfo jRoom then
+        watchRound cl jRoom chans = if isNothing $ gameInfo jRoom then
                     []
                 else
-                    [AnswerClients [sendChan cl]  ["RUN_GAME"],
-                    AnswerClients [sendChan cl] $ "EM" : toEngineMsg "e$spectate 1" : Foldable.toList (roundMsgs . fromJust . gameInfo $ jRoom)]
+                    [AnswerClients [sendChan cl]  ["RUN_GAME"]
+                    , AnswerClients chans ["CLIENT_FLAGS", "+g", nick cl]
+                    , ModifyClient (\c -> c{isInGame = True})
+                    , AnswerClients [sendChan cl] $ "EM" : toEngineMsg "e$spectate 1" : Foldable.toList (roundMsgs . fromJust . gameInfo $ jRoom)]
 
 
 handleCmd_lobby ["JOIN_ROOM", roomName] =
--- a/gameServer/NetRoutines.hs	Wed Dec 05 13:45:18 2012 -0500
+++ b/gameServer/NetRoutines.hs	Wed Dec 05 17:25:48 2012 -0500
@@ -41,6 +41,7 @@
                     False
                     False
                     False
+                    False
                     Nothing
                     0
                     )
--- a/hedgewars/uIO.pas	Wed Dec 05 13:45:18 2012 -0500
+++ b/hedgewars/uIO.pas	Wed Dec 05 17:25:48 2012 -0500
@@ -124,6 +124,7 @@
      'E': OutError(copy(s, 2, Length(s) - 1), true);
      'W': OutError(copy(s, 2, Length(s) - 1), false);
      'M': ParseCommand('landcheck ' + s, true);
+     'o': if fastUntilLag then ParseCommand('forcequit', true);
      'T': case s[2] of
                'L': GameType:= gmtLocal;
                'D': GameType:= gmtDemo;