Ejemplo n.º 1
0
        private int LoadAchievementStatsFromServer(string gamePage, List <AchievementStats> allStats, out AchievementStats mostWon, out AchievementStats leastWon)
        {
            int totalPoints = 0;

            var tokenizer = Tokenizer.CreateTokenizer(gamePage);

            tokenizer.ReadTo("<title>");
            if (tokenizer.Match("<title>"))
            {
                var title       = tokenizer.ReadTo("</title>");
                var titleString = title.ToString();
                var index       = title.IndexOf("RetroAchievements", StringComparison.OrdinalIgnoreCase);
                if (index != -1)
                {
                    var length = 17;
                    if (index > 3 && title.SubToken(index - 3, 3) == " - ")
                    {
                        index  -= 3;
                        length += 3;
                    }

                    if (index + length < title.Length - 4 && title.SubToken(index + length, 4) == ".org")
                    {
                        length += 4;
                    }

                    if (index + length < title.Length - 3 && title.SubToken(index + length, 3) == " - ")
                    {
                        length += 3;
                    }

                    titleString = titleString.Substring(0, index) + titleString.Substring(index + length);
                }

                _gameName = titleString;
            }

            mostWon     = null;
            leastWon    = null;
            totalPoints = 0;
            do
            {
                tokenizer.ReadTo("<div class='achievemententry'>");
                if (tokenizer.NextChar == '\0')
                {
                    break;
                }

                AchievementStats stats = new AchievementStats();

                tokenizer.ReadTo("won by ");
                tokenizer.Advance(7);
                if (tokenizer.NextChar != '-') // ignore buggy value "won by -200 (300) of 400"
                {
                    var winners = tokenizer.ReadNumber();
                    stats.EarnedBy = Int32.Parse(winners.ToString());
                }

                if (stats.EarnedBy > 0)
                {
                    tokenizer.SkipWhitespace();

                    if (tokenizer.NextChar == '<')
                    {
                        tokenizer.ReadTo('>');
                        tokenizer.Advance();
                        tokenizer.SkipWhitespace();
                    }

                    if (tokenizer.NextChar == '(')
                    {
                        tokenizer.Advance();
                        var hardcoreWinners = tokenizer.ReadNumber();
                        stats.EarnedHardcoreBy = Int32.Parse(hardcoreWinners.ToString());
                    }
                }

                if (NumberOfPlayers == 0)
                {
                    tokenizer.ReadTo("of ");
                    tokenizer.Advance(3);
                    var players = tokenizer.ReadNumber();
                    NumberOfPlayers = Int32.Parse(players.ToString());
                }

                tokenizer.ReadTo("<a href='/achievement/");
                if (tokenizer.Match("<a href='/achievement/"))
                {
                    var achievementId = tokenizer.ReadTo("'>");
                    stats.Id = Int32.Parse(achievementId.ToString());
                    tokenizer.Advance(2);

                    var   achievementTitle  = tokenizer.ReadTo("</a>").TrimRight();
                    Token achievementPoints = Token.Empty;
                    if (achievementTitle.EndsWith(")"))
                    {
                        for (int i = achievementTitle.Length - 1; i >= 0; i--)
                        {
                            if (achievementTitle[i] == '(')
                            {
                                achievementPoints = achievementTitle.SubToken(i + 1, achievementTitle.Length - i - 2);
                                achievementTitle  = achievementTitle.SubToken(0, i);
                                break;
                            }
                        }
                    }

                    stats.Title = achievementTitle.TrimRight().ToString();

                    int points;
                    if (Int32.TryParse(achievementPoints.ToString(), out points))
                    {
                        stats.Points = points;
                    }

                    tokenizer.ReadTo("<br>");
                    tokenizer.Advance(4);
                    var achievementDescription = tokenizer.ReadTo("<br>");
                    stats.Description = achievementDescription.Trim().ToString();
                }

                allStats.Add(stats);
                totalPoints += stats.Points;

                if (mostWon == null)
                {
                    mostWon = leastWon = stats;
                }
                else
                {
                    if (stats.EarnedHardcoreBy > mostWon.EarnedHardcoreBy)
                    {
                        mostWon = stats;
                    }
                    else if (stats.EarnedHardcoreBy == mostWon.EarnedHardcoreBy && stats.EarnedBy > mostWon.EarnedBy)
                    {
                        mostWon = stats;
                    }

                    if (stats.EarnedHardcoreBy < leastWon.EarnedHardcoreBy)
                    {
                        leastWon = stats;
                    }
                    else if (stats.EarnedHardcoreBy == leastWon.EarnedHardcoreBy && stats.EarnedBy < leastWon.EarnedBy)
                    {
                        leastWon = stats;
                    }
                }
            } while (true);

            return(totalPoints);
        }
Ejemplo n.º 2
0
        internal void LoadGame()
        {
            var gamePage = RAWebCache.Instance.GetGamePage(GameId);

            if (gamePage == null)
            {
                return;
            }

            var tokenizer = Tokenizer.CreateTokenizer(gamePage);

            tokenizer.ReadTo("<title>");
            if (tokenizer.Match("<title>"))
            {
                var title       = tokenizer.ReadTo("</title>");
                var titleString = title.ToString();
                var index       = title.IndexOf("RetroAchievements", StringComparison.OrdinalIgnoreCase);
                if (index != -1)
                {
                    var length = 17;
                    if (index > 3 && title.SubToken(index - 3, 3) == " - ")
                    {
                        index  -= 3;
                        length += 3;
                    }

                    if (index + length < title.Length - 4 && title.SubToken(index + length, 4) == ".org")
                    {
                        length += 4;
                    }

                    if (index + length < title.Length - 3 && title.SubToken(index + length, 3) == " - ")
                    {
                        length += 3;
                    }

                    titleString = titleString.Substring(0, index) + titleString.Substring(index + length);
                }

                DialogTitle = "Game Stats - " + titleString;
            }

            AchievementStats mostWon  = null;
            AchievementStats leastWon = null;
            var totalPoints           = 0;

            var allStats = new List <AchievementStats>();

            do
            {
                tokenizer.ReadTo("<div class='achievemententry'>");
                if (tokenizer.NextChar == '\0')
                {
                    break;
                }

                AchievementStats stats = new AchievementStats();

                tokenizer.ReadTo("won by ");
                tokenizer.Advance(7);
                var winners = tokenizer.ReadNumber();
                stats.EarnedBy = Int32.Parse(winners.ToString());

                if (stats.EarnedBy > 0)
                {
                    tokenizer.SkipWhitespace();
                    if (tokenizer.NextChar == '(')
                    {
                        tokenizer.Advance();
                        var hardcoreWinners = tokenizer.ReadNumber();
                        stats.EarnedHardcoreBy = Int32.Parse(hardcoreWinners.ToString());
                    }
                }

                if (NumberOfPlayers == 0)
                {
                    tokenizer.ReadTo("of ");
                    tokenizer.Advance(3);
                    var players = tokenizer.ReadNumber();
                    NumberOfPlayers = Int32.Parse(players.ToString());
                }

                tokenizer.ReadTo("<a href='/Achievement/");
                if (tokenizer.Match("<a href='/Achievement/"))
                {
                    var achievementId = tokenizer.ReadTo("'>");
                    stats.Id = Int32.Parse(achievementId.ToString());
                    tokenizer.Advance(2);

                    var   achievementTitle  = tokenizer.ReadTo("</a>");
                    Token achievementPoints = Token.Empty;
                    for (int i = achievementTitle.Length - 1; i >= 0; i--)
                    {
                        if (achievementTitle[i] == '(')
                        {
                            achievementPoints = achievementTitle.SubToken(i + 1, achievementTitle.Length - i - 2);
                            achievementTitle  = achievementTitle.SubToken(0, i);
                            break;
                        }
                    }

                    stats.Title  = achievementTitle.ToString();
                    stats.Points = Int32.Parse(achievementPoints.ToString());
                }

                allStats.Add(stats);
                totalPoints += stats.Points;

                if (mostWon == null)
                {
                    mostWon = leastWon = stats;
                }
                else
                {
                    if (stats.EarnedHardcoreBy > mostWon.EarnedHardcoreBy)
                    {
                        mostWon = stats;
                    }
                    else if (stats.EarnedHardcoreBy == mostWon.EarnedHardcoreBy && stats.EarnedBy > mostWon.EarnedBy)
                    {
                        mostWon = stats;
                    }

                    if (stats.EarnedHardcoreBy < leastWon.EarnedHardcoreBy)
                    {
                        leastWon = stats;
                    }
                    else if (stats.EarnedHardcoreBy == leastWon.EarnedHardcoreBy && stats.EarnedBy < leastWon.EarnedBy)
                    {
                        leastWon = stats;
                    }
                }
            } while (true);

            var masteryPoints = (totalPoints * 2).ToString();

            TotalPoints = totalPoints;

            var masters = new List <string>();

            tokenizer = Tokenizer.CreateTokenizer(gamePage);
            tokenizer.ReadTo("<h3>High Scores</h3>");
            do
            {
                tokenizer.ReadTo("<td class='user'>");
                if (tokenizer.NextChar == '\0')
                {
                    break;
                }

                tokenizer.ReadTo("<a href='");
                tokenizer.ReadTo('>');
                tokenizer.Advance();

                var userName = tokenizer.ReadTo('<');

                tokenizer.ReadTo("<span");
                tokenizer.ReadTo('>');
                tokenizer.Advance();

                var points = tokenizer.ReadTo('<');
                if (points != masteryPoints)
                {
                    break;
                }

                masters.Add(userName.ToString());
            } while (true);

            Progress.Label = "Fetching user stats";
            Progress.Reset(allStats.Count);

            allStats.Sort((l, r) =>
            {
                var diff = r.EarnedHardcoreBy - l.EarnedHardcoreBy;
                if (diff == 0)
                {
                    diff = String.Compare(l.Title, r.Title, StringComparison.OrdinalIgnoreCase);
                }

                return(diff);
            });

            Achievements = allStats;

            var nonHardcoreUsers = new List <string>();
            var userStats        = new List <UserStats>();

            foreach (var achievement in allStats)
            {
                var achievementPage = RAWebCache.Instance.GetAchievementPage(achievement.Id);
                if (achievementPage != null)
                {
                    tokenizer = Tokenizer.CreateTokenizer(achievementPage);
                    tokenizer.ReadTo("<h3>Winners</h3>");

                    // NOTE: this only lists the ~50 most recent unlocks! For games with more than 50 users who have mastered it, the oldest may be missed!
                    do
                    {
                        tokenizer.ReadTo("<a href='/User/");
                        if (tokenizer.NextChar == '\0')
                        {
                            break;
                        }

                        tokenizer.ReadTo("'>");
                        tokenizer.Advance(2);
                        var user = tokenizer.ReadTo("</a>");
                        if (user.StartsWith("<img"))
                        {
                            continue;
                        }

                        var mid = tokenizer.ReadTo("<small>");
                        if (mid.Contains("Hardcore!"))
                        {
                            tokenizer.Advance(7);
                            var when = tokenizer.ReadTo("</small>");
                            var date = DateTime.Parse(when.ToString());
                            date = DateTime.SpecifyKind(date, DateTimeKind.Utc);

                            var stats = new UserStats {
                                User = user.ToString()
                            };
                            var index = userStats.BinarySearch(stats, stats);
                            if (index < 0)
                            {
                                userStats.Insert(~index, stats);
                            }
                            else
                            {
                                stats = userStats[index];
                            }

                            stats.Achievements[achievement.Id] = date;
                            stats.PointsEarned += achievement.Points;

                            if (ReferenceEquals(achievement, leastWon))
                            {
                                if (!masters.Contains(stats.User))
                                {
                                    masters.Add(stats.User);
                                }
                            }
                        }
                        else
                        {
                            if (!nonHardcoreUsers.Contains(user.ToString()))
                            {
                                nonHardcoreUsers.Add(user.ToString());
                            }
                        }
                    } while (true);
                }

                Progress.Current++;
            }

            // if more than 50 people have earned achievements, people who mastered the game early may no longer display
            // in the individual pages. fetch mastery data by user
            if (mostWon.EarnedBy > 50)
            {
                HardcoreMasteredUserCountEstimated = (leastWon.EarnedBy > 50);

                Progress.Reset(masters.Count);
                foreach (var user in masters)
                {
                    Progress.Current++;

                    var masteryJson = RAWebCache.Instance.GetUserGameMasteryJson(user, GameId);
                    if (masteryJson == null) // not able to get - probably not logged in. don't try other users
                    {
                        break;
                    }

                    var stats = new UserStats {
                        User = user
                    };
                    var index = userStats.BinarySearch(stats, stats);
                    if (index < 0)
                    {
                        userStats.Insert(~index, stats);
                    }
                    else
                    {
                        stats = userStats[index];
                    }

                    if (stats.PointsEarned == totalPoints)
                    {
                        continue;
                    }

                    var achievements = masteryJson.GetField("achievements").ObjectValue;
                    foreach (var achievement in achievements)
                    {
                        var id = Int32.Parse(achievement.FieldName);
                        if (!stats.Achievements.ContainsKey(id))
                        {
                            var dateField = achievement.ObjectValue.GetField("DateEarnedHardcore");
                            if (dateField.Type != Jamiras.IO.Serialization.JsonFieldType.String)
                            {
                                dateField = achievement.ObjectValue.GetField("DateEarned");
                            }

                            if (dateField.Type == Jamiras.IO.Serialization.JsonFieldType.String)
                            {
                                var date = DateTime.Parse(dateField.StringValue);
                                date = DateTime.SpecifyKind(date, DateTimeKind.Utc);
                                stats.Achievements[id] = date;
                                stats.PointsEarned    += Int32.Parse(achievement.ObjectValue.GetField("Points").StringValue);
                            }
                        }
                    }
                }
            }
            else
            {
                HardcoreMasteredUserCountEstimated = false;
            }

            Progress.Label = "Analyzing data";

            var sessions = new List <int>(userStats.Count);
            var days     = new List <int>(userStats.Count);
            var idleTime = TimeSpan.FromHours(4);

            foreach (var user in userStats)
            {
                var times = new List <DateTime>(user.Achievements.Count);
                foreach (var achievement in user.Achievements)
                {
                    times.Add(achievement.Value);
                }

                times.Sort((l, r) => (int)((l - r).TotalSeconds));

                user.RealTime = times[times.Count - 1] - times[0];

                int start = 0, end = 0;
                while (end < times.Count)
                {
                    if (end + 1 == times.Count || (times[end + 1] - times[end]) >= idleTime)
                    {
                        user.Sessions++;
                        user.GameTime += times[end] - times[start];
                        start          = end + 1;
                    }

                    end++;
                }

                // assume every achievement took roughly the same amount of time to earn. divide the user's total known playtime
                // by the number of achievements they've earned to get the approximate time per achievement earned. add this value
                // to each session to account for time played before getting the first achievement of the session and time played
                // after gettin the last achievement of the session.
                double perSessionAdjustment = user.GameTime.TotalSeconds / user.Achievements.Count;
                user.GameTime += TimeSpan.FromSeconds(user.Sessions * perSessionAdjustment);

                if (user.PointsEarned == totalPoints)
                {
                    sessions.Add(user.Sessions);
                    days.Add((int)Math.Ceiling(user.RealTime.TotalDays));
                }
            }

            userStats.Sort((l, r) =>
            {
                var diff = r.PointsEarned - l.PointsEarned;
                if (diff == 0)
                {
                    diff = (int)((l.GameTime - r.GameTime).TotalSeconds);
                }

                return(diff);
            });

            HardcoreUserCount       = userStats.Count;
            NonHardcoreUserCount    = nonHardcoreUsers.Count;
            MedianHardcoreUserScore = userStats.Count > 0 ? userStats[userStats.Count / 2].PointsEarned : 0;

            int masteredCount = sessions.Count;

            if (masteredCount > 0)
            {
                HardcoreMasteredUserCount = masteredCount;
                var timeToMaster = masteredCount > 0 ? userStats[masteredCount / 2].Summary : "n/a";
                var space        = timeToMaster.IndexOf(' ');
                if (space > 0)
                {
                    timeToMaster = timeToMaster.Substring(0, space);
                }
                MedianTimeToMaster = timeToMaster;

                sessions.Sort();
                MedianSessionsToMaster = sessions[masteredCount / 2].ToString();

                days.Sort();
                MedianDaysToMaster = days[masteredCount / 2].ToString();
            }

            if (userStats.Count > 100)
            {
                userStats.RemoveRange(100, userStats.Count - 100);
            }

            TopUsers = userStats;

            Progress.Label = String.Empty;
        }
Ejemplo n.º 3
0
        private bool LoadGameFromFile(List <AchievementStats> achievementStats, List <UserStats> userStats, bool allowOldData)
        {
            var file = Path.Combine(_settings.DumpDirectory, GameId + ".txt");

            if (!_fileSystem.FileExists(file))
            {
                return(false);
            }

            TotalPoints = 0;
            using (var reader = new StreamReader(_fileSystem.OpenFile(file, OpenFileMode.Read)))
            {
                while (!reader.EndOfStream)
                {
                    var line = reader.ReadLine();
                    if (line.StartsWith("NonHardCoreCaptured="))
                    {
                        NonHardcoreUserCount = Int32.Parse(line.Substring(20));
                        continue;
                    }

                    if (line.StartsWith("NumberOfPlayers="))
                    {
                        NumberOfPlayers = Int32.Parse(line.Substring(16));
                        continue;
                    }

                    if (line.StartsWith("Game="))
                    {
                        _gameName = line.Substring(5);
                        continue;
                    }

                    if (line.StartsWith("Achievement:"))
                    {
                        var stats = new AchievementStats();
                        var index = line.IndexOf(';');
                        var parts = line.Substring(0, index).Split(':', '=', '/');
                        stats.Id = Int32.Parse(parts[1]);
                        stats.EarnedHardcoreBy = Int32.Parse(parts[2]);
                        stats.EarnedBy         = Int32.Parse(parts[3]);
                        stats.Points           = Int32.Parse(parts[4]);
                        stats.Title            = line.Substring(index + 1);

                        achievementStats.Add(stats);
                        TotalPoints += stats.Points;

                        while (!reader.EndOfStream)
                        {
                            line = reader.ReadLine();
                            if (line.Length < 1)
                            {
                                break;
                            }

                            parts = line.Split('@');

                            var user = new UserStats {
                                User = parts[0]
                            };
                            index = userStats.BinarySearch(user, user);
                            if (index < 0)
                            {
                                userStats.Insert(~index, user);
                            }
                            else
                            {
                                user = userStats[index];
                            }

                            user.Achievements[stats.Id] = DateTime.Parse(parts[1]);
                        }
                    }
                }
            }

            return(true);
        }