mirror of
https://github.com/ppy/osu.git
synced 2025-02-13 14:53:21 +08:00
Merge branch 'master' into catcher-trail-entry
This commit is contained in:
commit
9b98014606
@ -190,3 +190,5 @@ dotnet_diagnostic.CA2225.severity = none
|
||||
|
||||
# Banned APIs
|
||||
dotnet_diagnostic.RS0030.severity = error
|
||||
|
||||
dotnet_diagnostic.OLOC001.license_header = // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.\n// See the LICENCE file in the repository root for full licence text.
|
||||
|
@ -51,7 +51,7 @@
|
||||
<Reference Include="Java.Interop" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.722.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.730.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.728.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Transitive Dependencies">
|
||||
|
@ -64,7 +64,7 @@
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.6.1" />
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.7.0" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||
</Project>
|
@ -130,7 +130,8 @@ namespace osu.Game.Rulesets.Catch
|
||||
return new Mod[]
|
||||
{
|
||||
new MultiMod(new ModWindUp(), new ModWindDown()),
|
||||
new CatchModFloatingFruits()
|
||||
new CatchModFloatingFruits(),
|
||||
new CatchModMuted(),
|
||||
};
|
||||
|
||||
default:
|
||||
|
12
osu.Game.Rulesets.Catch/Mods/CatchModMuted.cs
Normal file
12
osu.Game.Rulesets.Catch/Mods/CatchModMuted.cs
Normal 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.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModMuted : ModMuted<CatchHitObject>
|
||||
{
|
||||
}
|
||||
}
|
@ -253,7 +253,8 @@ namespace osu.Game.Rulesets.Mania
|
||||
case ModType.Fun:
|
||||
return new Mod[]
|
||||
{
|
||||
new MultiMod(new ModWindUp(), new ModWindDown())
|
||||
new MultiMod(new ModWindUp(), new ModWindDown()),
|
||||
new ManiaModMuted(),
|
||||
};
|
||||
|
||||
default:
|
||||
|
12
osu.Game.Rulesets.Mania/Mods/ManiaModMuted.cs
Normal file
12
osu.Game.Rulesets.Mania/Mods/ManiaModMuted.cs
Normal 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.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public class ManiaModMuted : ModMuted<ManiaHitObject>
|
||||
{
|
||||
}
|
||||
}
|
12
osu.Game.Rulesets.Osu/Mods/OsuModMuted.cs
Normal file
12
osu.Game.Rulesets.Osu/Mods/OsuModMuted.cs
Normal 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.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
public class OsuModMuted : ModMuted<OsuHitObject>
|
||||
{
|
||||
}
|
||||
}
|
@ -4,8 +4,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
@ -16,7 +14,6 @@ using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
@ -29,7 +26,6 @@ using osu.Game.Rulesets.Osu.UI;
|
||||
using osu.Game.Rulesets.Osu.Utils;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -67,11 +63,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
/// </summary>
|
||||
private const float distance_cap = 380f;
|
||||
|
||||
// The distances from the hit objects to the borders of the playfield they start to "turn around" and curve towards the middle.
|
||||
// The closer the hit objects draw to the border, the sharper the turn
|
||||
private const byte border_distance_x = 192;
|
||||
private const byte border_distance_y = 144;
|
||||
|
||||
/// <summary>
|
||||
/// The extent of rotation towards playfield centre when a circle is near the edge
|
||||
/// </summary>
|
||||
@ -341,46 +332,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
|
||||
public void ApplyToDrawableRuleset(DrawableRuleset<OsuHitObject> drawableRuleset)
|
||||
{
|
||||
drawableRuleset.Overlays.Add(new TargetBeatContainer(drawableRuleset.Beatmap.HitObjects.First().StartTime));
|
||||
}
|
||||
|
||||
public class TargetBeatContainer : BeatSyncedContainer
|
||||
{
|
||||
private readonly double firstHitTime;
|
||||
|
||||
private PausableSkinnableSound sample;
|
||||
|
||||
public TargetBeatContainer(double firstHitTime)
|
||||
{
|
||||
this.firstHitTime = firstHitTime;
|
||||
AllowMistimedEventFiring = false;
|
||||
Divisor = 1;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
sample = new PausableSkinnableSound(new SampleInfo("Gameplay/catch-banana"))
|
||||
};
|
||||
}
|
||||
|
||||
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
|
||||
{
|
||||
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
|
||||
|
||||
if (!IsBeatSyncedWithTrack) return;
|
||||
|
||||
int timeSignature = (int)timingPoint.TimeSignature;
|
||||
|
||||
// play metronome from one measure before the first object.
|
||||
if (BeatSyncClock.CurrentTime < firstHitTime - timingPoint.BeatLength * timeSignature)
|
||||
return;
|
||||
|
||||
sample.Frequency.Value = beatIndex % timeSignature == 0 ? 1 : 0.5f;
|
||||
sample.Play();
|
||||
}
|
||||
drawableRuleset.Overlays.Add(new Metronome(drawableRuleset.Beatmap.HitObjects.First().StartTime));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -189,6 +189,7 @@ namespace osu.Game.Rulesets.Osu
|
||||
new OsuModTraceable(),
|
||||
new OsuModBarrelRoll(),
|
||||
new OsuModApproachDifferent(),
|
||||
new OsuModMuted(),
|
||||
};
|
||||
|
||||
case ModType.System:
|
||||
|
@ -104,7 +104,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
|
||||
private void onJudgementLoaded(DrawableOsuJudgement judgement)
|
||||
{
|
||||
judgementAboveHitObjectLayer.Add(judgement.GetProxyAboveHitObjectsContent());
|
||||
judgementAboveHitObjectLayer.Add(judgement.ProxiedAboveHitObjectsContent);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
@ -150,6 +150,10 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
DrawableOsuJudgement explosion = poolDictionary[result.Type].Get(doj => doj.Apply(result, judgedObject));
|
||||
|
||||
judgementLayer.Add(explosion);
|
||||
|
||||
// the proxied content is added to judgementAboveHitObjectLayer once, on first load, and never removed from it.
|
||||
// ensure that ordering is consistent with expectations (latest judgement should be front-most).
|
||||
judgementAboveHitObjectLayer.ChangeChildDepth(explosion.ProxiedAboveHitObjectsContent, (float)-result.TimeAbsolute);
|
||||
}
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => HitObjectContainer.ReceivePositionalInputAt(screenSpacePos);
|
||||
|
12
osu.Game.Rulesets.Taiko/Mods/TaikoModMuted.cs
Normal file
12
osu.Game.Rulesets.Taiko/Mods/TaikoModMuted.cs
Normal 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.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Mods
|
||||
{
|
||||
public class TaikoModMuted : ModMuted<TaikoHitObject>
|
||||
{
|
||||
}
|
||||
}
|
@ -149,7 +149,8 @@ namespace osu.Game.Rulesets.Taiko
|
||||
case ModType.Fun:
|
||||
return new Mod[]
|
||||
{
|
||||
new MultiMod(new ModWindUp(), new ModWindDown())
|
||||
new MultiMod(new ModWindUp(), new ModWindDown()),
|
||||
new TaikoModMuted(),
|
||||
};
|
||||
|
||||
default:
|
||||
|
41
osu.Game.Tests/NonVisual/TimeDisplayExtensionTest.cs
Normal file
41
osu.Game.Tests/NonVisual/TimeDisplayExtensionTest.cs
Normal file
@ -0,0 +1,41 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Game.Extensions;
|
||||
|
||||
namespace osu.Game.Tests.NonVisual
|
||||
{
|
||||
[TestFixture]
|
||||
public class TimeDisplayExtensionTest
|
||||
{
|
||||
private static readonly object[][] editor_formatted_duration_tests =
|
||||
{
|
||||
new object[] { new TimeSpan(0, 0, 0, 0, 50), "00:00:050" },
|
||||
new object[] { new TimeSpan(0, 0, 0, 10, 50), "00:10:050" },
|
||||
new object[] { new TimeSpan(0, 0, 5, 10), "05:10:000" },
|
||||
new object[] { new TimeSpan(0, 1, 5, 10), "65:10:000" },
|
||||
};
|
||||
|
||||
[TestCaseSource(nameof(editor_formatted_duration_tests))]
|
||||
public void TestEditorFormat(TimeSpan input, string expectedOutput)
|
||||
{
|
||||
Assert.AreEqual(expectedOutput, input.ToEditorFormattedString());
|
||||
}
|
||||
|
||||
private static readonly object[][] formatted_duration_tests =
|
||||
{
|
||||
new object[] { new TimeSpan(0, 0, 10), "00:10" },
|
||||
new object[] { new TimeSpan(0, 5, 10), "05:10" },
|
||||
new object[] { new TimeSpan(1, 5, 10), "01:05:10" },
|
||||
new object[] { new TimeSpan(1, 1, 5, 10), "01:01:05:10" },
|
||||
};
|
||||
|
||||
[TestCaseSource(nameof(formatted_duration_tests))]
|
||||
public void TestFormattedDuration(TimeSpan input, string expectedOutput)
|
||||
{
|
||||
Assert.AreEqual(expectedOutput, input.ToFormattedDuration().ToString());
|
||||
}
|
||||
}
|
||||
}
|
@ -168,8 +168,8 @@ namespace osu.Game.Tests.Online
|
||||
|
||||
public override async Task<BeatmapSetInfo> Import(BeatmapSetInfo item, ArchiveReader archive = null, bool lowPriority = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await AllowImport.Task;
|
||||
return await (CurrentImportTask = base.Import(item, archive, lowPriority, cancellationToken));
|
||||
await AllowImport.Task.ConfigureAwait(false);
|
||||
return await (CurrentImportTask = base.Import(item, archive, lowPriority, cancellationToken)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,9 +143,9 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
public override async Task<StarDifficulty> GetDifficultyAsync(BeatmapInfo beatmapInfo, RulesetInfo rulesetInfo = null, IEnumerable<Mod> mods = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (blockCalculation)
|
||||
await calculationBlocker.Task;
|
||||
await calculationBlocker.Task.ConfigureAwait(false);
|
||||
|
||||
return await base.GetDifficultyAsync(beatmapInfo, rulesetInfo, mods, cancellationToken);
|
||||
return await base.GetDifficultyAsync(beatmapInfo, rulesetInfo, mods, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +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.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Graphics.Cursor;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.UserInterfaceV2;
|
||||
using osuTK.Graphics;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestSceneLabelledColourPalette : OsuTestScene
|
||||
public class TestSceneLabelledColourPalette : OsuManualInputManagerTestScene
|
||||
{
|
||||
private LabelledColourPalette component;
|
||||
|
||||
@ -30,21 +35,41 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
}, 8);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUserInteractions()
|
||||
{
|
||||
createColourPalette();
|
||||
assertColourCount(4);
|
||||
|
||||
clickAddColour();
|
||||
assertColourCount(5);
|
||||
|
||||
deleteFirstColour();
|
||||
assertColourCount(4);
|
||||
|
||||
clickFirstColour();
|
||||
AddAssert("colour picker spawned", () => this.ChildrenOfType<OsuColourPicker>().Any());
|
||||
}
|
||||
|
||||
private void createColourPalette(bool hasDescription = false)
|
||||
{
|
||||
AddStep("create component", () =>
|
||||
{
|
||||
Child = new Container
|
||||
Child = new OsuContextMenuContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Width = 500,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Child = component = new LabelledColourPalette
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
ColourNamePrefix = "My colour #"
|
||||
Width = 500,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Child = component = new LabelledColourPalette
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
ColourNamePrefix = "My colour #"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -53,18 +78,49 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
component.Colours.AddRange(new[]
|
||||
{
|
||||
Color4.DarkRed,
|
||||
Color4.Aquamarine,
|
||||
Color4.Goldenrod,
|
||||
Color4.Gainsboro
|
||||
Colour4.DarkRed,
|
||||
Colour4.Aquamarine,
|
||||
Colour4.Goldenrod,
|
||||
Colour4.Gainsboro
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private Color4 randomColour() => new Color4(
|
||||
private Colour4 randomColour() => new Color4(
|
||||
RNG.NextSingle(),
|
||||
RNG.NextSingle(),
|
||||
RNG.NextSingle(),
|
||||
1);
|
||||
|
||||
private void assertColourCount(int count) => AddAssert($"colour count is {count}", () => component.Colours.Count == count);
|
||||
|
||||
private void clickAddColour() => AddStep("click new colour button", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(this.ChildrenOfType<ColourPalette.AddColourButton>().Single());
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
private void clickFirstColour() => AddStep("click first colour", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(this.ChildrenOfType<ColourDisplay>().First());
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
private void deleteFirstColour()
|
||||
{
|
||||
AddStep("right-click first colour", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(this.ChildrenOfType<ColourDisplay>().First());
|
||||
InputManager.Click(MouseButton.Right);
|
||||
});
|
||||
|
||||
AddUntilStep("wait for menu", () => this.ChildrenOfType<OsuContextMenu>().Any());
|
||||
|
||||
AddStep("click delete", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(this.ChildrenOfType<DrawableOsuMenuItem>().Single());
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,18 @@
|
||||
// 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.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Tournament.Configuration;
|
||||
using osu.Game.Tests;
|
||||
using osu.Game.Tournament.Configuration;
|
||||
|
||||
namespace osu.Game.Tournament.Tests.NonVisual
|
||||
{
|
||||
[TestFixture]
|
||||
public class CustomTourneyDirectoryTest
|
||||
public class CustomTourneyDirectoryTest : TournamentHostTest
|
||||
{
|
||||
[Test]
|
||||
public void TestDefaultDirectory()
|
||||
@ -24,7 +21,7 @@ namespace osu.Game.Tournament.Tests.NonVisual
|
||||
{
|
||||
try
|
||||
{
|
||||
var osu = loadOsu(host);
|
||||
var osu = LoadTournament(host);
|
||||
var storage = osu.Dependencies.Get<Storage>();
|
||||
|
||||
Assert.That(storage.GetFullPath("."), Is.EqualTo(Path.Combine(host.Storage.GetFullPath("."), "tournaments", "default")));
|
||||
@ -54,7 +51,7 @@ namespace osu.Game.Tournament.Tests.NonVisual
|
||||
|
||||
try
|
||||
{
|
||||
var osu = loadOsu(host);
|
||||
var osu = LoadTournament(host);
|
||||
|
||||
storage = osu.Dependencies.Get<Storage>();
|
||||
|
||||
@ -111,7 +108,7 @@ namespace osu.Game.Tournament.Tests.NonVisual
|
||||
|
||||
try
|
||||
{
|
||||
var osu = loadOsu(host);
|
||||
var osu = LoadTournament(host);
|
||||
|
||||
var storage = osu.Dependencies.Get<Storage>();
|
||||
|
||||
@ -151,25 +148,6 @@ namespace osu.Game.Tournament.Tests.NonVisual
|
||||
}
|
||||
}
|
||||
|
||||
private TournamentGameBase loadOsu(GameHost host)
|
||||
{
|
||||
var osu = new TournamentGameBase();
|
||||
Task.Run(() => host.Run(osu))
|
||||
.ContinueWith(t => Assert.Fail($"Host threw exception {t.Exception}"), TaskContinuationOptions.OnlyOnFaulted);
|
||||
waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time");
|
||||
return osu;
|
||||
}
|
||||
|
||||
private static void waitForOrAssert(Func<bool> result, string failureMessage, int timeout = 90000)
|
||||
{
|
||||
Task task = Task.Run(() =>
|
||||
{
|
||||
while (!result()) Thread.Sleep(200);
|
||||
});
|
||||
|
||||
Assert.IsTrue(task.Wait(timeout), failureMessage);
|
||||
}
|
||||
|
||||
private string basePath(string testInstance) => Path.Combine(RuntimeInfo.StartupDirectory, "headless", testInstance);
|
||||
}
|
||||
}
|
||||
|
45
osu.Game.Tournament.Tests/NonVisual/DataLoadTest.cs
Normal file
45
osu.Game.Tournament.Tests/NonVisual/DataLoadTest.cs
Normal file
@ -0,0 +1,45 @@
|
||||
// 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.IO;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Tests;
|
||||
|
||||
namespace osu.Game.Tournament.Tests.NonVisual
|
||||
{
|
||||
public class DataLoadTest : TournamentHostTest
|
||||
{
|
||||
[Test]
|
||||
public void TestUnavailableRuleset()
|
||||
{
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestUnavailableRuleset)))
|
||||
{
|
||||
try
|
||||
{
|
||||
var osu = new TestTournament();
|
||||
|
||||
LoadTournament(host, osu);
|
||||
var storage = osu.Dependencies.Get<Storage>();
|
||||
|
||||
Assert.That(storage.GetFullPath("."), Is.EqualTo(Path.Combine(host.Storage.GetFullPath("."), "tournaments", "default")));
|
||||
}
|
||||
finally
|
||||
{
|
||||
host.Exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TestTournament : TournamentGameBase
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Ruleset.Value = new RulesetInfo(); // not available
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +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 System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
@ -15,7 +12,7 @@ using osu.Game.Tournament.IPC;
|
||||
namespace osu.Game.Tournament.Tests.NonVisual
|
||||
{
|
||||
[TestFixture]
|
||||
public class IPCLocationTest
|
||||
public class IPCLocationTest : TournamentHostTest
|
||||
{
|
||||
[Test]
|
||||
public void CheckIPCLocation()
|
||||
@ -34,11 +31,11 @@ namespace osu.Game.Tournament.Tests.NonVisual
|
||||
|
||||
try
|
||||
{
|
||||
var osu = loadOsu(host);
|
||||
var osu = LoadTournament(host);
|
||||
TournamentStorage storage = (TournamentStorage)osu.Dependencies.Get<Storage>();
|
||||
FileBasedIPC ipc = null;
|
||||
|
||||
waitForOrAssert(() => (ipc = osu.Dependencies.Get<MatchIPCInfo>() as FileBasedIPC) != null, @"ipc could not be populated in a reasonable amount of time");
|
||||
WaitForOrAssert(() => (ipc = osu.Dependencies.Get<MatchIPCInfo>() as FileBasedIPC) != null, @"ipc could not be populated in a reasonable amount of time");
|
||||
|
||||
Assert.True(ipc.SetIPCLocation(testStableInstallDirectory));
|
||||
Assert.True(storage.AllTournaments.Exists("stable.json"));
|
||||
@ -51,24 +48,5 @@ namespace osu.Game.Tournament.Tests.NonVisual
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TournamentGameBase loadOsu(GameHost host)
|
||||
{
|
||||
var osu = new TournamentGameBase();
|
||||
Task.Run(() => host.Run(osu))
|
||||
.ContinueWith(t => Assert.Fail($"Host threw exception {t.Exception}"), TaskContinuationOptions.OnlyOnFaulted);
|
||||
waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time");
|
||||
return osu;
|
||||
}
|
||||
|
||||
private static void waitForOrAssert(Func<bool> result, string failureMessage, int timeout = 90000)
|
||||
{
|
||||
Task task = Task.Run(() =>
|
||||
{
|
||||
while (!result()) Thread.Sleep(200);
|
||||
});
|
||||
|
||||
Assert.IsTrue(task.Wait(timeout), failureMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
33
osu.Game.Tournament.Tests/NonVisual/TournamentHostTest.cs
Normal file
33
osu.Game.Tournament.Tests/NonVisual/TournamentHostTest.cs
Normal file
@ -0,0 +1,33 @@
|
||||
// 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.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Platform;
|
||||
|
||||
namespace osu.Game.Tournament.Tests.NonVisual
|
||||
{
|
||||
public abstract class TournamentHostTest
|
||||
{
|
||||
public static TournamentGameBase LoadTournament(GameHost host, TournamentGameBase tournament = null)
|
||||
{
|
||||
tournament ??= new TournamentGameBase();
|
||||
Task.Run(() => host.Run(tournament))
|
||||
.ContinueWith(t => Assert.Fail($"Host threw exception {t.Exception}"), TaskContinuationOptions.OnlyOnFaulted);
|
||||
WaitForOrAssert(() => tournament.IsLoaded, @"osu! failed to start in a reasonable amount of time");
|
||||
return tournament;
|
||||
}
|
||||
|
||||
public static void WaitForOrAssert(Func<bool> result, string failureMessage, int timeout = 90000)
|
||||
{
|
||||
Task task = Task.Run(() =>
|
||||
{
|
||||
while (!result()) Thread.Sleep(200);
|
||||
});
|
||||
|
||||
Assert.IsTrue(task.Wait(timeout), failureMessage);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
@ -11,6 +10,7 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Legacy;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Menu;
|
||||
@ -198,8 +198,8 @@ namespace osu.Game.Tournament.Components
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new DiffPiece(("Length", TimeSpan.FromMilliseconds(length).ToString(@"mm\:ss"))),
|
||||
new DiffPiece(("BPM", $"{bpm:0.#}"))
|
||||
new DiffPiece(("Length", length.ToFormattedDuration().ToString())),
|
||||
new DiffPiece(("BPM", $"{bpm:0.#}")),
|
||||
}
|
||||
},
|
||||
new Container
|
||||
|
@ -27,6 +27,9 @@ namespace osu.Game.Tournament.Screens.Drawings.Components
|
||||
{
|
||||
var teams = new List<TournamentTeam>();
|
||||
|
||||
if (!storage.Exists(teams_filename))
|
||||
return teams;
|
||||
|
||||
try
|
||||
{
|
||||
using (Stream stream = storage.GetStream(teams_filename, FileAccess.Read, FileMode.Open))
|
||||
|
@ -9,11 +9,13 @@ using System.Threading.Tasks;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Tournament.Components;
|
||||
using osu.Game.Tournament.Models;
|
||||
using osu.Game.Tournament.Screens.Drawings.Components;
|
||||
@ -51,6 +53,29 @@ namespace osu.Game.Tournament.Screens.Drawings
|
||||
|
||||
if (!TeamList.Teams.Any())
|
||||
{
|
||||
LinkFlowContainer links;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.Black,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Height = 0.3f,
|
||||
},
|
||||
new WarningBox("No drawings.txt file found. Please create one and restart the client."),
|
||||
links = new LinkFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Y = 60,
|
||||
AutoSizeAxes = Axes.Both
|
||||
}
|
||||
};
|
||||
|
||||
links.AddLink("Click for details on the file format", "https://osu.ppy.sh/wiki/en/Tournament_Drawings", t => t.Colour = Color4.White);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,9 @@ namespace osu.Game.Tournament
|
||||
}
|
||||
|
||||
ladder ??= new LadderInfo();
|
||||
ladder.Ruleset.Value ??= RulesetStore.AvailableRulesets.First();
|
||||
|
||||
ladder.Ruleset.Value = RulesetStore.GetRuleset(ladder.Ruleset.Value?.ShortName)
|
||||
?? RulesetStore.AvailableRulesets.First();
|
||||
|
||||
bool addedInfo = false;
|
||||
|
||||
|
@ -1,2 +1,3 @@
|
||||
[*.cs]
|
||||
dotnet_diagnostic.OLOC001.prefix_namespace = osu.Game.Resources.Localisation
|
||||
dotnet_diagnostic.OLOC001.prefix_namespace = osu.Game.Resources.Localisation
|
||||
dotnet_diagnostic.OLOC001.license_header = // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.\n// See the LICENCE file in the repository root for full licence text.
|
@ -1,26 +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;
|
||||
|
||||
namespace osu.Game.Extensions
|
||||
{
|
||||
public static class EditorDisplayExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Get an editor formatted string (mm:ss:mss)
|
||||
/// </summary>
|
||||
/// <param name="milliseconds">A time value in milliseconds.</param>
|
||||
/// <returns>An editor formatted display string.</returns>
|
||||
public static string ToEditorFormattedString(this double milliseconds) =>
|
||||
ToEditorFormattedString(TimeSpan.FromMilliseconds(milliseconds));
|
||||
|
||||
/// <summary>
|
||||
/// Get an editor formatted string (mm:ss:mss)
|
||||
/// </summary>
|
||||
/// <param name="timeSpan">A time value.</param>
|
||||
/// <returns>An editor formatted display string.</returns>
|
||||
public static string ToEditorFormattedString(this TimeSpan timeSpan) =>
|
||||
$"{(timeSpan < TimeSpan.Zero ? "-" : string.Empty)}{timeSpan:mm\\:ss\\:fff}";
|
||||
}
|
||||
}
|
51
osu.Game/Extensions/TimeDisplayExtensions.cs
Normal file
51
osu.Game/Extensions/TimeDisplayExtensions.cs
Normal file
@ -0,0 +1,51 @@
|
||||
// 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 osu.Framework.Localisation;
|
||||
|
||||
namespace osu.Game.Extensions
|
||||
{
|
||||
public static class TimeDisplayExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Get an editor formatted string (mm:ss:mss)
|
||||
/// </summary>
|
||||
/// <param name="milliseconds">A time value in milliseconds.</param>
|
||||
/// <returns>An editor formatted display string.</returns>
|
||||
public static string ToEditorFormattedString(this double milliseconds) =>
|
||||
ToEditorFormattedString(TimeSpan.FromMilliseconds(milliseconds));
|
||||
|
||||
/// <summary>
|
||||
/// Get an editor formatted string (mm:ss:mss)
|
||||
/// </summary>
|
||||
/// <param name="timeSpan">A time value.</param>
|
||||
/// <returns>An editor formatted display string.</returns>
|
||||
public static string ToEditorFormattedString(this TimeSpan timeSpan) =>
|
||||
$"{(timeSpan < TimeSpan.Zero ? "-" : string.Empty)}{(int)timeSpan.TotalMinutes:00}:{timeSpan:ss\\:fff}";
|
||||
|
||||
/// <summary>
|
||||
/// Get a formatted duration (dd:hh:mm:ss with days/hours omitted if zero).
|
||||
/// </summary>
|
||||
/// <param name="milliseconds">A duration in milliseconds.</param>
|
||||
/// <returns>A formatted duration string.</returns>
|
||||
public static LocalisableString ToFormattedDuration(this double milliseconds) =>
|
||||
ToFormattedDuration(TimeSpan.FromMilliseconds(milliseconds));
|
||||
|
||||
/// <summary>
|
||||
/// Get a formatted duration (dd:hh:mm:ss with days/hours omitted if zero).
|
||||
/// </summary>
|
||||
/// <param name="timeSpan">A duration value.</param>
|
||||
/// <returns>A formatted duration string.</returns>
|
||||
public static LocalisableString ToFormattedDuration(this TimeSpan timeSpan)
|
||||
{
|
||||
if (timeSpan.TotalDays >= 1)
|
||||
return new LocalisableFormattableString(timeSpan, @"dd\:hh\:mm\:ss");
|
||||
|
||||
if (timeSpan.TotalHours >= 1)
|
||||
return new LocalisableFormattableString(timeSpan, @"hh\:mm\:ss");
|
||||
|
||||
return new LocalisableFormattableString(timeSpan, @"mm\:ss");
|
||||
}
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ using System.Collections.Generic;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Users;
|
||||
|
||||
@ -25,6 +26,9 @@ namespace osu.Game.Graphics.Containers
|
||||
[Resolved(CanBeNull = true)]
|
||||
private OsuGame game { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private GameHost host { get; set; }
|
||||
|
||||
public void AddLinks(string text, List<Link> links)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text) || links == null)
|
||||
@ -91,8 +95,11 @@ namespace osu.Game.Graphics.Containers
|
||||
{
|
||||
if (action != null)
|
||||
action();
|
||||
else
|
||||
game?.HandleLink(link);
|
||||
else if (game != null)
|
||||
game.HandleLink(link);
|
||||
// fallback to handle cases where OsuGame is not available, ie. tournament client.
|
||||
else if (link.Action == LinkAction.External)
|
||||
host.OpenUrlExternally(link.Argument);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -59,33 +60,37 @@ namespace osu.Game.Graphics.Containers
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InternalChild = new GridContainer
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Content = new[]
|
||||
new GridContainer
|
||||
{
|
||||
new[]
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Content = new[]
|
||||
{
|
||||
handleContainer = new Container
|
||||
new[]
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Horizontal = 5 },
|
||||
Child = handle = new PlaylistItemHandle
|
||||
handleContainer = new Container
|
||||
{
|
||||
Size = new Vector2(12),
|
||||
Colour = HandleColour,
|
||||
AlwaysPresent = true,
|
||||
Alpha = 0
|
||||
}
|
||||
},
|
||||
CreateContent()
|
||||
}
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Horizontal = 5 },
|
||||
Child = handle = new PlaylistItemHandle
|
||||
{
|
||||
Size = new Vector2(12),
|
||||
Colour = HandleColour,
|
||||
AlwaysPresent = true,
|
||||
Alpha = 0
|
||||
}
|
||||
},
|
||||
CreateContent()
|
||||
}
|
||||
},
|
||||
ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
|
||||
RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }
|
||||
},
|
||||
ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
|
||||
RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }
|
||||
new HoverClickSounds()
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
Size = TwoLayerButton.SIZE_EXTENDED;
|
||||
|
||||
Child = button = new TwoLayerButton
|
||||
Child = button = new TwoLayerButton(HoverSampleSet.Submit)
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
|
@ -56,6 +56,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
private Vector2 hoverSpacing => new Vector2(3f, 0f);
|
||||
|
||||
public DialogButton()
|
||||
: base(HoverSampleSet.Submit)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
|
@ -23,14 +23,20 @@ namespace osu.Game.Graphics.UserInterface
|
||||
[Resolved]
|
||||
private GameHost host { get; set; }
|
||||
|
||||
private readonly SpriteIcon linkIcon;
|
||||
|
||||
public ExternalLinkButton(string link = null)
|
||||
{
|
||||
Link = link;
|
||||
Size = new Vector2(12);
|
||||
InternalChild = new SpriteIcon
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
Icon = FontAwesome.Solid.ExternalLinkAlt,
|
||||
RelativeSizeAxes = Axes.Both
|
||||
linkIcon = new SpriteIcon
|
||||
{
|
||||
Icon = FontAwesome.Solid.ExternalLinkAlt,
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
new HoverClickSounds(HoverSampleSet.Submit)
|
||||
};
|
||||
}
|
||||
|
||||
@ -42,13 +48,13 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
InternalChild.FadeColour(hoverColour, 500, Easing.OutQuint);
|
||||
linkIcon.FadeColour(hoverColour, 500, Easing.OutQuint);
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
InternalChild.FadeColour(Color4.White, 500, Easing.OutQuint);
|
||||
linkIcon.FadeColour(Color4.White, 500, Easing.OutQuint);
|
||||
base.OnHoverLost(e);
|
||||
}
|
||||
|
||||
|
@ -10,8 +10,8 @@ namespace osu.Game.Graphics.UserInterface
|
||||
[Description("default")]
|
||||
Default,
|
||||
|
||||
[Description("soft")]
|
||||
Soft,
|
||||
[Description("submit")]
|
||||
Submit,
|
||||
|
||||
[Description("button")]
|
||||
Button,
|
||||
|
@ -71,7 +71,8 @@ namespace osu.Game.Graphics.UserInterface
|
||||
}
|
||||
}
|
||||
|
||||
public TwoLayerButton()
|
||||
public TwoLayerButton(HoverSampleSet sampleSet = HoverSampleSet.Default)
|
||||
: base(sampleSet)
|
||||
{
|
||||
Size = SIZE_RETRACTED;
|
||||
Shear = shear;
|
||||
|
@ -1,32 +1,39 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterfaceV2
|
||||
{
|
||||
/// <summary>
|
||||
/// A component which displays a colour along with related description text.
|
||||
/// </summary>
|
||||
public class ColourDisplay : CompositeDrawable, IHasCurrentValue<Color4>
|
||||
public class ColourDisplay : CompositeDrawable, IHasCurrentValue<Colour4>
|
||||
{
|
||||
private readonly BindableWithCurrent<Color4> current = new BindableWithCurrent<Color4>();
|
||||
/// <summary>
|
||||
/// Invoked when the user has requested the colour corresponding to this <see cref="ColourDisplay"/>
|
||||
/// to be removed from its palette.
|
||||
/// </summary>
|
||||
public event Action<ColourDisplay> DeleteRequested;
|
||||
|
||||
private readonly BindableWithCurrent<Colour4> current = new BindableWithCurrent<Colour4>();
|
||||
|
||||
private Box fill;
|
||||
private OsuSpriteText colourHexCode;
|
||||
private OsuSpriteText colourName;
|
||||
|
||||
public Bindable<Color4> Current
|
||||
public Bindable<Colour4> Current
|
||||
{
|
||||
get => current.Current;
|
||||
set => current.Current = value;
|
||||
@ -62,24 +69,10 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
Spacing = new Vector2(0, 10),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new CircularContainer
|
||||
new ColourCircle
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 100,
|
||||
Masking = true,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
fill = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
colourHexCode = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Font = OsuFont.Default.With(size: 12)
|
||||
}
|
||||
}
|
||||
Current = { BindTarget = Current },
|
||||
DeleteRequested = () => DeleteRequested?.Invoke(this)
|
||||
},
|
||||
colourName = new OsuSpriteText
|
||||
{
|
||||
@ -90,18 +83,64 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
private class ColourCircle : OsuClickableContainer, IHasPopover, IHasContextMenu
|
||||
{
|
||||
base.LoadComplete();
|
||||
public Bindable<Colour4> Current { get; } = new Bindable<Colour4>();
|
||||
|
||||
current.BindValueChanged(_ => updateColour(), true);
|
||||
}
|
||||
public Action DeleteRequested { get; set; }
|
||||
|
||||
private void updateColour()
|
||||
{
|
||||
fill.Colour = current.Value;
|
||||
colourHexCode.Text = current.Value.ToHex();
|
||||
colourHexCode.Colour = OsuColour.ForegroundTextColourFor(current.Value);
|
||||
private readonly Box fill;
|
||||
private readonly OsuSpriteText colourHexCode;
|
||||
|
||||
public ColourCircle()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = 100;
|
||||
CornerRadius = 50;
|
||||
Masking = true;
|
||||
Action = this.ShowPopover;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
fill = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
colourHexCode = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Font = OsuFont.Default.With(size: 12)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
Current.BindValueChanged(_ => updateColour(), true);
|
||||
}
|
||||
|
||||
private void updateColour()
|
||||
{
|
||||
fill.Colour = Current.Value;
|
||||
colourHexCode.Text = Current.Value.ToHex();
|
||||
colourHexCode.Colour = OsuColour.ForegroundTextColourFor(Current.Value);
|
||||
}
|
||||
|
||||
public Popover GetPopover() => new OsuPopover(false)
|
||||
{
|
||||
Child = new OsuColourPicker
|
||||
{
|
||||
Current = { BindTarget = Current }
|
||||
}
|
||||
};
|
||||
|
||||
public MenuItem[] ContextMenuItems => new MenuItem[]
|
||||
{
|
||||
new OsuMenuItem("Delete", MenuItemType.Destructive, () => DeleteRequested?.Invoke())
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,19 @@
|
||||
// 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.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterfaceV2
|
||||
{
|
||||
@ -17,7 +22,7 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
/// </summary>
|
||||
public class ColourPalette : CompositeDrawable
|
||||
{
|
||||
public BindableList<Color4> Colours { get; } = new BindableList<Color4>();
|
||||
public BindableList<Colour4> Colours { get; } = new BindableList<Colour4>();
|
||||
|
||||
private string colourNamePrefix = "Colour";
|
||||
|
||||
@ -36,36 +41,24 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
}
|
||||
}
|
||||
|
||||
private FillFlowContainer<ColourDisplay> palette;
|
||||
private Container placeholder;
|
||||
private FillFlowContainer palette;
|
||||
|
||||
private IEnumerable<ColourDisplay> colourDisplays => palette.OfType<ColourDisplay>();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
AutoSizeDuration = fade_duration;
|
||||
AutoSizeEasing = Easing.OutQuint;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
InternalChild = palette = new FillFlowContainer
|
||||
{
|
||||
palette = new FillFlowContainer<ColourDisplay>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Spacing = new Vector2(10),
|
||||
Direction = FillDirection.Full
|
||||
},
|
||||
placeholder = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Child = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Text = "(none)",
|
||||
Font = OsuFont.Default.With(weight: FontWeight.Bold)
|
||||
}
|
||||
}
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Spacing = new Vector2(10),
|
||||
Direction = FillDirection.Full
|
||||
};
|
||||
}
|
||||
|
||||
@ -73,7 +66,11 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
Colours.BindCollectionChanged((_, __) => updatePalette(), true);
|
||||
Colours.BindCollectionChanged((_, args) =>
|
||||
{
|
||||
if (args.Action != NotifyCollectionChangedAction.Replace)
|
||||
updatePalette();
|
||||
}, true);
|
||||
FinishTransforms(true);
|
||||
}
|
||||
|
||||
@ -83,37 +80,103 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
{
|
||||
palette.Clear();
|
||||
|
||||
if (Colours.Any())
|
||||
for (int i = 0; i < Colours.Count; ++i)
|
||||
{
|
||||
palette.FadeIn(fade_duration, Easing.OutQuint);
|
||||
placeholder.FadeOut(fade_duration, Easing.OutQuint);
|
||||
}
|
||||
else
|
||||
{
|
||||
palette.FadeOut(fade_duration, Easing.OutQuint);
|
||||
placeholder.FadeIn(fade_duration, Easing.OutQuint);
|
||||
// copy to avoid accesses to modified closure.
|
||||
int colourIndex = i;
|
||||
ColourDisplay display;
|
||||
|
||||
palette.Add(display = new ColourDisplay
|
||||
{
|
||||
Current = { Value = Colours[colourIndex] }
|
||||
});
|
||||
|
||||
display.Current.BindValueChanged(colour => Colours[colourIndex] = colour.NewValue);
|
||||
display.DeleteRequested += colourDeletionRequested;
|
||||
}
|
||||
|
||||
foreach (var item in Colours)
|
||||
palette.Add(new AddColourButton
|
||||
{
|
||||
palette.Add(new ColourDisplay
|
||||
{
|
||||
Current = { Value = item }
|
||||
});
|
||||
}
|
||||
Action = () => Colours.Add(Colour4.White)
|
||||
});
|
||||
|
||||
reindexItems();
|
||||
}
|
||||
|
||||
private void colourDeletionRequested(ColourDisplay display) => Colours.RemoveAt(palette.IndexOf(display));
|
||||
|
||||
private void reindexItems()
|
||||
{
|
||||
int index = 1;
|
||||
|
||||
foreach (var colour in palette)
|
||||
foreach (var colourDisplay in colourDisplays)
|
||||
{
|
||||
colour.ColourName = $"{colourNamePrefix} {index}";
|
||||
colourDisplay.ColourName = $"{colourNamePrefix} {index}";
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
internal class AddColourButton : CompositeDrawable
|
||||
{
|
||||
public Action Action
|
||||
{
|
||||
set => circularButton.Action = value;
|
||||
}
|
||||
|
||||
private readonly OsuClickableContainer circularButton;
|
||||
|
||||
public AddColourButton()
|
||||
{
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Width = 100;
|
||||
|
||||
InternalChild = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 10),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
circularButton = new OsuClickableContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 100,
|
||||
CornerRadius = 50,
|
||||
Masking = true,
|
||||
BorderThickness = 5,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Colour4.Transparent,
|
||||
AlwaysPresent = true
|
||||
},
|
||||
new SpriteIcon
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(20),
|
||||
Icon = FontAwesome.Solid.Plus
|
||||
}
|
||||
}
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Text = "New"
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
circularButton.BorderColour = colours.BlueDarker;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Bindables;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterfaceV2
|
||||
{
|
||||
@ -13,7 +13,7 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
{
|
||||
}
|
||||
|
||||
public BindableList<Color4> Colours => Component.Colours;
|
||||
public BindableList<Colour4> Colours => Component.Colours;
|
||||
|
||||
public string ColourNamePrefix
|
||||
{
|
||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
{
|
||||
Depth = 1
|
||||
},
|
||||
new HoverClickSounds(HoverSampleSet.Soft)
|
||||
new HoverClickSounds()
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
{
|
||||
Depth = 1
|
||||
},
|
||||
new HoverClickSounds(HoverSampleSet.Soft)
|
||||
new HoverClickSounds()
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -150,7 +150,7 @@ namespace osu.Game.Online.API
|
||||
|
||||
userReq.Failure += ex =>
|
||||
{
|
||||
if (ex.InnerException is WebException webException && webException.Message == @"Unauthorized")
|
||||
if (ex is WebException webException && webException.Message == @"Unauthorized")
|
||||
{
|
||||
log.Add(@"Login no longer valid");
|
||||
Logout();
|
||||
|
@ -86,8 +86,6 @@ namespace osu.Game.Online.API
|
||||
/// </summary>
|
||||
private APIRequestCompletionState completionState;
|
||||
|
||||
private Action pendingFailure;
|
||||
|
||||
public void Perform(IAPIProvider api)
|
||||
{
|
||||
if (!(api is APIAccess apiAccess))
|
||||
@ -99,29 +97,23 @@ namespace osu.Game.Online.API
|
||||
API = apiAccess;
|
||||
User = apiAccess.LocalUser.Value;
|
||||
|
||||
if (checkAndScheduleFailure())
|
||||
return;
|
||||
if (isFailing) return;
|
||||
|
||||
WebRequest = CreateWebRequest();
|
||||
WebRequest.Failed += Fail;
|
||||
WebRequest.AllowRetryOnTimeout = false;
|
||||
WebRequest.AddHeader("Authorization", $"Bearer {API.AccessToken}");
|
||||
|
||||
if (checkAndScheduleFailure())
|
||||
return;
|
||||
if (isFailing) return;
|
||||
|
||||
if (!WebRequest.Aborted) // could have been aborted by a Cancel() call
|
||||
{
|
||||
Logger.Log($@"Performing request {this}", LoggingTarget.Network);
|
||||
WebRequest.Perform();
|
||||
}
|
||||
Logger.Log($@"Performing request {this}", LoggingTarget.Network);
|
||||
WebRequest.Perform();
|
||||
|
||||
if (checkAndScheduleFailure())
|
||||
return;
|
||||
if (isFailing) return;
|
||||
|
||||
PostProcess();
|
||||
|
||||
API.Schedule(TriggerSuccess);
|
||||
TriggerSuccess();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -141,7 +133,10 @@ namespace osu.Game.Online.API
|
||||
completionState = APIRequestCompletionState.Completed;
|
||||
}
|
||||
|
||||
Success?.Invoke();
|
||||
if (API == null)
|
||||
Success?.Invoke();
|
||||
else
|
||||
API.Schedule(() => Success?.Invoke());
|
||||
}
|
||||
|
||||
internal void TriggerFailure(Exception e)
|
||||
@ -154,7 +149,10 @@ namespace osu.Game.Online.API
|
||||
completionState = APIRequestCompletionState.Failed;
|
||||
}
|
||||
|
||||
Failure?.Invoke(e);
|
||||
if (API == null)
|
||||
Failure?.Invoke(e);
|
||||
else
|
||||
API.Schedule(() => Failure?.Invoke(e));
|
||||
}
|
||||
|
||||
public void Cancel() => Fail(new OperationCanceledException(@"Request cancelled"));
|
||||
@ -163,59 +161,47 @@ namespace osu.Game.Online.API
|
||||
{
|
||||
lock (completionStateLock)
|
||||
{
|
||||
// while it doesn't matter if code following this check is run more than once,
|
||||
// this avoids unnecessarily performing work where we are already sure the user has been informed.
|
||||
if (completionState != APIRequestCompletionState.Waiting)
|
||||
return;
|
||||
}
|
||||
|
||||
WebRequest?.Abort();
|
||||
WebRequest?.Abort();
|
||||
|
||||
// in the case of a cancellation we don't care about whether there's an error in the response.
|
||||
if (!(e is OperationCanceledException))
|
||||
{
|
||||
string responseString = WebRequest?.GetResponseString();
|
||||
|
||||
// naive check whether there's an error in the response to avoid unnecessary JSON deserialisation.
|
||||
if (!string.IsNullOrEmpty(responseString) && responseString.Contains(@"""error"""))
|
||||
// in the case of a cancellation we don't care about whether there's an error in the response.
|
||||
if (!(e is OperationCanceledException))
|
||||
{
|
||||
try
|
||||
{
|
||||
// attempt to decode a displayable error string.
|
||||
var error = JsonConvert.DeserializeObject<DisplayableError>(responseString);
|
||||
if (error != null)
|
||||
e = new APIException(error.ErrorMessage, e);
|
||||
}
|
||||
catch
|
||||
string responseString = WebRequest?.GetResponseString();
|
||||
|
||||
// naive check whether there's an error in the response to avoid unnecessary JSON deserialisation.
|
||||
if (!string.IsNullOrEmpty(responseString) && responseString.Contains(@"""error"""))
|
||||
{
|
||||
try
|
||||
{
|
||||
// attempt to decode a displayable error string.
|
||||
var error = JsonConvert.DeserializeObject<DisplayableError>(responseString);
|
||||
if (error != null)
|
||||
e = new APIException(error.ErrorMessage, e);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger.Log($@"Failing request {this} ({e})", LoggingTarget.Network);
|
||||
pendingFailure = () => TriggerFailure(e);
|
||||
checkAndScheduleFailure();
|
||||
Logger.Log($@"Failing request {this} ({e})", LoggingTarget.Network);
|
||||
TriggerFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checked for cancellation or error. Also queues up the Failed event if we can.
|
||||
/// Whether this request is in a failing or failed state.
|
||||
/// </summary>
|
||||
/// <returns>Whether we are in a failed or cancelled state.</returns>
|
||||
private bool checkAndScheduleFailure()
|
||||
private bool isFailing
|
||||
{
|
||||
lock (completionStateLock)
|
||||
get
|
||||
{
|
||||
if (pendingFailure == null)
|
||||
lock (completionStateLock)
|
||||
return completionState == APIRequestCompletionState.Failed;
|
||||
}
|
||||
|
||||
if (API == null)
|
||||
pendingFailure();
|
||||
else
|
||||
API.Schedule(pendingFailure);
|
||||
|
||||
pendingFailure = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
private class DisplayableError
|
||||
|
@ -31,6 +31,7 @@ namespace osu.Game.Online.Chat
|
||||
protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new LinkHoverSounds(sampleSet, Parts);
|
||||
|
||||
public DrawableLinkCompiler(IEnumerable<Drawable> parts)
|
||||
: base(HoverSampleSet.Submit)
|
||||
{
|
||||
Parts = parts.ToList();
|
||||
}
|
||||
|
@ -1058,7 +1058,7 @@ namespace osu.Game
|
||||
OverlayActivationMode.BindTo(newOsuScreen.OverlayActivationMode);
|
||||
API.Activity.BindTo(newOsuScreen.Activity);
|
||||
|
||||
MusicController.AllowRateAdjustments = newOsuScreen.AllowRateAdjustments;
|
||||
MusicController.AllowTrackAdjustments = newOsuScreen.AllowTrackAdjustments;
|
||||
|
||||
if (newOsuScreen.HideOverlaysOnEnter)
|
||||
CloseAllOverlays();
|
||||
|
@ -479,7 +479,7 @@ namespace osu.Game
|
||||
if (r.NewValue?.Available != true)
|
||||
{
|
||||
// reject the change if the ruleset is not available.
|
||||
Ruleset.Value = r.OldValue;
|
||||
Ruleset.Value = r.OldValue?.Available == true ? r.OldValue : RulesetStore.AvailableRulesets.First();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
protected Action ViewBeatmap;
|
||||
|
||||
protected BeatmapPanel(BeatmapSetInfo setInfo)
|
||||
: base(HoverSampleSet.Submit)
|
||||
{
|
||||
Debug.Assert(setInfo.OnlineBeatmapSetID != null);
|
||||
|
||||
|
@ -10,6 +10,7 @@ using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osuTK;
|
||||
@ -62,7 +63,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
}
|
||||
else
|
||||
{
|
||||
length.Value = TimeSpan.FromMilliseconds(beatmap.Length).ToString(@"m\:ss");
|
||||
length.Value = TimeSpan.FromMilliseconds(beatmap.Length).ToFormattedDuration();
|
||||
circleCount.Value = beatmap.OnlineInfo.CircleCount.ToString();
|
||||
sliderCount.Value = beatmap.OnlineInfo.SliderCount.ToString();
|
||||
}
|
||||
|
@ -3,6 +3,9 @@
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -13,6 +16,7 @@ using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.Chat;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
@ -39,6 +43,8 @@ namespace osu.Game.Overlays.Chat.Tabs
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
private Sample sampleTabSwitched;
|
||||
|
||||
public ChannelTabItem(Channel value)
|
||||
: base(value)
|
||||
{
|
||||
@ -112,6 +118,7 @@ namespace osu.Game.Overlays.Chat.Tabs
|
||||
},
|
||||
},
|
||||
},
|
||||
new HoverSounds()
|
||||
};
|
||||
}
|
||||
|
||||
@ -152,11 +159,12 @@ namespace osu.Game.Overlays.Chat.Tabs
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OsuColour colours, AudioManager audio)
|
||||
{
|
||||
BackgroundActive = colours.ChatBlue;
|
||||
BackgroundInactive = colours.Gray4;
|
||||
backgroundHover = colours.Gray7;
|
||||
sampleTabSwitched = audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select");
|
||||
|
||||
highlightBox.Colour = colours.Yellow;
|
||||
}
|
||||
@ -217,7 +225,14 @@ namespace osu.Game.Overlays.Chat.Tabs
|
||||
Text.Font = Text.Font.With(weight: FontWeight.Medium);
|
||||
}
|
||||
|
||||
protected override void OnActivated() => updateState();
|
||||
protected override void OnActivated()
|
||||
{
|
||||
if (IsLoaded)
|
||||
sampleTabSwitched?.Play();
|
||||
|
||||
updateState();
|
||||
}
|
||||
|
||||
protected override void OnDeactivated() => updateState();
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Chat.Tabs
|
||||
if (value.Type != ChannelType.PM)
|
||||
throw new ArgumentException("Argument value needs to have the targettype user!");
|
||||
|
||||
ClickableAvatar avatar;
|
||||
DrawableAvatar avatar;
|
||||
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
@ -48,10 +48,9 @@ namespace osu.Game.Overlays.Chat.Tabs
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Masking = true,
|
||||
Child = new DelayedLoadWrapper(avatar = new ClickableAvatar(value.Users.First())
|
||||
Child = new DelayedLoadWrapper(avatar = new DrawableAvatar(value.Users.First())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
OpenOnClick = false,
|
||||
RelativeSizeAxes = Axes.Both
|
||||
})
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
|
@ -400,35 +400,38 @@ namespace osu.Game.Overlays
|
||||
NextTrack();
|
||||
}
|
||||
|
||||
private bool allowRateAdjustments;
|
||||
private bool allowTrackAdjustments;
|
||||
|
||||
/// <summary>
|
||||
/// Whether mod rate adjustments are allowed to be applied.
|
||||
/// Whether mod track adjustments are allowed to be applied.
|
||||
/// </summary>
|
||||
public bool AllowRateAdjustments
|
||||
public bool AllowTrackAdjustments
|
||||
{
|
||||
get => allowRateAdjustments;
|
||||
get => allowTrackAdjustments;
|
||||
set
|
||||
{
|
||||
if (allowRateAdjustments == value)
|
||||
if (allowTrackAdjustments == value)
|
||||
return;
|
||||
|
||||
allowRateAdjustments = value;
|
||||
allowTrackAdjustments = value;
|
||||
ResetTrackAdjustments();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the speed adjustments currently applied on <see cref="CurrentTrack"/> and applies the mod adjustments if <see cref="AllowRateAdjustments"/> is <c>true</c>.
|
||||
/// Resets the adjustments currently applied on <see cref="CurrentTrack"/> and applies the mod adjustments if <see cref="AllowTrackAdjustments"/> is <c>true</c>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Does not reset speed adjustments applied directly to the beatmap track.
|
||||
/// Does not reset any adjustments applied directly to the beatmap track.
|
||||
/// </remarks>
|
||||
public void ResetTrackAdjustments()
|
||||
{
|
||||
CurrentTrack.ResetSpeedAdjustments();
|
||||
CurrentTrack.RemoveAllAdjustments(AdjustableProperty.Balance);
|
||||
CurrentTrack.RemoveAllAdjustments(AdjustableProperty.Frequency);
|
||||
CurrentTrack.RemoveAllAdjustments(AdjustableProperty.Tempo);
|
||||
CurrentTrack.RemoveAllAdjustments(AdjustableProperty.Volume);
|
||||
|
||||
if (allowRateAdjustments)
|
||||
if (allowTrackAdjustments)
|
||||
{
|
||||
foreach (var mod in mods.Value.OfType<IApplicableToTrack>())
|
||||
mod.ApplyToTrack(CurrentTrack);
|
||||
|
@ -14,6 +14,7 @@ using osu.Framework.Platform;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Overlays.News
|
||||
@ -28,6 +29,7 @@ namespace osu.Game.Overlays.News
|
||||
private TextFlowContainer main;
|
||||
|
||||
public NewsCard(APINewsPost post)
|
||||
: base(HoverSampleSet.Submit)
|
||||
{
|
||||
this.post = post;
|
||||
|
||||
|
@ -15,13 +15,18 @@ using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using System.Diagnostics;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Overlays.News.Sidebar
|
||||
{
|
||||
public class MonthSection : CompositeDrawable
|
||||
{
|
||||
private const int animation_duration = 250;
|
||||
private Sample sampleOpen;
|
||||
private Sample sampleClose;
|
||||
|
||||
public readonly BindableBool Expanded = new BindableBool();
|
||||
|
||||
@ -51,6 +56,21 @@ namespace osu.Game.Overlays.News.Sidebar
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Expanded.ValueChanged += expanded =>
|
||||
{
|
||||
if (expanded.NewValue)
|
||||
sampleOpen?.Play();
|
||||
else
|
||||
sampleClose?.Play();
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
sampleOpen = audio.Samples.Get(@"UI/dropdown-open");
|
||||
sampleClose = audio.Samples.Get(@"UI/dropdown-close");
|
||||
}
|
||||
|
||||
private class DropdownHeader : OsuClickableContainer
|
||||
@ -59,6 +79,8 @@ namespace osu.Game.Overlays.News.Sidebar
|
||||
|
||||
private readonly SpriteIcon icon;
|
||||
|
||||
protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverSounds();
|
||||
|
||||
public DropdownHeader(int month, int year)
|
||||
{
|
||||
var date = new DateTime(year, month, 1);
|
||||
@ -104,6 +126,7 @@ namespace osu.Game.Overlays.News.Sidebar
|
||||
private readonly APINewsPost post;
|
||||
|
||||
public PostButton(APINewsPost post)
|
||||
: base(HoverSampleSet.Submit)
|
||||
{
|
||||
this.post = post;
|
||||
|
||||
|
@ -6,6 +6,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections
|
||||
{
|
||||
@ -17,6 +18,7 @@ namespace osu.Game.Overlays.Profile.Sections
|
||||
private readonly BeatmapInfo beatmap;
|
||||
|
||||
protected BeatmapMetadataContainer(BeatmapInfo beatmap)
|
||||
: base(HoverSampleSet.Submit)
|
||||
{
|
||||
this.beatmap = beatmap;
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
@ -52,7 +53,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 12),
|
||||
Text = UsersStrings.ShowExtraTopRanksPpWeight(weight.ToString("0%"))
|
||||
Text = UsersStrings.ShowExtraTopRanksPpWeight(weight.ToLocalisableString("0%"))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -5,6 +5,9 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
using osu.Framework.Localisation;
|
||||
using System;
|
||||
|
||||
namespace osu.Game.Overlays.Rankings
|
||||
{
|
||||
@ -29,13 +32,14 @@ namespace osu.Game.Overlays.Rankings
|
||||
{
|
||||
public RankingsTitle()
|
||||
{
|
||||
Title = "ranking";
|
||||
Title = PageTitleStrings.MainRankingControllerDefault;
|
||||
Description = "find out who's the best right now";
|
||||
IconTexture = "Icons/Hexacons/rankings";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[LocalisableEnum(typeof(RankingsScopeEnumLocalisationMapper))]
|
||||
public enum RankingsScope
|
||||
{
|
||||
Performance,
|
||||
@ -43,4 +47,28 @@ namespace osu.Game.Overlays.Rankings
|
||||
Score,
|
||||
Country
|
||||
}
|
||||
|
||||
public class RankingsScopeEnumLocalisationMapper : EnumLocalisationMapper<RankingsScope>
|
||||
{
|
||||
public override LocalisableString Map(RankingsScope value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case RankingsScope.Performance:
|
||||
return RankingsStrings.TypePerformance;
|
||||
|
||||
case RankingsScope.Spotlights:
|
||||
return RankingsStrings.TypeCharts;
|
||||
|
||||
case RankingsScope.Score:
|
||||
return RankingsStrings.TypeScore;
|
||||
|
||||
case RankingsScope.Country:
|
||||
return RankingsStrings.TypeCountry;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(value), value, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,43 @@
|
||||
// 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 osu.Framework.Extensions.LocalisationExtensions;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
|
||||
namespace osu.Game.Overlays.Rankings
|
||||
{
|
||||
public class RankingsSortTabControl : OverlaySortTabControl<RankingsSortCriteria>
|
||||
{
|
||||
public RankingsSortTabControl()
|
||||
{
|
||||
Title = "Show";
|
||||
Title = RankingsStrings.FilterTitle.ToUpper();
|
||||
}
|
||||
}
|
||||
|
||||
[LocalisableEnum(typeof(RankingsSortCriteriaEnumLocalisationMapper))]
|
||||
public enum RankingsSortCriteria
|
||||
{
|
||||
All,
|
||||
Friends
|
||||
}
|
||||
|
||||
public class RankingsSortCriteriaEnumLocalisationMapper : EnumLocalisationMapper<RankingsSortCriteria>
|
||||
{
|
||||
public override LocalisableString Map(RankingsSortCriteria value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case RankingsSortCriteria.All:
|
||||
return SortStrings.All;
|
||||
|
||||
case RankingsSortCriteria.Friends:
|
||||
return SortStrings.Friends;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(value), value, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ using System.Collections.Generic;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
|
||||
namespace osu.Game.Overlays.Rankings
|
||||
{
|
||||
@ -92,10 +94,10 @@ namespace osu.Game.Overlays.Rankings
|
||||
Margin = new MarginPadding { Bottom = 5 },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
startDateColumn = new InfoColumn(@"Start Date"),
|
||||
endDateColumn = new InfoColumn(@"End Date"),
|
||||
mapCountColumn = new InfoColumn(@"Map Count"),
|
||||
participantsColumn = new InfoColumn(@"Participants")
|
||||
startDateColumn = new InfoColumn(RankingsStrings.SpotlightStartDate),
|
||||
endDateColumn = new InfoColumn(RankingsStrings.SpotlightEndDate),
|
||||
mapCountColumn = new InfoColumn(RankingsStrings.SpotlightMapCount),
|
||||
participantsColumn = new InfoColumn(RankingsStrings.SpotlightParticipants)
|
||||
}
|
||||
},
|
||||
new RankingsSortTabControl
|
||||
@ -122,22 +124,22 @@ namespace osu.Game.Overlays.Rankings
|
||||
{
|
||||
startDateColumn.Value = dateToString(response.Spotlight.StartDate);
|
||||
endDateColumn.Value = dateToString(response.Spotlight.EndDate);
|
||||
mapCountColumn.Value = response.BeatmapSets.Count.ToString();
|
||||
participantsColumn.Value = response.Spotlight.Participants?.ToString("N0");
|
||||
mapCountColumn.Value = response.BeatmapSets.Count.ToLocalisableString(@"N0");
|
||||
participantsColumn.Value = response.Spotlight.Participants?.ToLocalisableString(@"N0");
|
||||
}
|
||||
|
||||
private string dateToString(DateTimeOffset date) => date.ToString("yyyy-MM-dd");
|
||||
private LocalisableString dateToString(DateTimeOffset date) => date.ToLocalisableString(@"yyyy-MM-dd");
|
||||
|
||||
private class InfoColumn : FillFlowContainer
|
||||
{
|
||||
public string Value
|
||||
public LocalisableString Value
|
||||
{
|
||||
set => valueText.Text = value;
|
||||
}
|
||||
|
||||
private readonly OsuSpriteText valueText;
|
||||
|
||||
public InfoColumn(string name)
|
||||
public InfoColumn(LocalisableString name)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Direction = FillDirection.Vertical;
|
||||
|
@ -9,6 +9,8 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
using osu.Framework.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.Rankings.Tables
|
||||
{
|
||||
@ -19,14 +21,14 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
{
|
||||
}
|
||||
|
||||
protected override TableColumn[] CreateAdditionalHeaders() => new[]
|
||||
protected override RankingsTableColumn[] CreateAdditionalHeaders() => new[]
|
||||
{
|
||||
new TableColumn("Active Users", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new TableColumn("Play Count", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new TableColumn("Ranked Score", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new TableColumn("Avg. Score", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new TableColumn("Performance", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new TableColumn("Avg. Perf.", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new RankingsTableColumn(RankingsStrings.StatActiveUsers, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new RankingsTableColumn(RankingsStrings.StatPlayCount, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new RankingsTableColumn(RankingsStrings.StatRankedScore, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new RankingsTableColumn(RankingsStrings.StatAverageScore, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new RankingsTableColumn(RankingsStrings.StatPerformance, Anchor.Centre, new Dimension(GridSizeMode.AutoSize), true),
|
||||
new RankingsTableColumn(RankingsStrings.StatAveragePerformance, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
};
|
||||
|
||||
protected override Country GetCountry(CountryStatistics item) => item.Country;
|
||||
@ -35,29 +37,29 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
|
||||
protected override Drawable[] CreateAdditionalContent(CountryStatistics item) => new Drawable[]
|
||||
{
|
||||
new ColoredRowText
|
||||
new ColouredRowText
|
||||
{
|
||||
Text = $@"{item.ActiveUsers:N0}",
|
||||
Text = item.ActiveUsers.ToLocalisableString(@"N0")
|
||||
},
|
||||
new ColoredRowText
|
||||
new ColouredRowText
|
||||
{
|
||||
Text = $@"{item.PlayCount:N0}",
|
||||
Text = item.PlayCount.ToLocalisableString(@"N0")
|
||||
},
|
||||
new ColoredRowText
|
||||
new ColouredRowText
|
||||
{
|
||||
Text = $@"{item.RankedScore:N0}",
|
||||
Text = item.RankedScore.ToLocalisableString(@"N0")
|
||||
},
|
||||
new ColoredRowText
|
||||
new ColouredRowText
|
||||
{
|
||||
Text = $@"{item.RankedScore / Math.Max(item.ActiveUsers, 1):N0}",
|
||||
Text = (item.RankedScore / Math.Max(item.ActiveUsers, 1)).ToLocalisableString(@"N0")
|
||||
},
|
||||
new RowText
|
||||
{
|
||||
Text = $@"{item.Performance:N0}",
|
||||
Text = item.Performance.ToLocalisableString(@"N0")
|
||||
},
|
||||
new ColoredRowText
|
||||
new ColouredRowText
|
||||
{
|
||||
Text = $@"{item.Performance / Math.Max(item.ActiveUsers, 1):N0}",
|
||||
Text = (item.Performance / Math.Max(item.ActiveUsers, 1)).ToLocalisableString(@"N0")
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Overlays.Rankings.Tables
|
||||
@ -15,14 +17,14 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
{
|
||||
}
|
||||
|
||||
protected override TableColumn[] CreateUniqueHeaders() => new[]
|
||||
protected override RankingsTableColumn[] CreateUniqueHeaders() => new[]
|
||||
{
|
||||
new TableColumn("Performance", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new RankingsTableColumn(RankingsStrings.StatPerformance, Anchor.Centre, new Dimension(GridSizeMode.AutoSize), true),
|
||||
};
|
||||
|
||||
protected override Drawable[] CreateUniqueContent(UserStatistics item) => new Drawable[]
|
||||
{
|
||||
new RowText { Text = $@"{item.PP:N0}", }
|
||||
new RowText { Text = item.PP.ToLocalisableString(@"N0"), }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -55,29 +55,24 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
|
||||
rankings.ForEach(_ => backgroundFlow.Add(new TableRowBackground { Height = row_height }));
|
||||
|
||||
Columns = mainHeaders.Concat(CreateAdditionalHeaders()).ToArray();
|
||||
Columns = mainHeaders.Concat(CreateAdditionalHeaders()).Cast<TableColumn>().ToArray();
|
||||
Content = rankings.Select((s, i) => createContent((page - 1) * items_per_page + i, s)).ToArray().ToRectangular();
|
||||
}
|
||||
|
||||
private Drawable[] createContent(int index, TModel item) => new Drawable[] { createIndexDrawable(index), createMainContent(item) }.Concat(CreateAdditionalContent(item)).ToArray();
|
||||
|
||||
private static TableColumn[] mainHeaders => new[]
|
||||
private static RankingsTableColumn[] mainHeaders => new[]
|
||||
{
|
||||
new TableColumn(string.Empty, Anchor.Centre, new Dimension(GridSizeMode.Absolute, 40)), // place
|
||||
new TableColumn(string.Empty, Anchor.CentreLeft, new Dimension()), // flag and username (country name)
|
||||
new RankingsTableColumn(string.Empty, Anchor.Centre, new Dimension(GridSizeMode.Absolute, 40)), // place
|
||||
new RankingsTableColumn(string.Empty, Anchor.CentreLeft, new Dimension()), // flag and username (country name)
|
||||
};
|
||||
|
||||
protected abstract TableColumn[] CreateAdditionalHeaders();
|
||||
protected abstract RankingsTableColumn[] CreateAdditionalHeaders();
|
||||
|
||||
protected abstract Drawable[] CreateAdditionalContent(TModel item);
|
||||
|
||||
protected virtual string HighlightedColumn => @"Performance";
|
||||
|
||||
protected override Drawable CreateHeader(int index, TableColumn column)
|
||||
{
|
||||
var title = column?.Header ?? default;
|
||||
return new HeaderText(title, title == HighlightedColumn);
|
||||
}
|
||||
protected sealed override Drawable CreateHeader(int index, TableColumn column)
|
||||
=> (column as RankingsTableColumn)?.CreateHeaderText() ?? new HeaderText(column?.Header ?? default, false);
|
||||
|
||||
protected abstract Country GetCountry(TModel item);
|
||||
|
||||
@ -85,7 +80,7 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
|
||||
private OsuSpriteText createIndexDrawable(int index) => new RowText
|
||||
{
|
||||
Text = $"#{index + 1}",
|
||||
Text = (index + 1).ToLocalisableString(@"\##"),
|
||||
Font = OsuFont.GetFont(size: TEXT_SIZE, weight: FontWeight.SemiBold)
|
||||
};
|
||||
|
||||
@ -106,6 +101,19 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
}
|
||||
};
|
||||
|
||||
protected class RankingsTableColumn : TableColumn
|
||||
{
|
||||
protected readonly bool Highlighted;
|
||||
|
||||
public RankingsTableColumn(LocalisableString? header = null, Anchor anchor = Anchor.TopLeft, Dimension dimension = null, bool highlighted = false)
|
||||
: base(header, anchor, dimension)
|
||||
{
|
||||
Highlighted = highlighted;
|
||||
}
|
||||
|
||||
public virtual HeaderText CreateHeaderText() => new HeaderText(Header, Highlighted);
|
||||
}
|
||||
|
||||
protected class HeaderText : OsuSpriteText
|
||||
{
|
||||
private readonly bool isHighlighted;
|
||||
@ -136,7 +144,7 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
}
|
||||
}
|
||||
|
||||
protected class ColoredRowText : RowText
|
||||
protected class ColouredRowText : RowText
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
|
@ -4,6 +4,8 @@
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Overlays.Rankings.Tables
|
||||
@ -15,24 +17,22 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
{
|
||||
}
|
||||
|
||||
protected override TableColumn[] CreateUniqueHeaders() => new[]
|
||||
protected override RankingsTableColumn[] CreateUniqueHeaders() => new[]
|
||||
{
|
||||
new TableColumn("Total Score", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new TableColumn("Ranked Score", Anchor.Centre, new Dimension(GridSizeMode.AutoSize))
|
||||
new RankingsTableColumn(RankingsStrings.StatTotalScore, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new RankingsTableColumn(RankingsStrings.StatRankedScore, Anchor.Centre, new Dimension(GridSizeMode.AutoSize), true)
|
||||
};
|
||||
|
||||
protected override Drawable[] CreateUniqueContent(UserStatistics item) => new Drawable[]
|
||||
{
|
||||
new ColoredRowText
|
||||
new ColouredRowText
|
||||
{
|
||||
Text = $@"{item.TotalScore:N0}",
|
||||
Text = item.TotalScore.ToLocalisableString(@"N0"),
|
||||
},
|
||||
new RowText
|
||||
{
|
||||
Text = $@"{item.RankedScore:N0}",
|
||||
Text = item.RankedScore.ToLocalisableString(@"N0")
|
||||
}
|
||||
};
|
||||
|
||||
protected override string HighlightedColumn => @"Ranked Score";
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
|
||||
namespace osu.Game.Overlays.Rankings.Tables
|
||||
{
|
||||
@ -20,22 +21,16 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<string> GradeColumns => new List<string> { "SS", "S", "A" };
|
||||
protected virtual IEnumerable<LocalisableString> GradeColumns => new List<LocalisableString> { RankingsStrings.Statss, RankingsStrings.Stats, RankingsStrings.Stata };
|
||||
|
||||
protected override TableColumn[] CreateAdditionalHeaders() => new[]
|
||||
protected override RankingsTableColumn[] CreateAdditionalHeaders() => new[]
|
||||
{
|
||||
new TableColumn("Accuracy", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new TableColumn("Play Count", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new RankingsTableColumn(RankingsStrings.StatAccuracy, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new RankingsTableColumn(RankingsStrings.StatPlayCount, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
}.Concat(CreateUniqueHeaders())
|
||||
.Concat(GradeColumns.Select(grade => new TableColumn(grade, Anchor.Centre, new Dimension(GridSizeMode.AutoSize))))
|
||||
.Concat(GradeColumns.Select(grade => new GradeTableColumn(grade, Anchor.Centre, new Dimension(GridSizeMode.AutoSize))))
|
||||
.ToArray();
|
||||
|
||||
protected override Drawable CreateHeader(int index, TableColumn column)
|
||||
{
|
||||
var title = column?.Header ?? default;
|
||||
return new UserTableHeaderText(title, HighlightedColumn == title, GradeColumns.Contains(title.ToString()));
|
||||
}
|
||||
|
||||
protected sealed override Country GetCountry(UserStatistics item) => item.User.Country;
|
||||
|
||||
protected sealed override Drawable CreateFlagContent(UserStatistics item)
|
||||
@ -52,28 +47,38 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
|
||||
protected sealed override Drawable[] CreateAdditionalContent(UserStatistics item) => new[]
|
||||
{
|
||||
new ColoredRowText { Text = item.DisplayAccuracy, },
|
||||
new ColoredRowText { Text = $@"{item.PlayCount:N0}", },
|
||||
new ColouredRowText { Text = item.DisplayAccuracy, },
|
||||
new ColouredRowText { Text = item.PlayCount.ToLocalisableString(@"N0") },
|
||||
}.Concat(CreateUniqueContent(item)).Concat(new[]
|
||||
{
|
||||
new ColoredRowText { Text = $@"{item.GradesCount[ScoreRank.XH] + item.GradesCount[ScoreRank.X]:N0}", },
|
||||
new ColoredRowText { Text = $@"{item.GradesCount[ScoreRank.SH] + item.GradesCount[ScoreRank.S]:N0}", },
|
||||
new ColoredRowText { Text = $@"{item.GradesCount[ScoreRank.A]:N0}", }
|
||||
new ColouredRowText { Text = (item.GradesCount[ScoreRank.XH] + item.GradesCount[ScoreRank.X]).ToLocalisableString(@"N0"), },
|
||||
new ColouredRowText { Text = (item.GradesCount[ScoreRank.SH] + item.GradesCount[ScoreRank.S]).ToLocalisableString(@"N0"), },
|
||||
new ColouredRowText { Text = item.GradesCount[ScoreRank.A].ToLocalisableString(@"N0"), }
|
||||
}).ToArray();
|
||||
|
||||
protected abstract TableColumn[] CreateUniqueHeaders();
|
||||
protected abstract RankingsTableColumn[] CreateUniqueHeaders();
|
||||
|
||||
protected abstract Drawable[] CreateUniqueContent(UserStatistics item);
|
||||
|
||||
private class UserTableHeaderText : HeaderText
|
||||
private class GradeTableColumn : RankingsTableColumn
|
||||
{
|
||||
public UserTableHeaderText(LocalisableString text, bool isHighlighted, bool isGrade)
|
||||
public GradeTableColumn(LocalisableString? header = null, Anchor anchor = Anchor.TopLeft, Dimension dimension = null, bool highlighted = false)
|
||||
: base(header, anchor, dimension, highlighted)
|
||||
{
|
||||
}
|
||||
|
||||
public override HeaderText CreateHeaderText() => new GradeHeaderText(Header, Highlighted);
|
||||
}
|
||||
|
||||
private class GradeHeaderText : HeaderText
|
||||
{
|
||||
public GradeHeaderText(LocalisableString text, bool isHighlighted)
|
||||
: base(text, isHighlighted)
|
||||
{
|
||||
Margin = new MarginPadding
|
||||
{
|
||||
// Grade columns have extra horizontal padding for readibility
|
||||
Horizontal = isGrade ? 20 : 10,
|
||||
Horizontal = 20,
|
||||
Vertical = 5
|
||||
};
|
||||
}
|
||||
|
@ -138,7 +138,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new HoverClickSounds()
|
||||
};
|
||||
|
||||
foreach (var b in bindings)
|
||||
@ -458,6 +459,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
Origin = Anchor.Centre,
|
||||
Text = keyBinding.KeyCombination.ReadableString(),
|
||||
},
|
||||
new HoverSounds()
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,6 +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 System;
|
||||
using System.Diagnostics;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
@ -31,6 +32,9 @@ namespace osu.Game.Rulesets.Judgements
|
||||
|
||||
private readonly Container aboveHitObjectsContent;
|
||||
|
||||
private readonly Lazy<Drawable> proxiedAboveHitObjectsContent;
|
||||
public Drawable ProxiedAboveHitObjectsContent => proxiedAboveHitObjectsContent.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a drawable which visualises a <see cref="Judgements.Judgement"/>.
|
||||
/// </summary>
|
||||
@ -52,6 +56,8 @@ namespace osu.Game.Rulesets.Judgements
|
||||
Depth = float.MinValue,
|
||||
RelativeSizeAxes = Axes.Both
|
||||
});
|
||||
|
||||
proxiedAboveHitObjectsContent = new Lazy<Drawable>(() => aboveHitObjectsContent.CreateProxy());
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -60,8 +66,6 @@ namespace osu.Game.Rulesets.Judgements
|
||||
prepareDrawables();
|
||||
}
|
||||
|
||||
public Drawable GetProxyAboveHitObjectsContent() => aboveHitObjectsContent.CreateProxy();
|
||||
|
||||
/// <summary>
|
||||
/// Apply top-level animations to the current judgement when successfully hit.
|
||||
/// If displaying components which require lifetime extensions, manually adjusting <see cref="Drawable.LifetimeEnd"/> is required.
|
||||
|
@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public interface IApplicableToHealthProcessor : IApplicableMod
|
||||
{
|
||||
/// <summary>
|
||||
/// Provide a <see cref="HealthProcessor"/> to a mod. Called once on initialisation of a play instance.
|
||||
/// Provides a loaded <see cref="HealthProcessor"/> to a mod. Called once on initialisation of a play instance.
|
||||
/// </summary>
|
||||
void ApplyToHealthProcessor(HealthProcessor healthProcessor);
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public interface IApplicableToScoreProcessor : IApplicableMod
|
||||
{
|
||||
/// <summary>
|
||||
/// Provide a <see cref="ScoreProcessor"/> to a mod. Called once on initialisation of a play instance.
|
||||
/// Provides a loaded <see cref="ScoreProcessor"/> to a mod. Called once on initialisation of a play instance.
|
||||
/// </summary>
|
||||
void ApplyToScoreProcessor(ScoreProcessor scoreProcessor);
|
||||
|
||||
|
91
osu.Game/Rulesets/Mods/Metronome.cs
Normal file
91
osu.Game/Rulesets/Mods/Metronome.cs
Normal file
@ -0,0 +1,91 @@
|
||||
// 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.Audio;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
public class Metronome : BeatSyncedContainer, IAdjustableAudioComponent
|
||||
{
|
||||
private readonly double firstHitTime;
|
||||
|
||||
private readonly PausableSkinnableSound sample;
|
||||
|
||||
/// <param name="firstHitTime">Start time of the first hit object, used for providing a count down.</param>
|
||||
public Metronome(double firstHitTime)
|
||||
{
|
||||
this.firstHitTime = firstHitTime;
|
||||
AllowMistimedEventFiring = false;
|
||||
Divisor = 1;
|
||||
|
||||
InternalChild = sample = new PausableSkinnableSound(new SampleInfo("Gameplay/catch-banana"));
|
||||
}
|
||||
|
||||
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
|
||||
{
|
||||
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
|
||||
|
||||
if (!IsBeatSyncedWithTrack) return;
|
||||
|
||||
int timeSignature = (int)timingPoint.TimeSignature;
|
||||
|
||||
// play metronome from one measure before the first object.
|
||||
if (BeatSyncClock.CurrentTime < firstHitTime - timingPoint.BeatLength * timeSignature)
|
||||
return;
|
||||
|
||||
sample.Frequency.Value = beatIndex % timeSignature == 0 ? 1 : 0.5f;
|
||||
sample.Play();
|
||||
}
|
||||
|
||||
#region IAdjustableAudioComponent
|
||||
|
||||
public IBindable<double> AggregateVolume => sample.AggregateVolume;
|
||||
|
||||
public IBindable<double> AggregateBalance => sample.AggregateBalance;
|
||||
|
||||
public IBindable<double> AggregateFrequency => sample.AggregateFrequency;
|
||||
|
||||
public IBindable<double> AggregateTempo => sample.AggregateTempo;
|
||||
|
||||
public BindableNumber<double> Volume => sample.Volume;
|
||||
|
||||
public BindableNumber<double> Balance => sample.Balance;
|
||||
|
||||
public BindableNumber<double> Frequency => sample.Frequency;
|
||||
|
||||
public BindableNumber<double> Tempo => sample.Tempo;
|
||||
|
||||
public void BindAdjustments(IAggregateAudioAdjustment component)
|
||||
{
|
||||
sample.BindAdjustments(component);
|
||||
}
|
||||
|
||||
public void UnbindAdjustments(IAggregateAudioAdjustment component)
|
||||
{
|
||||
sample.UnbindAdjustments(component);
|
||||
}
|
||||
|
||||
public void AddAdjustment(AdjustableProperty type, IBindable<double> adjustBindable)
|
||||
{
|
||||
sample.AddAdjustment(type, adjustBindable);
|
||||
}
|
||||
|
||||
public void RemoveAdjustment(AdjustableProperty type, IBindable<double> adjustBindable)
|
||||
{
|
||||
sample.RemoveAdjustment(type, adjustBindable);
|
||||
}
|
||||
|
||||
public void RemoveAllAdjustments(AdjustableProperty type)
|
||||
{
|
||||
sample.RemoveAllAdjustments(type);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
104
osu.Game/Rulesets/Mods/ModMuted.cs
Normal file
104
osu.Game/Rulesets/Mods/ModMuted.cs
Normal file
@ -0,0 +1,104 @@
|
||||
// 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.Linq;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
public abstract class ModMuted : Mod
|
||||
{
|
||||
public override string Name => "Muted";
|
||||
public override string Acronym => "MU";
|
||||
public override IconUsage? Icon => FontAwesome.Solid.VolumeMute;
|
||||
public override string Description => "Can you still feel the rhythm without music?";
|
||||
public override ModType Type => ModType.Fun;
|
||||
public override double ScoreMultiplier => 1;
|
||||
}
|
||||
|
||||
public abstract class ModMuted<TObject> : ModMuted, IApplicableToDrawableRuleset<TObject>, IApplicableToTrack, IApplicableToScoreProcessor
|
||||
where TObject : HitObject
|
||||
{
|
||||
private readonly BindableNumber<double> mainVolumeAdjust = new BindableDouble(0.5);
|
||||
private readonly BindableNumber<double> metronomeVolumeAdjust = new BindableDouble(0.5);
|
||||
|
||||
private BindableNumber<int> currentCombo;
|
||||
|
||||
[SettingSource("Enable metronome", "Add a metronome beat to help you keep track of the rhythm.")]
|
||||
public BindableBool EnableMetronome { get; } = new BindableBool
|
||||
{
|
||||
Default = true,
|
||||
Value = true
|
||||
};
|
||||
|
||||
[SettingSource("Final volume at combo", "The combo count at which point the track reaches its final volume.")]
|
||||
public BindableInt MuteComboCount { get; } = new BindableInt
|
||||
{
|
||||
Default = 100,
|
||||
Value = 100,
|
||||
MinValue = 0,
|
||||
MaxValue = 500,
|
||||
};
|
||||
|
||||
[SettingSource("Start muted", "Increase volume as combo builds.")]
|
||||
public BindableBool InverseMuting { get; } = new BindableBool
|
||||
{
|
||||
Default = false,
|
||||
Value = false
|
||||
};
|
||||
|
||||
[SettingSource("Mute hit sounds", "Hit sounds are also muted alongside the track.")]
|
||||
public BindableBool AffectsHitSounds { get; } = new BindableBool
|
||||
{
|
||||
Default = true,
|
||||
Value = true
|
||||
};
|
||||
|
||||
public void ApplyToTrack(ITrack track)
|
||||
{
|
||||
track.AddAdjustment(AdjustableProperty.Volume, mainVolumeAdjust);
|
||||
}
|
||||
|
||||
public void ApplyToDrawableRuleset(DrawableRuleset<TObject> drawableRuleset)
|
||||
{
|
||||
if (EnableMetronome.Value)
|
||||
{
|
||||
Metronome metronome;
|
||||
|
||||
drawableRuleset.Overlays.Add(metronome = new Metronome(drawableRuleset.Beatmap.HitObjects.First().StartTime));
|
||||
|
||||
metronome.AddAdjustment(AdjustableProperty.Volume, metronomeVolumeAdjust);
|
||||
}
|
||||
|
||||
if (AffectsHitSounds.Value)
|
||||
drawableRuleset.Audio.AddAdjustment(AdjustableProperty.Volume, mainVolumeAdjust);
|
||||
}
|
||||
|
||||
public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
|
||||
{
|
||||
currentCombo = scoreProcessor.Combo.GetBoundCopy();
|
||||
currentCombo.BindValueChanged(combo =>
|
||||
{
|
||||
double dimFactor = Math.Min(1, (double)combo.NewValue / MuteComboCount.Value);
|
||||
|
||||
if (InverseMuting.Value)
|
||||
dimFactor = 1 - dimFactor;
|
||||
|
||||
scoreProcessor.TransformBindableTo(metronomeVolumeAdjust, dimFactor, 500, Easing.OutQuint);
|
||||
scoreProcessor.TransformBindableTo(mainVolumeAdjust, 1 - dimFactor, 500, Easing.OutQuint);
|
||||
}, true);
|
||||
}
|
||||
|
||||
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
|
||||
}
|
||||
}
|
@ -1,29 +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.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.Cursor;
|
||||
using osu.Game.Input.Handlers;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Replays;
|
||||
using osu.Game.Rulesets.Configuration;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Play;
|
||||
@ -98,6 +99,14 @@ namespace osu.Game.Rulesets.UI
|
||||
|
||||
private DrawableRulesetDependencies dependencies;
|
||||
|
||||
/// <summary>
|
||||
/// Audio adjustments which are applied to the playfield.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Does not affect <see cref="Overlays"/>.
|
||||
/// </remarks>
|
||||
public IAdjustableAudioComponent Audio { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a ruleset visualisation for the provided ruleset and beatmap.
|
||||
/// </summary>
|
||||
@ -155,23 +164,28 @@ namespace osu.Game.Rulesets.UI
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(CancellationToken? cancellationToken)
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
AudioContainer audioContainer;
|
||||
|
||||
InternalChild = frameStabilityContainer = new FrameStabilityContainer(GameplayStartTime)
|
||||
{
|
||||
frameStabilityContainer = new FrameStabilityContainer(GameplayStartTime)
|
||||
FrameStablePlayback = FrameStablePlayback,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
FrameStablePlayback = FrameStablePlayback,
|
||||
Children = new Drawable[]
|
||||
FrameStableComponents,
|
||||
audioContainer = new AudioContainer
|
||||
{
|
||||
FrameStableComponents,
|
||||
KeyBindingInputManager
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = KeyBindingInputManager
|
||||
.WithChild(CreatePlayfieldAdjustmentContainer()
|
||||
.WithChild(Playfield)
|
||||
),
|
||||
Overlays,
|
||||
}
|
||||
},
|
||||
},
|
||||
Overlays,
|
||||
}
|
||||
};
|
||||
|
||||
Audio = audioContainer;
|
||||
|
||||
if ((ResumeOverlay = CreateResumeOverlay()) != null)
|
||||
{
|
||||
AddInternal(CreateInputManager()
|
||||
|
@ -55,7 +55,7 @@ namespace osu.Game.Screens.Edit
|
||||
|
||||
public override bool DisallowExternalBeatmapRulesetChanges => true;
|
||||
|
||||
public override bool AllowRateAdjustments => false;
|
||||
public override bool AllowTrackAdjustments => false;
|
||||
|
||||
protected bool HasUnsavedChanges => lastSavedHash != changeHandler.CurrentStateHash;
|
||||
|
||||
|
@ -11,7 +11,6 @@ using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -67,7 +66,6 @@ namespace osu.Game.Screens.Edit
|
||||
private EditorClock clock { get; set; }
|
||||
|
||||
public RowBackground(object item)
|
||||
: base(HoverSampleSet.Soft)
|
||||
{
|
||||
Item = item;
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Localisation;
|
||||
@ -32,7 +33,7 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
|
||||
var colours = Beatmap.BeatmapSkin?.GetConfig<GlobalSkinColours, IReadOnlyList<Color4>>(GlobalSkinColours.ComboColours)?.Value;
|
||||
if (colours != null)
|
||||
comboColours.Colours.AddRange(colours);
|
||||
comboColours.Colours.AddRange(colours.Select(c => (Colour4)c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -59,9 +59,9 @@ namespace osu.Game.Screens
|
||||
Bindable<RulesetInfo> Ruleset { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether mod rate adjustments are allowed to be applied.
|
||||
/// Whether mod track adjustments are allowed to be applied.
|
||||
/// </summary>
|
||||
bool AllowRateAdjustments { get; }
|
||||
bool AllowTrackAdjustments { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the back button has been pressed to close any overlays before exiting this <see cref="IOsuScreen"/>.
|
||||
|
@ -36,7 +36,7 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
public override bool AllowExternalScreenChange => true;
|
||||
|
||||
public override bool AllowRateAdjustments => false;
|
||||
public override bool AllowTrackAdjustments => false;
|
||||
|
||||
private Screen songSelect;
|
||||
|
||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
|
||||
public override bool DisallowExternalBeatmapRulesetChanges => true;
|
||||
|
||||
// We are managing our own adjustments. For now, this happens inside the Player instances themselves.
|
||||
public override bool AllowRateAdjustments => false;
|
||||
public override bool AllowTrackAdjustments => false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether all spectating players have finished loading.
|
||||
|
@ -81,7 +81,7 @@ namespace osu.Game.Screens
|
||||
|
||||
public virtual float BackgroundParallaxAmount => 1;
|
||||
|
||||
public virtual bool AllowRateAdjustments => true;
|
||||
public virtual bool AllowTrackAdjustments => true;
|
||||
|
||||
public Bindable<WorkingBeatmap> Beatmap { get; private set; }
|
||||
|
||||
|
@ -56,7 +56,7 @@ namespace osu.Game.Screens.Play
|
||||
protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.UserTriggered;
|
||||
|
||||
// We are managing our own adjustments (see OnEntering/OnExiting).
|
||||
public override bool AllowRateAdjustments => false;
|
||||
public override bool AllowTrackAdjustments => false;
|
||||
|
||||
private readonly IBindable<bool> gameActive = new Bindable<bool>(true);
|
||||
|
||||
@ -297,11 +297,19 @@ namespace osu.Game.Screens.Play
|
||||
ScoreProcessor.HasCompleted.BindValueChanged(scoreCompletionChanged);
|
||||
HealthProcessor.Failed += onFail;
|
||||
|
||||
foreach (var mod in Mods.Value.OfType<IApplicableToScoreProcessor>())
|
||||
mod.ApplyToScoreProcessor(ScoreProcessor);
|
||||
// Provide judgement processors to mods after they're loaded so that they're on the gameplay clock,
|
||||
// this is required for mods that apply transforms to these processors.
|
||||
ScoreProcessor.OnLoadComplete += _ =>
|
||||
{
|
||||
foreach (var mod in Mods.Value.OfType<IApplicableToScoreProcessor>())
|
||||
mod.ApplyToScoreProcessor(ScoreProcessor);
|
||||
};
|
||||
|
||||
foreach (var mod in Mods.Value.OfType<IApplicableToHealthProcessor>())
|
||||
mod.ApplyToHealthProcessor(HealthProcessor);
|
||||
HealthProcessor.OnLoadComplete += _ =>
|
||||
{
|
||||
foreach (var mod in Mods.Value.OfType<IApplicableToHealthProcessor>())
|
||||
mod.ApplyToHealthProcessor(HealthProcessor);
|
||||
};
|
||||
|
||||
IsBreakTime.BindTo(breakTracker.IsBreakTime);
|
||||
IsBreakTime.BindValueChanged(onBreakTimeChanged, true);
|
||||
|
@ -178,7 +178,7 @@ namespace osu.Game.Screens.Play
|
||||
float barHeight = bottom_bar_height + handle_size.Y;
|
||||
|
||||
bar.ResizeHeightTo(ShowGraph.Value ? barHeight + graph_height : barHeight, transition_duration, Easing.In);
|
||||
graph.MoveToY(ShowGraph.Value ? 0 : bottom_bar_height + graph_height, transition_duration, Easing.In);
|
||||
graph.FadeTo(ShowGraph.Value ? 1 : 0, transition_duration, Easing.In);
|
||||
|
||||
updateInfoMargin();
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.UI;
|
||||
@ -333,7 +334,7 @@ namespace osu.Game.Screens.Select
|
||||
{
|
||||
Name = "Length",
|
||||
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Length),
|
||||
Content = TimeSpan.FromMilliseconds(beatmap.BeatmapInfo.Length).ToString(@"m\:ss"),
|
||||
Content = beatmap.BeatmapInfo.Length.ToFormattedDuration().ToString(),
|
||||
}),
|
||||
bpmLabelContainer = new Container
|
||||
{
|
||||
|
@ -14,6 +14,7 @@ using osu.Game.Graphics.Sprites;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Screens.Select.Options
|
||||
{
|
||||
@ -76,6 +77,7 @@ namespace osu.Game.Screens.Select.Options
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => box.ReceivePositionalInputAt(screenSpacePos);
|
||||
|
||||
public BeatmapOptionsButton()
|
||||
: base(HoverSampleSet.Submit)
|
||||
{
|
||||
Width = width;
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Screens
|
||||
|
||||
public override bool CursorVisible => false;
|
||||
|
||||
public override bool AllowRateAdjustments => false;
|
||||
public override bool AllowTrackAdjustments => false;
|
||||
|
||||
protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Users.Drawables
|
||||
{
|
||||
@ -71,6 +72,11 @@ namespace osu.Game.Users.Drawables
|
||||
{
|
||||
private LocalisableString tooltip = default_tooltip_text;
|
||||
|
||||
public ClickableArea()
|
||||
: base(HoverSampleSet.Submit)
|
||||
{
|
||||
}
|
||||
|
||||
public override LocalisableString TooltipText
|
||||
{
|
||||
get => Enabled.Value ? tooltip : default;
|
||||
|
@ -5,6 +5,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays;
|
||||
|
||||
namespace osu.Game.Users.Drawables
|
||||
@ -32,9 +33,17 @@ namespace osu.Game.Users.Drawables
|
||||
if (country == null && !ShowPlaceholderOnNull)
|
||||
return null;
|
||||
|
||||
return new DrawableFlag(country)
|
||||
return new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new DrawableFlag(country)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
new HoverClickSounds(HoverSampleSet.Submit)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ namespace osu.Game.Users
|
||||
protected Drawable Background { get; private set; }
|
||||
|
||||
protected UserPanel(User user)
|
||||
: base(HoverSampleSet.Submit)
|
||||
{
|
||||
if (user == null)
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
|
@ -22,7 +22,7 @@
|
||||
<PackageReference Include="DiffPlex" Version="1.7.0" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.34" />
|
||||
<PackageReference Include="Humanizer" Version="2.11.10" />
|
||||
<PackageReference Include="MessagePack" Version="2.2.113" />
|
||||
<PackageReference Include="MessagePack" Version="2.3.75" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="5.0.8" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="5.0.8" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="5.0.8" />
|
||||
@ -37,8 +37,8 @@
|
||||
</PackageReference>
|
||||
<PackageReference Include="Realm" Version="10.3.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2021.728.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.722.0" />
|
||||
<PackageReference Include="Sentry" Version="3.8.2" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.730.0" />
|
||||
<PackageReference Include="Sentry" Version="3.8.3" />
|
||||
<PackageReference Include="SharpCompress" Version="0.28.3" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||
|
@ -71,7 +71,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.728.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.722.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.730.0" />
|
||||
</ItemGroup>
|
||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
||||
<PropertyGroup>
|
||||
|
@ -117,7 +117,7 @@
|
||||
</ImageAsset>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.6.1" />
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.7.0" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
|
||||
</Project>
|
||||
|
Loading…
Reference in New Issue
Block a user