Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new medals #308

Merged
merged 1 commit into from
Dec 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using Dapper;
using osu.Server.Queues.ScoreStatisticsProcessor.Models;
using Xunit;

namespace osu.Server.Queues.ScoreStatisticsProcessor.Tests
{
public class DailySproutTest : MedalAwarderTest
{
private readonly Beatmap beatmap;

public DailySproutTest()
{
beatmap = AddBeatmap();
AddMedal(336);
}

[Fact]
public void MedalNotAwardedIfNoDailyChallengesOnRecord()
{
SetScoreForBeatmap(beatmap.beatmap_id);
AssertNoMedalsAwarded();
}

[Fact]
public void MedalAwardedIfAtLeastOneDailyChallengeOnRecord()
{
using (var db = Processor.GetDatabaseConnection())
db.Execute("INSERT INTO `daily_challenge_user_stats` (`user_id`, `daily_streak_best`) VALUES (2, 1)");
SetScoreForBeatmap(beatmap.beatmap_id);
AssertSingleMedalAwarded(336);
}
}
}
42 changes: 42 additions & 0 deletions osu.Server.Queues.ScoreStatisticsProcessor.Tests/GameNightTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Game.Online.API;
using osu.Game.Rulesets.Osu.Mods;
using osu.Server.Queues.ScoreStatisticsProcessor.Models;
using Xunit;

namespace osu.Server.Queues.ScoreStatisticsProcessor.Tests
{
public class GameNightTest : MedalAwarderTest
{
private readonly Beatmap beatmap;

public GameNightTest()
{
AddMedal(340);
beatmap = AddBeatmap();
}

[Fact]
public void TestMedalAwarded()
{
SetScoreForBeatmap(beatmap.beatmap_id, s => s.Score.ScoreData.Mods = [new APIMod(new OsuModBubbles())]);
AssertSingleMedalAwarded(340);
}

[Fact]
public void TestMedalAwardedWithExtraMods()
{
SetScoreForBeatmap(beatmap.beatmap_id, s => s.Score.ScoreData.Mods = [new APIMod(new OsuModBubbles()), new APIMod(new OsuModClassic())]);
AssertSingleMedalAwarded(340);
}

[Fact]
public void TestMedalNotAwardedIfFunModsMissing()
{
SetScoreForBeatmap(beatmap.beatmap_id, s => s.Score.ScoreData.Mods = [new APIMod(new OsuModClassic())]);
AssertNoMedalsAwarded();
}
}
}
42 changes: 42 additions & 0 deletions osu.Server.Queues.ScoreStatisticsProcessor.Tests/GearShiftTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Game.Online.API;
using osu.Game.Rulesets.Osu.Mods;
using osu.Server.Queues.ScoreStatisticsProcessor.Models;
using Xunit;

namespace osu.Server.Queues.ScoreStatisticsProcessor.Tests
{
public class GearShiftTest : MedalAwarderTest
{
private readonly Beatmap beatmap;

public GearShiftTest()
{
AddMedal(339);
beatmap = AddBeatmap();
}

[Fact]
public void TestMedalAwarded()
{
SetScoreForBeatmap(beatmap.beatmap_id, s => s.Score.ScoreData.Mods = [new APIMod(new OsuModAlternate())]);
AssertMedalAwarded(339);
}

[Fact]
public void TestMedalAwardedWithExtraMods()
{
SetScoreForBeatmap(beatmap.beatmap_id, s => s.Score.ScoreData.Mods = [new APIMod(new OsuModAlternate()), new APIMod(new OsuModDoubleTime())]);
AssertMedalAwarded(339);
}

[Fact]
public void TestMedalNotAwardedIfConversionModsMissing()
{
SetScoreForBeatmap(beatmap.beatmap_id, s => s.Score.ScoreData.Mods = [new APIMod(new OsuModFreezeFrame())]);
AssertNoMedalsAwarded();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ protected MedalAwarderTest(AssemblyName[]? externalProcessorAssemblies = null)

db.Execute("TRUNCATE TABLE osu_beatmappacks");
db.Execute("TRUNCATE TABLE osu_beatmappacks_items");

db.Execute("TRUNCATE TABLE daily_challenge_user_stats");
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using Dapper;
using osu.Server.Queues.ScoreStatisticsProcessor.Models;
using Xunit;

namespace osu.Server.Queues.ScoreStatisticsProcessor.Tests
{
public class MonthlyShrubTest : MedalAwarderTest
{
private readonly Beatmap beatmap;

public MonthlyShrubTest()
{
beatmap = AddBeatmap();
AddMedal(338);
}

[Theory]
[InlineData(0)]
[InlineData(9)]
[InlineData(26)]
public void MedalNotAwardedIfNotEnoughDailyChallengesOnRecord(int dailyChallengeCount)
{
using (var db = Processor.GetDatabaseConnection())
db.Execute($"INSERT INTO `daily_challenge_user_stats` (`user_id`, `daily_streak_best`) VALUES (2, {dailyChallengeCount})");
SetScoreForBeatmap(beatmap.beatmap_id);
AssertNoMedalsAwarded();
}

[Fact]
public void MedalAwardedIfAtLeastThirtyDailyChallengesOnRecord()
{
using (var db = Processor.GetDatabaseConnection())
db.Execute("INSERT INTO `daily_challenge_user_stats` (`user_id`, `daily_streak_best`) VALUES (2, 30)");
SetScoreForBeatmap(beatmap.beatmap_id);
AssertSingleMedalAwarded(338);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using Dapper;
using osu.Server.Queues.ScoreStatisticsProcessor.Models;
using Xunit;

namespace osu.Server.Queues.ScoreStatisticsProcessor.Tests
{
public class WeeklySaplingTest : MedalAwarderTest
{
private readonly Beatmap beatmap;

public WeeklySaplingTest()
{
beatmap = AddBeatmap();
AddMedal(337);
}

[Theory]
[InlineData(0)]
[InlineData(4)]
[InlineData(6)]
public void MedalNotAwardedIfNotEnoughDailyChallengesOnRecord(int dailyChallengeCount)
{
using (var db = Processor.GetDatabaseConnection())
db.Execute($"INSERT INTO `daily_challenge_user_stats` (`user_id`, `daily_streak_best`) VALUES (2, {dailyChallengeCount})");
SetScoreForBeatmap(beatmap.beatmap_id);
AssertNoMedalsAwarded();
}

[Fact]
public void MedalAwardedIfAtLeastSevenDailyChallengesOnRecord()
{
using (var db = Processor.GetDatabaseConnection())
db.Execute("INSERT INTO `daily_challenge_user_stats` (`user_id`, `daily_streak_best`) VALUES (2, 7)");
SetScoreForBeatmap(beatmap.beatmap_id);
AssertSingleMedalAwarded(337);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Diagnostics.CodeAnalysis;
using Dapper.Contrib.Extensions;

namespace osu.Server.Queues.ScoreStatisticsProcessor.Models
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[Serializable]
[Table("daily_challenge_user_stats")]
public record DailyChallengeUserStats
{
public uint daily_streak_current { get; set; }
public uint daily_streak_best { get; set; }
public uint playcount { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ namespace osu.Server.Queues.ScoreStatisticsProcessor.Models
/// </summary>
/// <param name="Score">The score to check for medals.</param>
/// <param name="UserStats">The calculated user statistics after <see cref="Score"/>.</param>
/// <param name="DailyChallengeUserStats">The user's daily challenge stats after <see cref="Score"/>.</param>
/// <param name="BeatmapStore">Allows retrieval of <see cref="Beatmap"/>s from database.</param>
/// <param name="Connection">MySQL connection for manual retrieval from database.</param>
/// <param name="Transaction">MySQL transaction for manual retrieval from database.</param>
public record MedalAwarderContext(
SoloScore Score,
UserStats UserStats,
DailyChallengeUserStats DailyChallengeUserStats,
BeatmapStore BeatmapStore,
MySqlConnection Connection,
MySqlTransaction Transaction);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System.Collections.Generic;
using JetBrains.Annotations;
using osu.Server.Queues.ScoreStatisticsProcessor.Models;

namespace osu.Server.Queues.ScoreStatisticsProcessor.Processors.MedalAwarders
{
[UsedImplicitly]
public class DailyChallengeMedalAwarder : IMedalAwarder
{
public bool RunOnFailedScores => false;
public bool RunOnLegacyScores => false;

public IEnumerable<Medal> Check(IEnumerable<Medal> medals, MedalAwarderContext context)
{
foreach (var medal in medals)
{
switch (medal.achievement_id)
{
case 336:
{
if (context.DailyChallengeUserStats.daily_streak_best >= 1)
yield return medal;

break;
}

case 337:
{
if (context.DailyChallengeUserStats.daily_streak_best >= 7)
yield return medal;

break;
}

case 338:
{
if (context.DailyChallengeUserStats.daily_streak_best >= 30)
yield return medal;

break;
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Server.Queues.ScoreStatisticsProcessor.Helpers;
using osu.Server.Queues.ScoreStatisticsProcessor.Models;

namespace osu.Server.Queues.ScoreStatisticsProcessor.Processors.MedalAwarders
{
[UsedImplicitly]
public class LazerModIntroductionMedalAwarder : IMedalAwarder
{
public bool RunOnFailedScores => false;
public bool RunOnLegacyScores => false;

public IEnumerable<Medal> Check(IEnumerable<Medal> medals, MedalAwarderContext context)
{
Ruleset ruleset = LegacyRulesetHelper.GetRulesetFromLegacyId(context.Score.ruleset_id);
Mod[] mods = context.Score.ScoreData.Mods.Select(m => m.ToMod(ruleset)).ToArray();

foreach (var medal in medals)
{
switch (medal.achievement_id)
{
// Gear Shift
case 339:
{
if (mods.Any(m => m.Type == ModType.Conversion))
yield return medal;

break;
}

// Game Night
case 340:
{
if (mods.Any(m => m.Type == ModType.Fun))
yield return medal;

break;
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,16 @@ public void ApplyToUserStats(SoloScore score, UserStats userStats, MySqlConnecti
.Where(m => !alreadyAchieved.Contains(m.achievement_id))
.ToArray();

var dailyChallengeUserStats = conn.QuerySingleOrDefault<DailyChallengeUserStats>(
@"SELECT * FROM `daily_challenge_user_stats` WHERE `user_id` = @user_id",
new
{
user_id = userStats.user_id
},
transaction) ?? new DailyChallengeUserStats();

var beatmapStore = BeatmapStore.CreateAsync(conn, transaction).Result;
var context = new MedalAwarderContext(score, userStats, beatmapStore, conn, transaction);
var context = new MedalAwarderContext(score, userStats, dailyChallengeUserStats, beatmapStore, conn, transaction);

foreach (var awarder in medal_awarders)
{
Expand Down
Loading