예제 #1
0
        public static Score FromDb(DbScore dbScore, RankedStatus status, DbScore[] scores = null)
        {
            var score = new Score
            {
                ScoreId           = dbScore.Id,
                User              = Base.UserCache[dbScore.UserId],
                Date              = dbScore.Date,
                UserId            = dbScore.UserId,
                FileChecksum      = dbScore.FileChecksum,
                ReplayChecksum    = dbScore.ReplayChecksum,
                TotalScore        = dbScore.TotalScore,
                PerformancePoints = dbScore.PerformancePoints,
                MaxCombo          = dbScore.MaxCombo,
                Count50           = dbScore.Count50,
                Count100          = dbScore.Count100,
                Count300          = dbScore.Count300,
                CountMiss         = dbScore.CountMiss,
                CountKatu         = dbScore.CountKatu,
                CountGeki         = dbScore.CountGeki,
                Perfect           = dbScore.Perfect,
                Mods              = dbScore.Mods
            };

            score.Relaxing = (score.Mods & Mods.Relax) != 0;
            score.CalculateLeaderboardRank(scores, status);

            return(score);
        }
예제 #2
0
        /// <summary>
        /// Check if User has Obtained an achievement on this Score Submission
        /// </summary>
        /// <param name="factory">Context Factory</param>
        /// <param name="user">Who tries to Obtain</param>
        /// <param name="score">Submitted Score</param>
        /// <param name="map">Beatmap</param>
        /// <param name="set">Beatmap Set</param>
        /// <param name="oldLb">Old LeaderBoard</param>
        /// <param name="newLb">New LeaderBoard</param>
        /// <returns>Obtained Achievements</returns>
        public static string ProcessAchievements(SoraDbContext ctx,
                                                 DbUser user,
                                                 DbScore score,
                                                 Beatmap map,
                                                 BeatmapSet set,
                                                 DbLeaderboard oldLb,
                                                 DbLeaderboard newLb
                                                 )
        {
            var l = new List <Achievement>();

            /*
             * if ((int) newLB.PerformancePointsOsu == 4914)
             * {
             *  var ach = DBAchievement.GetAchievement(factory, "oog");
             *  if (!user.AlreadyOptainedAchievement(ach))
             *      _l.Add(ach);
             * }
             */

            // Insert custom achievements here. I'll implement a Plugin System later! but this will work for now.


            // END OF CUSTOM ACHIEVEMENTS

            var retVal = l.Aggregate("", (current, ach) => current + ach.ToOsuString() + "/");

            retVal.TrimEnd('/');

            return(retVal);
        }
예제 #3
0
파일: Replay.cs 프로젝트: Mempler/Sora
        public async Task <IActionResult> GetReplay(
            [FromQuery(Name = "c")] int replayId,
            [FromQuery(Name = "m")] PlayMode mode,
            [FromQuery(Name = "u")] string userName,
            [FromQuery(Name = "h")] string pass,
            [FromServices] SoraDbContext ctx
            )
        {
            var user = await DbUser.GetDbUser(ctx, userName);

            if (user == null)
            {
                return(Ok("err: pass"));
            }

            if (!user.IsPassword(pass))
            {
                return(Ok("err: pass"));
            }

            var s = await DbScore.GetScore(ctx, replayId);

            if (s == null)
            {
                return(NotFound());
            }

            return(File(System.IO.File.OpenRead("data/replays/" + s.ReplayMd5), "binary/octet-stream", s.ReplayMd5));
        }
예제 #4
0
        public static async Task <(bool Pass, DbScore score)> ParseScore(SoraDbContext ctx, string encScore, string iv,
                                                                         string osuVersion)
        {
            var decryptedScore = Crypto.DecryptString(
                Convert.FromBase64String(encScore),
                Encoding.ASCII.GetBytes(string.Format(PRIVATE_KEY, osuVersion)),
                Convert.FromBase64String(iv)
                );

            var x     = decryptedScore.Split(':');
            var score = new DbScore
            {
                FileMd5    = x[0],
                ScoreOwner = await DbUser.GetDbUser(ctx, x[1]),
                Count300   = int.Parse(x[3]),
                Count100   = int.Parse(x[4]),
                Count50    = int.Parse(x[5]),
                CountGeki  = int.Parse(x[6]),
                CountKatu  = int.Parse(x[7]),
                CountMiss  = int.Parse(x[8]),
                TotalScore = int.Parse(x[9]),
                MaxCombo   = short.Parse(x[10]),
                Mods       = (Mod)uint.Parse(x[13]),
                PlayMode   = (PlayMode)byte.Parse(x[15]),
                Date       = DateTime.Now,
            };

            score.UserId = score.ScoreOwner?.Id ?? 0;

            return(bool.Parse(x[14]), score);
        }
예제 #5
0
        public static string CalculateRank(DbScore score)
        {
            var tHits    = score.Count50 + score.Count100 + score.Count300 + score.CountMiss;
            var ratio300 = (float)score.Count300 / tHits;
            var ratio50  = (float)score.Count50 / tHits;

            if (ratio300 == 1)
            {
                return((score.Mods & Mods.Hidden) > 0 ||
                       (score.Mods & Mods.Flashlight) > 0
                    ? "SSHD"
                    : "SS");
            }
            if (ratio300 > 0.9 && ratio50 <= 0.01 && score.CountMiss == 0)
            {
                return((score.Mods & Mods.Hidden) > 0 ||
                       (score.Mods & Mods.Flashlight) > 0
                    ? "SHD"
                    : "S");
            }
            if (ratio300 > 0.8 && score.CountMiss == 0 || ratio300 > 0.9)
            {
                return("A");
            }
            if (ratio300 > 0.7 && score.CountMiss == 0 || ratio300 > 0.8)
            {
                return("B");
            }
            return(ratio300 > 0.6 ? "C" : "D");
        }
예제 #6
0
        public DbUser RegisterUser(string username, string email, string pass)
        {
            PassHashingService phs = new PassHashingService();

            string salt         = phs.Salt();
            string passwordToDb = phs.HashedPass(pass, salt);

            using (var ctx = new MyDbContext())
            {
                if (CheckIfUserUnique(username, email, ctx))
                {
                    DbUser newUser = new DbUser {
                        Username = username, Email = email, Password = passwordToDb, Salt = salt
                    };
                    DbScore newScore = new DbScore {
                        User = newUser, Wins = 0, Losses = 0
                    };
                    ctx.Users.Add(newUser);
                    ctx.Scores.Add(newScore);
                    ctx.SaveChanges();
                    return(newUser);
                }

                return(null);
            }
        }
예제 #7
0
파일: Scoreboard.cs 프로젝트: Mempler/Sora
 public Scoreboard(Beatmap bm, BeatmapSet bmParent, IAsyncEnumerable <DbScore> scores, DbScore ownScore = null)
 {
     _bm       = bm;
     _parent   = bmParent;
     _scores   = scores;
     _ownScore = ownScore;
 }
예제 #8
0
        public async Task<IActionResult> GetReplay(
            [FromQuery(Name = "c")] int replayId,
            [FromQuery(Name = "m")] PlayMode mode,
            [FromQuery(Name = "u")] string userName,
            [FromQuery(Name = "h")] string pass
        )
        {
            var user = await DbUser.GetDbUser(_ctx, userName);
            if (user == null)
                return Ok("err: pass");

            if (!user.IsPassword(pass))
                return Ok("err: pass");

            var s = await DbScore.GetScore(_ctx, replayId);
            if (s == null)
                return NotFound();

            return File(System.IO.File.OpenRead("data/replays/" + s.ReplayMd5), "binary/octet-stream", s.ReplayMd5);
        }
예제 #9
0
        public static async Task <double> CalculatePerformancePoints(DbScore score)
        {
            var beatmapMd5 = await GetBeatmapByMd5(score.FileChecksum);

            if (beatmapMd5 == string.Empty)
            {
                return(0.0);
            }

            var workingBeatmap = new ProcessorWorkingBeatmap($"./data/beatmaps/{beatmapMd5}.osu");

            var psp         = new ProcessorScoreDecoder(workingBeatmap);
            var parsedScore = psp.Parse(score);

            var categoryAttribs = new Dictionary <string, double>();
            var pp = parsedScore.ScoreInfo.Ruleset
                     .CreateInstance()
                     .CreatePerformanceCalculator(workingBeatmap, parsedScore.ScoreInfo)
                     .Calculate(categoryAttribs);

            return(pp);
        }
예제 #10
0
        public async Task<IActionResult> GetScoreResult(
            [FromQuery(Name = "v")] ScoreboardType type,
            [FromQuery(Name = "c")] string fileMd5,
            [FromQuery(Name = "f")] string f,
            [FromQuery(Name = "m")] PlayMode playMode,
            [FromQuery(Name = "i")] int i,
            [FromQuery(Name = "mods")] Mod mods,
            [FromQuery(Name = "us")] string us,
            [FromQuery(Name = "ha")] string pa,
            [FromServices] IServiceProvider serviceProvider)
        {
            try
            {
                var dbUser = await DbUser.GetDbUser(_ctx, us);
                var user = dbUser?.ToUser();
                if (dbUser?.IsPassword(pa) != true)
                    return Ok("error: pass");

                var cacheHash =
                    Hex.ToHex(
                        Crypto.GetMd5(
                            $"{fileMd5}{playMode}{mods}{type}{user.Id}{user.UserName}"
                        )
                    );

                if (_cache.TryGet($"sora:Scoreboards:{cacheHash}", out string cachedData))
                    return Ok(cachedData);

                var scores = await DbScore.GetScores(_ctx, fileMd5, dbUser, playMode,
                                                     type == ScoreboardType.Friends,
                                                     type == ScoreboardType.Country,
                                                     type == ScoreboardType.Mods,
                                                     mods);

                var beatmap = DbBeatmap.GetBeatmap(_ctx, fileMd5);
                BeatmapSet apiSet;
                if (beatmap == null)
                {
                    apiSet = await _pisstaube.FetchBeatmapSetAsync(fileMd5);
                    
                    if (apiSet == null)
                        goto JustContinue;

                    var beatmaps = DbBeatmap.FromBeatmapSet(apiSet).ToList();
                    var beatmapChecksums = beatmaps.Select(s => s.FileMd5);
                    var dbBeatmaps =
                        _ctx.Beatmaps.Where(rset => beatmapChecksums.Any(lFileMd5 => rset.FileMd5 == lFileMd5))
                            .ToList();
                    
                    var concurrentLock = new object();
                    var pool = serviceProvider.GetRequiredService<DbContextPool<SoraDbContext>>();
                    Task.WaitAll(beatmaps.Select(rawBeatmap => Task.Run(async () =>
                    {
                        var context = pool.Rent();
    
                        var dbBeatmap = dbBeatmaps.FirstOrDefault(s => s.FileMd5 == rawBeatmap.FileMd5);

                        if (dbBeatmap != null && (dbBeatmap.Flags & DbBeatmapFlags.RankedFreeze) != 0)
                        {
                            rawBeatmap.RankedStatus = dbBeatmap.RankedStatus;
                            rawBeatmap.Flags        = dbBeatmap.Flags;
                        }

                        context.Beatmaps.AddOrUpdate(rawBeatmap);
                        await context.SaveChangesAsync();

                        pool.Return(context);
                    })).ToArray());
                    
                    beatmap = beatmaps.FirstOrDefault(s => s.FileMd5 == fileMd5);
                }

                JustContinue:
                var ownScore = await DbScore.GetLatestScore(_ctx, new DbScore
                {
                    FileMd5 = fileMd5,
                    UserId = user.Id,
                    PlayMode = playMode,
                    TotalScore = 0
                });

                var sScores = scores.Select(s => new Score
                {
                    Count100 = s.Count100,
                    Count50 = s.Count50,
                    Count300 = s.Count300,
                    Date = s.Date,
                    Mods = s.Mods,
                    CountGeki = s.CountGeki,
                    CountKatu = s.CountKatu,
                    CountMiss = s.CountMiss,
                    FileMd5 = s.FileMd5,
                    MaxCombo = s.MaxCombo,
                    PlayMode = s.PlayMode,
                    TotalScore = s.TotalScore,
                    UserId = s.UserId,
                    UserName = s.ScoreOwner.UserName,
                }).ToList();

                // Fetch the correct position for sScore
                for (var j = 0; j < scores.Count; j++)
                {
                    sScores[j].Position = await scores[j].Position(_ctx);
                }

                Score ownsScore = null;
                if (ownScore != null)
                    ownsScore = new Score
                    {
                        Count100 = ownScore.Count100,
                        Count50 = ownScore.Count50,
                        Count300 = ownScore.Count300,
                        Date = ownScore.Date,
                        Mods = ownScore.Mods,
                        CountGeki = ownScore.CountGeki,
                        CountKatu = ownScore.CountKatu,
                        CountMiss = ownScore.CountMiss,
                        FileMd5 = ownScore.FileMd5,
                        MaxCombo = ownScore.MaxCombo,
                        PlayMode = ownScore.PlayMode,
                        TotalScore = ownScore.TotalScore,
                        UserId = dbUser.Id,
                        UserName = dbUser.UserName,
                        Position = await ownScore.Position(_ctx)
                    };

                BeatmapSet set = null;
                
                if (beatmap != null)
                    set = new BeatmapSet
                    {
                        SetID = beatmap.Id,
                        Artist = beatmap.Artist,
                        Title = beatmap.Title,
                        RankedStatus = beatmap.RankedStatus,
                        
                        ChildrenBeatmaps = new List<Beatmap>
                        {
                            new Beatmap
                            {
                                FileMD5 = beatmap.FileMd5,
                                DiffName = beatmap.DiffName,
                                ParentSetID = beatmap.SetId,
                                BeatmapID = beatmap.Id,
                                Mode = beatmap.PlayMode
                            }
                        }
                    };
                
                var sboard = new Scoreboard(set?.ChildrenBeatmaps.FirstOrDefault(bm => bm.FileMD5 == fileMd5),
                                            set, sScores, ownsScore);

                _cache.Set($"sora:Scoreboards:{cacheHash}", cachedData = sboard.ToOsuString(), TimeSpan.FromSeconds(30));
                return Ok(cachedData);
            }
            catch (Exception ex)
            {
                Logger.Err(ex);
                return Ok("Failed");
            }
        }
예제 #11
0
        public async Task<IActionResult> PostSubmitModular()
        {
            if (!Directory.Exists("data/replays"))
                Directory.CreateDirectory("data/replays");
            
            string encScore = Request.Form["score"];
            string iv = Request.Form["iv"];
            string osuver = Request.Form["osuver"];
            string passwd = Request.Form["pass"];

            var (pass, score) = ScoreSubmissionParser.ParseScore(encScore, iv, osuver);
            var dbUser = await DbUser.GetDbUser(_ctx, score.UserName);

            if (dbUser == null)
                return Ok("error: pass");
            
            if (!dbUser.IsPassword(passwd))
                return Ok("error: pass");

            if (!_ps.TryGet(dbUser.Id, out var pr))
                return Ok("error: pass"); // User not logged in in Bancho!

            if (!pass || !RankedMods.IsRanked(score.Mods))
            {
                var lb = await DbLeaderboard.GetLeaderboardAsync(_ctx, dbUser);

                lb.IncreasePlaycount(score.PlayMode);
                lb.IncreaseScore((ulong) score.TotalScore, false, score.PlayMode);

                await lb.SaveChanges(_ctx);
                
                // Send to other People
                await _ev.RunEvent(
                    EventType.BanchoUserStatsRequest,
                    new BanchoUserStatsRequestArgs {UserIds = new List<int> {score.Id}, Pr = pr}
                );

                // Send to self
                await _ev.RunEvent(
                    EventType.BanchoSendUserStatus,
                    new BanchoSendUserStatusArgs {Status = pr.Status, Pr = pr}
                );

                return Ok("Thanks for your hard work! onii-chyan~"); // even though, we're Sora, we can still be cute!
            }

            var replayFileData = Request.Form.Files.GetFile("score");

            var dbScore = new DbScore
            {
                Accuracy = score.ComputeAccuracy(),
                Count100 = score.Count100,
                Count50 = score.Count50,
                Count300 = score.Count300,
                Date = score.Date,
                Mods = score.Mods,
                CountGeki = score.CountGeki,
                CountKatu = score.CountKatu,
                CountMiss = score.CountMiss,
                FileMd5 = score.FileMd5,
                MaxCombo = score.MaxCombo,
                PlayMode = score.PlayMode,
                ScoreOwner = dbUser,
                TotalScore = score.TotalScore,
                UserId = dbUser.Id
            };

            await _pisstaube.DownloadBeatmapAsync(dbScore.FileMd5);

            await using (var m = new MemoryStream())
            {
                replayFileData.CopyTo(m);
                m.Position = 0;
                dbScore.ReplayMd5 = Hex.ToHex(Crypto.GetMd5(m)) ?? string.Empty;
                if (!string.IsNullOrEmpty(dbScore.ReplayMd5))
                {
                    await using var replayFile = System.IO.File.Create($"data/replays/{dbScore.ReplayMd5}");
                    m.Position = 0;
                    m.WriteTo(replayFile);
                    m.Close();
                    replayFile.Close();
                }
            }

            dbScore.PerformancePoints = dbScore.ComputePerformancePoints();

            var oldScore = await DbScore.GetLatestScore(_ctx, dbScore);

            var oldLb = await DbLeaderboard.GetLeaderboardAsync(_ctx, dbScore.ScoreOwner);
            var oldStdPos = oldLb.GetPosition(_ctx, dbScore.PlayMode);
            
            var oldAcc = oldLb.GetAccuracy(_ctx, dbScore.PlayMode);
            double newAcc;

            if (oldScore != null && oldScore.TotalScore <= dbScore.TotalScore)
            {
                _ctx.Remove(oldScore);
                System.IO.File.Delete($"data/replays/{oldScore.ReplayMd5}");

                await DbScore.InsertScore(_ctx, dbScore);
            }
            else if (oldScore == null)
            {
                await DbScore.InsertScore(_ctx, dbScore);
            }
            else
            {
                System.IO.File.Delete($"data/replays/{oldScore.ReplayMd5}");
            }

            var newlb = await DbLeaderboard.GetLeaderboardAsync(_ctx, dbScore.ScoreOwner);

            newlb.IncreasePlaycount(dbScore.PlayMode);
            newlb.IncreaseScore((ulong) dbScore.TotalScore, true, dbScore.PlayMode);
            newlb.IncreaseScore((ulong) dbScore.TotalScore, false, dbScore.PlayMode);

            newlb.UpdatePp(_ctx, dbScore.PlayMode);

            await newlb.SaveChanges(_ctx);

            var newStdPos = newlb.GetPosition(_ctx, dbScore.PlayMode);
            newAcc = newlb.GetAccuracy(_ctx, dbScore.PlayMode);

            var newScore = await DbScore.GetLatestScore(_ctx, dbScore);

            var set = await _pisstaube.FetchBeatmapSetAsync(dbScore.FileMd5);

            var bm = set?.ChildrenBeatmaps.First(x => x.FileMD5 == dbScore.FileMd5) ?? new Beatmap();

            ulong oldRankedScore;
            ulong newRankedScore;

            double oldPp;
            double newPp;

            switch (dbScore.PlayMode)
            {
                case PlayMode.Osu:
                    oldRankedScore = oldLb.RankedScoreOsu;
                    newRankedScore = newlb.RankedScoreOsu;

                    oldPp = oldLb.PerformancePointsOsu;
                    newPp = newlb.PerformancePointsOsu;
                    break;
                case PlayMode.Taiko:
                    oldRankedScore = oldLb.RankedScoreTaiko;
                    newRankedScore = newlb.RankedScoreTaiko;

                    oldPp = oldLb.PerformancePointsTaiko;
                    newPp = newlb.PerformancePointsTaiko;
                    break;
                case PlayMode.Ctb:
                    oldRankedScore = oldLb.RankedScoreCtb;
                    newRankedScore = newlb.RankedScoreCtb;

                    oldPp = oldLb.PerformancePointsCtb;
                    newPp = newlb.PerformancePointsCtb;
                    break;
                case PlayMode.Mania:
                    oldRankedScore = oldLb.RankedScoreMania;
                    newRankedScore = newlb.RankedScoreMania;

                    oldPp = oldLb.PerformancePointsMania;
                    newPp = newlb.PerformancePointsMania;
                    break;
                default:
                    return Ok("");
            }

            var newScorePosition = newScore != null ? await newScore.Position(_ctx) : 0;
            var oldScorePosition = oldScore != null ? await oldScore.Position(_ctx) : 0;
            
            if (newScorePosition == 1)
                _sora.SendMessage(
                    $"[http://{_config.Server.ScreenShotHostname}/{dbScore.ScoreOwner.Id} {dbScore.ScoreOwner.UserName}] " +
                    $"has reached #1 on [https://osu.ppy.sh/b/{bm.BeatmapID} {set?.Title} [{bm.DiffName}]] " +
                    $"using {ModUtil.ToString(newScore.Mods)} " +
                    $"Good job! +{newScore.PerformancePoints:F}PP",
                    "#announce",
                    false
                );

            Logger.Info(
                $"{LCol.RED}{dbScore.ScoreOwner.UserName}",
                $"{LCol.PURPLE}( {dbScore.ScoreOwner.Id} ){LCol.WHITE}",
                $"has just submitted a Score! he earned {LCol.BLUE}{newScore?.PerformancePoints:F}PP",
                $"{LCol.WHITE}with an Accuracy of {LCol.RED}{newScore?.Accuracy * 100:F}",
                $"{LCol.WHITE}on {LCol.YELLOW}{set?.Title} [{bm.DiffName}]",
                $"{LCol.WHITE}using {LCol.BLUE}{ModUtil.ToString(newScore?.Mods ?? Mod.None)}"
            );

            var bmChart = new Chart(
                "beatmap",
                "Beatmap Ranking",
                $"https://osu.ppy.sh/b/{bm.BeatmapID}",
                oldScorePosition,
                newScorePosition,
                oldScore?.MaxCombo ?? 0,
                newScore?.MaxCombo ?? 0,
                oldScore?.Accuracy * 100 ?? 0,
                newScore?.Accuracy * 100 ?? 0,
                (ulong) (oldScore?.TotalScore ?? 0),
                (ulong) (newScore?.TotalScore ?? 0),
                oldScore?.PerformancePoints ?? 0,
                newScore?.PerformancePoints ?? 0,
                newScore?.Id ?? 0
            );

            var overallChart = new Chart(
                "overall",
                "Global Ranking",
                $"https://osu.ppy.sh/u/{dbUser.Id}",
                (int) oldStdPos,
                (int) newStdPos,
                0,
                0,
                oldAcc * 100,
                newAcc * 100,
                oldRankedScore,
                newRankedScore,
                oldPp,
                newPp,
                newScore?.Id ?? 0,
                AchievementProcessor.ProcessAchievements(
                    _ctx, dbScore.ScoreOwner, score, bm, set, oldLb, newlb
                )
            );

            pr["LB"] = newlb;
            pr.Stats.Accuracy = (float) newlb.GetAccuracy(_ctx, score.PlayMode);
            pr.Stats.Position = newlb.GetPosition(_ctx, score.PlayMode);
            switch (score.PlayMode)
            {
                case PlayMode.Osu:
                    pr.Stats.PerformancePoints = (ushort) newlb.PerformancePointsOsu;
                    pr.Stats.TotalScore = (ushort) newlb.TotalScoreOsu;
                    pr.Stats.RankedScore = (ushort) newlb.RankedScoreOsu;
                    pr.Stats.PlayCount = (ushort) newlb.PlayCountOsu;
                    break;
                case PlayMode.Taiko:
                    pr.Stats.PerformancePoints = (ushort) newlb.PerformancePointsTaiko;
                    pr.Stats.TotalScore = (ushort) newlb.TotalScoreTaiko;
                    pr.Stats.RankedScore = (ushort) newlb.RankedScoreTaiko;
                    pr.Stats.PlayCount = (ushort) newlb.PlayCountTaiko;
                    break;
                case PlayMode.Ctb:
                    pr.Stats.PerformancePoints = (ushort) newlb.PerformancePointsCtb;
                    pr.Stats.TotalScore = (ushort) newlb.TotalScoreCtb;
                    pr.Stats.RankedScore = (ushort) newlb.RankedScoreCtb;
                    pr.Stats.PlayCount = (ushort) newlb.PlayCountCtb;
                    break;
                case PlayMode.Mania:
                    pr.Stats.PerformancePoints = (ushort) newlb.PerformancePointsMania;
                    pr.Stats.TotalScore = (ushort) newlb.TotalScoreMania;
                    pr.Stats.RankedScore = (ushort) newlb.RankedScoreMania;
                    pr.Stats.PlayCount = (ushort) newlb.PlayCountMania;
                    break;
            }
            
            // Send to other People
            await _ev.RunEvent(
                EventType.BanchoUserStatsRequest,
                new BanchoUserStatsRequestArgs {UserIds = new List<int> {score.Id}, Pr = pr}
            );

            // Send to self
            await _ev.RunEvent(
                EventType.BanchoSendUserStatus,
                new BanchoSendUserStatusArgs {Status = pr.Status, Pr = pr}
            );

            return Ok(
                $"beatmapId:{bm.BeatmapID}|beatmapSetId:{bm.ParentSetID}|beatmapPlaycount:0|beatmapPasscount:0|approvedDate:\n\n" +
                bmChart.ToOsuString() + "\n" + overallChart.ToOsuString()
            );
        }
예제 #12
0
        public async Task <IActionResult> GetScoreResult(
            [FromQuery(Name = "v")] ScoreboardType type,
            [FromQuery(Name = "c")] string fileMd5,
            [FromQuery(Name = "f")] string f,
            [FromQuery(Name = "m")] PlayMode playMode,
            [FromQuery(Name = "i")] int i,
            [FromQuery(Name = "mods")] Mod mods,
            [FromQuery(Name = "us")] string us,
            [FromQuery(Name = "ha")] string pa,
            [FromServices] IServiceProvider serviceProvider,
            [FromServices] SoraDbContext ctx,
            [FromServices] DbContextPool <SoraDbContext> ctxPool,
            [FromServices] Pisstaube pisstaube,
            [FromServices] Cache cache)
        {
            try
            {
                var dbUser = await DbUser.GetDbUser(ctx, us);

                if (dbUser?.IsPassword(pa) != true)
                {
                    return(Ok("error: pass"));
                }

                var cacheHash =
                    Hex.ToHex(
                        Crypto.GetMd5(
                            $"{fileMd5}{playMode}{mods}{type}{dbUser.Id}{dbUser.UserName}"
                            )
                        );

                if (cache.TryGet($"sora:Scoreboards:{cacheHash}", out string cachedData))
                {
                    return(Ok(cachedData));
                }

                var scores = DbScore.GetScores(ctx, fileMd5, dbUser, playMode,
                                               type == ScoreboardType.Friends,
                                               type == ScoreboardType.Country,
                                               type == ScoreboardType.Mods,
                                               mods);

                BeatmapSet set      = null;
                DbScore    ownScore = null;

                var beatmap = DbBeatmap.GetBeatmap(ctx, fileMd5);
                if (beatmap == null)
                {
                    var apiSet = await pisstaube.FetchBeatmapSetAsync(fileMd5);

                    if (apiSet == null)
                    {
                        goto JustContinue;
                    }

                    var beatmaps         = DbBeatmap.FromBeatmapSet(apiSet).ToList();
                    var beatmapChecksums = beatmaps.Select(s => s.FileMd5);
                    var dbBeatmaps       =
                        ctx.Beatmaps.Where(rset => beatmapChecksums.Any(lFileMd5 => rset.FileMd5 == lFileMd5))
                        .ToList();

                    var pool = serviceProvider.GetRequiredService <DbContextPool <SoraDbContext> >();
                    Task.WaitAll(beatmaps.Select(rawBeatmap => Task.Run(async() =>
                    {
                        var context = pool.Rent();

                        try
                        {
                            var dbBeatmap = dbBeatmaps.FirstOrDefault(s => s.FileMd5 == rawBeatmap.FileMd5);

                            if (dbBeatmap != null && (dbBeatmap.Flags & DbBeatmapFlags.RankedFreeze) != 0)
                            {
                                rawBeatmap.RankedStatus = dbBeatmap.RankedStatus;
                                rawBeatmap.Flags        = dbBeatmap.Flags;
                            }

                            context.Beatmaps.AddOrUpdate(rawBeatmap);
                            await context.SaveChangesAsync();
                        }
                        finally
                        {
                            pool.Return(context);
                        }
                    })).ToArray());

                    beatmap = beatmaps.FirstOrDefault(s => s.FileMd5 == fileMd5);
                }

                await foreach (var score in DbScore.GetScores(ctx, fileMd5, dbUser, playMode, false, false, false, mods, true))
                {
                    ownScore = score;
                    break;
                }

                if (beatmap != null)
                {
                    set = new BeatmapSet
                    {
                        SetID        = beatmap.Id,
                        Artist       = beatmap.Artist,
                        Title        = beatmap.Title,
                        RankedStatus = beatmap.RankedStatus,

                        ChildrenBeatmaps = new List <Beatmap>
                        {
                            new Beatmap
                            {
                                FileMD5     = beatmap.FileMd5,
                                DiffName    = beatmap.DiffName,
                                ParentSetID = beatmap.SetId,
                                BeatmapID   = beatmap.Id,
                                Mode        = beatmap.PlayMode,
                            },
                        },
                    }
                }
                ;

JustContinue:
                var sboard = new Scoreboard(set?.ChildrenBeatmaps.FirstOrDefault(bm => bm.FileMD5 == fileMd5),
                                            set, scores, ownScore);

                cache.Set($"sora:Scoreboards:{cacheHash}", cachedData = await sboard.ToOsuString(ctxPool), TimeSpan.FromSeconds(30));
                return(Ok(cachedData));
            }
            catch (Exception ex)
            {
                Logger.Err(ex);
                return(Ok("Failed"));
            }
        }