1 Commits

Author SHA1 Message Date
e78c8fa03d (NOT STABLE!!) Added custom mode using music from MainMenu 2025-08-23 22:54:22 +03:00
93 changed files with 728 additions and 1122 deletions

View File

@@ -148,7 +148,9 @@ jobs:
# https://github.com/dotnet/macios/issues/19157
# https://github.com/actions/runner-images/issues/12758
- name: Use Xcode 16.4
run: sudo xcode-select -switch /Applications/Xcode_16.4.app
run: |
sudo xcode-select -switch /Applications/Xcode_16.4.app
xcodebuild -downloadPlatform iOS
- name: Build
run: dotnet build -c Debug osu.iOS.slnf

View File

@@ -3,7 +3,6 @@
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
@@ -17,7 +16,7 @@ namespace osu.Game.Rulesets.Catch.Mods
public override string Acronym => "FF";
public override LocalisableString Description => "The fruits are... floating?";
public override double ScoreMultiplier => 1;
public override IconUsage? Icon => OsuIcon.ModFloatingFruits;
public override IconUsage? Icon => FontAwesome.Solid.Cloud;
public void ApplyToDrawableRuleset(DrawableRuleset<CatchHitObject> drawableRuleset)
{

View File

@@ -7,7 +7,6 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Mods;
@@ -24,7 +23,7 @@ namespace osu.Game.Rulesets.Catch.Mods
public override LocalisableString Description => "Dashing by default, slow down!";
public override ModType Type => ModType.Fun;
public override double ScoreMultiplier => 1;
public override IconUsage? Icon => OsuIcon.ModMovingFast;
public override IconUsage? Icon => FontAwesome.Solid.Running;
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModRelax) };
private DrawableCatchRuleset drawableRuleset = null!;

View File

@@ -4,7 +4,6 @@
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods;
@@ -22,7 +21,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public override LocalisableString Description => "No more tricky speed changes!";
public override IconUsage? Icon => OsuIcon.ModConstantSpeed;
public override IconUsage? Icon => FontAwesome.Solid.Equals;
public override ModType Type => ModType.Conversion;

View File

@@ -4,10 +4,8 @@
using System;
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.UI;
namespace osu.Game.Rulesets.Mania.Mods
@@ -16,7 +14,6 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override string Name => "Cover";
public override string Acronym => "CO";
public override IconUsage? Icon => OsuIcon.ModCover;
public override LocalisableString Description => @"Decrease the playfield's viewing area.";

View File

@@ -1,10 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mods;
@@ -15,7 +13,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Name => "Dual Stages";
public override string Acronym => "DS";
public override LocalisableString Description => @"Double the stages, double the fun!";
public override IconUsage? Icon => OsuIcon.ModDualStages;
public override ModType Type => ModType.Conversion;
public override double ScoreMultiplier => 1;

View File

@@ -3,9 +3,7 @@
using System;
using System.Linq;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.UI;
namespace osu.Game.Rulesets.Mania.Mods
@@ -14,7 +12,6 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override string Name => "Fade In";
public override string Acronym => "FI";
public override IconUsage? Icon => OsuIcon.ModFadeIn;
public override LocalisableString Description => @"Keys appear out of nowhere!";
public override double ScoreMultiplier => 1;
public override bool ValidForFreestyleAsRequiredMod => false;

View File

@@ -9,7 +9,6 @@ using osu.Game.Rulesets.Mods;
using osu.Framework.Graphics.Sprites;
using System.Collections.Generic;
using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Beatmaps;
namespace osu.Game.Rulesets.Mania.Mods
@@ -24,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public override LocalisableString Description => @"Replaces all hold notes with normal notes.";
public override IconUsage? Icon => OsuIcon.ModHoldOff;
public override IconUsage? Icon => FontAwesome.Solid.DotCircle;
public override ModType Type => ModType.Conversion;

View File

@@ -8,7 +8,6 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mods;
@@ -24,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public override LocalisableString Description => "Hold the keys. To the beat.";
public override IconUsage? Icon => OsuIcon.ModInvert;
public override IconUsage? Icon => FontAwesome.Solid.YinYang;
public override ModType Type => ModType.Conversion;

View File

@@ -1,9 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mania.Mods
{
@@ -12,7 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override int KeyCount => 1;
public override string Name => "One Key";
public override string Acronym => "1K";
public override IconUsage? Icon => OsuIcon.ModOneKey;
public override LocalisableString Description => @"Play with one key.";
public override bool Ranked => false;
}

View File

@@ -1,9 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mania.Mods
{
@@ -12,7 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override int KeyCount => 10;
public override string Name => "Ten Keys";
public override string Acronym => "10K";
public override IconUsage? Icon => OsuIcon.ModTenKeys;
public override LocalisableString Description => @"Play with ten keys.";
public override bool Ranked => false;
}

View File

@@ -1,9 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mania.Mods
{
@@ -12,7 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override int KeyCount => 2;
public override string Name => "Two Keys";
public override string Acronym => "2K";
public override IconUsage? Icon => OsuIcon.ModTwoKeys;
public override LocalisableString Description => @"Play with two keys.";
public override bool Ranked => false;
}

View File

@@ -1,9 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mania.Mods
{
@@ -12,7 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override int KeyCount => 3;
public override string Name => "Three Keys";
public override string Acronym => "3K";
public override IconUsage? Icon => OsuIcon.ModThreeKeys;
public override LocalisableString Description => @"Play with three keys.";
public override bool Ranked => false;
}

View File

@@ -1,9 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mania.Mods
{
@@ -12,7 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override int KeyCount => 4;
public override string Name => "Four Keys";
public override string Acronym => "4K";
public override IconUsage? Icon => OsuIcon.ModFourKeys;
public override LocalisableString Description => @"Play with four keys.";
}
}

View File

@@ -1,9 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mania.Mods
{
@@ -12,7 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override int KeyCount => 5;
public override string Name => "Five Keys";
public override string Acronym => "5K";
public override IconUsage? Icon => OsuIcon.ModFiveKeys;
public override LocalisableString Description => @"Play with five keys.";
}
}

View File

@@ -1,9 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mania.Mods
{
@@ -12,7 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override int KeyCount => 6;
public override string Name => "Six Keys";
public override string Acronym => "6K";
public override IconUsage? Icon => OsuIcon.ModSixKeys;
public override LocalisableString Description => @"Play with six keys.";
}
}

View File

@@ -1,9 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mania.Mods
{
@@ -12,7 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override int KeyCount => 7;
public override string Name => "Seven Keys";
public override string Acronym => "7K";
public override IconUsage? Icon => OsuIcon.ModSevenKeys;
public override LocalisableString Description => @"Play with seven keys.";
}
}

View File

@@ -1,9 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mania.Mods
{
@@ -12,7 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override int KeyCount => 8;
public override string Name => "Eight Keys";
public override string Acronym => "8K";
public override IconUsage? Icon => OsuIcon.ModEightKeys;
public override LocalisableString Description => @"Play with eight keys.";
}
}

View File

@@ -1,9 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mania.Mods
{
@@ -12,7 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override int KeyCount => 9;
public override string Name => "Nine Keys";
public override string Acronym => "9K";
public override IconUsage? Icon => OsuIcon.ModNineKeys;
public override LocalisableString Description => @"Play with nine keys.";
}
}

View File

@@ -4,10 +4,8 @@
using System;
using System.Linq;
using System.Threading;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
@@ -28,8 +26,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override double ScoreMultiplier => 0.9;
public override IconUsage? Icon => OsuIcon.ModNoRelease;
public override ModType Type => ModType.DifficultyReduction;
public override Type[] IncompatibleMods => new[] { typeof(ManiaModHoldOff) };

View File

@@ -5,7 +5,6 @@ using System;
using System.Linq;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Osu.Mods
{
@@ -14,7 +13,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override string Name => @"Alternate";
public override string Acronym => @"AL";
public override LocalisableString Description => @"Don't use the same key twice in a row!";
public override IconUsage? Icon => OsuIcon.ModAlternate;
public override IconUsage? Icon => FontAwesome.Solid.Keyboard;
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModSingleTap) }).ToArray();
protected override bool CheckValidNewAction(OsuAction action) => LastAcceptedAction != action;

View File

@@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables;
@@ -20,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override string Acronym => "AD";
public override LocalisableString Description => "Never trust the approach circles...";
public override double ScoreMultiplier => 1;
public override IconUsage? Icon => OsuIcon.ModApproachDifferent;
public override IconUsage? Icon { get; } = FontAwesome.Regular.Circle;
public override Type[] IncompatibleMods => new[] { typeof(IHidesApproachCircles), typeof(OsuModFreezeFrame) };

View File

@@ -11,7 +11,6 @@ using osu.Framework.Graphics.Textures;
using osu.Framework.Localisation;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Scoring;
@@ -27,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override LocalisableString Description => "Play with blinds on your screen.";
public override string Acronym => "BL";
public override IconUsage? Icon => OsuIcon.ModBlinds;
public override IconUsage? Icon => FontAwesome.Solid.Adjust;
public override ModType Type => ModType.DifficultyIncrease;
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;

View File

@@ -3,11 +3,9 @@
using System;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Framework.Utils;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets.Mods;
@@ -23,7 +21,6 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Name => "Bloom";
public override string Acronym => "BM";
public override IconUsage? Icon => OsuIcon.ModBloom;
public override ModType Type => ModType.Fun;
public override LocalisableString Description => "The cursor blooms into.. a larger cursor!";
public override double ScoreMultiplier => 1;

View File

@@ -11,9 +11,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Pooling;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
@@ -36,8 +34,6 @@ namespace osu.Game.Rulesets.Osu.Mods
public override double ScoreMultiplier => 1;
public override IconUsage? Icon => OsuIcon.ModBubbles;
public override ModType Type => ModType.Fun;
// Compatibility with these seems potentially feasible in the future, blocked for now because they don't work as one would expect

View File

@@ -4,7 +4,6 @@
using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Osu.Mods
{
@@ -14,7 +13,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override string Acronym => "DF";
public override IconUsage? Icon => OsuIcon.ModDeflate;
public override IconUsage? Icon => FontAwesome.Solid.CompressArrowsAlt;
public override LocalisableString Description => "Hit them at the right size!";

View File

@@ -7,7 +7,6 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
@@ -22,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Name => "Depth";
public override string Acronym => "DP";
public override IconUsage? Icon => OsuIcon.ModDepth;
public override IconUsage? Icon => FontAwesome.Solid.Cube;
public override ModType Type => ModType.Fun;
public override LocalisableString Description => "3D. Almost.";
public override double ScoreMultiplier => 1;

View File

@@ -4,10 +4,8 @@
using System;
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
@@ -21,8 +19,6 @@ namespace osu.Game.Rulesets.Osu.Mods
public override string Acronym => "FR";
public override IconUsage? Icon => OsuIcon.ModFreezeFrame;
public override double ScoreMultiplier => 1;
public override LocalisableString Description => "Burn the notes into your memory.";

View File

@@ -4,7 +4,6 @@
using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Osu.Mods
{
@@ -14,7 +13,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override string Acronym => "GR";
public override IconUsage? Icon => OsuIcon.ModGrow;
public override IconUsage? Icon => FontAwesome.Solid.ArrowsAltV;
public override LocalisableString Description => "Hit them at the right size!";

View File

@@ -9,7 +9,6 @@ using osu.Framework.Localisation;
using osu.Framework.Timing;
using osu.Framework.Utils;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
@@ -24,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Name => "Magnetised";
public override string Acronym => "MG";
public override IconUsage? Icon => OsuIcon.ModMagnetised;
public override IconUsage? Icon => FontAwesome.Solid.Magnet;
public override ModType Type => ModType.Fun;
public override LocalisableString Description => "No need to chase the circles your cursor is a magnet!";
public override double ScoreMultiplier => 0.5;

View File

@@ -4,12 +4,10 @@
using System;
using osu.Framework.Bindables;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Framework.Timing;
using osu.Framework.Utils;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
@@ -25,7 +23,6 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Name => "Repel";
public override string Acronym => "RP";
public override IconUsage? Icon => OsuIcon.ModRepel;
public override ModType Type => ModType.Fun;
public override LocalisableString Description => "Hit objects run away!";
public override double ScoreMultiplier => 1;

View File

@@ -3,9 +3,7 @@
using System;
using System.Linq;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Osu.Mods
{
@@ -13,7 +11,6 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Name => @"Single Tap";
public override string Acronym => @"SG";
public override IconUsage? Icon => OsuIcon.ModSingleTap;
public override LocalisableString Description => @"You must only use one key!";
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAlternate) }).ToArray();

View File

@@ -5,7 +5,6 @@ using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
@@ -18,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Name => "Spin In";
public override string Acronym => "SI";
public override IconUsage? Icon => OsuIcon.ModSpinIn;
public override IconUsage? Icon => FontAwesome.Solid.Undo;
public override ModType Type => ModType.Fun;
public override LocalisableString Description => "Circles spin in. No approach circles.";
public override double ScoreMultiplier => 1;

View File

@@ -4,10 +4,8 @@
using System;
using System.Linq;
using System.Threading;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
@@ -26,7 +24,6 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Name => @"Strict Tracking";
public override string Acronym => @"ST";
public override IconUsage? Icon => OsuIcon.ModStrictTracking;
public override ModType Type => ModType.DifficultyIncrease;
public override LocalisableString Description => @"Once you start a slider, follow precisely or get a miss.";
public override double ScoreMultiplier => 1.0;

View File

@@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override string Name => "Target Practice";
public override string Acronym => "TP";
public override ModType Type => ModType.Conversion;
public override IconUsage? Icon => OsuIcon.ModTargetPractice;
public override IconUsage? Icon => OsuIcon.ModTarget;
public override LocalisableString Description => @"Practice keeping up with the beat of the song.";
public override double ScoreMultiplier => 0.1;

View File

@@ -4,9 +4,7 @@
using System;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
@@ -20,7 +18,6 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Name => "Traceable";
public override string Acronym => "TC";
public override IconUsage? Icon => OsuIcon.ModTraceable;
public override ModType Type => ModType.Fun;
public override LocalisableString Description => "Put your faith in the approach circles...";
public override double ScoreMultiplier => 1;

View File

@@ -6,7 +6,6 @@ using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
@@ -19,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Name => "Transform";
public override string Acronym => "TR";
public override IconUsage? Icon => OsuIcon.ModTransform;
public override IconUsage? Icon => FontAwesome.Solid.ArrowsAlt;
public override ModType Type => ModType.Fun;
public override LocalisableString Description => "Everything rotates. EVERYTHING.";
public override double ScoreMultiplier => 1;

View File

@@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
@@ -20,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Name => "Wiggle";
public override string Acronym => "WG";
public override IconUsage? Icon => OsuIcon.ModWiggle;
public override IconUsage? Icon => FontAwesome.Solid.Certificate;
public override ModType Type => ModType.Fun;
public override LocalisableString Description => "They just won't stay still...";
public override double ScoreMultiplier => 1;

View File

@@ -4,7 +4,6 @@
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.UI;
using osu.Game.Rulesets.Mods;
@@ -18,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Mods
public override string Acronym => "CS";
public override double ScoreMultiplier => 0.9;
public override LocalisableString Description => "No more tricky speed changes!";
public override IconUsage? Icon => OsuIcon.ModConstantSpeed;
public override IconUsage? Icon => FontAwesome.Solid.Equals;
public override ModType Type => ModType.Conversion;
public void ApplyToDrawableRuleset(DrawableRuleset<TaikoHitObject> drawableRuleset)

View File

@@ -5,12 +5,10 @@ using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Taiko.Beatmaps;
using osu.Game.Rulesets.Taiko.Objects;
@@ -23,7 +21,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
public override string Acronym => "SR";
public override double ScoreMultiplier => 0.6;
public override LocalisableString Description => "Simplify tricky rhythms!";
public override IconUsage? Icon => OsuIcon.ModSimplifiedRhythm;
public override ModType Type => ModType.DifficultyReduction;
[SettingSource("1/3 to 1/2 conversion", "Converts 1/3 patterns to 1/2 rhythm.")]

View File

@@ -6,11 +6,9 @@ using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Beatmaps.Timing;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Taiko.Objects;
@@ -26,7 +24,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
{
public override string Name => @"Single Tap";
public override string Acronym => @"SG";
public override IconUsage? Icon => OsuIcon.ModSingleTap;
public override LocalisableString Description => @"One key for dons, one key for kats.";
public override double ScoreMultiplier => 1.0;

View File

@@ -3,10 +3,8 @@
using System;
using System.Linq;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Taiko.Beatmaps;
using osu.Game.Rulesets.Taiko.Objects;
@@ -18,7 +16,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
public override string Name => "Swap";
public override string Acronym => "SW";
public override LocalisableString Description => @"Dons become kats, kats become dons";
public override IconUsage? Icon => OsuIcon.ModSwap;
public override ModType Type => ModType.Conversion;
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModRandom)).ToArray();

View File

@@ -66,18 +66,6 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("toggle black background", () => blackBackground?.FadeTo(1 - blackBackground.Alpha, 300, Easing.OutQuint));
AddSliderStep("leaderboard width", 0, 800, 300, v =>
{
if (leaderboard.IsNotNull())
leaderboard.Width = v;
});
AddSliderStep("leaderboard height", 0, 1000, 300, v =>
{
if (leaderboard.IsNotNull())
leaderboard.Height = v;
});
AddSliderStep("set player score", 50, 1_000_000, 700_000, v => gameplayState.ScoreProcessor.TotalScore.Value = v);
}
@@ -120,45 +108,6 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("wait for 1st spot", () => leaderboard.TrackedScore!.ScorePosition.Value, () => Is.EqualTo(1));
}
[Test]
public void TestLongScores()
{
AddStep("set scores", () =>
{
var friend = new APIUser { Username = "Friend", Id = 1337 };
var api = (DummyAPIAccess)API;
api.Friends.Clear();
api.Friends.Add(new APIRelation
{
Mutual = true,
RelationType = RelationType.Friend,
TargetID = friend.OnlineID,
TargetUser = friend
});
// this is dodgy but anything less dodgy is a lot of work
((Bindable<LeaderboardScores?>)leaderboardManager.Scores).Value = LeaderboardScores.Success(new[]
{
new ScoreInfo { User = new APIUser { Username = "Top", Id = 2 }, TotalScore = 900_000_000, Accuracy = 0.99, MaxCombo = 999999 },
new ScoreInfo { User = new APIUser { Username = "Second", Id = 14 }, TotalScore = 800_000_000, Accuracy = 0.9, MaxCombo = 888888 },
new ScoreInfo { User = friend, TotalScore = 700_000_000, Accuracy = 0.88, MaxCombo = 777777 },
}, 3, null);
});
createLeaderboard();
AddStep("set score to 650k", () => gameplayState.ScoreProcessor.TotalScore.Value = 650_000_000);
AddUntilStep("wait for 4th spot", () => leaderboard.TrackedScore!.ScorePosition.Value, () => Is.EqualTo(4));
AddStep("set score to 750k", () => gameplayState.ScoreProcessor.TotalScore.Value = 750_000_000);
AddUntilStep("wait for 3rd spot", () => leaderboard.TrackedScore!.ScorePosition.Value, () => Is.EqualTo(3));
AddStep("set score to 850k", () => gameplayState.ScoreProcessor.TotalScore.Value = 850_000_000);
AddUntilStep("wait for 2nd spot", () => leaderboard.TrackedScore!.ScorePosition.Value, () => Is.EqualTo(2));
AddStep("set score to 950k", () => gameplayState.ScoreProcessor.TotalScore.Value = 950_000_000);
AddUntilStep("wait for 1st spot", () => leaderboard.TrackedScore!.ScorePosition.Value, () => Is.EqualTo(1));
}
[Test]
public void TestLayoutWithManyScores()
{

View File

@@ -7,7 +7,6 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
@@ -43,8 +42,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
private DialogOverlay dialogOverlay = null!;
private LeaderboardManager leaderboardManager = null!;
private readonly IBindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?> onlineLookupResult = new Bindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?>();
private RealmPopulatingOnlineLookupSource lookupSource = null!;
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
@@ -54,7 +52,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, dependencies.Get<AudioManager>(), Resources, dependencies.Get<GameHost>(), Beatmap.Default));
dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, Realm, API));
dependencies.Cache(leaderboardManager = new LeaderboardManager());
dependencies.CacheAs(onlineLookupResult);
dependencies.Cache(lookupSource = new RealmPopulatingOnlineLookupSource());
Dependencies.Cache(Realm);
@@ -70,6 +68,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
});
LoadComponent(leaderboardManager);
LoadComponent(lookupSource);
Child = contentContainer = new OsuContextMenuContainer
{

View File

@@ -4,12 +4,13 @@
using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Extensions;
using osu.Game.Models;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Screens.SelectV2;
@@ -17,25 +18,64 @@ namespace osu.Game.Tests.Visual.SongSelectV2
{
public partial class TestSceneBeatmapMetadataWedge : SongSelectComponentsTestScene
{
private BeatmapMetadataWedge wedge = null!;
private APIBeatmapSet? currentOnlineSet;
[Cached(typeof(IBindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?>))]
private Bindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?> onlineLookupResult = new Bindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?>();
private BeatmapMetadataWedge wedge = null!;
protected override void LoadComplete()
{
base.LoadComplete();
Child = wedge = new BeatmapMetadataWedge
var lookupSource = new RealmPopulatingOnlineLookupSource();
Child = new DependencyProvidingContainer
{
State = { Value = Visibility.Visible },
RelativeSizeAxes = Axes.Both,
CachedDependencies = [(typeof(RealmPopulatingOnlineLookupSource), lookupSource)],
Children =
[
lookupSource,
wedge = new BeatmapMetadataWedge
{
State = { Value = Visibility.Visible },
}
]
};
}
[SetUpSteps]
public override void SetUpSteps()
{
AddStep("register request handling", () =>
{
((DummyAPIAccess)API).HandleRequest = request =>
{
switch (request)
{
case GetBeatmapSetRequest set:
if (set.ID == currentOnlineSet?.OnlineID)
{
set.TriggerSuccess(currentOnlineSet);
return true;
}
return false;
default:
return false;
}
};
});
}
[Test]
public void TestShowHide()
{
AddStep("all metrics", () => (Beatmap.Value, onlineLookupResult.Value) = createTestBeatmap());
AddStep("all metrics", () =>
{
var (working, onlineSet) = createTestBeatmap();
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddStep("hide wedge", () => wedge.Hide());
AddStep("show wedge", () => wedge.Show());
@@ -44,63 +84,67 @@ namespace osu.Game.Tests.Visual.SongSelectV2
[Test]
public void TestVariousMetrics()
{
AddStep("all metrics", () => (Beatmap.Value, onlineLookupResult.Value) = createTestBeatmap());
AddStep("all metrics", () =>
{
var (working, onlineSet) = createTestBeatmap();
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddStep("null beatmap", () => Beatmap.SetDefault());
AddStep("no source", () =>
{
var (working, online) = createTestBeatmap();
var (working, onlineSet) = createTestBeatmap();
working.Metadata.Source = string.Empty;
onlineLookupResult.Value = online;
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddStep("no success rate", () =>
{
var (working, online) = createTestBeatmap();
var (working, onlineSet) = createTestBeatmap();
online.Result!.Beatmaps.Single().PlayCount = 0;
online.Result!.Beatmaps.Single().PassCount = 0;
onlineSet.Beatmaps.Single().PlayCount = 0;
onlineSet.Beatmaps.Single().PassCount = 0;
onlineLookupResult.Value = online;
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddStep("no user ratings", () =>
{
var (working, online) = createTestBeatmap();
var (working, onlineSet) = createTestBeatmap();
online.Result!.Ratings = Array.Empty<int>();
onlineSet.Ratings = Array.Empty<int>();
onlineLookupResult.Value = online;
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddStep("no fail times", () =>
{
var (working, online) = createTestBeatmap();
var (working, onlineSet) = createTestBeatmap();
online.Result!.Beatmaps.Single().FailTimes = null;
onlineSet.Beatmaps.Single().FailTimes = null;
onlineLookupResult.Value = online;
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddStep("no metrics", () =>
{
var (working, online) = createTestBeatmap();
var (working, onlineSet) = createTestBeatmap();
online.Result!.Ratings = Array.Empty<int>();
online.Result!.Beatmaps.Single().FailTimes = null;
onlineSet.Ratings = Array.Empty<int>();
onlineSet.Beatmaps.Single().FailTimes = null;
onlineLookupResult.Value = online;
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddStep("local beatmap", () =>
{
var (working, _) = createTestBeatmap();
var (working, onlineSet) = createTestBeatmap();
working.BeatmapInfo.OnlineID = 0;
onlineLookupResult.Value = null;
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
}
@@ -110,16 +154,16 @@ namespace osu.Game.Tests.Visual.SongSelectV2
{
AddStep("long text", () =>
{
var (working, online) = createTestBeatmap();
var (working, onlineSet) = createTestBeatmap();
working.BeatmapInfo.Metadata.Author = new RealmUser { Username = "Verrrrryyyy llooonngggggg author" };
working.BeatmapInfo.Metadata.Source = "Verrrrryyyy llooonngggggg source";
working.BeatmapInfo.Metadata.Tags = string.Join(' ', Enumerable.Repeat(working.BeatmapInfo.Metadata.Tags, 3));
online.Result!.Genre = new BeatmapSetOnlineGenre { Id = 12, Name = "Verrrrryyyy llooonngggggg genre" };
online.Result!.Language = new BeatmapSetOnlineLanguage { Id = 12, Name = "Verrrrryyyy llooonngggggg language" };
online.Result!.Beatmaps.Single().TopTags = Enumerable.Repeat(online.Result!.Beatmaps.Single().TopTags, 3).SelectMany(t => t!).ToArray();
onlineSet.Genre = new BeatmapSetOnlineGenre { Id = 12, Name = "Verrrrryyyy llooonngggggg genre" };
onlineSet.Language = new BeatmapSetOnlineLanguage { Id = 12, Name = "Verrrrryyyy llooonngggggg language" };
onlineSet.Beatmaps.Single().TopTags = Enumerable.Repeat(onlineSet.Beatmaps.Single().TopTags, 3).SelectMany(t => t!).ToArray();
onlineLookupResult.Value = online;
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
}
@@ -127,17 +171,22 @@ namespace osu.Game.Tests.Visual.SongSelectV2
[Test]
public void TestOnlineAvailability()
{
AddStep("online beatmapset", () => (Beatmap.Value, onlineLookupResult.Value) = createTestBeatmap());
AddStep("online beatmapset", () =>
{
var (working, onlineSet) = createTestBeatmap();
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddUntilStep("rating wedge visible", () => wedge.RatingsVisible);
AddUntilStep("fail time wedge visible", () => wedge.FailRetryVisible);
AddStep("online beatmapset with local diff", () =>
{
var (working, lookupResult) = createTestBeatmap();
var (working, onlineSet) = createTestBeatmap();
working.BeatmapInfo.ResetOnlineInfo();
onlineLookupResult.Value = lookupResult;
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddUntilStep("rating wedge hidden", () => !wedge.RatingsVisible);
@@ -146,7 +195,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
{
var (working, _) = createTestBeatmap();
onlineLookupResult.Value = null;
currentOnlineSet = null;
Beatmap.Value = working;
});
AddAssert("rating wedge still hidden", () => !wedge.RatingsVisible);
@@ -156,17 +205,21 @@ namespace osu.Game.Tests.Visual.SongSelectV2
[Test]
public void TestUserTags()
{
AddStep("user tags", () => (Beatmap.Value, onlineLookupResult.Value) = createTestBeatmap());
AddStep("user tags", () =>
{
var (working, onlineSet) = createTestBeatmap();
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddStep("no user tags", () =>
{
var (working, online) = createTestBeatmap();
var (working, onlineSet) = createTestBeatmap();
online.Result!.Beatmaps.Single().TopTags = null;
online.Result!.RelatedTags = null;
working.BeatmapSetInfo.Beatmaps.Single().Metadata.UserTags.Clear();
onlineSet.Beatmaps.Single().TopTags = null;
onlineSet.RelatedTags = null;
onlineLookupResult.Value = online;
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
}
@@ -174,60 +227,72 @@ namespace osu.Game.Tests.Visual.SongSelectV2
[Test]
public void TestLoading()
{
AddStep("override request handling", () =>
{
currentOnlineSet = null;
((DummyAPIAccess)API).HandleRequest = request =>
{
switch (request)
{
case GetBeatmapSetRequest set:
Scheduler.AddDelayed(() => set.TriggerSuccess(currentOnlineSet!), 500);
return true;
default:
return false;
}
};
});
AddStep("set beatmap", () =>
{
var (working, online) = createTestBeatmap();
var (working, onlineSet) = createTestBeatmap();
onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress();
Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500);
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddWaitStep("wait", 5);
AddStep("set beatmap", () =>
{
var (working, online) = createTestBeatmap();
var (working, onlineSet) = createTestBeatmap();
online.Result!.RelatedTags![0].Name = "other/tag";
online.Result!.RelatedTags[1].Name = "another/tag";
online.Result!.RelatedTags[2].Name = "some/tag";
onlineSet.RelatedTags![0].Name = "other/tag";
onlineSet.RelatedTags[1].Name = "another/tag";
onlineSet.RelatedTags[2].Name = "some/tag";
onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress();
Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500);
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddWaitStep("wait", 5);
AddStep("no user tags", () =>
{
var (working, online) = createTestBeatmap();
var (working, onlineSet) = createTestBeatmap();
online.Result!.Beatmaps.Single().TopTags = null;
online.Result!.RelatedTags = null;
working.BeatmapSetInfo.Beatmaps.Single().Metadata.UserTags.Clear();
onlineSet.Beatmaps.Single().TopTags = null;
onlineSet.RelatedTags = null;
onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress();
Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500);
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddWaitStep("wait", 5);
AddStep("no user tags", () =>
{
var (working, online) = createTestBeatmap();
var (working, onlineSet) = createTestBeatmap();
online.Result!.Beatmaps.Single().TopTags = null;
online.Result!.RelatedTags = null;
working.BeatmapSetInfo.Beatmaps.Single().Metadata.UserTags.Clear();
onlineSet.Beatmaps.Single().TopTags = null;
onlineSet.RelatedTags = null;
onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress();
Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500);
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddWaitStep("wait", 5);
}
private (WorkingBeatmap, Screens.SelectV2.SongSelect.BeatmapSetLookupResult) createTestBeatmap()
private (WorkingBeatmap, APIBeatmapSet) createTestBeatmap()
{
var working = CreateWorkingBeatmap(Ruleset.Value);
var onlineSet = new APIBeatmapSet
@@ -281,8 +346,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
working.BeatmapSetInfo.DateSubmitted = DateTimeOffset.Now;
working.BeatmapSetInfo.DateRanked = DateTimeOffset.Now;
working.Metadata.UserTags.AddRange(onlineSet.RelatedTags.Select(t => t.Name));
return (working, Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(onlineSet));
return (working, onlineSet);
}
}
}

View File

@@ -11,7 +11,6 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;
@@ -42,8 +41,10 @@ namespace osu.Game.Tests.Visual.SongSelectV2
private BeatmapTitleWedge titleWedge = null!;
private BeatmapTitleWedge.DifficultyDisplay difficultyDisplay => titleWedge.ChildrenOfType<BeatmapTitleWedge.DifficultyDisplay>().Single();
[Cached(typeof(IBindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?>))]
private Bindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?> onlineLookupResult = new Bindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?>();
private APIBeatmapSet? currentOnlineSet;
[Cached]
private RealmPopulatingOnlineLookupSource lookupSource = new RealmPopulatingOnlineLookupSource();
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
@@ -57,6 +58,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
AddRange(new Drawable[]
{
lookupSource,
new Container
{
RelativeSizeAxes = Axes.Both,
@@ -140,18 +142,44 @@ namespace osu.Game.Tests.Visual.SongSelectV2
[Test]
public void TestOnlineAvailability()
{
AddStep("online beatmapset", () => (Beatmap.Value, onlineLookupResult.Value) = createTestBeatmap());
AddStep("set up request handler", () =>
{
((DummyAPIAccess)API).HandleRequest = request =>
{
switch (request)
{
case GetBeatmapSetRequest set:
if (set.ID == currentOnlineSet?.OnlineID)
{
set.TriggerSuccess(currentOnlineSet);
return true;
}
return false;
default:
return false;
}
};
});
AddStep("online beatmapset", () =>
{
var (working, onlineSet) = createTestBeatmap();
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddUntilStep("play count is 10000", () => this.ChildrenOfType<BeatmapTitleWedge.Statistic>().ElementAt(0).Text.ToString(), () => Is.EqualTo("10,000"));
AddUntilStep("favourites count is 2345", () => this.ChildrenOfType<BeatmapTitleWedge.FavouriteButton>().Single().Text.ToString(), () => Is.EqualTo("2,345"));
AddStep("online beatmapset with local diff", () =>
{
var (working, lookupResult) = createTestBeatmap();
var (working, onlineSet) = createTestBeatmap();
working.BeatmapInfo.ResetOnlineInfo();
currentOnlineSet = onlineSet;
Beatmap.Value = working;
onlineLookupResult.Value = lookupResult;
});
AddUntilStep("play count is -", () => this.ChildrenOfType<BeatmapTitleWedge.Statistic>().ElementAt(0).Text.ToString(), () => Is.EqualTo("-"));
AddUntilStep("favourites count is 2345", () => this.ChildrenOfType<BeatmapTitleWedge.FavouriteButton>().Single().Text.ToString(), () => Is.EqualTo("2,345"));
@@ -159,8 +187,8 @@ namespace osu.Game.Tests.Visual.SongSelectV2
{
var (working, _) = createTestBeatmap();
currentOnlineSet = null;
Beatmap.Value = working;
onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(null);
});
AddUntilStep("play count is -", () => this.ChildrenOfType<BeatmapTitleWedge.Statistic>().ElementAt(0).Text.ToString(), () => Is.EqualTo("-"));
AddUntilStep("favourites count is -", () => this.ChildrenOfType<BeatmapTitleWedge.FavouriteButton>().Single().Text.ToString(), () => Is.EqualTo("-"));
@@ -177,6 +205,15 @@ namespace osu.Game.Tests.Visual.SongSelectV2
{
switch (request)
{
case GetBeatmapSetRequest set:
if (set.ID == currentOnlineSet?.OnlineID)
{
set.TriggerSuccess(currentOnlineSet);
return true;
}
return false;
case PostBeatmapFavouriteRequest favourite:
Task.Run(() =>
{
@@ -191,8 +228,13 @@ namespace osu.Game.Tests.Visual.SongSelectV2
};
});
AddStep("online beatmapset", () => (Beatmap.Value, onlineLookupResult.Value) = createTestBeatmap());
AddStep("online beatmapset", () =>
{
var (working, onlineSet) = createTestBeatmap();
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddUntilStep("play count is 10000", () => this.ChildrenOfType<BeatmapTitleWedge.Statistic>().ElementAt(0).Text.ToString(), () => Is.EqualTo("10,000"));
AddUntilStep("favourites count is 2345", () => this.ChildrenOfType<BeatmapTitleWedge.FavouriteButton>().Single().Text.ToString(), () => Is.EqualTo("2,345"));
@@ -209,13 +251,13 @@ namespace osu.Game.Tests.Visual.SongSelectV2
AddStep("click favourite button", () => this.ChildrenOfType<BeatmapTitleWedge.FavouriteButton>().Single().TriggerClick());
AddStep("change to another beatmap", () =>
{
var (working, online) = createTestBeatmap();
online.Result!.FavouriteCount = 9999;
online.Result!.HasFavourited = true;
working.BeatmapSetInfo.OnlineID = online.Result!.OnlineID = 99999;
var (working, onlineSet) = createTestBeatmap();
onlineSet.FavouriteCount = 9999;
onlineSet.HasFavourited = true;
working.BeatmapSetInfo.OnlineID = onlineSet.OnlineID = 99999;
currentOnlineSet = onlineSet;
Beatmap.Value = working;
onlineLookupResult.Value = online;
});
AddStep("allow request to complete", () => resetEvent.Set());
AddUntilStep("favourites count is 9999", () => this.ChildrenOfType<BeatmapTitleWedge.FavouriteButton>().Single().Text.ToString(), () => Is.EqualTo("9,999"));
@@ -226,6 +268,15 @@ namespace osu.Game.Tests.Visual.SongSelectV2
{
switch (request)
{
case GetBeatmapSetRequest set:
if (set.ID == currentOnlineSet?.OnlineID)
{
set.TriggerSuccess(currentOnlineSet);
return true;
}
return false;
case PostBeatmapFavouriteRequest favourite:
Task.Run(() =>
{
@@ -299,7 +350,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
});
}
private (WorkingBeatmap, Screens.SelectV2.SongSelect.BeatmapSetLookupResult) createTestBeatmap()
private (WorkingBeatmap, APIBeatmapSet) createTestBeatmap()
{
var working = CreateWorkingBeatmap(Ruleset.Value);
var onlineSet = new APIBeatmapSet
@@ -320,7 +371,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
working.BeatmapSetInfo.DateSubmitted = DateTimeOffset.Now;
working.BeatmapSetInfo.DateRanked = DateTimeOffset.Now;
return (working, Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(onlineSet));
return (working, onlineSet);
}
private class TestHitObject : ConvertHitObject;

View File

@@ -4,13 +4,11 @@
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
@@ -24,9 +22,6 @@ namespace osu.Game.Tests.Visual.UserInterface
private FillFlowContainer spreadOutFlow = null!;
private ModDisplay modDisplay = null!;
[Resolved]
private RulesetStore rulesetStore { get; set; } = null!;
[SetUpSteps]
public void SetUpSteps()
{
@@ -75,26 +70,9 @@ namespace osu.Game.Tests.Visual.UserInterface
[Test]
public void TestShowAllMods()
{
createModIconsForRuleset(0);
createModIconsForRuleset(1);
createModIconsForRuleset(2);
createModIconsForRuleset(3);
AddStep("toggle selected", () =>
AddStep("create mod icons", () =>
{
foreach (var icon in this.ChildrenOfType<ModIcon>())
icon.Selected.Toggle();
});
}
private void createModIconsForRuleset(int rulesetId)
{
AddStep($"create mod icons for ruleset {rulesetId}", () =>
{
spreadOutFlow.Clear();
modDisplay.Current.Value = [];
addRange(rulesetStore.GetRuleset(rulesetId)!.CreateInstance().CreateAllMods().Select(m =>
addRange(Ruleset.Value.CreateInstance().CreateAllMods().Select(m =>
{
if (m is OsuModFlashlight fl)
fl.FollowDelay.Value = 1245;
@@ -111,6 +89,12 @@ namespace osu.Game.Tests.Visual.UserInterface
return m;
}));
});
AddStep("toggle selected", () =>
{
foreach (var icon in this.ChildrenOfType<ModIcon>())
icon.Selected.Toggle();
});
}
[Test]

View File

@@ -0,0 +1,128 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Framework.Utils;
using osu.Game.Configuration;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Audio
{
[Cached]
public partial class WelcomeMusicManager : Drawable
{
public event Action<Exception> OnLoadFailure;
public event Action OnCategoriesRefreshed;
public readonly Bindable<IEnumerable<string>> AvailableCategories = new Bindable<IEnumerable<string>>();
private ITrack preloadedTrack;
private List<APIWelcomeMusic> currentTracks;
[Resolved]
private IAPIProvider api { get; set; }
[Resolved]
private AudioManager audioManager { get; set; }
[Resolved]
private OsuConfigManager config { get; set; }
[Resolved]
private GameHost host { get; set; }
private Bindable<WelcomeMusicMode> musicMode;
private Bindable<string> selectedCategory;
[BackgroundDependencyLoader]
private void load()
{
musicMode = config.GetBindable<WelcomeMusicMode>(OsuSetting.WelcomeMusicMode);
selectedCategory = config.GetBindable<string>(OsuSetting.WelcomeMusicCategory);
fetchCategories();
}
public void RefreshCategories() => fetchCategories();
private void fetchCategories()
{
var request = new GetMusicCategoriesRequest();
request.Success += response =>
{
var serverCategories = response.Categories ?? Enumerable.Empty<string>();
AvailableCategories.Value = serverCategories.ToList();
OnCategoriesRefreshed?.Invoke();
};
request.Failure += exception =>
{
Logger.Error(exception, "ОШИБКА: Не удалось загрузить категории музыки!");
AvailableCategories.Value = new[] { "Не удалось загрузить..." };
OnLoadFailure?.Invoke(exception);
};
api.PerformAsync(request);
}
public async Task PreloadCurrentTrack()
{
if (musicMode.Value == WelcomeMusicMode.Default)
{
preloadedTrack = audioManager.Tracks.Get("Samples/welcome.ogg");
return;
}
if (string.IsNullOrEmpty(selectedCategory.Value) || selectedCategory.Value.Contains("Не удалось"))
return;
var request = new GetWelcomeMusicRequest(selectedCategory.Value);
var tcs = new TaskCompletionSource<bool>();
request.Success += response =>
{
currentTracks = response;
tcs.SetResult(true);
};
request.Failure += exception =>
{
Logger.Error(exception, "ОШИБКА: Не удалось загрузить список треков!");
tcs.SetResult(false);
};
api.PerformAsync(request);
await tcs.Task;
if (currentTracks?.Any() != true)
return;
var randomTrackInfo = currentTracks[RNG.Next(0, currentTracks.Count)];
try
{
preloadedTrack = audioManager.Tracks.Get(randomTrackInfo.Url);
if (preloadedTrack != null)
preloadedTrack.Looping = false;
}
catch (Exception e)
{
Logger.Error(e, $"ОШИБКА: Не удалось загрузить трек по URL: {randomTrackInfo.Url}");
}
}
public ITrack GetPreloadedTrack() => preloadedTrack;
public void RequestRestart()
{
host.Exit();
}
}
}

View File

@@ -8,7 +8,6 @@ using osu.Framework.Configuration;
using osu.Framework.Configuration.Tracking;
using osu.Framework.Extensions;
using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics;
using osu.Framework.Localisation;
using osu.Framework.Platform;
using osu.Game.Beatmaps.Drawables.Cards;
@@ -42,8 +41,6 @@ namespace osu.Game.Configuration
SetDefault(OsuSetting.Ruleset, string.Empty);
SetDefault(OsuSetting.Skin, SkinInfo.ARGON_SKIN.ToString());
SetDefault(OsuSetting.MenuCookieColor, Colour4.FromHex(@"ff66ba"));
SetDefault(OsuSetting.BeatmapDetailTab, BeatmapDetailTab.Local);
SetDefault(OsuSetting.BeatmapLeaderboardSortMode, LeaderboardSortMode.Score);
SetDefault(OsuSetting.BeatmapDetailModsFilter, false);
@@ -68,7 +65,6 @@ namespace osu.Game.Configuration
SetDefault(OsuSetting.ToolbarClockDisplayMode, ToolbarClockDisplayMode.Full);
SetDefault(OsuSetting.ForceLegacySongSelect, false);
SetDefault(OsuSetting.SongSelectBackgroundBlur, false);
// Online settings
@@ -217,6 +213,8 @@ namespace osu.Game.Configuration
SetDefault(OsuSetting.MultiplayerShowInProgressFilter, true);
SetDefault(OsuSetting.LastProcessedMetadataId, -1);
SetDefault(OsuSetting.WelcomeMusicMode, WelcomeMusicMode.Default);
SetDefault(OsuSetting.WelcomeMusicCategory, "Default");
SetDefault(OsuSetting.ComboColourNormalisationAmount, 0.2f, 0f, 1f, 0.01f);
SetDefault(OsuSetting.UserOnlineStatus, UserStatus.Online);
@@ -386,6 +384,8 @@ namespace osu.Game.Configuration
AudioOffset,
VolumeInactive,
WelcomeMusicMode,
WelcomeMusicCategory,
MenuMusic,
MenuVoice,
MenuTips,
@@ -409,7 +409,6 @@ namespace osu.Game.Configuration
ChatDisplayHeight,
BeatmapListingCardSize,
ToolbarClockDisplayMode,
ForceLegacySongSelect,
SongSelectBackgroundBlur,
Version,
ShowFirstRunSetup,
@@ -417,7 +416,6 @@ namespace osu.Game.Configuration
Skin,
ScreenshotFormat,
ScreenshotCaptureMenuCursor,
MenuCookieColor,
BeatmapSkins,
BeatmapColours,
BeatmapHitsounds,

View File

@@ -0,0 +1,11 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
namespace osu.Game.Configuration
{
public enum WelcomeMusicMode
{
Default,
Custom
}
}

View File

@@ -558,15 +558,9 @@ namespace osu.Game.Database
Logger.Log("Querying for beatmap sets that contain missing submission/rank date...");
// find all ranked beatmap sets with missing date ranked or date submitted that have at least one difficulty ranked as well.
// the reason for checking ranked status of the difficulties is that they can be locally modified or unknown too, and for those the lookup is likely to fail.
// this is because metadata lookups are primarily based on file hash, so they will fail to match if the beatmap does not match the online version
// (which is likely to be the case if the beatmap is locally modified or unknown).
// that said, one difficulty in ranked state is enough for the backpopulation to work.
HashSet<Guid> beatmapSetIds = realmAccess.Run(r => new HashSet<Guid>(
r.All<BeatmapSetInfo>()
.Filter($@"{nameof(BeatmapSetInfo.StatusInt)} > 0 && ({nameof(BeatmapSetInfo.DateRanked)} == null || {nameof(BeatmapSetInfo.DateSubmitted)} == null) "
+ $@"&& ANY {nameof(BeatmapSetInfo.Beatmaps)}.{nameof(BeatmapInfo.StatusInt)} > 0")
.Where(b => b.StatusInt > 0 && (b.DateRanked == null || b.DateSubmitted == null))
.AsEnumerable()
.Select(b => b.ID)));
@@ -597,7 +591,11 @@ namespace osu.Game.Database
{
BeatmapSetInfo beatmapSet = r.Find<BeatmapSetInfo>(id)!;
var beatmap = beatmapSet.Beatmaps.First(b => b.Status >= BeatmapOnlineStatus.Ranked);
// we want any ranked representative of the set.
// the reason for checking ranked status of the difficulty is that it can be locally modified,
// at which point the lookup will fail - but there might still be another unmodified difficulty on which it will work.
if (beatmapSet.Beatmaps.FirstOrDefault(b => b.Status >= BeatmapOnlineStatus.Ranked) is not BeatmapInfo beatmap)
return false;
bool lookupSucceeded = localMetadataSource.TryLookup(beatmap, out var result);

View File

@@ -81,6 +81,27 @@ namespace osu.Game.Graphics
public static IconUsage InsaneMania => get(0xe027);
public static IconUsage ExpertMania => get(0xe028);
// mod icons
public static IconUsage ModPerfect => get(0xe049);
public static IconUsage ModAutopilot => get(0xe03a);
public static IconUsage ModAuto => get(0xe03b);
public static IconUsage ModCinema => get(0xe03c);
public static IconUsage ModDoubleTime => get(0xe03d);
public static IconUsage ModEasy => get(0xe03e);
public static IconUsage ModFlashlight => get(0xe03f);
public static IconUsage ModHalftime => get(0xe040);
public static IconUsage ModHardRock => get(0xe041);
public static IconUsage ModHidden => get(0xe042);
public static IconUsage ModNightcore => get(0xe043);
public static IconUsage ModNoFail => get(0xe044);
public static IconUsage ModRelax => get(0xe045);
public static IconUsage ModSpunOut => get(0xe046);
public static IconUsage ModSuddenDeath => get(0xe047);
public static IconUsage ModTarget => get(0xe048);
// Use "Icons/BeatmapDetails/mod-icon" instead
// public static IconUsage ModBg => Get(0xe04a);
#endregion
#region New single-file-based icons
@@ -160,88 +181,6 @@ namespace osu.Game.Graphics
public static IconUsage Tortoise => get(OsuIconMapping.Tortoise);
public static IconUsage Hare => get(OsuIconMapping.Hare);
// mod icons
public static IconUsage ModNoMod => get(OsuIconMapping.ModNoMod);
/*
can be regenerated semi-automatically using osu-web's mod database via
$ jq -r '.[].Mods[].Name' mods.json | sort | uniq | \
sed 's/ //g' | \
awk '{print "public static IconUsage Mod" $0 " => get(OsuIconMapping.Mod" $0 ");"}' | pbcopy
*/
public static IconUsage ModAccuracyChallenge => get(OsuIconMapping.ModAccuracyChallenge);
public static IconUsage ModAdaptiveSpeed => get(OsuIconMapping.ModAdaptiveSpeed);
public static IconUsage ModAlternate => get(OsuIconMapping.ModAlternate);
public static IconUsage ModApproachDifferent => get(OsuIconMapping.ModApproachDifferent);
public static IconUsage ModAutopilot => get(OsuIconMapping.ModAutopilot);
public static IconUsage ModAutoplay => get(OsuIconMapping.ModAutoplay);
public static IconUsage ModBarrelRoll => get(OsuIconMapping.ModBarrelRoll);
public static IconUsage ModBlinds => get(OsuIconMapping.ModBlinds);
public static IconUsage ModBloom => get(OsuIconMapping.ModBloom);
public static IconUsage ModBubbles => get(OsuIconMapping.ModBubbles);
public static IconUsage ModCinema => get(OsuIconMapping.ModCinema);
public static IconUsage ModClassic => get(OsuIconMapping.ModClassic);
public static IconUsage ModConstantSpeed => get(OsuIconMapping.ModConstantSpeed);
public static IconUsage ModCover => get(OsuIconMapping.ModCover);
public static IconUsage ModDaycore => get(OsuIconMapping.ModDaycore);
public static IconUsage ModDeflate => get(OsuIconMapping.ModDeflate);
public static IconUsage ModDepth => get(OsuIconMapping.ModDepth);
public static IconUsage ModDifficultyAdjust => get(OsuIconMapping.ModDifficultyAdjust);
public static IconUsage ModDoubleTime => get(OsuIconMapping.ModDoubleTime);
public static IconUsage ModDualStages => get(OsuIconMapping.ModDualStages);
public static IconUsage ModEasy => get(OsuIconMapping.ModEasy);
public static IconUsage ModEightKeys => get(OsuIconMapping.ModEightKeys);
public static IconUsage ModFadeIn => get(OsuIconMapping.ModFadeIn);
public static IconUsage ModFiveKeys => get(OsuIconMapping.ModFiveKeys);
public static IconUsage ModFlashlight => get(OsuIconMapping.ModFlashlight);
public static IconUsage ModFloatingFruits => get(OsuIconMapping.ModFloatingFruits);
public static IconUsage ModFourKeys => get(OsuIconMapping.ModFourKeys);
public static IconUsage ModFreezeFrame => get(OsuIconMapping.ModFreezeFrame);
public static IconUsage ModGrow => get(OsuIconMapping.ModGrow);
public static IconUsage ModHalfTime => get(OsuIconMapping.ModHalfTime);
public static IconUsage ModHardRock => get(OsuIconMapping.ModHardRock);
public static IconUsage ModHidden => get(OsuIconMapping.ModHidden);
public static IconUsage ModHoldOff => get(OsuIconMapping.ModHoldOff);
public static IconUsage ModInvert => get(OsuIconMapping.ModInvert);
public static IconUsage ModMagnetised => get(OsuIconMapping.ModMagnetised);
public static IconUsage ModMirror => get(OsuIconMapping.ModMirror);
public static IconUsage ModMovingFast => get(OsuIconMapping.ModMovingFast);
public static IconUsage ModMuted => get(OsuIconMapping.ModMuted);
public static IconUsage ModNightcore => get(OsuIconMapping.ModNightcore);
public static IconUsage ModNineKeys => get(OsuIconMapping.ModNineKeys);
public static IconUsage ModNoFail => get(OsuIconMapping.ModNoFail);
public static IconUsage ModNoRelease => get(OsuIconMapping.ModNoRelease);
public static IconUsage ModNoScope => get(OsuIconMapping.ModNoScope);
public static IconUsage ModOneKey => get(OsuIconMapping.ModOneKey);
public static IconUsage ModPerfect => get(OsuIconMapping.ModPerfect);
public static IconUsage ModRandom => get(OsuIconMapping.ModRandom);
public static IconUsage ModRelax => get(OsuIconMapping.ModRelax);
public static IconUsage ModRepel => get(OsuIconMapping.ModRepel);
public static IconUsage ModScoreV2 => get(OsuIconMapping.ModScoreV2);
public static IconUsage ModSevenKeys => get(OsuIconMapping.ModSevenKeys);
public static IconUsage ModSimplifiedRhythm => get(OsuIconMapping.ModSimplifiedRhythm);
public static IconUsage ModSingleTap => get(OsuIconMapping.ModSingleTap);
public static IconUsage ModSixKeys => get(OsuIconMapping.ModSixKeys);
public static IconUsage ModSpinIn => get(OsuIconMapping.ModSpinIn);
public static IconUsage ModSpunOut => get(OsuIconMapping.ModSpunOut);
public static IconUsage ModStrictTracking => get(OsuIconMapping.ModStrictTracking);
public static IconUsage ModSuddenDeath => get(OsuIconMapping.ModSuddenDeath);
public static IconUsage ModSwap => get(OsuIconMapping.ModSwap);
public static IconUsage ModSynesthesia => get(OsuIconMapping.ModSynesthesia);
public static IconUsage ModTargetPractice => get(OsuIconMapping.ModTargetPractice);
public static IconUsage ModTenKeys => get(OsuIconMapping.ModTenKeys);
public static IconUsage ModThreeKeys => get(OsuIconMapping.ModThreeKeys);
public static IconUsage ModTouchDevice => get(OsuIconMapping.ModTouchDevice);
public static IconUsage ModTraceable => get(OsuIconMapping.ModTraceable);
public static IconUsage ModTransform => get(OsuIconMapping.ModTransform);
public static IconUsage ModTwoKeys => get(OsuIconMapping.ModTwoKeys);
public static IconUsage ModWiggle => get(OsuIconMapping.ModWiggle);
public static IconUsage ModWindDown => get(OsuIconMapping.ModWindDown);
public static IconUsage ModWindUp => get(OsuIconMapping.ModWindUp);
private static IconUsage get(OsuIconMapping glyph) => new IconUsage((char)glyph, FONT_NAME);
private enum OsuIconMapping
@@ -461,224 +400,6 @@ namespace osu.Game.Graphics
[Description(@"hare")]
Hare,
// mod icons
[Description(@"Mods/mod-no-mod")]
ModNoMod,
/*
rest can be regenerated semi-automatically using osu-web's mod database via
$ jq -r '.[].Mods[].Name' mods.json | sort | uniq | \
awk '{kebab = $0; gsub(" ", "-", kebab); pascal = $0; gsub(" ", "", pascal); print "[Description(@\"Mods/mod-" tolower(kebab) "\")]\nMod" pascal ",\n" }' | pbcopy
*/
[Description(@"Mods/mod-accuracy-challenge")]
ModAccuracyChallenge,
[Description(@"Mods/mod-adaptive-speed")]
ModAdaptiveSpeed,
[Description(@"Mods/mod-alternate")]
ModAlternate,
[Description(@"Mods/mod-approach-different")]
ModApproachDifferent,
[Description(@"Mods/mod-autopilot")]
ModAutopilot,
[Description(@"Mods/mod-autoplay")]
ModAutoplay,
[Description(@"Mods/mod-barrel-roll")]
ModBarrelRoll,
[Description(@"Mods/mod-blinds")]
ModBlinds,
[Description(@"Mods/mod-bloom")]
ModBloom,
[Description(@"Mods/mod-bubbles")]
ModBubbles,
[Description(@"Mods/mod-cinema")]
ModCinema,
[Description(@"Mods/mod-classic")]
ModClassic,
[Description(@"Mods/mod-constant-speed")]
ModConstantSpeed,
[Description(@"Mods/mod-cover")]
ModCover,
[Description(@"Mods/mod-daycore")]
ModDaycore,
[Description(@"Mods/mod-deflate")]
ModDeflate,
[Description(@"Mods/mod-depth")]
ModDepth,
[Description(@"Mods/mod-difficulty-adjust")]
ModDifficultyAdjust,
[Description(@"Mods/mod-double-time")]
ModDoubleTime,
[Description(@"Mods/mod-dual-stages")]
ModDualStages,
[Description(@"Mods/mod-easy")]
ModEasy,
[Description(@"Mods/mod-eight-keys")]
ModEightKeys,
[Description(@"Mods/mod-fade-in")]
ModFadeIn,
[Description(@"Mods/mod-five-keys")]
ModFiveKeys,
[Description(@"Mods/mod-flashlight")]
ModFlashlight,
[Description(@"Mods/mod-floating-fruits")]
ModFloatingFruits,
[Description(@"Mods/mod-four-keys")]
ModFourKeys,
[Description(@"Mods/mod-freeze-frame")]
ModFreezeFrame,
[Description(@"Mods/mod-grow")]
ModGrow,
[Description(@"Mods/mod-half-time")]
ModHalfTime,
[Description(@"Mods/mod-hard-rock")]
ModHardRock,
[Description(@"Mods/mod-hidden")]
ModHidden,
[Description(@"Mods/mod-hold-off")]
ModHoldOff,
[Description(@"Mods/mod-invert")]
ModInvert,
[Description(@"Mods/mod-magnetised")]
ModMagnetised,
[Description(@"Mods/mod-mirror")]
ModMirror,
[Description(@"Mods/mod-moving-fast")]
ModMovingFast,
[Description(@"Mods/mod-muted")]
ModMuted,
[Description(@"Mods/mod-nightcore")]
ModNightcore,
[Description(@"Mods/mod-nine-keys")]
ModNineKeys,
[Description(@"Mods/mod-no-fail")]
ModNoFail,
[Description(@"Mods/mod-no-release")]
ModNoRelease,
[Description(@"Mods/mod-no-scope")]
ModNoScope,
[Description(@"Mods/mod-one-key")]
ModOneKey,
[Description(@"Mods/mod-perfect")]
ModPerfect,
[Description(@"Mods/mod-random")]
ModRandom,
[Description(@"Mods/mod-relax")]
ModRelax,
[Description(@"Mods/mod-repel")]
ModRepel,
[Description(@"Mods/mod-score-v2")]
ModScoreV2,
[Description(@"Mods/mod-seven-keys")]
ModSevenKeys,
[Description(@"Mods/mod-simplified-rhythm")]
ModSimplifiedRhythm,
[Description(@"Mods/mod-single-tap")]
ModSingleTap,
[Description(@"Mods/mod-six-keys")]
ModSixKeys,
[Description(@"Mods/mod-spin-in")]
ModSpinIn,
[Description(@"Mods/mod-spun-out")]
ModSpunOut,
[Description(@"Mods/mod-strict-tracking")]
ModStrictTracking,
[Description(@"Mods/mod-sudden-death")]
ModSuddenDeath,
[Description(@"Mods/mod-swap")]
ModSwap,
[Description(@"Mods/mod-synesthesia")]
ModSynesthesia,
[Description(@"Mods/mod-target-practice")]
ModTargetPractice,
[Description(@"Mods/mod-ten-keys")]
ModTenKeys,
[Description(@"Mods/mod-three-keys")]
ModThreeKeys,
[Description(@"Mods/mod-touch-device")]
ModTouchDevice,
[Description(@"Mods/mod-traceable")]
ModTraceable,
[Description(@"Mods/mod-transform")]
ModTransform,
[Description(@"Mods/mod-two-keys")]
ModTwoKeys,
[Description(@"Mods/mod-wiggle")]
ModWiggle,
[Description(@"Mods/mod-wind-down")]
ModWindDown,
[Description(@"Mods/mod-wind-up")]
ModWindUp,
}
public class OsuIconStore : ITextureStore, ITexturedGlyphLookupStore

View File

@@ -184,11 +184,6 @@ namespace osu.Game.Localisation
/// </summary>
public static LocalisableString SelectedMods => new TranslatableString(getKey(@"selected_mods"), @"Selected Mods");
/// <summary>
/// "Use legacy song select (SelectV1)"
/// </summary>
public static LocalisableString ForceLegacySongSelect => new TranslatableString(getKey(@"force_select_v1"), @"Use legacy song select (SelectV1)");
private static string getKey(string key) => $@"{prefix}:{key}";
}
}

View File

@@ -0,0 +1,12 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Online.API.Requests
{
public class GetMusicCategoriesRequest : APIRequest<APIBackgroundCategories>
{
protected override string Target => @"https://osu.jvnko.boats/welcome-music/categories";
}
}

View File

@@ -0,0 +1,21 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Net;
using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Online.API.Requests
{
public class GetWelcomeMusicRequest : APIRequest<List<APIWelcomeMusic>>
{
private readonly string category;
public GetWelcomeMusicRequest(string category)
{
this.category = category;
}
protected override string Target => $"https://osu.jvnko.boats/welcome-music/list?category={WebUtility.UrlEncode(category)}";
}
}

View File

@@ -0,0 +1,17 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using Newtonsoft.Json;
namespace osu.Game.Online.API.Requests.Responses
{
// Описывает один трек, как он приходит с сервера
public class APIWelcomeMusic
{
[JsonProperty("name")]
public string? Name { get; set; }
[JsonProperty("url")]
public string? Url { get; set; }
}
}

View File

@@ -32,6 +32,7 @@ using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Threading;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Collections;
using osu.Game.Configuration;
@@ -170,8 +171,11 @@ namespace osu.Game
[Cached]
private readonly ScreenshotManager screenshotManager = new ScreenshotManager();
// --- ÍÀØÈ ÍÎÂÛÅ ÊÎÌÏÎÍÅÍÒÛ ---
[Cached]
private readonly SeasonalBackgroundLoader backgroundLoader;
[Cached]
private readonly WelcomeMusicManager musicManager;
protected SentryLogger SentryLogger;
@@ -253,9 +257,11 @@ namespace osu.Game
public OsuGame(string[] args = null)
{
// --- ÑÎÇÄÀÅÌ ÍÀØÈ ÊÎÌÏÎÍÅÍÒÛ È ÏÎÄÏÈÑÛÂÀÅÌÑß ÍÀ ÑÎÁÛÒÈß ---
backgroundLoader = new SeasonalBackgroundLoader();
backgroundLoader.OnLoadFailure += handleBackgroundLoadFailure;
backgroundLoader.OnCategoriesRefreshed += handleCategoriesRefreshed;
musicManager = new WelcomeMusicManager();
this.args = args;
@@ -415,9 +421,8 @@ namespace osu.Game
{
Notifications?.Post(new SimpleNotification
{
Text = ButtonSystemStrings.SeasonalBackgroundsRefreshed,
Icon = FontAwesome.Solid.CheckCircle,
Transient = true
Text = "Ñïèñîê êàòåãîðèé ôîíîâ îáíîâëåí.",
Icon = FontAwesome.Solid.CheckCircle
});
});
}
@@ -471,7 +476,8 @@ namespace osu.Game
IsActive.BindValueChanged(active => updateActiveState(active.NewValue), true);
Audio.AddAdjustment(AdjustableProperty.Volume, inactiveVolumeFade);
dependencies.CacheAs(musicManager);
Add(musicManager);
SelectedMods.BindValueChanged(modsChanged);
Beatmap.BindValueChanged(beatmapChanged, true);
configUserActivity.BindValueChanged(_ => updateWindowTitle());
@@ -1287,7 +1293,12 @@ namespace osu.Game
}, rightFloatingOverlayContent.Add, true);
loadComponentSingleFile(new AccountCreationOverlay(), topMostOverlayContent.Add, true);
loadComponentSingleFile<IDialogOverlay>(new DialogOverlay(), topMostOverlayContent.Add, true);
var dialogOverlay = new DialogOverlay();
dependencies.CacheAs<IDialogOverlay>(dialogOverlay);
dependencies.Cache(dialogOverlay);
loadComponentSingleFile(dialogOverlay, topMostOverlayContent.Add);
loadComponentSingleFile(new MedalOverlay(), topMostOverlayContent.Add);
loadComponentSingleFile(new BackgroundDataStoreProcessor(), Add);

View File

@@ -5,16 +5,15 @@
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Localisation;
using osu.Game.Audio;
using osu.Game.Configuration;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Localisation;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Settings;
using osu.Game.Overlays.Dialog;
namespace osu.Game.Overlays.Settings.Sections.UserInterface
{
@@ -24,19 +23,24 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
[Resolved]
private SeasonalBackgroundLoader backgroundLoader { get; set; }
[Resolved]
private WelcomeMusicManager musicManager { get; set; }
[Resolved]
private DialogOverlay dialogOverlay { get; set; }
private IBindable<APIUser> user;
private SettingsEnumDropdown<BackgroundSource> backgroundSourceDropdown;
[BackgroundDependencyLoader]
private void load(OsuConfigManager config, IAPIProvider api)
{
AutoSizeAxes = Axes.Y;
user = api.LocalUser.GetBoundCopy();
var backgroundModeBindable = config.GetBindable<SeasonalBackgroundMode>(OsuSetting.SeasonalBackgroundMode);
var enabledProxyBindable = new Bindable<bool>();
backgroundModeBindable.BindValueChanged(mode => enabledProxyBindable.Value = mode.NewValue == SeasonalBackgroundMode.Always, true);
enabledProxyBindable.BindValueChanged(enabled => backgroundModeBindable.Value = enabled.NewValue ? SeasonalBackgroundMode.Always : SeasonalBackgroundMode.Never);
@@ -45,21 +49,17 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
LabelText = UserInterfaceStrings.UseSeasonalBackgrounds,
Current = enabledProxyBindable
};
var categoryDropdown = new SettingsDropdown<string>
{
LabelText = UserInterfaceStrings.SeasonalBackgroundsCategories,
Current = config.GetBindable<string>(OsuSetting.BackgroundCategory)
};
var refreshButton = new SettingsButton
{
Text = UserInterfaceStrings.SeasonalBackgroundsRefresh,
Action = () => backgroundLoader.RefreshCategories()
};
backgroundLoader.AvailableCategories.BindValueChanged(categories => categoryDropdown.Items = categories.NewValue, true);
backgroundModeBindable.BindValueChanged(mode =>
{
if (mode.NewValue == SeasonalBackgroundMode.Always)
@@ -74,6 +74,51 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
}
}, true);
var musicModeDropdown = new SettingsEnumDropdown<WelcomeMusicMode>
{
LabelText = "Музыкальное приветствие",
Current = config.GetBindable<WelcomeMusicMode>(OsuSetting.WelcomeMusicMode)
};
var musicCategoryDropdown = new SettingsDropdown<string>
{
LabelText = "Категория музыки",
Current = config.GetBindable<string>(OsuSetting.WelcomeMusicCategory)
};
var refreshMusicButton = new SettingsButton
{
Text = "Обновить категории музыки",
Action = () => musicManager.RefreshCategories()
};
musicModeDropdown.Current.BindValueChanged(mode =>
{
if (mode.NewValue == WelcomeMusicMode.Custom)
{
musicCategoryDropdown.Show();
refreshMusicButton.Show();
}
else
{
musicCategoryDropdown.Hide();
refreshMusicButton.Hide();
}
}, true);
musicCategoryDropdown.Current.BindValueChanged(category =>
{
if (category.OldValue != null &&
musicModeDropdown.Current.Value == WelcomeMusicMode.Custom &&
!category.OldValue.Equals(category.NewValue))
{
dialogOverlay.Push(new ConfirmDialog("Для применения этой настройки требуется перезапуск.",
() => musicManager.RequestRestart()));
}
});
musicManager.AvailableCategories.BindValueChanged(categories => musicCategoryDropdown.Items = categories.NewValue, true);
Children = new Drawable[]
{
new SettingsCheckbox
@@ -93,6 +138,9 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
LabelText = UserInterfaceStrings.OsuMusicTheme,
Current = config.GetBindable<bool>(OsuSetting.MenuMusic)
},
musicModeDropdown,
musicCategoryDropdown,
refreshMusicButton,
new SettingsEnumDropdown<IntroSequence>
{
LabelText = UserInterfaceStrings.IntroSequence,
@@ -106,12 +154,6 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
backgroundToggle,
categoryDropdown,
refreshButton,
new SettingsColour
{
LabelText = @"osu! logo colour",
Current = config.GetBindable<Colour4>(OsuSetting.MenuCookieColor),
ClassicDefault = Colour4.FromHex(@"ff66ba"),
},
};
}

View File

@@ -19,12 +19,6 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
{
Children = new Drawable[]
{
new SettingsCheckbox
{
LabelText = UserInterfaceStrings.ForceLegacySongSelect,
Current = config.GetBindable<bool>(OsuSetting.ForceLegacySongSelect),
ClassicDefault = false
},
new SettingsCheckbox
{
LabelText = UserInterfaceStrings.ShowConvertedBeatmaps,

View File

@@ -6,10 +6,8 @@ using System.Collections.Generic;
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Localisation.HUD;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets.Scoring;
@@ -26,8 +24,6 @@ namespace osu.Game.Rulesets.Mods
public override LocalisableString Description => "Fail if your accuracy drops too low!";
public override IconUsage? Icon => OsuIcon.ModAccuracyChallenge;
public override ModType Type => ModType.DifficultyIncrease;
public override double ScoreMultiplier => 1.0;

View File

@@ -6,12 +6,10 @@ using System.Collections.Generic;
using System.Linq;
using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
@@ -29,8 +27,6 @@ namespace osu.Game.Rulesets.Mods
public override LocalisableString Description => "Let track speed adapt to you.";
public override IconUsage? Icon => OsuIcon.ModAdaptiveSpeed;
public override ModType Type => ModType.Fun;
public override double ScoreMultiplier => 0.5;

View File

@@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mods
{
public override string Name => "Autoplay";
public override string Acronym => "AT";
public override IconUsage? Icon => OsuIcon.ModAutoplay;
public override IconUsage? Icon => OsuIcon.ModAuto;
public override ModType Type => ModType.Automation;
public override LocalisableString Description => "Watch a perfect automated play through the song.";
public override double ScoreMultiplier => 1;

View File

@@ -6,10 +6,8 @@ using System.Collections.Generic;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.UI;
using osuTK;
@@ -38,7 +36,6 @@ namespace osu.Game.Rulesets.Mods
public override string Name => "Barrel Roll";
public override string Acronym => "BR";
public override IconUsage? Icon => OsuIcon.ModBarrelRoll;
public override LocalisableString Description => "The whole playfield is on a wheel!";
public override double ScoreMultiplier => 1;

View File

@@ -3,7 +3,6 @@
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods
{
@@ -15,7 +14,7 @@ namespace osu.Game.Rulesets.Mods
public override double ScoreMultiplier => 0.96;
public override IconUsage? Icon => OsuIcon.ModClassic;
public override IconUsage? Icon => FontAwesome.Solid.History;
public override LocalisableString Description => "Feeling nostalgic?";

View File

@@ -6,7 +6,6 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Overlays.Settings;
namespace osu.Game.Rulesets.Mods
@@ -15,7 +14,7 @@ namespace osu.Game.Rulesets.Mods
{
public override string Name => "Daycore";
public override string Acronym => "DC";
public override IconUsage? Icon => OsuIcon.ModDaycore;
public override IconUsage? Icon => null;
public override ModType Type => ModType.DifficultyReduction;
public override LocalisableString Description => "Whoaaaaa...";
public override bool Ranked => UsesDefaultConfiguration;

View File

@@ -9,7 +9,6 @@ using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Extensions;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods
{
@@ -23,7 +22,7 @@ namespace osu.Game.Rulesets.Mods
public override ModType Type => ModType.Conversion;
public override IconUsage? Icon => OsuIcon.ModDifficultyAdjust;
public override IconUsage? Icon => FontAwesome.Solid.Hammer;
public override double ScoreMultiplier => 0.5;

View File

@@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mods
{
public override string Name => "Half Time";
public override string Acronym => "HT";
public override IconUsage? Icon => OsuIcon.ModHalfTime;
public override IconUsage? Icon => OsuIcon.ModHalftime;
public override ModType Type => ModType.DifficultyReduction;
public override LocalisableString Description => "Less zoom...";
public override bool Ranked => SpeedChange.IsDefault;

View File

@@ -1,16 +1,12 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods
{
public abstract class ModMirror : Mod
{
public override string Name => "Mirror";
public override string Acronym => "MR";
public override IconUsage? Icon => OsuIcon.ModMirror;
public override ModType Type => ModType.Conversion;
public override double ScoreMultiplier => 1;
}

View File

@@ -8,7 +8,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets.Objects;
@@ -22,7 +21,7 @@ namespace osu.Game.Rulesets.Mods
{
public override string Name => "Muted";
public override string Acronym => "MU";
public override IconUsage? Icon => OsuIcon.ModMuted;
public override IconUsage? Icon => FontAwesome.Solid.VolumeMute;
public override LocalisableString Description => "Can you still feel the rhythm without music?";
public override ModType Type => ModType.Fun;
public override double ScoreMultiplier => 1;

View File

@@ -3,7 +3,6 @@
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods
{
@@ -16,7 +15,7 @@ namespace osu.Game.Rulesets.Mods
public override string Acronym => "NM";
public override LocalisableString Description => "No mods applied.";
public override double ScoreMultiplier => 1;
public override IconUsage? Icon => OsuIcon.ModNoMod;
public override IconUsage? Icon => FontAwesome.Solid.Ban;
public override ModType Type => ModType.System;
}
}

View File

@@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets.Scoring;
@@ -21,7 +20,7 @@ namespace osu.Game.Rulesets.Mods
public override string Name => "No Scope";
public override string Acronym => "NS";
public override ModType Type => ModType.Fun;
public override IconUsage? Icon => OsuIcon.ModNoScope;
public override IconUsage? Icon => FontAwesome.Solid.EyeSlash;
public override double ScoreMultiplier => 1;
public override bool Ranked => true;

View File

@@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Mods
public override string Name => "Random";
public override string Acronym => "RD";
public override ModType Type => ModType.Conversion;
public override IconUsage? Icon => OsuIcon.ModRandom;
public override IconUsage? Icon => OsuIcon.Dice;
public override double ScoreMultiplier => 1;
[SettingSource("Seed", "Use a custom seed instead of a random one", SettingControlType = typeof(SettingsNumberBox))]

View File

@@ -1,9 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods
{
@@ -15,7 +13,6 @@ namespace osu.Game.Rulesets.Mods
{
public override string Name => "Score V2";
public override string Acronym => @"SV2";
public override IconUsage? Icon => OsuIcon.ModScoreV2;
public override ModType Type => ModType.System;
public override LocalisableString Description => "Score set on earlier osu! versions with the V2 scoring algorithm active.";
public override double ScoreMultiplier => 1;

View File

@@ -1,9 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods
{
@@ -16,7 +14,6 @@ namespace osu.Game.Rulesets.Mods
public override string Acronym => "SY";
public override LocalisableString Description => "Colours hit objects based on the rhythm.";
public override double ScoreMultiplier => 0.8;
public override IconUsage? Icon => OsuIcon.ModSynesthesia;
public override ModType Type => ModType.Fun;
}
}

View File

@@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Mods
{
public sealed override string Name => "Touch Device";
public sealed override string Acronym => "TD";
public sealed override IconUsage? Icon => OsuIcon.ModTouchDevice;
public sealed override IconUsage? Icon => OsuIcon.PlayStyleTouch;
public sealed override LocalisableString Description => "Automatically applied to plays on devices with a touchscreen.";
public sealed override double ScoreMultiplier => 1;
public sealed override ModType Type => ModType.System;

View File

@@ -6,7 +6,6 @@ using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods
{
@@ -15,7 +14,7 @@ namespace osu.Game.Rulesets.Mods
public override string Name => "Wind Down";
public override string Acronym => "WD";
public override LocalisableString Description => "Sloooow doooown...";
public override IconUsage? Icon => OsuIcon.ModWindDown;
public override IconUsage? Icon => FontAwesome.Solid.ChevronCircleDown;
public override BindableNumber<double> InitialRate { get; } = new BindableDouble(1)
{

View File

@@ -6,7 +6,6 @@ using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods
{
@@ -15,7 +14,7 @@ namespace osu.Game.Rulesets.Mods
public override string Name => "Wind Up";
public override string Acronym => "WU";
public override LocalisableString Description => "Can you keep up?";
public override IconUsage? Icon => OsuIcon.ModWindUp;
public override IconUsage? Icon => FontAwesome.Solid.ChevronCircleUp;
public override BindableNumber<double> InitialRate { get; } = new BindableDouble(1)
{

View File

@@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.UI
{
public ReplayInputHandler? ReplayInputHandler { get; set; }
private int invalidBassTimeLogCount;
private double? lastBackwardsSeekLogTime;
/// <summary>
/// The number of CPU milliseconds to spend at most during seek catch-up.
@@ -161,11 +161,11 @@ namespace osu.Game.Rulesets.UI
//
// In testing this triggers *very* rarely even when set to super low values (10 ms). The cases we're worried about involve multi-second jumps.
// A difference of more than 500 ms seems like a sane number we should never exceed.
if (!allowReferenceClockSeeks && Math.Abs(proposedTime - referenceClock.CurrentTime) > 1500)
if (!allowReferenceClockSeeks && Math.Abs(proposedTime - referenceClock.CurrentTime) > 500)
{
if (invalidBassTimeLogCount < 10)
if (lastBackwardsSeekLogTime == null || Math.Abs(Clock.CurrentTime - lastBackwardsSeekLogTime.Value) > 1000)
{
invalidBassTimeLogCount++;
lastBackwardsSeekLogTime = Clock.CurrentTime;
Logger.Log("Ignoring likely invalid time value provided by BASS during gameplay");
Logger.Log($"- provided: {referenceClock.CurrentTime:N2}");
Logger.Log($"- expected: {proposedTime:N2}");
@@ -175,8 +175,6 @@ namespace osu.Game.Rulesets.UI
return;
}
invalidBassTimeLogCount = 0;
// if the proposed time is the same as the current time, assume that the clock will continue progressing in the same direction as previously.
// this avoids spurious flips in direction from -1 to 1 during rewinds.
if (state == PlaybackState.Valid && proposedTime != manualClock.CurrentTime)

View File

@@ -167,13 +167,7 @@ namespace osu.Game.Rulesets.UI
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
// the mod icon assets in `osu-resources` are sized such that they are flush with the hexagonal background with no shadow baked in.
// the `Icons/BeatmapDetails/mod-icon` asset (of size 135x100) has a shadow and some extra transparent pixels baked in.
// the hexagonal background on that asset, excluding its shadow and the transparent pixels, is 131px wide and 92px high.
// height is divided by 135 rather than by 100, because this entire component is square-sized.
Width = 131 / 135f,
Height = 92 / 135f,
Size = new Vector2(45),
Icon = FontAwesome.Solid.Question
},
adjustmentMarker = new Container

View File

@@ -61,6 +61,7 @@ namespace osu.Game.Rulesets.UI
AutoSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Spacing = new Vector2(0, 4),
Direction = FillDirection.Vertical,
Child = tinySwitch = new ModSwitchTiny(mod)
{
@@ -78,9 +79,7 @@ namespace osu.Game.Rulesets.UI
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Size = new Vector2(37, 26),
// arbitrary adjustment for better vertical alignment
Margin = new MarginPadding { Top = -1 },
Size = new Vector2(21),
Icon = mod.Icon.Value
});
tinySwitch.Scale = new Vector2(0.3f);

View File

@@ -3,13 +3,10 @@
#nullable disable
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Development;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shaders;
using osu.Framework.Utils;
using osu.Game.Screens.Menu;
using osu.Framework.Screens;
@@ -18,11 +15,19 @@ using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface;
using osu.Game.Seasonal;
using IntroSequence = osu.Game.Configuration.IntroSequence;
using osu.Game.Audio;
namespace osu.Game.Screens
{
public partial class Loader : StartupScreen
{
[Resolved]
private OsuConfigManager config { get; set; }
[Resolved]
private WelcomeMusicManager musicManager { get; set; }
private WelcomeMusicMode musicMode;
public Loader()
{
ValidForResume = false;
@@ -30,17 +35,16 @@ namespace osu.Game.Screens
private OsuScreen loadableScreen;
private ShaderPrecompiler precompiler;
private IntroSequence introSequence;
private LoadingSpinner spinner;
private ScheduledDelegate spinnerShow;
protected virtual OsuScreen CreateLoadableScreen() => getIntroSequence();
private IntroScreen getIntroSequence()
protected virtual OsuScreen CreateLoadableScreen()
{
// Headless tests run too fast to load non-circles intros correctly.
// They will hit the "audio can't play" notification and cause random test failures.
var introSequence = config.Get<IntroSequence>(OsuSetting.IntroSequence);
if (musicMode == WelcomeMusicMode.Custom)
return new IntroFade();
if (SeasonalUIConfig.ENABLED && !DebugUtils.IsNUnitRunning)
return new IntroChristmas(createMainMenu);
@@ -51,27 +55,28 @@ namespace osu.Game.Screens
{
case IntroSequence.Circles:
return new IntroCircles(createMainMenu);
case IntroSequence.Welcome:
return new IntroWelcome(createMainMenu);
default:
return new IntroTriangles(createMainMenu);
}
MainMenu createMainMenu() => new MainMenu();
}
private static MainMenu createMainMenu() => new MainMenu();
protected virtual ShaderPrecompiler CreateShaderPrecompiler() => new ShaderPrecompiler();
public override void OnEntering(ScreenTransitionEvent e)
public override async void OnEntering(ScreenTransitionEvent e)
{
base.OnEntering(e);
LoadComponentAsync(precompiler = CreateShaderPrecompiler(), AddInternal);
musicMode = config.Get<WelcomeMusicMode>(OsuSetting.WelcomeMusicMode);
await musicManager.PreloadCurrentTrack().ConfigureAwait(true);
LoadComponentAsync(loadableScreen = CreateLoadableScreen());
LoadComponentAsync(precompiler = CreateShaderPrecompiler(), AddInternal);
LoadComponentAsync(spinner = new LoadingSpinner(true, true)
{
Anchor = Anchor.BottomRight,
@@ -88,7 +93,7 @@ namespace osu.Game.Screens
private void checkIfLoaded()
{
if (loadableScreen?.LoadState != LoadState.Ready || !precompiler.FinishedCompiling)
if (loadableScreen?.LoadState != LoadState.Ready || !precompiler.IsLoaded)
{
Schedule(checkIfLoaded);
return;
@@ -105,55 +110,9 @@ namespace osu.Game.Screens
this.Push(loadableScreen);
}
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
introSequence = config.Get<IntroSequence>(OsuSetting.IntroSequence);
}
/// <summary>
/// Compiles a set of shaders before continuing. Attempts to draw some frames between compilation by limiting to one compile per draw frame.
/// </summary>
public partial class ShaderPrecompiler : Drawable
{
private readonly List<IShader> loadTargets = new List<IShader>();
public bool FinishedCompiling { get; private set; }
[BackgroundDependencyLoader]
private void load(ShaderManager manager)
{
loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE));
loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.BLUR));
loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_3, FragmentShaderDescriptor.TEXTURE));
loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_2, @"TriangleBorder"));
loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_2, @"FastCircle"));
loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_2, @"CircularProgress"));
loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_2, @"ArgonBarPath"));
loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_2, @"ArgonBarPathBackground"));
loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_2, @"SaturationSelectorBackground"));
loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_2, @"HueSelectorBackground"));
loadTargets.Add(manager.Load(@"LogoAnimation", @"LogoAnimation"));
// Ruleset local shader usage (should probably move somewhere else).
loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_2, @"SpinnerGlow"));
loadTargets.Add(manager.Load(@"CursorTrail", FragmentShaderDescriptor.TEXTURE));
}
protected virtual bool AllLoaded => loadTargets.All(s => s.IsLoaded);
protected override void Update()
{
base.Update();
// if our target is null we are done.
if (AllLoaded)
{
FinishedCompiling = true;
Expire();
}
}
// ... код ShaderPrecompiler остается без изменений ... (Блять, а где он?)
}
}
}

View File

@@ -0,0 +1,30 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Screens;
using osu.Game.Audio;
namespace osu.Game.Screens.Menu
{
public partial class IntroFade : OsuScreen
{
[Resolved]
private WelcomeMusicManager? musicManager { get; set; }
public override void OnEntering(ScreenTransitionEvent e)
{
base.OnEntering(e);
this.FadeInFromZero(1000, Easing.OutQuint);
#pragma warning disable CS8602 // Разыменование вероятной пустой ссылки.
var track = musicManager.GetPreloadedTrack();
#pragma warning restore CS8602 // Разыменование вероятной пустой ссылки.
track?.Start();
Scheduler.AddDelayed(() => this.Push(new MainMenu()), 2000);
}
}
}

View File

@@ -39,7 +39,6 @@ using osu.Game.Screens.Edit;
using osu.Game.Screens.OnlinePlay.DailyChallenge;
using osu.Game.Screens.OnlinePlay.Multiplayer;
using osu.Game.Screens.OnlinePlay.Playlists;
using osu.Game.Screens.Select;
using osu.Game.Screens.SelectV2;
using osu.Game.Seasonal;
using osuTK;
@@ -106,7 +105,7 @@ namespace osu.Game.Screens.Menu
private ParallaxContainer buttonsContainer;
private SongTicker songTicker;
private Container logoTarget;
private OnlineMenuBanner onlineMenuBanner;
/*private OnlineMenuBanner onlineMenuBanner;*/
private MenuTipDisplay menuTipDisplay;
private FillFlowContainer bottomElementsFlow;
private SupporterDisplay supporterDisplay;
@@ -119,15 +118,12 @@ namespace osu.Game.Screens.Menu
[CanBeNull]
private IDisposable logoProxy;
private Bindable<bool> forceSSV1;
[BackgroundDependencyLoader(true)]
private void load(BeatmapListingOverlay beatmapListing, SettingsOverlay settings, OsuConfigManager config, SessionStatics statics, AudioManager audio)
{
holdDelay = config.GetBindable<double>(OsuSetting.UIHoldActivationDelay);
loginDisplayed = statics.GetBindable<bool>(Static.LoginOverlayDisplayed);
showMobileDisclaimer = config.GetBindable<bool>(OsuSetting.ShowMobileDisclaimer);
forceSSV1 = config.GetBindable<bool>(OsuSetting.ForceLegacySongSelect);
if (host.CanExit)
{
@@ -202,12 +198,12 @@ namespace osu.Game.Screens.Menu
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
},
onlineMenuBanner = new OnlineMenuBanner
}
/*onlineMenuBanner = new OnlineMenuBanner
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
}
}*/
}
},
supporterDisplay = new SupporterDisplay
@@ -228,12 +224,12 @@ namespace osu.Game.Screens.Menu
case ButtonSystemState.Initial:
case ButtonSystemState.Exit:
ApplyToBackground(b => b.FadeColour(OsuColour.Gray(baseDim), 500, Easing.OutSine));
onlineMenuBanner.State.Value = Visibility.Hidden;
/*onlineMenuBanner.State.Value = Visibility.Hidden;*/
break;
default:
ApplyToBackground(b => b.FadeColour(OsuColour.Gray(baseDim * 0.8f), 500, Easing.OutSine));
onlineMenuBanner.State.Value = Visibility.Visible;
/*onlineMenuBanner.State.Value = Visibility.Visible;*/
break;
}
};
@@ -483,7 +479,7 @@ namespace osu.Game.Screens.Menu
{
}
private void loadSongSelect() => this.Push(forceSSV1.Value ? new PlaySongSelect() : new SoloSongSelect());
private void loadSongSelect() => this.Push(new SoloSongSelect());
private partial class MobileDisclaimerDialog : PopupDialog
{

View File

@@ -9,7 +9,6 @@ using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
@@ -21,7 +20,6 @@ using osu.Framework.Input.Events;
using osu.Framework.Input.StateChanges;
using osu.Framework.Utils;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Configuration;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers;
using osu.Game.Overlays;
@@ -65,10 +63,7 @@ namespace osu.Game.Screens.Menu
protected Sample SampleDownbeat;
private readonly Container colourAndTriangles;
private Box colourBox;
private TrianglesV2 triangles;
private Bindable<Colour4> logoColour;
private readonly TrianglesV2 triangles;
/// <summary>
/// Return value decides whether the logo should play its own sample for the click action.
@@ -191,13 +186,10 @@ namespace osu.Game.Screens.Menu
Origin = Anchor.Centre,
Children = new Drawable[]
{
colourBox = new Box
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientVertical(
Color4Extensions.FromHex(@"ff66ba"), // original osu! cookie pink
Color4Extensions.Darken(Color4Extensions.FromHex(@"ff66ba"), 1.0f)
),
Colour = ColourInfo.GradientVertical(Color4Extensions.FromHex(@"ff66ab"), Color4Extensions.FromHex(@"cc5289")),
},
triangles = new TrianglesV2
{
@@ -206,10 +198,7 @@ namespace osu.Game.Screens.Menu
Thickness = 0.009f,
ScaleAdjust = 3,
SpawnRatio = 1.4f,
Colour = ColourInfo.GradientVertical(
Color4Extensions.FromHex(@"ff66ba"),
Color4Extensions.Darken(Color4Extensions.FromHex(@"ff66ba"), 2.5f)
),
Colour = ColourInfo.GradientVertical(Color4Extensions.FromHex(@"ff66ab"), Color4Extensions.FromHex(@"b6346f")),
RelativeSizeAxes = Axes.Both,
},
}
@@ -260,21 +249,6 @@ namespace osu.Game.Screens.Menu
};
}
public void UpdateColour() {
if (triangles == null || colourBox == null)
return; // we're still loading
triangles.Colour = ColourInfo.GradientVertical(
logoColour.Value,
Color4Extensions.Darken(logoColour.Value, 1.0f)
);
colourBox.Colour = ColourInfo.GradientVertical(
logoColour.Value,
Color4Extensions.Darken(logoColour.Value, 2.5f)
);
}
public Container LogoElements { get; private set; }
/// <summary>
@@ -302,7 +276,7 @@ namespace osu.Game.Screens.Menu
}
[BackgroundDependencyLoader]
private void load(TextureStore textures, AudioManager audio, OsuConfigManager config)
private void load(TextureStore textures, AudioManager audio)
{
sampleClick = audio.Samples.Get(@"Menu/osu-logo-select");
@@ -311,8 +285,6 @@ namespace osu.Game.Screens.Menu
logo.Texture = textures.Get(@"Menu/logo");
ripple.Texture = textures.Get(@"Menu/logo");
logoColour = config.GetBindable<Colour4>(OsuSetting.MenuCookieColor);
}
private int lastBeatIndex;
@@ -393,7 +365,6 @@ namespace osu.Game.Screens.Menu
protected override void Update()
{
base.Update();
UpdateColour();
const float scale_adjust_cutoff = 0.4f;

View File

@@ -54,7 +54,7 @@ namespace osu.Game.Screens.Play.HUD
// Extra lenience is applied so the scores don't get cut off from the left due to elastic easing transforms.
float xOffset = DrawableGameplayLeaderboardScore.SHEAR_WIDTH + DrawableGameplayLeaderboardScore.ELASTIC_WIDTH_LENIENCE;
Width = 260 + xOffset;
Width = DrawableGameplayLeaderboardScore.EXTENDED_WIDTH + xOffset;
Height = 300;
InternalChildren = new Drawable[]
@@ -155,10 +155,6 @@ namespace osu.Game.Screens.Play.HUD
{
base.Update();
// limit leaderboard dimensions to a sane minimum.
Width = Math.Max(Width, Flow.X + DrawableGameplayLeaderboardScore.MIN_WIDTH);
Height = Math.Max(Height, DrawableGameplayLeaderboardScore.PANEL_HEIGHT);
requiresScroll = Flow.DrawHeight > Height;
if (requiresScroll && TrackedScore != null)

View File

@@ -10,7 +10,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Layout;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
@@ -27,15 +26,13 @@ namespace osu.Game.Screens.Play.HUD
{
public partial class DrawableGameplayLeaderboardScore : CompositeDrawable
{
public const float MIN_WIDTH = extended_left_panel_width + avatar_size / 2 + 5;
public const float EXTENDED_WIDTH = extended_left_panel_width + right_panel_width;
private const float left_panel_extension_width = 20;
private const float regular_left_panel_width = avatar_size + avatar_size / 2;
private const float extended_left_panel_width = regular_left_panel_width + left_panel_extension_width;
private const float accuracy_combo_width_cutoff = 150;
private const float username_score_width_cutoff = 50;
private const float right_panel_width = 180;
private const float avatar_size = PANEL_HEIGHT;
@@ -101,8 +98,6 @@ namespace osu.Game.Screens.Play.HUD
[Resolved]
private OsuColour colours { get; set; } = null!;
private readonly LayoutValue drawSizeLayout = new LayoutValue(Invalidation.DrawSize);
/// <summary>
/// Creates a new <see cref="DrawableGameplayLeaderboardScore"/>.
/// </summary>
@@ -121,12 +116,10 @@ namespace osu.Game.Screens.Play.HUD
if (score.TeamColour != null)
BackgroundColour = score.TeamColour.Value;
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.X;
Height = PANEL_HEIGHT;
Shear = OsuGame.SHEAR;
AddLayout(drawSizeLayout);
}
[BackgroundDependencyLoader]
@@ -205,6 +198,7 @@ namespace osu.Game.Screens.Play.HUD
},
rightLayer = new Container
{
Width = right_panel_width,
RelativeSizeAxes = Axes.Y,
// negative left margin to make the X position of the right layer directly at the avatar center (rendered behind it).
Margin = new MarginPadding { Left = -avatar_size / 2 },
@@ -216,7 +210,8 @@ namespace osu.Game.Screens.Play.HUD
},
scoreComponents = new Container
{
RelativeSizeAxes = Axes.Both,
Width = right_panel_width,
RelativeSizeAxes = Axes.Y,
Padding = new MarginPadding { Left = avatar_size / 2 + 4, Right = 20, Vertical = 5 },
Shear = -OsuGame.SHEAR,
Children = new Drawable[]
@@ -228,6 +223,7 @@ namespace osu.Game.Screens.Play.HUD
ColumnDimensions = new[]
{
new Dimension(),
new Dimension(GridSizeMode.Absolute, 10),
new Dimension(GridSizeMode.AutoSize),
},
RowDimensions = new[]
@@ -246,6 +242,7 @@ namespace osu.Game.Screens.Play.HUD
Font = OsuFont.Style.Caption1.With(weight: FontWeight.SemiBold),
RelativeSizeAxes = Axes.X,
},
Empty(),
accuracyText = new OsuSpriteText
{
Anchor = Anchor.BottomLeft,
@@ -255,40 +252,27 @@ namespace osu.Game.Screens.Play.HUD
}
},
},
new GridContainer
new Container
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
ColumnDimensions = new[]
Children = new[]
{
new Dimension(),
new Dimension(GridSizeMode.AutoSize),
},
RowDimensions = new[]
{
new Dimension(GridSizeMode.AutoSize),
},
Content = new[]
{
new[]
scoreText = new OsuSpriteText
{
scoreText = new TruncatingSpriteText
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Font = OsuFont.Style.Body.With(weight: FontWeight.Regular),
RelativeSizeAxes = Axes.X,
},
comboText = new OsuSpriteText
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Font = OsuFont.Style.Caption2.With(weight: FontWeight.SemiBold),
},
}
},
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Font = OsuFont.Style.Body.With(weight: FontWeight.Regular),
},
comboText = new OsuSpriteText
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Font = OsuFont.Style.Caption2.With(weight: FontWeight.SemiBold),
},
}
},
},
}
@@ -327,7 +311,7 @@ namespace osu.Game.Screens.Play.HUD
{
if (expanded.NewValue)
{
rightLayer.ResizeWidthTo(computeRightLayerWidth(), panel_transition_duration, Easing.OutQuint);
rightLayer.ResizeWidthTo(right_panel_width, panel_transition_duration, Easing.OutQuint);
scoreComponents.FadeIn(panel_transition_duration, Easing.OutQuint);
}
else
@@ -387,34 +371,6 @@ namespace osu.Game.Screens.Play.HUD
scorePanel.BorderColour = ColourInfo.GradientVertical(colours.Blue1.Opacity(0.2f), colours.Blue1);
}
protected override void Update()
{
base.Update();
if (!drawSizeLayout.IsValid)
{
if (Expanded.Value)
{
rightLayer.ClearTransforms(targetMember: nameof(Width));
rightLayer.Width = computeRightLayerWidth();
}
drawSizeLayout.Validate();
}
bool showAccuracyAndCombo = rightLayer.Width >= accuracy_combo_width_cutoff;
accuracyText.Alpha = showAccuracyAndCombo ? 1 : 0;
comboText.Alpha = showAccuracyAndCombo ? 1 : 0;
bool showUsernameAndScore = rightLayer.Width >= username_score_width_cutoff;
usernameText.Alpha = showUsernameAndScore ? 1 : 0;
scoreText.Alpha = showUsernameAndScore ? 1 : 0;
}
private float computeRightLayerWidth() => Math.Max(0, DrawWidth - extended_left_panel_width - avatar_size / 2);
private partial class ScoreAvatar : CompositeDrawable
{
private readonly IUser? user;

View File

@@ -1,166 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets.Mods;
using osu.Game.Scoring;
using osu.Game.Screens.Play;
using osu.Game.Screens.Ranking;
using osu.Game.Users;
using osu.Game.Utils;
using osuTK.Input;
namespace osu.Game.Screens.Select
{
public partial class PlaySongSelect : SongSelect
{
private OsuScreen? playerLoader;
[Resolved]
private INotificationOverlay? notifications { get; set; }
public override bool AllowExternalScreenChange => true;
public override MenuItem[] CreateForwardNavigationMenuItemsForBeatmap(Func<BeatmapInfo> getBeatmap) => new MenuItem[]
{
new OsuMenuItem(ButtonSystemStrings.Play.ToSentence(), MenuItemType.Highlighted, () => FinaliseSelection(getBeatmap())),
new OsuMenuItem(ButtonSystemStrings.Edit.ToSentence(), MenuItemType.Standard, () => Edit(getBeatmap()))
};
protected override UserActivity InitialActivity => new UserActivity.ChoosingBeatmap();
private PlayBeatmapDetailArea playBeatmapDetailArea = null!;
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BeatmapOptions.AddButton(ButtonSystemStrings.Edit.ToSentence(), @"beatmap", FontAwesome.Solid.PencilAlt, colours.Yellow, () => Edit());
AddInternal(new SongSelectTouchInputDetector());
}
protected void PresentScore(ScoreInfo score) =>
FinaliseSelection(score.BeatmapInfo, score.Ruleset, () => this.Push(new SoloResultsScreen(score)));
protected override BeatmapDetailArea CreateBeatmapDetailArea()
{
playBeatmapDetailArea = new PlayBeatmapDetailArea
{
Leaderboard =
{
ScoreSelected = PresentScore
}
};
return playBeatmapDetailArea;
}
protected override bool OnKeyDown(KeyDownEvent e)
{
switch (e.Key)
{
case Key.Enter:
case Key.KeypadEnter:
// this is a special hard-coded case; we can't rely on OnPressed (of SongSelect) as GlobalActionContainer is
// matching with exact modifier consideration (so Ctrl+Enter would be ignored).
FinaliseSelection();
return true;
}
return base.OnKeyDown(e);
}
private IReadOnlyList<Mod>? modsAtGameplayStart;
private ModAutoplay? getAutoplayMod() => Ruleset.Value.CreateInstance().GetAutoplayMod();
protected override bool OnStart()
{
if (playerLoader != null) return false;
modsAtGameplayStart = Mods.Value.Select(m => m.DeepClone()).ToArray();
// Ctrl+Enter should start map with autoplay enabled.
if (GetContainingInputManager()?.CurrentState?.Keyboard.ControlPressed == true)
{
var autoInstance = getAutoplayMod();
if (autoInstance == null)
{
notifications?.Post(new SimpleNotification
{
Text = NotificationsStrings.NoAutoplayMod
});
return false;
}
var mods = Mods.Value.Append(autoInstance).ToArray();
if (!ModUtils.CheckCompatibleSet(mods, out var invalid))
mods = mods.Except(invalid).Append(autoInstance).ToArray();
Mods.Value = mods;
}
SampleConfirm?.Play();
this.Push(playerLoader = new PlayerLoader(createPlayer));
return true;
Player createPlayer()
{
Player player;
var replayGeneratingMod = Mods.Value.OfType<ICreateReplayData>().FirstOrDefault();
if (replayGeneratingMod != null)
{
player = new ReplayPlayer((beatmap, mods) => replayGeneratingMod.CreateScoreFromReplayData(beatmap, mods));
}
else
{
player = new SoloPlayer();
}
return player;
}
}
public override void OnResuming(ScreenTransitionEvent e)
{
base.OnResuming(e);
revertMods();
}
public override bool OnExiting(ScreenExitEvent e)
{
if (base.OnExiting(e))
return true;
revertMods();
return false;
}
private void revertMods()
{
if (playerLoader == null) return;
Mods.Value = modsAtGameplayStart;
playerLoader = null;
}
}
}

View File

@@ -3,12 +3,16 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Logging;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Database;
@@ -16,6 +20,7 @@ using osu.Game.Graphics.Containers;
using osu.Game.Localisation;
using osu.Game.Online;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Chat;
using osu.Game.Resources.Localisation.Web;
using osuTK;
@@ -50,10 +55,10 @@ namespace osu.Game.Screens.SelectV2
private IBindable<WorkingBeatmap> beatmap { get; set; } = null!;
[Resolved]
private IBindable<SongSelect.BeatmapSetLookupResult> onlineLookupResult { get; set; } = null!;
private IAPIProvider api { get; set; } = null!;
[Resolved]
private IAPIProvider api { get; set; } = null!;
private RealmPopulatingOnlineLookupSource onlineLookupSource { get; set; } = null!;
[Resolved]
private RealmAccess realm { get; set; } = null!;
@@ -249,7 +254,6 @@ namespace osu.Game.Screens.SelectV2
{
base.LoadComplete();
beatmap.BindValueChanged(_ => updateDisplay());
onlineLookupResult.BindValueChanged(_ => updateDisplay());
apiState = api.State.GetBoundCopy();
apiState.BindValueChanged(_ => Scheduler.AddOnce(updateDisplay), true);
@@ -279,7 +283,7 @@ namespace osu.Game.Screens.SelectV2
// Needs some experimentation on what looks good.
var beatmapInfo = beatmap.Value.BeatmapInfo;
var currentOnlineBeatmap = onlineLookupResult.Value?.Result?.Beatmaps.SingleOrDefault(b => b.OnlineID == beatmapInfo.OnlineID);
var currentOnlineBeatmap = currentOnlineBeatmapSet?.Beatmaps.SingleOrDefault(b => b.OnlineID == beatmapInfo.OnlineID);
if (State.Value == Visibility.Visible && currentOnlineBeatmap != null)
{
@@ -361,12 +365,41 @@ namespace osu.Game.Screens.SelectV2
submitted.Date = beatmapSetInfo.DateSubmitted;
ranked.Date = beatmapSetInfo.DateRanked;
if (currentOnlineBeatmapSet == null || currentOnlineBeatmapSet.OnlineID != beatmapSetInfo.OnlineID)
refetchBeatmapSet();
updateOnlineDisplay();
}
private APIBeatmapSet? currentOnlineBeatmapSet;
private CancellationTokenSource? cancellationTokenSource;
private Task<APIBeatmapSet?>? currentFetchTask;
private void refetchBeatmapSet()
{
var beatmapSetInfo = beatmap.Value.BeatmapSetInfo;
cancellationTokenSource?.Cancel();
currentOnlineBeatmapSet = null;
if (beatmapSetInfo.OnlineID >= 1)
{
cancellationTokenSource = new CancellationTokenSource();
currentFetchTask = onlineLookupSource.GetBeatmapSetAsync(beatmapSetInfo.OnlineID);
currentFetchTask.ContinueWith(t =>
{
if (t.IsCompletedSuccessfully)
currentOnlineBeatmapSet = t.GetResultSafely();
if (t.Exception != null)
Logger.Log($"Error when fetching online beatmap set: {t.Exception}", LoggingTarget.Network);
Scheduler.AddOnce(updateOnlineDisplay);
});
}
}
private void updateOnlineDisplay()
{
if (onlineLookupResult.Value?.Status != SongSelect.BeatmapSetLookupStatus.Completed)
if (currentFetchTask?.IsCompleted == false)
{
genre.Data = null;
language.Data = null;
@@ -374,7 +407,7 @@ namespace osu.Game.Screens.SelectV2
return;
}
if (onlineLookupResult.Value.Result == null)
if (currentOnlineBeatmapSet == null)
{
genre.Data = ("-", null);
language.Data = ("-", null);
@@ -383,7 +416,7 @@ namespace osu.Game.Screens.SelectV2
{
var beatmapInfo = beatmap.Value.BeatmapInfo;
var onlineBeatmapSet = onlineLookupResult.Value.Result;
var onlineBeatmapSet = currentOnlineBeatmapSet;
var onlineBeatmap = onlineBeatmapSet.Beatmaps.SingleOrDefault(b => b.OnlineID == beatmapInfo.OnlineID);
genre.Data = (onlineBeatmapSet.Genre.Name, () => songSelect?.Search(onlineBeatmapSet.Genre.Name));
@@ -407,7 +440,6 @@ namespace osu.Game.Screens.SelectV2
string[] tags = realm.Run(r =>
{
// need to refetch because `beatmap.Value.BeatmapInfo` is not going to have the latest tags
r.Refresh();
var refetchedBeatmap = r.Find<BeatmapInfo>(beatmap.Value.BeatmapInfo.ID);
return refetchedBeatmap?.Metadata.UserTags.ToArray() ?? [];
});

View File

@@ -8,9 +8,11 @@ using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Localisation;
using osu.Framework.Logging;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Configuration;
@@ -19,6 +21,7 @@ using osu.Game.Extensions;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Resources.Localisation.Web;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
@@ -40,9 +43,6 @@ namespace osu.Game.Screens.SelectV2
[Resolved]
private IBindable<IReadOnlyList<Mod>> mods { get; set; } = null!;
[Resolved]
private IBindable<SongSelect.BeatmapSetLookupResult?> onlineLookupResult { get; set; } = null!;
protected override bool StartHidden => true;
private ModSettingChangeTracker? settingChangeTracker;
@@ -69,9 +69,16 @@ namespace osu.Game.Screens.SelectV2
[Resolved]
private LocalisationManager localisation { get; set; } = null!;
[Resolved]
private RealmPopulatingOnlineLookupSource onlineLookupSource { get; set; } = null!;
[Resolved]
private RealmAccess realm { get; set; } = null!;
private APIBeatmapSet? currentOnlineBeatmapSet;
private CancellationTokenSource? cancellationTokenSource;
private Task<APIBeatmapSet?>? currentFetchTask;
private FillFlowContainer statisticsFlow = null!;
public BeatmapTitleWedge()
@@ -183,7 +190,6 @@ namespace osu.Game.Screens.SelectV2
working.BindValueChanged(_ => updateDisplay());
ruleset.BindValueChanged(_ => updateDisplay());
onlineLookupResult.BindValueChanged(_ => updateDisplay());
mods.BindValueChanged(m =>
{
@@ -224,6 +230,7 @@ namespace osu.Game.Screens.SelectV2
{
var metadata = working.Value.Metadata;
var beatmapInfo = working.Value.BeatmapInfo;
var beatmapSetInfo = working.Value.BeatmapSetInfo;
statusPill.Status = beatmapInfo.Status;
@@ -236,6 +243,10 @@ namespace osu.Game.Screens.SelectV2
artistLink.Action = () => songSelect?.Search(artistText.GetPreferred(localisation.CurrentParameters.Value.PreferOriginalScript));
updateLengthAndBpmStatistics();
if (currentOnlineBeatmapSet == null || currentOnlineBeatmapSet.OnlineID != beatmapSetInfo.OnlineID)
refetchBeatmapSet();
updateOnlineDisplay();
}
@@ -278,18 +289,40 @@ namespace osu.Game.Screens.SelectV2
}, token);
}
private void refetchBeatmapSet()
{
var beatmapSetInfo = working.Value.BeatmapSetInfo;
cancellationTokenSource?.Cancel();
currentOnlineBeatmapSet = null;
if (beatmapSetInfo.OnlineID >= 1)
{
cancellationTokenSource = new CancellationTokenSource();
currentFetchTask = onlineLookupSource.GetBeatmapSetAsync(beatmapSetInfo.OnlineID);
currentFetchTask.ContinueWith(t =>
{
if (t.IsCompletedSuccessfully)
currentOnlineBeatmapSet = t.GetResultSafely();
if (t.Exception != null)
Logger.Log($"Error when fetching online beatmap set: {t.Exception}", LoggingTarget.Network);
Scheduler.AddOnce(updateOnlineDisplay);
});
}
}
private void updateOnlineDisplay()
{
if (onlineLookupResult.Value?.Status != SongSelect.BeatmapSetLookupStatus.Completed)
if (currentFetchTask?.IsCompleted == false)
{
playCount.Value = null;
favouriteButton.SetLoading();
}
else
{
var onlineBeatmap = onlineLookupResult.Value.Result?.Beatmaps.SingleOrDefault(b => b.OnlineID == working.Value.BeatmapInfo.OnlineID);
var onlineBeatmap = currentOnlineBeatmapSet?.Beatmaps.SingleOrDefault(b => b.OnlineID == working.Value.BeatmapInfo.OnlineID);
playCount.Value = new StatisticPlayCount.Data(onlineBeatmap?.PlayCount ?? -1, onlineBeatmap?.UserPlayCount ?? -1);
favouriteButton.SetBeatmapSet(onlineLookupResult.Value.Result);
favouriteButton.SetBeatmapSet(currentOnlineBeatmapSet);
// the online fetch may have also updated the beatmap's status.
// this needs to be checked against the *local* beatmap model rather than the online one, because it's not known here whether the status change has occurred or not
@@ -299,7 +332,6 @@ namespace osu.Game.Screens.SelectV2
// which prevents working beatmap refetches caused by changes to the realm model of perceived low importance).
var status = realm.Run(r =>
{
r.Refresh();
var refetchedBeatmap = r.Find<BeatmapInfo>(working.Value.BeatmapInfo.ID);
return refetchedBeatmap?.Status;
});

View File

@@ -229,10 +229,7 @@ namespace osu.Game.Screens.SelectV2
bool hasFavourited = favouriteRequest.Action == BeatmapFavouriteAction.Favourite;
beatmapSet.HasFavourited = hasFavourited;
beatmapSet.FavouriteCount += hasFavourited ? 1 : -1;
// if the beatmap set reference changed under the callback, abort visual updates to avoid showing stale data
if (onlineBeatmapSet == null || ReferenceEquals(beatmapSet, onlineBeatmapSet))
setBeatmapSet(beatmapSet, withHeartAnimation: hasFavourited);
setBeatmapSet(beatmapSet, withHeartAnimation: hasFavourited);
};
favouriteRequest.Failure += e =>
{
@@ -241,10 +238,7 @@ namespace osu.Game.Screens.SelectV2
Text = e.Message,
Icon = FontAwesome.Solid.Times,
});
// if the beatmap set reference changed under the callback, abort visual updates to avoid showing stale data
if (onlineBeatmapSet == null || ReferenceEquals(beatmapSet, onlineBeatmapSet))
setBeatmapSet(beatmapSet, withHeartAnimation: false);
setBeatmapSet(beatmapSet, withHeartAnimation: false);
};
api.Queue(favouriteRequest);
setLoading();

View File

@@ -5,14 +5,11 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
@@ -37,7 +34,6 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Input.Bindings;
using osu.Game.Localisation;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
using osu.Game.Overlays.Mods;
using osu.Game.Overlays.Volume;
@@ -137,7 +133,8 @@ namespace osu.Game.Screens.SelectV2
[Resolved]
private IDialogOverlay? dialogOverlay { get; set; }
private readonly RealmPopulatingOnlineLookupSource onlineLookupSource = new RealmPopulatingOnlineLookupSource();
[Cached]
private RealmPopulatingOnlineLookupSource onlineLookupSource = new RealmPopulatingOnlineLookupSource();
private Bindable<bool> configBackgroundBlur = null!;
@@ -352,7 +349,6 @@ namespace osu.Game.Screens.SelectV2
ensurePlayingSelected();
updateBackgroundDim();
updateWedgeVisibility();
fetchOnlineInfo();
});
}
@@ -854,7 +850,7 @@ namespace osu.Game.Screens.SelectV2
// For simplicity, disable this functionality on mobile.
bool isTouchInput = e.CurrentState.Mouse.LastSource is ISourcedFromTouch;
if (!carousel.AbsoluteScrolling && !isTouchInput && mouseDownPriority && revealingBackground == null)
if (!carousel.AbsoluteScrolling && !isTouchInput && mouseDownPriority)
{
revealingBackground = Scheduler.AddDelayed(() =>
{
@@ -958,74 +954,6 @@ namespace osu.Game.Screens.SelectV2
#endregion
#region Online lookups
public enum BeatmapSetLookupStatus
{
InProgress,
Completed,
}
public class BeatmapSetLookupResult
{
public BeatmapSetLookupStatus Status { get; }
public APIBeatmapSet? Result { get; }
private BeatmapSetLookupResult(BeatmapSetLookupStatus status, APIBeatmapSet? result)
{
Status = status;
Result = result;
}
public static BeatmapSetLookupResult InProgress() => new BeatmapSetLookupResult(BeatmapSetLookupStatus.InProgress, null);
public static BeatmapSetLookupResult Completed(APIBeatmapSet? beatmapSet) => new BeatmapSetLookupResult(BeatmapSetLookupStatus.Completed, beatmapSet);
}
/// <summary>
/// Result of the latest online beatmap set lookup.
/// Note that this being <see langword="null"/> or <see cref="BeatmapSetLookupResult.InProgress"/> is different from
/// being a <see cref="BeatmapSetLookupResult.Completed"/> with a <see cref="BeatmapSetLookupResult.Result"/> of null.
/// The former indicates a lookup never occurring or being in progress, while the latter indicates a completed lookup with no result.
/// </summary>
[Cached(typeof(IBindable<BeatmapSetLookupResult?>))]
private readonly Bindable<BeatmapSetLookupResult?> lastLookupResult = new Bindable<BeatmapSetLookupResult?>();
private CancellationTokenSource? onlineLookupCancellation;
private Task<APIBeatmapSet?>? currentOnlineLookup;
private void fetchOnlineInfo()
{
var beatmapSetInfo = Beatmap.Value.BeatmapSetInfo;
if (lastLookupResult.Value?.Result?.OnlineID == beatmapSetInfo.OnlineID)
return;
onlineLookupCancellation?.Cancel();
if (beatmapSetInfo.OnlineID < 0)
{
lastLookupResult.Value = BeatmapSetLookupResult.Completed(null);
return;
}
lastLookupResult.Value = BeatmapSetLookupResult.InProgress();
onlineLookupCancellation = new CancellationTokenSource();
currentOnlineLookup = onlineLookupSource.GetBeatmapSetAsync(beatmapSetInfo.OnlineID);
currentOnlineLookup.ContinueWith(t =>
{
if (t.IsCompletedSuccessfully)
Schedule(() => lastLookupResult.Value = BeatmapSetLookupResult.Completed(t.GetResultSafely()));
if (t.Exception != null)
{
Logger.Log($"Error when fetching online beatmap set: {t.Exception}", LoggingTarget.Network);
Schedule(() => lastLookupResult.Value = BeatmapSetLookupResult.Completed(null));
}
});
}
#endregion
#region Implementation of ISongSelect
void ISongSelect.Search(string query) => filterControl.Search(query);

View File

@@ -195,7 +195,6 @@ namespace osu.Game.Tests.Visual
{
base.Update();
// when running in visual tests and the window loses focus, we generally don't want the game to pause.
((Bindable<bool>)IsActive).Value = true;
}
}
@@ -206,7 +205,18 @@ namespace osu.Game.Tests.Visual
private partial class TestShaderPrecompiler : ShaderPrecompiler
{
protected override bool AllLoaded => true;
// Старый код, который больше не работает:
// protected override bool AllLoaded => true;
// НОВЫЙ, ПРАВИЛЬНЫЙ КОД:
[BackgroundDependencyLoader]
private void load()
{
// Этот "фальшивый" компилятор не должен ничего делать.
// Мы сразу же вызываем Expire(), чтобы он считался "загруженным" (IsLoaded станет true).
// Это позволит нашему основному Loader'у продолжить работу, как и было задумано.
Expire();
}
}
}
}

View File

@@ -36,7 +36,7 @@
</PackageReference>
<PackageReference Include="Realm" Version="20.1.0" />
<PackageReference Include="ppy.osu.Framework" Version="2025.808.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2025.821.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2025.819.0" />
<PackageReference Include="Sentry" Version="5.1.1" />
<!-- Held back due to 0.34.0 failing AOT compilation on ZstdSharp.dll dependency. -->
<PackageReference Include="SharpCompress" Version="0.39.0" />