Example #1
0
        public static byte[] SendProfile(ref LoginSocketState state, Dictionary <string, string> keyValues)
        {
            var id      = long.Parse(keyValues["profileid"]);
            var profile = ProfilesCache.GetProfileByPid(keyValues["profileid"]);

            if (profile == null)
            {
                return(DataFunctions.StringToBytes(String.Format(@"\error\\err\265\fatal\\errmsg\Username [{0}] doesn't exist!\id\1\final\", state.Name)));
            }

            string message = String.Format(
                @"\pi\\profileid\{0}\nick\{1}\userid\{2}\email\{3}\sig\{4}\uniquenick\{5}\pid\{6}" +
                @"\firstname\lastname\countrycode\{7}\birthday\{8}\lon\{9}\lat\{10}\loc\id\{11}\final\",
                profile.Id,
                profile.Name,
                profile.Id,
                profile.Email,
                _random.GetString(32, "0123456789abcdef"),
                profile.Name,
                profile.Id,
                profile.Country,
                16844722,
                "0.000000",
                "0.000000",
                keyValues["id"]
                //retrieve ? 5 : 2
                );

            //if (!retrieve && id == state.ProfileId)
            //    state.State++;

            return(DataFunctions.StringToBytes(message));
        }
        private unsafe void OnDataReceived(IAsyncResult async)
        {
            SocketState state = (SocketState)async.AsyncState;

            if (state == null || state.Socket == null || !state.Socket.Connected)
                return;

            try
            {
                // receive data from the socket
                int received = state.Socket.EndReceive(async);

                if (received == 0)
                    return;

                var buffer = state.Buffer;

                var input = Encoding.UTF8.GetString(XorBytes(buffer, 0, received - 7, XorKEY), 0, received);

                Logger.Info($"Receive data from the socket: {input}");

                if (input.StartsWith(@"\auth\\gamename\"))
                {
                    var sesskey = Interlocked.Increment(ref _sessionCounter).ToString("0000000000");

                    SendToClient(state, $@"\lc\2\sesskey\{sesskey}\proof\0\id\1\final\");

                    goto CONTINUE;
                }

                if (input.StartsWith(@"\authp\\pid\"))
                {
                    try
                    {
                        var pid = GetPidFromInput(input, 12);
                        var profileId = long.Parse(pid);

                        state.ProfileId = profileId;
                        state.Nick = Database.UsersDBInstance.GetProfileById(profileId).Name;

                        SendToClient(state, $@"\pauthr\{pid}\lid\1\final\");
                    }
                    catch (Exception)
                    {
                        state.Dispose();
                        return;
                    }

                    goto CONTINUE;
                }

                if (input.StartsWith(@"\getpd\"))
                {
                    // \\getpd\\\\pid\\87654321\\ptype\\3\\dindex\\0\\keys\\\u0001points\u0001points2\u0001points3\u0001stars\u0001games\u0001wins\u0001disconn\u0001a_durat\u0001m_streak\u0001f_race\u0001SM_wins\u0001Chaos_wins\u0001Ork_wins\u0001Tau_wins\u0001SoB_wins\u0001DE_wins\u0001Eldar_wins\u0001IG_wins\u0001Necron_wins\u0001lsw\u0001rnkd_vics\u0001con_rnkd_vics\u0001team_vics\u0001mdls1\u0001mdls2\u0001rg\u0001pw\\lid\\1\\final\\
                    // \getpd\\pid\87654321\ptype\3\dindex\0\keys\pointspoints2points3starsgameswinsdisconna_duratm_streakf_raceSM_winsChaos_winsOrk_winsTau_winsSoB_winsDE_winsEldar_winsIG_winsNecron_winslswrnkd_vicscon_rnkd_vicsteam_vicsmdls1mdls2rgpw\lid\1\final\
                    var pid = GetPidFromInput(input, 12);

                    var keysIndex = input.IndexOf("keys") + 5;
                    var keys = input.Substring(keysIndex);
                    var keysList = keys.Split(new string[] { "\u0001", "\\lid\\1\\final\\", "final", "\\", "lid" }, StringSplitOptions.RemoveEmptyEntries );

                    var keysResult = new StringBuilder();
                    var stats = ProfilesCache.GetProfileByPid(pid);

                    for (int i = 0; i < keysList.Length; i++)
                    {
                        var key = keysList[i];

                        keysResult.Append("\\"+key+"\\");

                        switch (key)
                        {
                            case "points": keysResult.Append(stats.Score1v1); break;
                            case "points2": keysResult.Append(stats.Score2v2); break;
                            case "points3": keysResult.Append(stats.Score3v3); break;

                            case "stars": keysResult.Append(stats.StarsCount); break;

                            case "games": keysResult.Append(stats.GamesCount); break;
                            case "wins": keysResult.Append(stats.WinsCount); break;
                            case "disconn": keysResult.Append(stats.Disconnects); break;
                            case "a_durat": keysResult.Append(stats.AverageDuractionTicks); break;
                            case "m_streak": keysResult.Append(stats.Best1v1Winstreak); break;

                            case "f_race": keysResult.Append(stats.FavouriteRace); break;

                            case "SM_wins": keysResult.Append(stats.Smwincount); break;
                            case "Chaos_wins": keysResult.Append(stats.Csmwincount); break;
                            case "Ork_wins": keysResult.Append(stats.Orkwincount); break;
                            case "Tau_wins": keysResult.Append(stats.Tauwincount); break;
                            case "SoB_wins": keysResult.Append(stats.Sobwincount); break;
                            case "DE_wins": keysResult.Append(stats.Dewincount); break;
                            case "Eldar_wins": keysResult.Append(stats.Eldarwincount); break;
                            case "IG_wins": keysResult.Append(stats.Igwincount); break;
                            case "Necron_wins": keysResult.Append(stats.Necrwincount); break;
                            /*case "lsw": keysResult.Append("123"); break;
                            case "rnkd_vics": keysResult.Append("50"); break;
                            case "con_rnkd_vics": keysResult.Append("200"); break;
                            case "team_vics": keysResult.Append("250"); break;
                            case "mdls1": keysResult.Append("260"); break;
                            case "mdls2": keysResult.Append("270"); break;
                            case "rg": keysResult.Append("280"); break;
                            case "pw": keysResult.Append("290"); break;*/
                            default:
                                keysResult.Append("0");
                                break;
                        }

                    }

                    SendToClient(state, $@"\getpdr\1\lid\1\pid\{pid}\mod\{stats.Modified}\length\{keys.Length}\data\{keysResult}\final\");

                    goto CONTINUE;
                }

                if (input.StartsWith(@"\setpd\"))
                {
                    var pid = GetPidFromInput(input, 12);

                    var lidIndex = input.IndexOf("\\lid\\", StringComparison.OrdinalIgnoreCase);
                    var lid = input.Substring(lidIndex+5, 1);

                    var timeInSeconds = (ulong)((DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds);

                    SendToClient(state, $@"\setpdr\1\lid\{lid}\pid\{pid}\mod\{timeInSeconds}\final\");

                    goto CONTINUE;
                }

                if (input.StartsWith(@"\updgame\"))
                {
                    Task.Factory.StartNew(() =>
                    {
                        var gamedataIndex = input.IndexOf("gamedata");
                        var finalIndex = input.IndexOf("final");

                        var gameDataString = input.Substring(gamedataIndex + 9, finalIndex - gamedataIndex - 10);

                        var valuesList = gameDataString.Split(new string[] { "\u0001", "\\lid\\1\\final\\", "final", "\\", "lid" }, StringSplitOptions.RemoveEmptyEntries);

                        var dictionary = new Dictionary<string, string>();

                        for (int i = 0; i < valuesList.Length; i += 2)
                            dictionary[valuesList[i]] = valuesList[i + 1];

                        var playersCount = int.Parse(dictionary["Players"]);

                        for (int i = 0; i < playersCount; i++)
                        {
                            // Dont process games with AI
                            if (dictionary["PHuman_" + i] != "1")
                                return;
                        }

                        var gameInternalSession = dictionary["SessionID"];
                        var teamsCount = int.Parse(dictionary["Teams"]);
                        var version = dictionary["Version"];
                        var mod = dictionary["Mod"];
                        var modVersion = dictionary["ModVer"];

                        var uniqueGameSessionBuilder = new StringBuilder(gameInternalSession);

                        for (int i = 0; i < playersCount; i++)
                        {
                            uniqueGameSessionBuilder.Append('<');
                            uniqueGameSessionBuilder.Append(dictionary["player_" + i]);
                            uniqueGameSessionBuilder.Append('>');
                        }

                        var uniqueSession = uniqueGameSessionBuilder.ToString();

                        if (!HandledGamesCache.Add(uniqueSession, uniqueSession, new CacheItemPolicy() { SlidingExpiration = TimeSpan.FromDays(1) }))
                        {
                            return;
                        }

                        var usersGameInfos = new GameUserInfo[playersCount];

                        GameUserInfo currentUserInfo = null;

                        for (int i = 0; i < playersCount; i++)
                        {
                            var nick = dictionary["player_"+i];

                            var info = new GameUserInfo
                            {
                                Profile = ProfilesCache.GetProfileByName(nick),
                                Race = Enum.Parse<Race>(dictionary["PRace_" + i], true),
                                Team = int.Parse(dictionary["PTeam_" + i]),
                                FinalState = Enum.Parse<PlayerFinalState>(dictionary["PFnlState_" + i]),
                            };

                            usersGameInfos[i] = info;

                            if (nick.Equals(state.Nick, StringComparison.Ordinal))
                                currentUserInfo = info;
                        }

                        var teams = usersGameInfos.GroupBy(x => x.Team).ToDictionary(x => x.Key, x => x.ToArray());
                        var gameDuration = long.Parse(dictionary["Duration"]);

                        foreach (var team in teams)
                        {
                            for (int i = 0; i < team.Value.Length; i++)
                            {
                                var info = team.Value[i];

                                info.Profile.AllInGameTicks += gameDuration;

                                switch (info.Race)
                                {
                                    case Race.space_marine_race:
                                        info.Profile.Smgamescount++;
                                        break;
                                    case Race.chaos_marine_race:
                                        info.Profile.Csmgamescount++;
                                        break;
                                    case Race.ork_race:
                                        info.Profile.Orkgamescount++;
                                        break;
                                    case Race.eldar_race:
                                        info.Profile.Eldargamescount++;
                                        break;
                                    case Race.guard_race:
                                        info.Profile.Iggamescount++;
                                        break;
                                    case Race.necron_race:
                                        info.Profile.Necrgamescount++;
                                        break;
                                    case Race.tau_race:
                                        info.Profile.Taugamescount++;
                                        break;
                                    case Race.dark_eldar_race:
                                        info.Profile.Degamescount++;
                                        break;
                                    case Race.sisters_race:
                                        info.Profile.Sobgamescount++;
                                        break;
                                    default:
                                        break;
                                }

                                if (info.FinalState == PlayerFinalState.Winner)
                                {
                                    switch (info.Race)
                                    {
                                        case Race.space_marine_race:
                                            info.Profile.Smwincount++;
                                            break;
                                        case Race.chaos_marine_race:
                                            info.Profile.Csmwincount++;
                                            break;
                                        case Race.ork_race:
                                            info.Profile.Orkwincount++;
                                            break;
                                        case Race.eldar_race:
                                            info.Profile.Eldarwincount++;
                                            break;
                                        case Race.guard_race:
                                            info.Profile.Igwincount++;
                                            break;
                                        case Race.necron_race:
                                            info.Profile.Necrwincount++;
                                            break;
                                        case Race.tau_race:
                                            info.Profile.Tauwincount++;
                                            break;
                                        case Race.dark_eldar_race:
                                            info.Profile.Dewincount++;
                                            break;
                                        case Race.sisters_race:
                                            info.Profile.Sobwincount++;
                                            break;
                                        default:
                                            break;
                                    }
                                }
                            }
                        }

                        bool isRateGame = false;

                        if (ChatServer.IrcDaemon.Users.TryGetValue(state.ProfileId, out UserInfo chatUserInfo))
                        {
                            var game = chatUserInfo.Game;
                            isRateGame = game != null && game.Clean();

                            // For rated games
                            if (isRateGame)
                            {
                                Console.WriteLine("UPDATE RATING GAME " + uniqueSession);

                                chatUserInfo.Game = null;

                                var usersInGame = game.UsersInGame;

                                if (usersGameInfos.Select(x => x.Profile.Id).OrderBy(x => x).SequenceEqual(usersInGame.OrderBy(x => x)))
                                {
                                    // Update winstreaks for 1v1 only
                                    if (usersInGame.Length == 2)
                                    {
                                        UpdateStreak(usersGameInfos[0]);
                                        UpdateStreak(usersGameInfos[1]);
                                    }

                                    var groupedTeams = usersGameInfos.GroupBy(x => x.Team).Select(x => x.ToArray()).ToArray();

                                    var players1Team = groupedTeams[0];
                                    var players2Team = groupedTeams[1];

                                    Func<ProfileData, long> scoreSelector = null;
                                    Action<ProfileData, long> scoreUpdater = null;

                                    ReatingGameType type = ReatingGameType.Unknown;

                                    switch (usersInGame.Length)
                                    {
                                        case 2:
                                            scoreSelector = StatsDelegates.Score1v1Selector;
                                            scoreUpdater = StatsDelegates.Score1v1Updated;
                                            type = ReatingGameType.Rating1v1;
                                            break;
                                        case 4:
                                            scoreSelector = StatsDelegates.Score2v2Selector;
                                            scoreUpdater = StatsDelegates.Score2v2Updated;
                                            type = ReatingGameType.Rating2v2;
                                            break;
                                        case 6:
                                        case 8:
                                            type = ReatingGameType.Rating3v3_4v4;
                                            scoreSelector = StatsDelegates.Score3v3Selector;
                                            scoreUpdater = StatsDelegates.Score3v3Updated;
                                            break;
                                        default:
                                            goto UPDATE;
                                    }

                                    var team0score = (long)players1Team.Average(x => scoreSelector(x.Profile));
                                    var team1score = (long)players2Team.Average(x => scoreSelector(x.Profile));

                                    var isFirstTeamResult = players1Team.Any(x => x.FinalState == PlayerFinalState.Winner);
                                    var delta = EloRating.CalculateELOdelta(team0score, team1score, isFirstTeamResult ? EloRating.GameOutcome.Win : EloRating.GameOutcome.Loss);

                                    for (int i = 0; i < players1Team.Length; i++)
                                    {
                                        players1Team[i].Delta = delta;
                                        players1Team[i].RatingGameType = type;
                                        scoreUpdater(players1Team[i].Profile, Math.Max(1000L, scoreSelector(players1Team[i].Profile) + delta));
                                    }

                                    for (int i = 0; i < players2Team.Length; i++)
                                    {
                                        players2Team[i].Delta = -delta;
                                        players2Team[i].RatingGameType = type;
                                        scoreUpdater(players2Team[i].Profile, Math.Max(1000L, scoreSelector(players2Team[i].Profile) - delta));
                                    }
                                }
                            }
                        }

                    UPDATE:
                        for (int i = 0; i < usersGameInfos.Length; i++)
                        {
                            var info = usersGameInfos[i];
                            var profile = info.Profile;
                            ProfilesCache.UpdateProfilesCache(profile);
                            Database.UsersDBInstance.UpdateProfileData(profile);

                            if (info.Delta != 0)
                            {
                                Task.Delay(5000).ContinueWith(task =>
                                {
                                    switch (info.RatingGameType)
                                    {
                                        case ReatingGameType.Unknown:
                                            break;
                                        case ReatingGameType.Rating1v1:
                                            ChatServer.IrcDaemon.SendToUser(profile.Id, $@"Ваш рейтинг 1v1 изменился на {GetDeltaString(info.Delta)} и сейчас равен {info.Profile.Score1v1}.");
                                            break;
                                        case ReatingGameType.Rating2v2:
                                            ChatServer.IrcDaemon.SendToUser(profile.Id, $@"Ваш рейтинг 2v2 изменился на {GetDeltaString(info.Delta)} и сейчас равен {info.Profile.Score2v2}.");
                                            break;
                                        case ReatingGameType.Rating3v3_4v4:
                                            ChatServer.IrcDaemon.SendToUser(profile.Id, $@"Ваш рейтинг 3v3/4v4 изменился на {GetDeltaString(info.Delta)} и сейчас равен {info.Profile.Score3v3}.");
                                            break;
                                        default:
                                            break;
                                    }
                                });
                            }
                        }

                        Dowstats.UploadGame(dictionary, usersGameInfos, isRateGame);
                    }, CancellationToken.None, TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness, _exclusiveScheduler);

                    goto CONTINUE;
                }
            }
            catch (ObjectDisposedException)
            {
                if (state != null)
                    state.Dispose();
                state = null;
                return;
            }
            catch (SocketException e)
            {
                switch (e.SocketErrorCode)
                {
                    case SocketError.ConnectionReset:
                        if (state != null)
                            state.Dispose();
                        state = null;
                        return;
                    case SocketError.Disconnecting:
                        if (state != null)
                            state.Dispose();
                        state = null;
                        return;
                    default:
                        Logger.Error(e, $"Error receiving data. SocketErrorCode: {e.SocketErrorCode}");
                        if (state != null)
                            state.Dispose();
                        state = null;
                        return;
                }
            }
            catch (Exception e)
            {
                Logger.Error(e, "Error receiving data");
            }

            // and we wait for more data...
            CONTINUE: WaitForData(state);
        }