private void AddFolder(FolderViewModel parent, string[] path, int pathIndex) { FolderViewModel child = parent.Children.FirstOrDefault(f => String.Compare(f.Name, path[pathIndex], StringComparison.OrdinalIgnoreCase) == 0); if (child == null) { child = new FolderViewModel(path[pathIndex], parent); _backgroundWorkerService.InvokeOnUiThread(() => parent.Children.Add(child)); } pathIndex++; if (pathIndex < path.Length) { AddFolder(child, path, pathIndex); } }
private void RefreshFromServer(int gameId, IFileSystemService fileSystemService, IHttpRequestService httpRequestService) { var file = Path.Combine(_settings.DumpDirectory, String.Format("{0}.json", gameId)); if (fileSystemService.FileExists(file)) { bool fileValid = (DateTime.Now - fileSystemService.GetFileLastModified(file)) < TimeSpan.FromHours(16); if (fileValid) { return; } } Debug.WriteLine(String.Format("{0} fetching patch data {1}", DateTime.Now, gameId)); var url = String.Format("http://retroachievements.org/dorequest.php?u={0}&t={1}&g={2}&h=1&r=patch", _settings.UserName, _settings.DoRequestToken, gameId); var request = new HttpRequest(url); var response = httpRequestService.Request(request); if (response.Status == System.Net.HttpStatusCode.OK) { using (var outputStream = fileSystemService.CreateFile(file)) { byte[] buffer = new byte[4096]; using (var stream = response.GetResponseStream()) { int bytesRead; while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0) { if (bytesRead < 100) { var str = Encoding.UTF8.GetString(buffer, 0, bytesRead); if (str.Contains("Error")) { if (_progress != null) { _progress.IsEnabled = false; _progress.Label = String.Empty; } _backgroundWorkerService.InvokeOnUiThread(() => MessageBoxViewModel.ShowMessage(str)); return; } } outputStream.Write(buffer, 0, bytesRead); } } } string contents; using (var stream = new StreamReader(fileSystemService.OpenFile(file, OpenFileMode.Read))) { contents = stream.ReadToEnd(); } } }
private void LoadTickets() { var games = new Dictionary <int, GameTickets>(); var tickets = new Dictionary <int, AchievementTickets>(); int totalTickets = 0; Progress.Reset(25); Progress.Label = "Fetching Open Tickets"; int pageTickets; int page = 0; do { var ticketsPage = RAWebCache.Instance.GetOpenTicketsPage(page); if (ticketsPage == null) { return; } if (page == 0 && !ticketsPage.Contains("<title>Ticket")) { _backgroundWorkerService.InvokeOnUiThread(() => { MessageBoxViewModel.ShowMessage("Could not retrieve open tickets. Please make sure the Cookie value is up to date in your ini file."); Progress.Label = String.Empty; }); var filename = Path.Combine(Path.GetTempPath(), String.Format("raTickets{0}.html", page)); File.Delete(filename); return; } pageTickets = GetPageTickets(games, tickets, ticketsPage); ++page; totalTickets += pageTickets; Progress.Current++; } while (pageTickets == 100); Progress.Label = "Sorting data"; var ticketList = new List <AchievementTickets>(tickets.Count); foreach (var kvp in tickets) { ticketList.Add(kvp.Value); } ticketList.Sort((l, r) => { var diff = r.OpenTickets.Count - l.OpenTickets.Count; if (diff == 0) { diff = String.Compare(l.AchievementName, r.AchievementName, StringComparison.OrdinalIgnoreCase); } return(diff); }); TopAchievements = ticketList; var gameList = new List <GameTickets>(games.Count); foreach (var kvp in games) { gameList.Add(kvp.Value); } gameList.Sort((l, r) => { var diff = r.OpenTickets - l.OpenTickets; if (diff == 0) { diff = String.Compare(l.GameName, r.GameName, StringComparison.OrdinalIgnoreCase); } return(diff); }); TopGames = gameList; OpenTickets = totalTickets; DialogTitle = "Open Tickets: " + totalTickets; Progress.Label = String.Empty; }
private void DoSearch() { var criteria = new SearchCriteria(); ((RangeFilterFieldViewModel)NumConditions).Parse(out criteria.NumConditions, out criteria.NumConditionsComparison); ((RangeFilterFieldViewModel)NumAltGroups).Parse(out criteria.NumAltGroups, out criteria.NumAltGroupsComparison); criteria.Flag = (RequirementType)Flag.SelectedId; criteria.SourceType = (FieldType)SourceType.SelectedId; ((RangeFilterFieldViewModel)SourceValue).Parse(out criteria.SourceValue, out criteria.SourceValueComparison); criteria.Comparison = (RequirementOperator)Comparison.SelectedId; criteria.TargetType = (FieldType)TargetType.SelectedId; ((RangeFilterFieldViewModel)TargetValue).Parse(out criteria.TargetValue, out criteria.TargetValueComparison); ((RangeFilterFieldViewModel)HitCount).Parse(out criteria.HitCount, out criteria.HitCountComparison); var directory = _settings.DumpDirectory; var filesToRead = 0; if (IsCoreAchievementsScanned || IsNonCoreAchievementsScanned) { filesToRead += Snapshot.AchievementGameCount; } if (IsLeaderboardCancelScanned || IsLeaderboardStartScanned || IsLeaderboardSubmitScanned) { filesToRead += Snapshot.LeaderboardGameCount; } if (IsRichPresenceScanned) { filesToRead += Snapshot.RichPresenceCount; } Progress.Reset(filesToRead); Progress.IsEnabled = true; var results = new List <Result>(); if (IsCoreAchievementsScanned || IsNonCoreAchievementsScanned) { Progress.Label = "Processing Achievements..."; foreach (var gameId in Snapshot.GamesWithAchievements) { Progress.Current++; if (!Progress.IsEnabled) { break; } var file = Path.Combine(directory, gameId + ".json"); var contents = File.ReadAllText(file); var json = new Jamiras.IO.Serialization.JsonObject(contents); var patchData = json.GetField("PatchData"); var achievements = patchData.ObjectValue.GetField("Achievements").ObjectArrayValue; if (achievements == null) { continue; } var gameName = patchData.ObjectValue.GetField("Title").StringValue; foreach (var achievement in achievements) { var flags = achievement.GetField("Flags").IntegerValue; if (!IsCoreAchievementsScanned) { if (flags == 3) { continue; } } else if (!IsNonCoreAchievementsScanned) { if (flags != 3) { continue; } } var memAddr = achievement.GetField("MemAddr").StringValue; if (Matches(memAddr, criteria)) { results.Add(new Result { GameId = gameId, GameName = gameName, AchievementId = achievement.GetField("ID").IntegerValue.GetValueOrDefault(), ItemName = achievement.GetField("Title").StringValue, Details = memAddr, IsUnofficial = flags == 5 }); } } } } if (IsLeaderboardStartScanned || IsLeaderboardSubmitScanned || IsLeaderboardCancelScanned) { Progress.Label = "Processing Leaderboards..."; foreach (var gameId in Snapshot.GamesWithLeaderboards) { Progress.Current++; if (!Progress.IsEnabled) { break; } var file = Path.Combine(directory, gameId + ".json"); var contents = File.ReadAllText(file); var json = new Jamiras.IO.Serialization.JsonObject(contents); var patchData = json.GetField("PatchData"); var leaderboards = patchData.ObjectValue.GetField("Leaderboards").ObjectArrayValue; if (leaderboards == null) { continue; } var gameName = patchData.ObjectValue.GetField("Title").StringValue; foreach (var leaderboard in leaderboards) { var details = String.Empty; var token = Token.Empty; var memAddr = leaderboard.GetField("Mem").StringValue; foreach (var part in Tokenizer.Split(memAddr, ':')) { if (part == "STA" && IsLeaderboardStartScanned) { token = part; continue; } if (part == "CAN" && IsLeaderboardCancelScanned) { token = part; continue; } if (part == "SUB" && IsLeaderboardSubmitScanned) { token = part; continue; } if (token.IsEmpty) { continue; } if (Matches(part.ToString(), criteria)) { if (details.Length > 0) { details += ", "; } details += token.ToString(); details += ':'; details += part.ToString(); } token = Token.Empty; } if (details.Length > 0) { results.Add(new Result { GameId = gameId, GameName = gameName, LeaderboardId = leaderboard.GetField("ID").IntegerValue.GetValueOrDefault(), ItemName = "Leaderboard: " + leaderboard.GetField("Title").StringValue, Details = details, }); } } } } if (IsRichPresenceScanned) { Progress.Label = "Processing Rich Presence..."; foreach (var gameId in Snapshot.GamesWithRichPresence) { Progress.Current++; if (!Progress.IsEnabled) { break; } var file = Path.Combine(directory, gameId + ".json"); var contents = File.ReadAllText(file); var json = new Jamiras.IO.Serialization.JsonObject(contents); var patchData = json.GetField("PatchData"); var richPresence = patchData.ObjectValue.GetField("RichPresencePatch").StringValue; if (richPresence != null) { int index = richPresence.IndexOf("Display:"); if (index != -1) { var details = String.Empty; foreach (var line in richPresence.Substring(index).Split('\n')) { if (line.Trim().Length == 0) { break; } if (line.StartsWith("?")) { index = line.IndexOf('?', 1); if (index != -1) { var memAddr = line.Substring(1, index - 1); if (Matches(memAddr, criteria)) { if (details.Length > 0) { details += ", "; } details += '?'; details += memAddr; details += '?'; } } } } if (details.Length > 0) { results.Add(new Result { GameId = gameId, GameName = patchData.ObjectValue.GetField("Title").StringValue, ItemName = "Rich Presence", Details = details, }); } } } } } if (Progress.IsEnabled) { results.Sort((l, r) => { var diff = String.Compare(l.GameName, r.GameName); if (diff == 0) { diff = String.Compare(l.ItemName, r.ItemName); } return(diff); }); _backgroundWorkerService.InvokeOnUiThread(() => { Results.Clear(); foreach (var result in results) { Results.Add(result); } }); Progress.IsEnabled = false; Progress.Label = String.Empty; } }
internal void LoadGameFromServer(string gamePage, List <AchievementStats> achievementStats, List <UserStats> userStats) { NumberOfPlayers = 0; // reset so it gets updated from server data AchievementStats mostWon, leastWon; TotalPoints = LoadAchievementStatsFromServer(gamePage, achievementStats, out mostWon, out leastWon); var masteryPoints = (TotalPoints * 2).ToString(); var masters = GetMastersFromServer(gamePage, masteryPoints); Progress.Label = "Fetching user stats"; Progress.Reset(achievementStats.Count); achievementStats.Sort((l, r) => { var diff = r.EarnedHardcoreBy - l.EarnedHardcoreBy; if (diff == 0) { diff = String.Compare(l.Title, r.Title, StringComparison.OrdinalIgnoreCase); } return(diff); }); var possibleMasters = new List <string>(); var nonHardcoreUsers = new List <string>(); foreach (var achievement in achievementStats) { var achievementPage = RAWebCache.Instance.GetAchievementPage(achievement.Id); if (achievementPage != null) { var 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 { var front = tokenizer.ReadTo("<a href='/user/"); if (tokenizer.NextChar == '\0') { break; } if (front.Contains("<div id=\"rightcontainer\">")) { break; } tokenizer.ReadTo("'>"); tokenizer.Advance(2); // skip user image, we'll get the name from the text 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; if (ReferenceEquals(achievement, leastWon)) { if (!masters.Contains(stats.User)) { possibleMasters.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 == null || mostWon.EarnedBy <= 50) { HardcoreMasteredUserCountEstimated = false; } else { HardcoreMasteredUserCountEstimated = (leastWon.EarnedBy > 50); bool incompleteData = false; possibleMasters.AddRange(masters); Progress.Reset(possibleMasters.Count); foreach (var user in possibleMasters) { Progress.Current++; 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.Achievements.Count >= achievementStats.Count) { continue; } } if (!incompleteData && !MergeUserGameMastery(stats)) { incompleteData = true; } stats.Incomplete = incompleteData; } if (incompleteData) { _backgroundWorkerService.InvokeOnUiThread(() => { var settings = ServiceRepository.Instance.FindService <ISettings>(); if (String.IsNullOrEmpty(settings.ApiKey)) { MessageBoxViewModel.ShowMessage("Data is limited without an ApiKey in the ini file."); } else { MessageBoxViewModel.ShowMessage("Failed to fetch mastery information. Please make sure the ApiKey value is up to date in your ini file."); } }); } } NonHardcoreUserCount = nonHardcoreUsers.Count; WriteGameStats(_gameName, achievementStats, userStats); }