void AnalyzeDiff(GameStateMessage gameStateMessage) { var priorityPlayer = gameStateMessage.turnInfo?.priorityPlayer; if (priorityPlayer.HasValue) { State.PriorityPlayer = priorityPlayer.Value; } var turnNumber = gameStateMessage.turnInfo?.turnNumber ?? -1; if (turnNumber >= 0) { if (turnNumber > State.TurnNumber) { // ReSharper disable once PossibleNullReferenceException (false positive) var activePlayer = gameStateMessage.turnInfo.activePlayer == State.MySeatId ? PlayerEnum.Me : PlayerEnum.Opponent; State.AddGameEvent(evt.StartTurn(turnNumber, activePlayer)); } State.TurnNumber = turnNumber; } if (gameStateMessage.players != null) { foreach (var p in gameStateMessage.players) { // Update the players state State.Players[p.systemSeatNumber] = p; } } var currentGameObjects = AddNewGameObjects(gameStateMessage.gameObjects); var annotationsByType = ParseAnnotations(gameStateMessage.annotations); Log.Debug("Annotations: {annotationsByType}", annotationsByType.Select(x => (x.Key, x.Count()))); var objectIdChanges = ParseObjectIdChanges(annotationsByType); var zoneTransfers = ParseZoneTransfers(annotationsByType, objectIdChanges); var scries = ParseScryAnnotations(annotationsByType); foreach (var(topIds, bottomIds) in scries) { State.HandleScryDone(topIds, bottomIds); } // Surveils should be handled by ZoneTransfers var shuffles = ParseShuffles(annotationsByType); // Clear the Mind draws in the same message with the shuffle // so we have to handle shuffles before moves State.HandleShuffles(shuffles); State.HandleMoves(zoneTransfers); var instanceIdsInZones = gameStateMessage.zones?.ToDictionary(z => zonesInfo[z.zoneId], z => z.objectInstanceIds); var mulliganCount = gameStateMessage.players ?.FirstOrDefault(i => i.systemSeatNumber == State.MySeatId) ?.mulliganCount ?? 0; if (mulliganCount > State.MyMulliganCount) { // Mulligan State.MyMulliganCount = mulliganCount; State.DrawHands(instanceIdsInZones, currentGameObjects); } State.SetGameObjects(instanceIdsInZones, currentGameObjects); }