Fix spectator desync in rare conditions (there was team which left during its turn, and last command with timestamp from it was '+')
authorunc0rr
Sat, 29 Jun 2013 23:58:37 +0400
changeset 9304 3f4c3fc146c2
parent 9303 457efde100b5
child 9305 8e5140875ab5
Fix spectator desync in rare conditions (there was team which left during its turn, and last command with timestamp from it was '+')
gameServer/CoreTypes.hs
gameServer/EngineInteraction.hs
gameServer/HWProtoInRoomState.hs
gameServer/HWProtoLobbyState.hs
--- a/gameServer/CoreTypes.hs	Sat Jun 29 00:18:17 2013 +0400
+++ b/gameServer/CoreTypes.hs	Sat Jun 29 23:58:37 2013 +0400
@@ -144,6 +144,7 @@
     GameInfo
     {
         roundMsgs :: [B.ByteString],
+        lastFilteredTimedMsg :: Maybe B.ByteString,
         leftTeams :: [B.ByteString],
         teamsAtStart :: [TeamInfo],
         teamsInGameNumber :: Int,
@@ -161,6 +162,7 @@
 newGameInfo =
     GameInfo
         []
+        Nothing
         []
 
 data RoomInfo =
--- a/gameServer/EngineInteraction.hs	Sat Jun 29 00:18:17 2013 +0400
+++ b/gameServer/EngineInteraction.hs	Sat Jun 29 23:58:37 2013 +0400
@@ -32,17 +32,22 @@
 splitMessages = L.unfoldr (\b -> if B.null b then Nothing else Just $ B.splitAt (1 + fromIntegral (BW.head b)) b)
 
 
-checkNetCmd :: B.ByteString -> (B.ByteString, B.ByteString)
+checkNetCmd :: B.ByteString -> (B.ByteString, B.ByteString, Maybe (Maybe B.ByteString))
 checkNetCmd msg = check decoded
     where
         decoded = liftM (splitMessages . BW.pack) $ Base64.decode $ B.unpack msg
-        check Nothing = (B.empty, B.empty)
-        check (Just msgs) = let (a, b) = (filter isLegal msgs, filter isNonEmpty a) in (encode a, encode b)
+        check Nothing = (B.empty, B.empty, Nothing)
+        check (Just msgs) = let (a, b) = (filter isLegal msgs, filter isNonEmpty a) in (encode a, encode b, lft a)
         encode = B.pack . Base64.encode . BW.unpack . B.concat
         isLegal m = (B.length m > 1) && (flip Set.member legalMessages . B.head . B.tail $ m)
+        lft = foldr l Nothing
+        l m n = let m' = B.head $ B.tail m; tst = flip Set.member in 
+                      if not $ tst timedMessages m' then n
+                        else if '+' /= m' then Just Nothing else Just $ Just m
         isNonEmpty = (/=) '+' . B.head . B.tail
         legalMessages = Set.fromList $ "M#+LlRrUuDdZzAaSjJ,sNpPwtghbc12345" ++ slotMessages
         slotMessages = "\128\129\130\131\132\133\134\135\136\137\138"
+        timedMessages = Set.fromList $ "+LlRrUuDdZzAaSjJ,NpPwtgc12345" ++ slotMessages
 
 
 replayToDemo :: [TeamInfo]
@@ -50,18 +55,18 @@
         -> Map.Map B.ByteString [B.ByteString]
         -> [B.ByteString]
         -> [B.ByteString]
-replayToDemo teams mapParams params msgs = concat [
+replayToDemo ti mParams prms msgs = concat [
         [em "TD"]
         , maybeScript
         , maybeMap
-        , [eml ["etheme ", head $ params Map.! "THEME"]]
-        , [eml ["eseed ", mapParams Map.! "SEED"]]
+        , [eml ["etheme ", head $ prms Map.! "THEME"]]
+        , [eml ["eseed ", mParams Map.! "SEED"]]
         , [eml ["e$gmflags ", showB gameFlags]]
         , schemeFlags
-        , [eml ["e$template_filter ", mapParams Map.! "TEMPLATE"]]
+        , [eml ["e$template_filter ", mParams Map.! "TEMPLATE"]]
         , [eml ["e$mapgen ", mapgen]]
         , mapgenSpecific
-        , concatMap teamSetup teams
+        , concatMap teamSetup ti
         , msgs
         , [em "!"]
         ]
@@ -69,13 +74,13 @@
         em = toEngineMsg
         eml = em . B.concat
         mapGenTypes = ["+rnd+", "+maze+", "+drawn+"]
-        maybeScript = let s = head $ params Map.! "SCRIPT" in if s == "Normal" then [] else [eml ["escript Scripts/Multiplayer/", s, ".lua"]]
-        maybeMap = let m = mapParams Map.! "MAP" in if m `elem` mapGenTypes then [] else [eml ["emap ", m]]
-        scheme = tail $ params Map.! "SCHEME"
-        mapgen = mapParams Map.! "MAPGEN"
+        maybeScript = let s = head $ prms Map.! "SCRIPT" in if s == "Normal" then [] else [eml ["escript Scripts/Multiplayer/", s, ".lua"]]
+        maybeMap = let m = mParams Map.! "MAP" in if m `elem` mapGenTypes then [] else [eml ["emap ", m]]
+        scheme = tail $ prms Map.! "SCHEME"
+        mapgen = mParams Map.! "MAPGEN"
         mapgenSpecific = case mapgen of
-            "+maze+" -> [eml ["e$maze_size ", head $ params Map.! "MAZE_SIZE"]]
-            "+drawn" -> drawnMapData . head $ params Map.! "DRAWNMAP"
+            "+maze+" -> [eml ["e$maze_size ", head $ prms Map.! "MAZE_SIZE"]]
+            "+drawn" -> drawnMapData . head $ prms Map.! "DRAWNMAP"
             _ -> []
         gameFlags :: Word32
         gameFlags = foldl (\r (b, f) -> if b == "false" then r else r .|. f) 0 $ zip scheme gameFlagConsts
@@ -83,7 +88,7 @@
             $ filter (\(_, (n, _)) -> not $ B.null n)
             $ zip (drop (length gameFlagConsts) scheme) schemeParams
         ammoStr :: B.ByteString
-        ammoStr = head . tail $ params Map.! "AMMO"
+        ammoStr = head . tail $ prms Map.! "AMMO"
         ammo = let l = B.length ammoStr `div` 4; ((a, b), (c, d)) = (B.splitAt l . fst &&& B.splitAt l . snd) . B.splitAt (l * 2) $ ammoStr in
                    (map (\(x, y) -> eml [x, " ", y]) $ zip ["eammloadt", "eammprob", "eammdelay", "eammreinf"] [a, b, c, d])
                    ++ [em "eammstore" | scheme !! 14 == "true" || scheme !! 20 == "false"]
--- a/gameServer/HWProtoInRoomState.hs	Sat Jun 29 00:18:17 2013 +0400
+++ b/gameServer/HWProtoInRoomState.hs	Sat Jun 29 23:58:37 2013 +0400
@@ -217,11 +217,15 @@
 
     if teamsInGame cl > 0 && (isJust $ gameInfo rm) && (not $ B.null legalMsgs) then
         return $ AnswerClients chans ["EM", legalMsgs]
-            : [ModifyRoom (\r -> r{gameInfo = liftM (\g -> g{roundMsgs = nonEmptyMsgs : roundMsgs g}) $ gameInfo r}) | not $ B.null nonEmptyMsgs]
+            : [ModifyRoom (\r -> r{gameInfo = liftM 
+                (\g -> g{
+                    roundMsgs = if B.null nonEmptyMsgs then roundMsgs g else nonEmptyMsgs : roundMsgs g
+                    , lastFilteredTimedMsg = fromMaybe (lastFilteredTimedMsg g) lastFTMsg})
+                $ gameInfo r})]
         else
         return []
     where
-        (legalMsgs, nonEmptyMsgs) = checkNetCmd msg
+        (legalMsgs, nonEmptyMsgs, lastFTMsg) = checkNetCmd msg
 
 
 handleCmd_inRoom ["ROUNDFINISHED", _] = do
--- a/gameServer/HWProtoLobbyState.hs	Sat Jun 29 00:18:17 2013 +0400
+++ b/gameServer/HWProtoLobbyState.hs	Sat Jun 29 23:58:37 2013 +0400
@@ -115,10 +115,13 @@
         watchRound cl jRoom chans = if isNothing $ gameInfo jRoom then
                     []
                 else
-                    [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" : (reverse . 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" : (reverse . roundMsgs . fromJust . gameInfo $ jRoom))
+                    : [AnswerClients [sendChan cl] $ "EM" : [fromJust msg] | isJust msg]
+            where
+            msg = lastFilteredTimedMsg . fromJust . gameInfo $ jRoom
 
 
 handleCmd_lobby ["JOIN_ROOM", roomName] =