# HG changeset patch # User unc0rr # Date 1372535917 -14400 # Node ID 3f4c3fc146c20b69fc989f419d13391703bcd370 # Parent 457efde100b5d764374c2aa3af7711f1f285c943 Fix spectator desync in rare conditions (there was team which left during its turn, and last command with timestamp from it was '+') diff -r 457efde100b5 -r 3f4c3fc146c2 gameServer/CoreTypes.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 = diff -r 457efde100b5 -r 3f4c3fc146c2 gameServer/EngineInteraction.hs --- 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"] diff -r 457efde100b5 -r 3f4c3fc146c2 gameServer/HWProtoInRoomState.hs --- 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 diff -r 457efde100b5 -r 3f4c3fc146c2 gameServer/HWProtoLobbyState.hs --- 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] =