예제 #1
0
        public async Task QueueRequest(ConnectedUser user, MatchMakerQueueRequest cmd)
        {
            var banTime = BannedSeconds(user.Name);

            if (banTime != null)
            {
                await UpdatePlayerStatus(user.Name);

                await user.Respond($"Please rest and wait for {banTime}s because you refused previous match");

                return;
            }

            //assure people don't rejoin (possibly accidentally) directly after starting a game
            if (server.Battles.Values.Any(x => x.IsInGame && DateTime.UtcNow.Subtract(x.RunningSince ?? DateTime.UtcNow).TotalMinutes < DynamicConfig.Instance.MmMinimumMinutesBetweenGames && x.spring.LobbyStartContext.Players.Count(p => !p.IsSpectator) > 1 && x.spring.LobbyStartContext.Players.Any(p => !p.IsSpectator && p.Name == user.Name)))
            {
                await UpdatePlayerStatus(user.Name);

                await user.Respond($"You have recently started a match. Please play for at least {DynamicConfig.Instance.MmMinimumMinutesBetweenGames} minutes before starting another match");

                return;
            }

            DateTime player;

            lastTimePlayerDeniedMatch.TryRemove(user.Name, out player); //this player might be interested in suggestive MM games after all

            var wantedQueueNames = cmd.Queues?.ToList() ?? new List <string>();
            var wantedQueues     = PossibleQueues.Where(x => wantedQueueNames.Contains(x.Name)).ToList();

            await AddOrUpdateUser(user, wantedQueues);
        }
예제 #2
0
        public async Task ProcessPartyInviteResponse(ConnectedUser usr, PartyInviteResponse response)
        {
            RemoveOldInvites();

            if (response.Accepted)
            {
                var inv = partyInvites.FirstOrDefault(x => x.PartyID == response.PartyID);
                if ((inv != null) && (inv.Invitee == usr.Name))
                {
                    var inviteeUser = usr;
                    var inviterUser = server.ConnectedUsers.Get(inv.Inviter);

                    if (inviterUser != null)
                    {
                        var targetBattle = inviterUser.MyBattle ?? inviteeUser.MyBattle; // join inviter user's battle, if its empty join invitee user's battle
                        if (targetBattle != null)
                        {
                            if (inviteeUser.MyBattle != targetBattle)
                            {
                                await server.ForceJoinBattle(inviteeUser.Name, targetBattle);
                            }
                            if (inviterUser.MyBattle != targetBattle)
                            {
                                await server.ForceJoinBattle(inviterUser.Name, targetBattle);
                            }
                        }
                    }


                    var inviterParty = parties.FirstOrDefault(x => x.PartyID == response.PartyID);
                    var inviteeParty = parties.FirstOrDefault(x => x.UserNames.Contains(usr.Name));

                    Party party = null;

                    if ((inviterParty == null) && (inviteeParty != null))
                    {
                        party = inviteeParty;
                    }
                    if ((inviterParty == null) && (inviteeParty == null))
                    {
                        party = new Party(inv.PartyID);
                        parties.Add(party);
                    }
                    if ((inviterParty != null) && (inviteeParty == null))
                    {
                        party = inviterParty;
                    }
                    if ((inviterParty != null) && (inviteeParty != null))
                    {
                        await RemoveFromParty(inviterParty, inv.Invitee);

                        party = inviterParty;
                    }


                    await AddToParty(party, inv.Invitee, inv.Inviter);
                }
            }
        }
예제 #3
0
        public async Task AreYouReadyResponse(ConnectedUser user, AreYouReadyResponse response)
        {
            PlayerEntry entry;

            if (players.TryGetValue(user.Name, out entry))
            {
                if (entry.InvitedToPlay)
                {
                    if (response.Ready)
                    {
                        entry.LastReadyResponse = true;
                    }
                    else
                    {
                        entry.LastReadyResponse = false;
                        await RemoveUser(user.Name, true);
                    }

                    var invitedPeople = players.Values.Where(x => x?.InvitedToPlay == true).ToList();

                    if (invitedPeople.Count <= 1)
                    {
                        foreach (var p in invitedPeople)
                        {
                            p.LastReadyResponse = true;
                        }
                        // if we are doing tick because too few people, make sure we count remaining people as readied to not ban them
                        OnTick();
                    }
                    else if (invitedPeople.All(x => x.LastReadyResponse))
                    {
                        OnTick();
                    }
                    else
                    {
                        var readyCounts = CountQueuedPeople(invitedPeople.Where(x => x.LastReadyResponse));

                        var proposedBattles = ProposeBattles(invitedPeople.Where(x => x.LastReadyResponse));

                        await Task.WhenAll(invitedPeople.Select(async(p) =>
                        {
                            var invitedBattle = invitationBattles?.FirstOrDefault(x => x.Players.Contains(p));
                            await
                            server.SendToUser(p.Name,
                                              new AreYouReadyUpdate()
                            {
                                QueueReadyCounts = readyCounts,
                                ReadyAccepted    = p.LastReadyResponse == true,
                                LikelyToPlay     = proposedBattles.Any(y => y.Players.Contains(p)),
                                YourBattleSize   = invitedBattle?.Size,
                                YourBattleReady  =
                                    invitedPeople.Count(x => x.LastReadyResponse && (invitedBattle?.Players.Contains(x) == true))
                            });
                        }));
                    }
                }
            }
        }
예제 #4
0
        public async Task ProcessLeaveParty(ConnectedUser usr, LeaveParty msg)
        {
            var party = parties.FirstOrDefault(x => x.PartyID == msg.PartyID);

            if (party != null)
            {
                await RemoveFromParty(party, usr.Name);
            }
        }
예제 #5
0
        public async Task OnLoginAccepted(ConnectedUser conus)
        {
            await conus.SendCommand(new MatchMakerSetup()
            {
                PossibleQueues = PossibleQueues
            });

            await UpdatePlayerStatus(conus.Name);
        }
예제 #6
0
        private async Task AddOrUpdateUser(ConnectedUser user, List <MatchMakerSetup.Queue> wantedQueues)
        {
            var party = server.PartyManager.GetParty(user.Name);

            if (party != null)
            {
                foreach (var p in party.UserNames)
                {
                    var conUs = server.ConnectedUsers.Get(p);
                    if (conUs != null)
                    {
                        players.AddOrUpdate(p,
                                            (str) => new PlayerEntry(conUs.User, wantedQueues, party),
                                            (str, usr) =>
                        {
                            usr.UpdateTypes(wantedQueues);
                            usr.Party = party;
                            return(usr);
                        });
                    }
                }
            }
            else
            {
                players.AddOrUpdate(user.Name,
                                    (str) => new PlayerEntry(user.User, wantedQueues, null),
                                    (str, usr) =>
                {
                    usr.UpdateTypes(wantedQueues);
                    usr.Party = null;
                    return(usr);
                });
            }


            // if nobody is invited, we can do tick now to speed up things
            bool doUpdates = false;

            lock (tickLock) {//wait for running tick to finish first
                if (invitationBattles?.Any() != true)
                {
                    OnTick();
                }
                else
                {
                    doUpdates = true;
                }
            }
            if (doUpdates)
            {
                await UpdateAllPlayerStatuses();            // else we just send statuses
            }
        }
예제 #7
0
        public async Task ProcessInviteToParty(ConnectedUser usr, InviteToParty msg)
        {
            ConnectedUser target;

            if (server.ConnectedUsers.TryGetValue(msg.UserName, out target))
            {
                if (target.Ignores.Contains(usr.Name))
                {
                    return;
                }
                var myParty     = GetParty(usr.Name);
                var targetParty = GetParty(target.Name);
                if ((myParty != null) && (myParty == targetParty))
                {
                    return;
                }

                // if i dont have battle but target has, join him
                if (myParty == null && usr.MyBattle == null && target.MyBattle != null && !target.MyBattle.IsPassworded)
                {
                    await server.ForceJoinBattle(usr.Name, target.MyBattle);
                }

                RemoveOldInvites();
                var partyInvite = partyInvites.FirstOrDefault(x => (x.Inviter == usr.Name) && (x.Invitee == target.Name));

                if (partyInvite == null)
                {
                    partyInvite = new PartyInvite()
                    {
                        PartyID = myParty?.PartyID ?? Interlocked.Increment(ref partyCounter),
                        Inviter = usr.Name,
                        Invitee = target.Name
                    };
                    partyInvites.Add(partyInvite);
                }

                await
                target.SendCommand(new OnPartyInvite()
                {
                    PartyID   = partyInvite.PartyID,
                    UserNames = myParty?.UserNames?.ToList() ?? new List <string>()
                    {
                        usr.Name
                    },
                    TimeoutSeconds = inviteTimeoutSeconds
                });
            }
        }
예제 #8
0
        public bool IsAdmin(ServerBattle battle, string userName)
        {
            UserBattleStatus ubs = null;

            battle.Users.TryGetValue(userName, out ubs);
            if (ubs != null)
            {
                return(ubs.LobbyUser.IsAdmin);
            }

            ConnectedUser con = null;

            battle.server.ConnectedUsers.TryGetValue(userName, out con);
            return(con?.User?.IsAdmin ?? false);
        }
        public static bool HasSeen(ConnectedUser uWatcher, ConnectedUser uWatched)
        {
            if (uWatched == null || uWatcher == null)
            {
                return(true);
            }
            int lastSync;
            var newSync = uWatched.User.SyncVersion;

            if (!uWatcher.HasSeenUserVersion.TryGetValue(uWatched.Name, out lastSync) || lastSync != newSync)
            {
                uWatcher.HasSeenUserVersion[uWatched.Name] = newSync;
                return(false);
            }
            return(true);
        }
예제 #10
0
        public async Task RequestConnectSpring(ConnectedUser conus, string joinPassword)
        {
            UserBattleStatus ubs;

            if (!Users.TryGetValue(conus.Name, out ubs) && !(IsInGame && spring.LobbyStartContext.Players.Any(x => x.Name == conus.Name)))
            {
                if (IsPassworded && (Password != joinPassword))
                {
                    await conus.Respond("Invalid password");

                    return;
                }
            }
            var pwd = GenerateClientScriptPassword(conus.Name);

            spring.AddUser(conus.Name, pwd, conus.User);

            await conus.SendCommand(GetConnectSpringStructure(pwd));
        }
예제 #11
0
        public async Task QueueRequest(ConnectedUser user, MatchMakerQueueRequest cmd)
        {
            var banTime = BannedSeconds(user.Name);

            if (banTime != null)
            {
                await UpdatePlayerStatus(user.Name);

                await user.Respond($"Please rest and wait for {banTime}s because you refused previous match");

                return;
            }

            // already invited ignore requests
            PlayerEntry entry;

            if (players.TryGetValue(user.Name, out entry) && entry.InvitedToPlay)
            {
                await UpdatePlayerStatus(user.Name);

                return;
            }

            var wantedQueueNames = cmd.Queues?.ToList() ?? new List <string>();
            var wantedQueues     = possibleQueues.Where(x => wantedQueueNames.Contains(x.Name)).ToList();

            var party = server.PartyManager.GetParty(user.Name);

            if (party != null)
            {
                wantedQueues = wantedQueues.Where(x => x.MaxSize / 2 >= party.UserNames.Count).ToList(); // if is in party keep only queues where party fits
            }
            if (wantedQueues.Count == 0)                                                                 // delete
            {
                await RemoveUser(user.Name, true);

                return;
            }

            await AddOrUpdateUser(user, wantedQueues);
        }
예제 #12
0
        public async Task Process(Login login)
        {
            var ret = await Task.Run(() => server.LoginChecker.DoLogin(login, RemoteEndpointIP, login.Dlc));

            if (ret.LoginResponse.ResultCode == LoginResponse.Code.Ok)
            {
                var user = ret.User;
                //Trace.TraceInformation("{0} login: {1}", this, response.ResultCode.Description());

                await this.SendCommand(user); // send self to self first

                connectedUser      = server.ConnectedUsers.GetOrAdd(user.Name, (n) => new ConnectedUser(server, user));
                connectedUser.User = user;
                connectedUser.Connections.TryAdd(this, true);

                // close other connections
                foreach (var otherConnection in connectedUser.Connections.Keys.Where(x => x != null && x != this).ToList())
                {
                    otherConnection.RequestClose();
                    bool oth;
                    connectedUser.Connections.TryRemove(otherConnection, out oth);
                }

                server.SessionTokens[ret.LoginResponse.SessionToken] = user.AccountID;

                await SendCommand(ret.LoginResponse); // login accepted

                connectedUser.ResetHasSeen();


                foreach (var b in server.Battles.Values.Where(x => x != null))
                {
                    await SendCommand(new BattleAdded()
                    {
                        Header = b.GetHeader()
                    });
                }

                // mutually syncs users based on visibility rules
                await server.TwoWaySyncUsers(Name, server.ConnectedUsers.Keys);


                server.OfflineMessageHandler.SendMissedMessagesAsync(this, SayPlace.User, Name, user.AccountID);

                var defChans = await server.ChannelManager.GetDefaultChannels(user.AccountID);

                defChans.AddRange(server.Channels.Where(x => x.Value.Users.ContainsKey(user.Name)).Select(x => x.Key)); // add currently connected channels to list too

                foreach (var chan in defChans.ToList().Distinct())
                {
                    await connectedUser.Process(new JoinChannel()
                    {
                        ChannelName = chan,
                        Password    = null
                    });
                }


                foreach (var bat in server.Battles.Values.Where(x => x != null && x.IsInGame))
                {
                    var s = bat.spring;
                    if (s.LobbyStartContext.Players.Any(x => !x.IsSpectator && x.Name == Name) && !s.Context.ActualPlayers.Any(x => x.Name == Name && x.LoseTime != null))
                    {
                        await SendCommand(new RejoinOption()
                        {
                            BattleID = bat.BattleID
                        });
                    }
                }


                await SendCommand(new FriendList()
                {
                    Friends = connectedUser.FriendEntries.ToList()
                });
                await SendCommand(new IgnoreList()
                {
                    Ignores = connectedUser.Ignores.ToList()
                });

                await server.MatchMaker.OnLoginAccepted(connectedUser);

                await server.PlanetWarsMatchMaker.OnLoginAccepted(connectedUser);

                await SendCommand(server.NewsListManager.GetCurrentNewsList());
                await SendCommand(server.LadderListManager.GetCurrentLadderList());
                await SendCommand(server.ForumListManager.GetCurrentForumList(user.AccountID));

                using (var db = new ZkDataContext())
                {
                    var acc = db.Accounts.Find(user.AccountID);
                    if (acc != null)
                    {
                        await server.PublishUserProfileUpdate(acc);
                    }
                }
            }
            else
            {
                await SendCommand(ret.LoginResponse);

                if (ret.LoginResponse.ResultCode == LoginResponse.Code.Banned)
                {
                    await Task.Delay(500); // this is needed because socket writes are async and might not be queued yet

                    await transport.Flush();

                    transport.RequestClose();
                }
            }
        }
예제 #13
0
        private async Task AddOrUpdateUser(ConnectedUser user, List <MatchMakerSetup.Queue> wantedQueues, bool massJoin = false)
        {
            // already invited ignore requests
            PlayerEntry entry;

            if (players.TryGetValue(user.Name, out entry) && entry.InvitedToPlay)
            {
                await UpdatePlayerStatus(user.Name);

                return;
            }


            var party = server.PartyManager.GetParty(user.Name);

            if (party != null)
            {
                wantedQueues = wantedQueues.Where(x => x.MaxSize / 2 >= party.UserNames.Count).ToList(); // if is in party keep only queues where party fits
            }
            if (wantedQueues.Count == 0)                                                                 // delete
            {
                if (entry?.QueueTypes?.Count > 0 && entry?.QuickPlay == false)
                {
                    await server.UserLogSay($"{user.Name} has left the matchmaker.");
                }

                await RemoveUser(user.Name, true);

                return;
            }

            if (party != null)
            {
                foreach (var p in party.UserNames)
                {
                    var conUs = server.ConnectedUsers.Get(p);
                    if (conUs != null)
                    {
                        players.AddOrUpdate(p,
                                            (str) => new PlayerEntry(conUs.User, wantedQueues, party),
                                            (str, usr) =>
                        {
                            usr.UpdateTypes(wantedQueues);
                            usr.Party = party;
                            return(usr);
                        });
                    }
                }
            }
            else
            {
                players.AddOrUpdate(user.Name,
                                    (str) => new PlayerEntry(user.User, wantedQueues, null),
                                    (str, usr) =>
                {
                    usr.UpdateTypes(wantedQueues);
                    usr.Party = null;
                    return(usr);
                });
            }


            //if many people are joined simultaneously, wait until join is completed before sending updates or trying to create battles.
            if (massJoin)
            {
                return;
            }

            await server.UserLogSay($"{user.Name} has joined the following queues: {wantedQueues.Select(q => q.Name).StringJoin()}.");

            // if nobody is invited, we can do tick now to speed up things
            if (invitationBattles?.Any() != true)
            {
                OnTick();
            }
            else
            {
                await UpdateAllPlayerStatuses();  // else we just send statuses
            }
        }
예제 #14
0
        public async Task Process(Login login)
        {
            var ret = await Task.Run(() => server.LoginChecker.DoLogin(login, RemoteEndpointIP));

            if (ret.LoginResponse.ResultCode == LoginResponse.Code.Ok)
            {
                var user = ret.User;
                //Trace.TraceInformation("{0} login: {1}", this, response.ResultCode.Description());

                await this.SendCommand(user); // send self to self first

                connectedUser      = server.ConnectedUsers.GetOrAdd(user.Name, (n) => new ConnectedUser(server, user));
                connectedUser.User = user;
                connectedUser.Connections.TryAdd(this, true);

                server.SessionTokens[ret.LoginResponse.SessionToken] = user.AccountID;

                await SendCommand(ret.LoginResponse); // login accepted

                connectedUser.ResetHasSeen();


                foreach (var b in server.Battles.Values.Where(x => x != null))
                {
                    await SendCommand(new BattleAdded()
                    {
                        Header = b.GetHeader()
                    });
                }

                // mutually syncs users based on visibility rules
                await server.TwoWaySyncUsers(Name, server.ConnectedUsers.Keys);


                server.OfflineMessageHandler.SendMissedMessagesAsync(this, SayPlace.User, Name, user.AccountID);

                var defChans = await server.ChannelManager.GetDefaultChannels(user.AccountID);

                defChans.AddRange(server.Channels.Where(x => x.Value.Users.ContainsKey(user.Name)).Select(x => x.Key)); // add currently connected channels to list too

                foreach (var chan in defChans.ToList().Distinct())
                {
                    await connectedUser.Process(new JoinChannel()
                    {
                        ChannelName = chan,
                        Password    = null
                    });
                }


                foreach (var bat in server.Battles.Values.Where(x => x != null && x.IsInGame))
                {
                    var s = bat.spring;
                    if (s.LobbyStartContext.Players.Any(x => !x.IsSpectator && x.Name == Name) && !s.Context.ActualPlayers.Any(x => x.Name == Name && x.LoseTime != null))
                    {
                        await SendCommand(new RejoinOption()
                        {
                            BattleID = bat.BattleID
                        });
                    }
                }


                await SendCommand(new FriendList()
                {
                    Friends = connectedUser.FriendEntries.ToList()
                });
                await SendCommand(new IgnoreList()
                {
                    Ignores = connectedUser.Ignores.ToList()
                });

                await server.MatchMaker.OnLoginAccepted(connectedUser);

                await server.PlanetWarsMatchMaker.OnLoginAccepted(connectedUser);
            }
            else
            {
                await SendCommand(ret.LoginResponse);

                if (ret.LoginResponse.ResultCode == LoginResponse.Code.Banned)
                {
                    transport.RequestClose();
                }
            }
        }
예제 #15
0
        public virtual async Task ProcessPlayerJoin(ConnectedUser user, string joinPassword)
        {
            if (IsPassworded && (Password != joinPassword))
            {
                await user.Respond("Invalid password");

                return;
            }

            if (IsKicked(user.Name))
            {
                await KickFromBattle(user.Name, "Banned for five minutes");

                return;
            }

            if ((user.MyBattle != null) && (user.MyBattle != this))
            {
                await user.Process(new LeaveBattle());
            }

            UserBattleStatus ubs;

            if (!Users.TryGetValue(user.Name, out ubs))
            {
                ubs = new UserBattleStatus(user.Name, user.User, GenerateClientScriptPassword(user.Name));
                Users[user.Name] = ubs;
            }

            ValidateBattleStatus(ubs);
            user.MyBattle = this;


            await server.TwoWaySyncUsers(user.Name, Users.Keys); // mutually sync user statuses

            await server.SyncUserToAll(user);

            await RecalcSpectators();

            await
            user.SendCommand(new JoinBattleSuccess()
            {
                BattleID = BattleID,
                Players  = Users.Values.Select(x => x.ToUpdateBattleStatus()).ToList(),
                Bots     = Bots.Values.Select(x => x.ToUpdateBotStatus()).ToList(),
                Options  = ModOptions
            });


            await server.Broadcast(Users.Keys.Where(x => x != user.Name), ubs.ToUpdateBattleStatus()); // send my UBS to others in battle

            if (spring.IsRunning)
            {
                spring.AddUser(ubs.Name, ubs.ScriptPassword, ubs.LobbyUser);
                var started = DateTime.UtcNow.Subtract(spring.IngameStartTime ?? RunningSince ?? DateTime.UtcNow);
                started = new TimeSpan((int)started.TotalHours, started.Minutes, started.Seconds);
                await SayBattle($"THIS GAME IS CURRENTLY IN PROGRESS, PLEASE WAIT UNTIL IT ENDS! Running for {started}", ubs.Name);
                await SayBattle("If you say !notify, I will message you when the current game ends.", ubs.Name);
            }

            try
            {
                var ret = PlayerJoinHandler.AutohostPlayerJoined(GetContext(), ubs.LobbyUser.AccountID);
                if (ret != null)
                {
                    if (!IsNullOrEmpty(ret.PrivateMessage))
                    {
                        await SayBattle(ret.PrivateMessage, ubs.Name);
                    }
                    if (!IsNullOrEmpty(ret.PublicMessage))
                    {
                        await SayBattle(ret.PublicMessage);
                    }
                }
            }
            catch (Exception ex)
            {
                Trace.TraceError(ex.ToString());
                await SayBattle("ServerManage error: " + ex);
            }
        }
예제 #16
0
        public async Task AreYouReadyResponse(ConnectedUser user, AreYouReadyResponse response)
        {
            PlayerEntry entry;

            if (players.TryGetValue(user.Name, out entry))
            {
                if (entry.InvitedToPlay)
                {
                    if (response.Ready)
                    {
                        entry.LastReadyResponse = true;
                        if (entry.QuickPlay)
                        {
                            await server.UserLogSay($"{user.Name} accepted his quickplay MM invitation");
                        }
                        else
                        {
                            await server.UserLogSay($"{user.Name} accepted his pop-up MM invitation");
                        }
                    }
                    else
                    {
                        if (entry.QuickPlay)
                        {
                            await server.UserLogSay($"{user.Name} rejected his quickplay MM invitation");

                            entry.InvitedToPlay = false; //don't ban quickplayers
                        }
                        else
                        {
                            await server.UserLogSay($"{user.Name} rejected his pop-up MM invitation");
                        }
                        lastTimePlayerDeniedMatch[entry.Name] = DateTime.UtcNow; //store that this player is probably not interested in suggestive MM games
                        entry.LastReadyResponse = false;
                        await RemoveUser(user.Name, true);
                    }

                    var invitedPeople = players.Values.Where(x => x?.InvitedToPlay == true).ToList();

                    if (invitedPeople.Count <= 1)
                    {
                        await server.UserLogSay($"Aborting MM invitations because only {invitedPeople.Count} invitations outstanding.");

                        foreach (var p in invitedPeople)
                        {
                            p.LastReadyResponse = true;
                        }
                        // if we are doing tick because too few people, make sure we count remaining people as readied to not ban them
                        OnTick();
                    }
                    else if (invitedPeople.All(x => x.LastReadyResponse))
                    {
                        await server.UserLogSay($"All {invitedPeople.Count} invitations have been accepted, doing tick.");

                        OnTick();
                    }
                    else
                    {
                        var readyCounts = CountQueuedPeople(invitedPeople.Where(x => x.LastReadyResponse));

                        var proposedBattles = ProposeBattles(invitedPeople.Where(x => x.LastReadyResponse), false);

                        await Task.WhenAll(invitedPeople.Select(async(p) =>
                        {
                            var invitedBattle = invitationBattles?.FirstOrDefault(x => x.Players.Contains(p));
                            await server.SendToUser(p.Name,
                                                    new AreYouReadyUpdate()
                            {
                                QueueReadyCounts = readyCounts,
                                ReadyAccepted    = p.LastReadyResponse == true,
                                LikelyToPlay     = proposedBattles.Any(y => y.Players.Contains(p)),
                                YourBattleSize   = invitedBattle?.Size,
                                YourBattleReady  = invitedPeople.Count(x => x.LastReadyResponse && (invitedBattle?.Players.Contains(x) == true))
                            });
                        }));
                    }
                }
            }
        }
        public bool CanUserSee(ConnectedUser uWatcher, ConnectedUser uWatched)
        {
            if (uWatched == null || uWatcher == null)
            {
                return(false);
            }
            if (uWatched.Name == uWatcher.Name)
            {
                return(true);
            }

            // admins always visible
            if (uWatched.User?.IsAdmin == true)
            {
                return(true);
            }

            // friends see each other
            if (uWatcher.FriendNames.Contains(uWatched.Name))
            {
                return(true);
            }

            // already seen, cannot be unseen
            if (uWatcher.HasSeenUserVersion.ContainsKey(uWatched.Name))
            {
                return(true);
            }

            // clanmates see each other
            if (uWatcher.User?.Clan != null && uWatcher.User?.Clan == uWatched.User?.Clan)
            {
                return(true);
            }

            // people in same battle see each other
            if (uWatcher.MyBattle != null && uWatcher.MyBattle == uWatched.MyBattle)
            {
                return(true);
            }

            // people in same party see each other
            if (uWatcher.User?.PartyID != null && uWatcher.User.PartyID == uWatched.User?.PartyID)
            {
                return(true);
            }


            // people in same non "zk" channel see each other
            foreach (var chan in Channels.Values.Where(x => x != null))
            {
                if (chan.Users.ContainsKey(uWatcher.Name)) // my channel
                {
                    if (chan.IsDeluge)
                    {
                        if (GlobalConst.DelugeChannelDisplayUsers > 0)
                        {
                            var myEffectiveElo = uWatcher?.User?.EffectiveElo ?? 1200;

                            var channelUsersBySkill = chan.Users.Keys.Select(x => ConnectedUsers.Get(x)).Where(x => x != null)
                                                      .OrderBy(x => Math.Abs((x.User?.EffectiveMmElo ?? 1200) - myEffectiveElo)).Select(x => x.Name).Take(GlobalConst.DelugeChannelDisplayUsers);

                            if (channelUsersBySkill.Contains(uWatched.Name))
                            {
                                return(true);
                            }
                        }
                    }
                    else
                    {
                        if (chan.Users.ContainsKey(uWatched.Name))
                        {
                            return(true);
                        }
                    }
                }
            }
            return(false);
        }
 public async Task SyncUserToAll(ConnectedUser changer)
 {
     await Broadcast(ConnectedUsers.Values.Where(x => x != null).Where(x => CanUserSee(x, changer) && !HasSeen(x, changer)), changer.User);
 }
        public async Task Process(Login login)
        {
            var user     = new User();
            var response = await Task.Run(() => state.LoginChecker.Login(user, login, this));

            if (response.ResultCode == LoginResponse.Code.Ok)
            {
                connectedUser = state.ConnectedUsers.GetOrAdd(user.Name, (n) => new ConnectedUser(state, user));
                connectedUser.Connections.TryAdd(this, true);
                connectedUser.User = user;

                Trace.TraceInformation("{0} login: {1}", this, response.ResultCode.Description());

                await state.Broadcast(state.ConnectedUsers.Values, connectedUser.User); // send self to all

                await SendCommand(response);                                            // login accepted

                foreach (var c in state.ConnectedUsers.Values.Where(x => x != connectedUser))
                {
                    await SendCommand(c.User);                                                                           // send others to self
                }
                foreach (var b in state.Battles.Values)
                {
                    if (b != null)
                    {
                        await
                        SendCommand(new BattleAdded()
                        {
                            Header =
                                new BattleHeader()
                            {
                                BattleID       = b.BattleID,
                                Engine         = b.EngineVersion,
                                Game           = b.ModName,
                                Founder        = b.Founder.Name,
                                Map            = b.MapName,
                                Ip             = b.Ip,
                                Port           = b.HostPort,
                                Title          = b.Title,
                                SpectatorCount = b.SpectatorCount,
                                MaxPlayers     = b.MaxPlayers,
                                Password       = b.Password != null ? "?" : null
                            }
                        });

                        foreach (var u in b.Users.Values.Select(x => x.ToUpdateBattleStatus()).ToList())
                        {
                            await SendCommand(new JoinedBattle()
                            {
                                BattleID = b.BattleID, User = u.Name
                            });
                        }
                    }
                }


                await state.OfflineMessageHandler.SendMissedMessages(this, SayPlace.User, Name, user.AccountID);

                foreach (var chan in await state.ChannelManager.GetDefaultChannels(user.AccountID))
                {
                    await connectedUser.Process(new JoinChannel()
                    {
                        ChannelName = chan,
                        Password    = null
                    });
                }
            }
            else
            {
                await SendCommand(response);

                if (response.ResultCode == LoginResponse.Code.Banned)
                {
                    transport.RequestClose();
                }
            }
        }