public ScoreInfo CreateScoreInfo(RulesetStore rulesets)
        {
            var ruleset = rulesets.GetRuleset(OnlineRulesetID);

            var mods = Mods != null?ruleset.CreateInstance().GetAllMods().Where(mod => Mods.Contains(mod.Acronym)).ToArray() : Array.Empty <Mod>();

            var scoreInfo = new ScoreInfo
            {
                TotalScore    = TotalScore,
                MaxCombo      = MaxCombo,
                User          = User,
                Accuracy      = Accuracy,
                OnlineScoreID = OnlineScoreID,
                Date          = Date,
                PP            = PP,
                Beatmap       = Beatmap,
                RulesetID     = OnlineRulesetID,
                Hash          = Replay ? "online" : string.Empty, // todo: temporary?
                Rank          = Rank,
                Ruleset       = ruleset,
                Mods          = mods,
                IsLegacyScore = true
            };

            if (Statistics != null)
            {
                foreach (var kvp in Statistics)
                {
                    switch (kvp.Key)
                    {
                    case @"count_geki":
                        scoreInfo.SetCountGeki(kvp.Value);
                        break;

                    case @"count_300":
                        scoreInfo.SetCount300(kvp.Value);
                        break;

                    case @"count_katu":
                        scoreInfo.SetCountKatu(kvp.Value);
                        break;

                    case @"count_100":
                        scoreInfo.SetCount100(kvp.Value);
                        break;

                    case @"count_50":
                        scoreInfo.SetCount50(kvp.Value);
                        break;

                    case @"count_miss":
                        scoreInfo.SetCountMiss(kvp.Value);
                        break;
                    }
                }
            }

            return(scoreInfo);
        }
Example #2
0
        public Score Parse(Stream stream)
        {
            var score = new Score
            {
                Replay = new Replay()
            };

            WorkingBeatmap workingBeatmap;

            using (SerializationReader sr = new SerializationReader(stream))
            {
                currentRuleset = GetRuleset(sr.ReadByte());
                var scoreInfo = new ScoreInfo {
                    Ruleset = currentRuleset.RulesetInfo
                };

                score.ScoreInfo = scoreInfo;

                int version = sr.ReadInt32();

                workingBeatmap = GetBeatmap(sr.ReadString());
                if (workingBeatmap is DummyWorkingBeatmap)
                {
                    throw new BeatmapNotFoundException();
                }

                scoreInfo.User = new APIUser {
                    Username = sr.ReadString()
                };

                // MD5Hash
                sr.ReadString();

                scoreInfo.SetCount300(sr.ReadUInt16());
                scoreInfo.SetCount100(sr.ReadUInt16());
                scoreInfo.SetCount50(sr.ReadUInt16());
                scoreInfo.SetCountGeki(sr.ReadUInt16());
                scoreInfo.SetCountKatu(sr.ReadUInt16());
                scoreInfo.SetCountMiss(sr.ReadUInt16());

                scoreInfo.TotalScore = sr.ReadInt32();
                scoreInfo.MaxCombo   = sr.ReadUInt16();

                /* score.Perfect = */
                sr.ReadBoolean();

                scoreInfo.Mods = currentRuleset.ConvertFromLegacyMods((LegacyMods)sr.ReadInt32()).ToArray();

                // lazer replays get a really high version number.
                if (version < LegacyScoreEncoder.FIRST_LAZER_VERSION)
                {
                    scoreInfo.Mods = scoreInfo.Mods.Append(currentRuleset.CreateMod <ModClassic>()).ToArray();
                }

                currentBeatmap        = workingBeatmap.GetPlayableBeatmap(currentRuleset.RulesetInfo, scoreInfo.Mods);
                scoreInfo.BeatmapInfo = currentBeatmap.BeatmapInfo;

                /* score.HpGraphString = */
                sr.ReadString();

                scoreInfo.Date = sr.ReadDateTime();

                byte[] compressedReplay = sr.ReadByteArray();

                if (version >= 20140721)
                {
                    scoreInfo.OnlineID = sr.ReadInt64();
                }
                else if (version >= 20121008)
                {
                    scoreInfo.OnlineID = sr.ReadInt32();
                }

                if (compressedReplay?.Length > 0)
                {
                    using (var replayInStream = new MemoryStream(compressedReplay))
                    {
                        byte[] properties = new byte[5];
                        if (replayInStream.Read(properties, 0, 5) != 5)
                        {
                            throw new IOException("input .lzma is too short");
                        }

                        long outSize = 0;

                        for (int i = 0; i < 8; i++)
                        {
                            int v = replayInStream.ReadByte();
                            if (v < 0)
                            {
                                throw new IOException("Can't Read 1");
                            }

                            outSize |= (long)(byte)v << (8 * i);
                        }

                        long compressedSize = replayInStream.Length - replayInStream.Position;

                        using (var lzma = new LzmaStream(properties, replayInStream, compressedSize, outSize))
                            using (var reader = new StreamReader(lzma))
                                readLegacyReplay(score.Replay, reader);
                    }
                }
            }

            PopulateAccuracy(score.ScoreInfo);

            // before returning for database import, we must restore the database-sourced BeatmapInfo.
            // if not, the clone operation in GetPlayableBeatmap will cause a dereference and subsequent database exception.
            score.ScoreInfo.BeatmapInfo = workingBeatmap.BeatmapInfo;

            return(score);
        }
Example #3
0
        public ScoreInfo CreateScoreInfo(RulesetStore rulesets)
        {
            var ruleset = rulesets.GetRuleset(OnlineRulesetID);

            var rulesetInstance = ruleset.CreateInstance();

            var mods = Mods != null?Mods.Select(acronym => rulesetInstance.CreateModFromAcronym(acronym)).Where(m => m != null).ToArray() : Array.Empty <Mod>();

            // all API scores provided by this class are considered to be legacy.
            mods = mods.Append(rulesetInstance.CreateMod <ModClassic>()).ToArray();

            var scoreInfo = new ScoreInfo
            {
                TotalScore    = TotalScore,
                MaxCombo      = MaxCombo,
                User          = User,
                Accuracy      = Accuracy,
                OnlineScoreID = OnlineScoreID,
                Date          = Date,
                PP            = PP,
                BeatmapInfo   = BeatmapInfo,
                RulesetID     = OnlineRulesetID,
                Hash          = Replay ? "online" : string.Empty, // todo: temporary?
                Rank          = Rank,
                Ruleset       = ruleset,
                Mods          = mods,
            };

            if (Statistics != null)
            {
                foreach (var kvp in Statistics)
                {
                    switch (kvp.Key)
                    {
                    case @"count_geki":
                        scoreInfo.SetCountGeki(kvp.Value);
                        break;

                    case @"count_300":
                        scoreInfo.SetCount300(kvp.Value);
                        break;

                    case @"count_katu":
                        scoreInfo.SetCountKatu(kvp.Value);
                        break;

                    case @"count_100":
                        scoreInfo.SetCount100(kvp.Value);
                        break;

                    case @"count_50":
                        scoreInfo.SetCount50(kvp.Value);
                        break;

                    case @"count_miss":
                        scoreInfo.SetCountMiss(kvp.Value);
                        break;
                    }
                }
            }

            return(scoreInfo);
        }
Example #4
0
        public override void Execute()
        {
            var displayPlays = new List <UserPlayInfo>();

            var ruleset        = LegacyHelper.GetRulesetFromLegacyID(Ruleset ?? 0);
            var rulesetApiName = LegacyHelper.GetRulesetShortNameFromId(Ruleset ?? 0);

            Console.WriteLine("Getting user data...");
            dynamic userData = GetJsonFromApi($"users/{ProfileName}/{rulesetApiName}");

            Console.WriteLine("Getting user top scores...");

            foreach (var play in GetJsonFromApi($"users/{userData.id}/scores/best?mode={rulesetApiName}&limit=100"))
            {
                var working = ProcessorWorkingBeatmap.FromFileOrId((string)play.beatmap.id);

                var   modsAcronyms = ((JArray)play.mods).Select(x => x.ToString()).ToArray();
                Mod[] mods         = ruleset.CreateAllMods().Where(m => modsAcronyms.Contains(m.Acronym)).ToArray();

                var scoreInfo = new ScoreInfo(working.BeatmapInfo, ruleset.RulesetInfo)
                {
                    TotalScore = play.score,
                    MaxCombo   = play.max_combo,
                    Mods       = mods,
                    Statistics = new Dictionary <HitResult, int>()
                };

                scoreInfo.SetCount300((int)play.statistics.count_300);
                scoreInfo.SetCountGeki((int)play.statistics.count_geki);
                scoreInfo.SetCount100((int)play.statistics.count_100);
                scoreInfo.SetCountKatu((int)play.statistics.count_katu);
                scoreInfo.SetCount50((int)play.statistics.count_50);
                scoreInfo.SetCountMiss((int)play.statistics.count_miss);

                var score = new ProcessorScoreDecoder(working).Parse(scoreInfo);

                var difficultyCalculator  = ruleset.CreateDifficultyCalculator(working);
                var difficultyAttributes  = difficultyCalculator.Calculate(LegacyHelper.ConvertToLegacyDifficultyAdjustmentMods(ruleset, scoreInfo.Mods).ToArray());
                var performanceCalculator = ruleset.CreatePerformanceCalculator();

                var ppAttributes = performanceCalculator?.Calculate(score.ScoreInfo, difficultyAttributes);
                var thisPlay     = new UserPlayInfo
                {
                    Beatmap   = working.BeatmapInfo,
                    LocalPP   = ppAttributes?.Total ?? 0,
                    LivePP    = play.pp,
                    Mods      = scoreInfo.Mods.Select(m => m.Acronym).ToArray(),
                    MissCount = play.statistics.count_miss,
                    Accuracy  = scoreInfo.Accuracy * 100,
                    Combo     = play.max_combo,
                    MaxCombo  = difficultyAttributes.MaxCombo
                };

                displayPlays.Add(thisPlay);
            }

            var localOrdered = displayPlays.OrderByDescending(p => p.LocalPP).ToList();
            var liveOrdered  = displayPlays.OrderByDescending(p => p.LivePP).ToList();

            int    index        = 0;
            double totalLocalPP = localOrdered.Sum(play => Math.Pow(0.95, index++) * play.LocalPP);
            double totalLivePP  = userData.statistics.pp;

            index = 0;
            double nonBonusLivePP = liveOrdered.Sum(play => Math.Pow(0.95, index++) * play.LivePP);

            //todo: implement properly. this is pretty damn wrong.
            var playcountBonusPP = (totalLivePP - nonBonusLivePP);

            totalLocalPP += playcountBonusPP;
            double totalDiffPP = totalLocalPP - totalLivePP;

            if (OutputJson)
            {
                var json = JsonConvert.SerializeObject(new
                {
                    Username    = userData.username,
                    LivePp      = totalLivePP,
                    LocalPp     = totalLocalPP,
                    PlaycountPp = playcountBonusPP,
                    Scores      = localOrdered.Select(item => new
                    {
                        BeatmapId   = item.Beatmap.OnlineID,
                        BeatmapName = item.Beatmap.ToString(),
                        item.Combo,
                        item.Accuracy,
                        item.MissCount,
                        item.Mods,
                        LivePp         = item.LivePP,
                        LocalPp        = item.LocalPP,
                        PositionChange = liveOrdered.IndexOf(item) - localOrdered.IndexOf(item)
                    })
                });

                Console.Write(json);

                if (OutputFile != null)
                {
                    File.WriteAllText(OutputFile, json);
                }
            }
            else
            {
                OutputDocument(new Document(
                                   new Span($"User:     {userData.username}"), "\n",
                                   new Span($"Live PP:  {totalLivePP:F1} (including {playcountBonusPP:F1}pp from playcount)"), "\n",
                                   new Span($"Local PP: {totalLocalPP:F1} ({totalDiffPP:+0.0;-0.0;-})"), "\n",
                                   new Grid
                {
                    Columns =
                    {
                        GridLength.Auto, GridLength.Auto, GridLength.Auto, GridLength.Auto, GridLength.Auto, GridLength.Auto, GridLength.Auto, GridLength.Auto, GridLength.Auto, GridLength.Auto
                    },
                    Children =
                    {
                        new Cell("#"),
                        new Cell("beatmap"),
                        new Cell("max combo"),
                        new Cell("accuracy"),
                        new Cell("misses"),
                        new Cell("mods"),
                        new Cell("live pp"),
                        new Cell("local pp"),
                        new Cell("pp change"),
                        new Cell("position change"),
                        localOrdered.Select(item => new[]
                        {
                            new Cell($"{localOrdered.IndexOf(item) + 1}"),
                            new Cell($"{item.Beatmap.OnlineID} - {item.Beatmap}"),
                            new Cell($"{item.Combo}/{item.MaxCombo}x")
                            {
                                Align = Align.Right
                            },
                            new Cell($"{Math.Round(item.Accuracy, 2)}%")
                            {
                                Align = Align.Right
                            },
                            new Cell($"{item.MissCount}")
                            {
                                Align = Align.Right
                            },
                            new Cell($"{(item.Mods.Length > 0 ? string.Join(", ", item.Mods) : "None")}")
                            {
                                Align = Align.Right
                            },
                            new Cell($"{item.LivePP:F1}")
                            {
                                Align = Align.Right
                            },
                            new Cell($"{item.LocalPP:F1}")
                            {
                                Align = Align.Right
                            },
                            new Cell($"{item.LocalPP - item.LivePP:F1}")
                            {
                                Align = Align.Right
                            },
                            new Cell($"{liveOrdered.IndexOf(item) - localOrdered.IndexOf(item):+0;-0;-}")
                            {
                                Align = Align.Center
                            },
                        })
                    }
                })
                               );
            }
        }
Example #5
0
        public Score Parse(Stream stream)
        {
            var score = new Score
            {
                ScoreInfo = new ScoreInfo(),
                Replay    = new Replay()
            };

            using (SerializationReader sr = new SerializationReader(stream))
            {
                currentRuleset = GetRuleset(sr.ReadByte());
                var scoreInfo = new ScoreInfo {
                    Ruleset = currentRuleset.RulesetInfo
                };

                score.ScoreInfo = scoreInfo;

                var version = sr.ReadInt32();

                var workingBeatmap = GetBeatmap(sr.ReadString());
                if (workingBeatmap is DummyWorkingBeatmap)
                {
                    throw new BeatmapNotFoundException();
                }

                currentBeatmap    = workingBeatmap.Beatmap;
                scoreInfo.Beatmap = currentBeatmap.BeatmapInfo;

                scoreInfo.User = new User {
                    Username = sr.ReadString()
                };

                // MD5Hash
                sr.ReadString();

                scoreInfo.SetCount300(sr.ReadUInt16());
                scoreInfo.SetCount100(sr.ReadUInt16());
                scoreInfo.SetCount50(sr.ReadUInt16());
                scoreInfo.SetCountGeki(sr.ReadUInt16());
                scoreInfo.SetCountKatu(sr.ReadUInt16());
                scoreInfo.SetCountMiss(sr.ReadUInt16());

                scoreInfo.TotalScore = sr.ReadInt32();
                scoreInfo.MaxCombo   = sr.ReadUInt16();

                /* score.Perfect = */
                sr.ReadBoolean();

                scoreInfo.Mods = currentRuleset.ConvertLegacyMods((LegacyMods)sr.ReadInt32()).ToArray();

                /* score.HpGraphString = */
                sr.ReadString();

                scoreInfo.Date = sr.ReadDateTime();

                var compressedReplay = sr.ReadByteArray();

                if (version >= 20140721)
                {
                    scoreInfo.OnlineScoreID = sr.ReadInt64();
                }
                else if (version >= 20121008)
                {
                    scoreInfo.OnlineScoreID = sr.ReadInt32();
                }

                if (scoreInfo.OnlineScoreID <= 0)
                {
                    scoreInfo.OnlineScoreID = null;
                }

                if (compressedReplay?.Length > 0)
                {
                    using (var replayInStream = new MemoryStream(compressedReplay))
                    {
                        byte[] properties = new byte[5];
                        if (replayInStream.Read(properties, 0, 5) != 5)
                        {
                            throw new IOException("input .lzma is too short");
                        }

                        long outSize = 0;

                        for (int i = 0; i < 8; i++)
                        {
                            int v = replayInStream.ReadByte();
                            if (v < 0)
                            {
                                throw new IOException("Can't Read 1");
                            }

                            outSize |= (long)(byte)v << (8 * i);
                        }

                        long compressedSize = replayInStream.Length - replayInStream.Position;

                        using (var lzma = new LzmaStream(properties, replayInStream, compressedSize, outSize))
                            using (var reader = new StreamReader(lzma))
                                readLegacyReplay(score.Replay, reader);
                    }
                }
            }

            CalculateAccuracy(score.ScoreInfo);

            return(score);
        }
Example #6
0
        public override void Execute()
        {
            var rulesetApiName = LegacyHelper.GetRulesetShortNameFromId(Ruleset ?? 0);
            var leaderboard    = GetJsonFromApi($"rankings/{rulesetApiName}/performance?cursor[page]={LeaderboardPage - 1}");

            var calculatedPlayers = new List <LeaderboardPlayerInfo>();

            foreach (var player in leaderboard.ranking)
            {
                if (calculatedPlayers.Count >= Limit)
                {
                    break;
                }

                var plays = new List <(double, double)>(); // (local, live)

                var ruleset = LegacyHelper.GetRulesetFromLegacyID(Ruleset ?? 0);

                Console.WriteLine($"Calculating {player.user.username} top scores...");

                foreach (var play in GetJsonFromApi($"users/{player.user.id}/scores/best?mode={rulesetApiName}&limit=100"))
                {
                    var working = ProcessorWorkingBeatmap.FromFileOrId((string)play.beatmap.id);

                    var   modsAcronyms = ((JArray)play.mods).Select(x => x.ToString()).ToArray();
                    Mod[] mods         = ruleset.CreateAllMods().Where(m => modsAcronyms.Contains(m.Acronym)).ToArray();

                    var scoreInfo = new ScoreInfo(working.BeatmapInfo, ruleset.RulesetInfo)
                    {
                        TotalScore = play.score,
                        MaxCombo   = play.max_combo,
                        Mods       = mods,
                        Statistics = new Dictionary <HitResult, int>()
                    };

                    scoreInfo.SetCount300((int)play.statistics.count_300);
                    scoreInfo.SetCountGeki((int)play.statistics.count_geki);
                    scoreInfo.SetCount100((int)play.statistics.count_100);
                    scoreInfo.SetCountKatu((int)play.statistics.count_katu);
                    scoreInfo.SetCount50((int)play.statistics.count_50);
                    scoreInfo.SetCountMiss((int)play.statistics.count_miss);

                    var score = new ProcessorScoreDecoder(working).Parse(scoreInfo);

                    var difficultyCalculator  = ruleset.CreateDifficultyCalculator(working);
                    var difficultyAttributes  = difficultyCalculator.Calculate(LegacyHelper.ConvertToLegacyDifficultyAdjustmentMods(ruleset, scoreInfo.Mods).ToArray());
                    var performanceCalculator = ruleset.CreatePerformanceCalculator();

                    plays.Add((performanceCalculator?.Calculate(score.ScoreInfo, difficultyAttributes).Total ?? 0, play.pp));
                }

                var localOrdered = plays.Select(x => x.Item1).OrderByDescending(x => x).ToList();
                var liveOrdered  = plays.Select(x => x.Item2).OrderByDescending(x => x).ToList();

                int    index        = 0;
                double totalLocalPP = localOrdered.Sum(play => Math.Pow(0.95, index++) * play);
                double totalLivePP  = player.pp;

                index = 0;
                double nonBonusLivePP = liveOrdered.Sum(play => Math.Pow(0.95, index++) * play);

                //todo: implement properly. this is pretty damn wrong.
                var playcountBonusPP = (totalLivePP - nonBonusLivePP);
                totalLocalPP += playcountBonusPP;

                calculatedPlayers.Add(new LeaderboardPlayerInfo
                {
                    LivePP   = totalLivePP,
                    LocalPP  = totalLocalPP,
                    Username = player.user.username
                });
            }

            calculatedPlayers = calculatedPlayers.OrderByDescending(x => x.LocalPP).ToList();
            var liveOrderedPlayers = calculatedPlayers.OrderByDescending(x => x.LivePP).ToList();

            if (OutputJson)
            {
                var json = JsonConvert.SerializeObject(calculatedPlayers);

                Console.Write(json);

                if (OutputFile != null)
                {
                    File.WriteAllText(OutputFile, json);
                }
            }
            else
            {
                OutputDocument(new Document(
                                   new Grid
                {
                    Columns =
                    {
                        GridLength.Auto, GridLength.Auto, GridLength.Auto, GridLength.Auto, GridLength.Auto
                    },
                    Children =
                    {
                        new Cell("#"),
                        new Cell("username"),
                        new Cell("live pp"),
                        new Cell("local pp"),
                        new Cell("pp change"),
                        calculatedPlayers.Select(item => new[]
                        {
                            new Cell($"{liveOrderedPlayers.IndexOf(item) - calculatedPlayers.IndexOf(item):+0;-0;-}"),
                            new Cell($"{item.Username}"),
                            new Cell($"{item.LivePP:F1}")
                            {
                                Align = Align.Right
                            },
                            new Cell($"{item.LocalPP:F1}")
                            {
                                Align = Align.Right
                            },
                            new Cell($"{item.LocalPP - item.LivePP:F1}")
                            {
                                Align = Align.Right
                            }
                        })
                    }
                })
                               );
            }
        }
Example #7
0
        public override void Execute()
        {
            var displayPlays = new List<UserPlayInfo>();

            var ruleset = LegacyHelper.GetRulesetFromLegacyID(Ruleset ?? 0);

            Console.WriteLine("Getting user data...");
            dynamic userData = getJsonFromApi($"get_user?k={Key}&u={ProfileName}&m={Ruleset}")[0];

            Console.WriteLine("Getting user top scores...");

            foreach (var play in getJsonFromApi($"get_user_best?k={Key}&u={ProfileName}&m={Ruleset}&limit=100"))
            {
                string beatmapID = play.beatmap_id;

                string cachePath = Path.Combine("cache", $"{beatmapID}.osu");

                if (!File.Exists(cachePath))
                {
                    Console.WriteLine($"Downloading {beatmapID}.osu...");
                    new FileWebRequest(cachePath, $"{base_url}/osu/{beatmapID}").Perform();
                }

                Mod[] mods = ruleset.ConvertFromLegacyMods((LegacyMods)play.enabled_mods).ToArray();

                var working = new ProcessorWorkingBeatmap(cachePath, (int)play.beatmap_id);

                var scoreInfo = new ScoreInfo
                {
                    Ruleset = ruleset.RulesetInfo,
                    TotalScore = play.score,
                    MaxCombo = play.maxcombo,
                    Mods = mods,
                    Statistics = new Dictionary<HitResult, int>()
                };

                scoreInfo.SetCount300((int)play.count300);
                scoreInfo.SetCountGeki((int)play.countgeki);
                scoreInfo.SetCount100((int)play.count100);
                scoreInfo.SetCountKatu((int)play.countkatu);
                scoreInfo.SetCount50((int)play.count50);
                scoreInfo.SetCountMiss((int)play.countmiss);

                var score = new ProcessorScoreDecoder(working).Parse(scoreInfo);

                var thisPlay = new UserPlayInfo
                {
                    Beatmap = working.BeatmapInfo,
                    LocalPP = ruleset.CreatePerformanceCalculator(working, score.ScoreInfo).Calculate(),
                    LivePP = play.pp,
                    Mods = mods.Length > 0 ? mods.Select(m => m.Acronym).Aggregate((c, n) => $"{c}, {n}") : "None"
                };

                displayPlays.Add(thisPlay);
            }

            var localOrdered = displayPlays.OrderByDescending(p => p.LocalPP).ToList();
            var liveOrdered = displayPlays.OrderByDescending(p => p.LivePP).ToList();

            int index = 0;
            double totalLocalPP = localOrdered.Sum(play => Math.Pow(0.95, index++) * play.LocalPP);
            double totalLivePP = userData.pp_raw;

            index = 0;
            double nonBonusLivePP = liveOrdered.Sum(play => Math.Pow(0.95, index++) * play.LivePP);

            //todo: implement properly. this is pretty damn wrong.
            var playcountBonusPP = (totalLivePP - nonBonusLivePP);
            totalLocalPP += playcountBonusPP;
            double totalDiffPP = totalLocalPP - totalLivePP;

            OutputDocument(new Document(
                new Span($"User:     {userData.username}"), "\n",
                new Span($"Live PP:  {totalLivePP:F1} (including {playcountBonusPP:F1}pp from playcount)"), "\n",
                new Span($"Local PP: {totalLocalPP:F1} ({totalDiffPP:+0.0;-0.0;-})"), "\n",
                new Grid
                {
                    Columns = { GridLength.Auto, GridLength.Auto, GridLength.Auto, GridLength.Auto, GridLength.Auto },
                    Children =
                    {
                        new Cell("beatmap"),
                        new Cell("live pp"),
                        new Cell("local pp"),
                        new Cell("pp change"),
                        new Cell("position change"),
                        localOrdered.Select(item => new[]
                        {
                            new Cell($"{item.Beatmap.OnlineBeatmapID} - {item.Beatmap}"),
                            new Cell($"{item.LivePP:F1}") { Align = Align.Right },
                            new Cell($"{item.LocalPP:F1}") { Align = Align.Right },
                            new Cell($"{item.LocalPP - item.LivePP:F1}") { Align = Align.Right },
                            new Cell($"{liveOrdered.IndexOf(item) - localOrdered.IndexOf(item):+0;-0;-}") { Align = Align.Center },
                        })
                    }
                }
            ));
        }
Example #8
0
        public override void Execute()
        {
            var displayPlays = new List <UserPlayInfo>();

            var ruleset = LegacyHelper.GetRulesetFromLegacyID(Ruleset ?? 0);

            Console.WriteLine("Getting user data...");
            dynamic userData = getJsonFromApi($"get_user?k={Key}&u={ProfileName}&m={Ruleset}")[0];

            Console.WriteLine("Getting user top scores...");

            foreach (var play in getJsonFromApi($"get_user_best?k={Key}&u={ProfileName}&m={Ruleset}&limit=100"))
            {
                string beatmapID = play.beatmap_id;
                string cachePath = Path.Combine("cache", $"{beatmapID}.osu");

                if (!File.Exists(cachePath))
                {
                    Console.WriteLine($"Downloading {beatmapID}.osu...");
                    new FileWebRequest(cachePath, $"{base_url}/osu/{beatmapID}").Perform();
                }

                var working   = new ProcessorWorkingBeatmap(cachePath, (int)play.beatmap_id);
                var scoreInfo = new ScoreInfo
                {
                    Ruleset    = ruleset.RulesetInfo,
                    TotalScore = play.score,
                    MaxCombo   = play.maxcombo,
                    Mods       = ruleset.ConvertFromLegacyMods((LegacyMods)play.enabled_mods).ToArray(),
                    Statistics = new Dictionary <HitResult, int>()
                };

                scoreInfo.SetCount300((int)play.count300);
                scoreInfo.SetCountGeki((int)play.countgeki);
                scoreInfo.SetCount100((int)play.count100);
                scoreInfo.SetCountKatu((int)play.countkatu);
                scoreInfo.SetCount50((int)play.count50);
                scoreInfo.SetCountMiss((int)play.countmiss);

                var score = new ProcessorScoreDecoder(working).Parse(scoreInfo);

                var difficultyCalculator  = ruleset.CreateDifficultyCalculator(working);
                var difficultyAttributes  = difficultyCalculator.Calculate(LegacyHelper.TrimNonDifficultyAdjustmentMods(ruleset, scoreInfo.Mods).ToArray());
                var performanceCalculator = ruleset.CreatePerformanceCalculator(difficultyAttributes, score.ScoreInfo);

                var categories = new Dictionary <string, double>();
                var localPP    = performanceCalculator.Calculate(categories);
                var thisPlay   = new UserPlayInfo
                {
                    Beatmap   = working.BeatmapInfo,
                    LocalPP   = localPP,
                    LivePP    = play.pp,
                    Mods      = scoreInfo.Mods.Select(m => m.Acronym).ToArray(),
                    MissCount = play.countmiss,
                    Accuracy  = scoreInfo.Accuracy * 100,
                    Combo     = play.maxcombo,
                    MaxCombo  = (int)categories.GetValueOrDefault("Max Combo")
                };

                displayPlays.Add(thisPlay);
            }

            var localOrdered = displayPlays.OrderByDescending(p => p.LocalPP).ToList();
            var liveOrdered  = displayPlays.OrderByDescending(p => p.LivePP).ToList();

            int    index        = 0;
            double totalLocalPP = localOrdered.Sum(play => Math.Pow(0.95, index++) * play.LocalPP);
            double totalLivePP  = userData.pp_raw;

            index = 0;
            double nonBonusLivePP = liveOrdered.Sum(play => Math.Pow(0.95, index++) * play.LivePP);

            //todo: implement properly. this is pretty damn wrong.
            var playcountBonusPP = (totalLivePP - nonBonusLivePP);

            totalLocalPP += playcountBonusPP;
            double totalDiffPP = totalLocalPP - totalLivePP;

            if (OutputJson)
            {
                var json = JsonConvert.SerializeObject(new
                {
                    Username    = userData.username,
                    LivePp      = totalLivePP,
                    LocalPp     = totalLocalPP,
                    PlaycountPp = playcountBonusPP,
                    Scores      = localOrdered.Select(item => new
                    {
                        BeatmapId   = item.Beatmap.OnlineBeatmapID,
                        BeatmapName = item.Beatmap.ToString(),
                        item.Combo,
                        item.Accuracy,
                        item.MissCount,
                        item.Mods,
                        LivePp         = item.LivePP,
                        LocalPp        = item.LocalPP,
                        PositionChange = liveOrdered.IndexOf(item) - localOrdered.IndexOf(item)
                    })
                });

                Console.Write(json);

                if (OutputFile != null)
                {
                    File.WriteAllText(OutputFile, json);
                }
            }
            else
            {
                OutputDocument(new Document(
                                   new Span($"User:     {userData.username}"), "\n",
                                   new Span($"Live PP:  {totalLivePP:F1} (including {playcountBonusPP:F1}pp from playcount)"), "\n",
                                   new Span($"Local PP: {totalLocalPP:F1} ({totalDiffPP:+0.0;-0.0;-})"), "\n",
                                   new Grid
                {
                    Columns  = { GridLength.Auto, GridLength.Auto, GridLength.Auto, GridLength.Auto, GridLength.Auto, GridLength.Auto, GridLength.Auto, GridLength.Auto, GridLength.Auto, GridLength.Auto },
                    Children =
                    {
                        new Cell("#"),
                        new Cell("beatmap"),
                        new Cell("max combo"),
                        new Cell("accuracy"),
                        new Cell("misses"),
                        new Cell("mods"),
                        new Cell("live pp"),
                        new Cell("local pp"),
                        new Cell("pp change"),
                        new Cell("position change"),
                        localOrdered.Select(item => new[]
                        {
                            new Cell($"{localOrdered.IndexOf(item) + 1}"),
                            new Cell($"{item.Beatmap.OnlineBeatmapID} - {item.Beatmap}"),
                            new Cell($"{item.Combo}/{item.MaxCombo}x")
                            {
                                Align = Align.Right
                            },
                            new Cell($"{Math.Round(item.Accuracy, 2)}%")
                            {
                                Align = Align.Right
                            },
                            new Cell($"{item.MissCount}")
                            {
                                Align = Align.Right
                            },
                            new Cell($"{(item.Mods.Length > 0 ? string.Join(", ", item.Mods) : "None")}")
                            {
                                Align = Align.Right
                            },
                            new Cell($"{item.LivePP:F1}")
                            {
                                Align = Align.Right
                            },
                            new Cell($"{item.LocalPP:F1}")
                            {
                                Align = Align.Right
                            },
                            new Cell($"{item.LocalPP - item.LivePP:F1}")
                            {
                                Align = Align.Right
                            },
                            new Cell($"{liveOrdered.IndexOf(item) - localOrdered.IndexOf(item):+0;-0;-}")
                            {
                                Align = Align.Center
                            },
                        })
                    }
                })
                               );
            }
        }