mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 13:37:25 +08:00
Merge branch 'master' into better-beatmap-conversion
This commit is contained in:
commit
504a55e803
@ -54,6 +54,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1215.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.1219.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.1225.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscordRPC;
|
||||
using DiscordRPC.Message;
|
||||
using osu.Framework.Allocation;
|
||||
@ -43,6 +45,10 @@ namespace osu.Desktop
|
||||
};
|
||||
|
||||
client.OnReady += onReady;
|
||||
|
||||
// safety measure for now, until we performance test / improve backoff for failed connections.
|
||||
client.OnConnectionFailed += (_, __) => client.Deinitialize();
|
||||
|
||||
client.OnError += (_, e) => Logger.Log($"An error occurred with Discord RPC Client: {e.Code} {e.Message}", LoggingTarget.Network);
|
||||
|
||||
(user = provider.LocalUser.GetBoundCopy()).BindValueChanged(u =>
|
||||
@ -77,8 +83,8 @@ namespace osu.Desktop
|
||||
|
||||
if (status.Value is UserStatusOnline && activity.Value != null)
|
||||
{
|
||||
presence.State = activity.Value.Status;
|
||||
presence.Details = getDetails(activity.Value);
|
||||
presence.State = truncate(activity.Value.Status);
|
||||
presence.Details = truncate(getDetails(activity.Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -96,6 +102,27 @@ namespace osu.Desktop
|
||||
client.SetPresence(presence);
|
||||
}
|
||||
|
||||
private static readonly int ellipsis_length = Encoding.UTF8.GetByteCount(new[] { '…' });
|
||||
|
||||
private string truncate(string str)
|
||||
{
|
||||
if (Encoding.UTF8.GetByteCount(str) <= 128)
|
||||
return str;
|
||||
|
||||
ReadOnlyMemory<char> strMem = str.AsMemory();
|
||||
|
||||
do
|
||||
{
|
||||
strMem = strMem[..^1];
|
||||
} while (Encoding.UTF8.GetByteCount(strMem.Span) + ellipsis_length > 128);
|
||||
|
||||
return string.Create(strMem.Length + 1, strMem, (span, mem) =>
|
||||
{
|
||||
mem.Span.CopyTo(span);
|
||||
span[^1] = '…';
|
||||
});
|
||||
}
|
||||
|
||||
private string getDetails(UserActivity activity)
|
||||
{
|
||||
switch (activity)
|
||||
|
@ -106,6 +106,12 @@ namespace osu.Game.Rulesets.Catch
|
||||
new CatchModFlashlight(),
|
||||
};
|
||||
|
||||
case ModType.Conversion:
|
||||
return new Mod[]
|
||||
{
|
||||
new CatchModDifficultyAdjust(),
|
||||
};
|
||||
|
||||
case ModType.Automation:
|
||||
return new Mod[]
|
||||
{
|
||||
|
49
osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs
Normal file
49
osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs
Normal file
@ -0,0 +1,49 @@
|
||||
// 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.Bindables;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModDifficultyAdjust : ModDifficultyAdjust
|
||||
{
|
||||
[SettingSource("Fruit Size", "Override a beatmap's set CS.")]
|
||||
public BindableNumber<float> CircleSize { get; } = new BindableFloat
|
||||
{
|
||||
Precision = 0.1f,
|
||||
MinValue = 1,
|
||||
MaxValue = 10,
|
||||
Default = 5,
|
||||
Value = 5,
|
||||
};
|
||||
|
||||
[SettingSource("Approach Rate", "Override a beatmap's set AR.")]
|
||||
public BindableNumber<float> ApproachRate { get; } = new BindableFloat
|
||||
{
|
||||
Precision = 0.1f,
|
||||
MinValue = 1,
|
||||
MaxValue = 10,
|
||||
Default = 5,
|
||||
Value = 5,
|
||||
};
|
||||
|
||||
protected override void TransferSettings(BeatmapDifficulty difficulty)
|
||||
{
|
||||
base.TransferSettings(difficulty);
|
||||
|
||||
CircleSize.Value = CircleSize.Default = difficulty.CircleSize;
|
||||
ApproachRate.Value = ApproachRate.Default = difficulty.ApproachRate;
|
||||
}
|
||||
|
||||
protected override void ApplySettings(BeatmapDifficulty difficulty)
|
||||
{
|
||||
base.ApplySettings(difficulty);
|
||||
|
||||
difficulty.CircleSize = CircleSize.Value;
|
||||
difficulty.ApproachRate = ApproachRate.Value;
|
||||
}
|
||||
}
|
||||
}
|
@ -151,6 +151,7 @@ namespace osu.Game.Rulesets.Mania
|
||||
new ManiaModRandom(),
|
||||
new ManiaModDualStages(),
|
||||
new ManiaModMirror(),
|
||||
new ManiaModDifficultyAdjust(),
|
||||
};
|
||||
|
||||
case ModType.Automation:
|
||||
|
11
osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs
Normal file
11
osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs
Normal file
@ -0,0 +1,11 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public class ManiaModDifficultyAdjust : ModDifficultyAdjust
|
||||
{
|
||||
}
|
||||
}
|
155
osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs
Normal file
155
osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs
Normal file
@ -0,0 +1,155 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
public class TestSceneLegacyBeatmapSkin : OsuTestScene
|
||||
{
|
||||
[Resolved]
|
||||
private AudioManager audio { get; set; }
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestBeatmapComboColours(bool customSkinColoursPresent)
|
||||
{
|
||||
ExposedPlayer player = null;
|
||||
|
||||
AddStep("load coloured beatmap", () => player = loadBeatmap(customSkinColoursPresent, true));
|
||||
AddUntilStep("wait for player", () => player.IsLoaded);
|
||||
|
||||
AddAssert("is beatmap skin colours", () => player.UsableComboColours.SequenceEqual(TestBeatmapSkin.Colours));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBeatmapNoComboColours()
|
||||
{
|
||||
ExposedPlayer player = null;
|
||||
|
||||
AddStep("load no-colour beatmap", () => player = loadBeatmap(false, false));
|
||||
AddUntilStep("wait for player", () => player.IsLoaded);
|
||||
|
||||
AddAssert("is default user skin colours", () => player.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBeatmapNoComboColoursSkinOverride()
|
||||
{
|
||||
ExposedPlayer player = null;
|
||||
|
||||
AddStep("load custom-skin colour", () => player = loadBeatmap(true, false));
|
||||
AddUntilStep("wait for player", () => player.IsLoaded);
|
||||
|
||||
AddAssert("is custom user skin colours", () => player.UsableComboColours.SequenceEqual(TestSkin.Colours));
|
||||
}
|
||||
|
||||
private ExposedPlayer loadBeatmap(bool userHasCustomColours, bool beatmapHasColours)
|
||||
{
|
||||
ExposedPlayer player;
|
||||
|
||||
Beatmap.Value = new CustomSkinWorkingBeatmap(audio, beatmapHasColours);
|
||||
Child = new OsuScreenStack(player = new ExposedPlayer(userHasCustomColours)) { RelativeSizeAxes = Axes.Both };
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
private class ExposedPlayer : Player
|
||||
{
|
||||
private readonly bool userHasCustomColours;
|
||||
|
||||
public ExposedPlayer(bool userHasCustomColours)
|
||||
: base(false, false)
|
||||
{
|
||||
this.userHasCustomColours = userHasCustomColours;
|
||||
}
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
dependencies.CacheAs<ISkinSource>(new TestSkin(userHasCustomColours));
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
public IReadOnlyList<Color4> UsableComboColours =>
|
||||
GameplayClockContainer.ChildrenOfType<BeatmapSkinProvidingContainer>()
|
||||
.First()
|
||||
.GetConfig<GlobalSkinConfiguration, IReadOnlyList<Color4>>(GlobalSkinConfiguration.ComboColours)?.Value;
|
||||
}
|
||||
|
||||
private class CustomSkinWorkingBeatmap : ClockBackedTestWorkingBeatmap
|
||||
{
|
||||
private readonly bool hasColours;
|
||||
|
||||
public CustomSkinWorkingBeatmap(AudioManager audio, bool hasColours)
|
||||
: base(new Beatmap
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
BeatmapSet = new BeatmapSetInfo(),
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
},
|
||||
HitObjects = { new HitCircle { Position = new Vector2(256, 192) } }
|
||||
}, null, null, audio)
|
||||
{
|
||||
this.hasColours = hasColours;
|
||||
}
|
||||
|
||||
protected override ISkin GetSkin() => new TestBeatmapSkin(BeatmapInfo, hasColours);
|
||||
}
|
||||
|
||||
private class TestBeatmapSkin : LegacyBeatmapSkin
|
||||
{
|
||||
public static Color4[] Colours { get; } =
|
||||
{
|
||||
new Color4(50, 100, 150, 255),
|
||||
new Color4(40, 80, 120, 255),
|
||||
};
|
||||
|
||||
public TestBeatmapSkin(BeatmapInfo beatmap, bool hasColours)
|
||||
: base(beatmap, new ResourceStore<byte[]>(), null)
|
||||
{
|
||||
if (hasColours)
|
||||
Configuration.AddComboColours(Colours);
|
||||
}
|
||||
}
|
||||
|
||||
private class TestSkin : LegacySkin, ISkinSource
|
||||
{
|
||||
public static Color4[] Colours { get; } =
|
||||
{
|
||||
new Color4(150, 100, 50, 255),
|
||||
new Color4(20, 20, 20, 255),
|
||||
};
|
||||
|
||||
public TestSkin(bool hasCustomColours)
|
||||
: base(new SkinInfo(), null, null, string.Empty)
|
||||
{
|
||||
if (hasCustomColours)
|
||||
Configuration.AddComboColours(Colours);
|
||||
}
|
||||
|
||||
public event Action SourceChanged
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
49
osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs
Normal file
49
osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs
Normal file
@ -0,0 +1,49 @@
|
||||
// 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.Bindables;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
public class OsuModDifficultyAdjust : ModDifficultyAdjust
|
||||
{
|
||||
[SettingSource("Circle Size", "Override a beatmap's set CS.")]
|
||||
public BindableNumber<float> CircleSize { get; } = new BindableFloat
|
||||
{
|
||||
Precision = 0.1f,
|
||||
MinValue = 1,
|
||||
MaxValue = 10,
|
||||
Default = 5,
|
||||
Value = 5,
|
||||
};
|
||||
|
||||
[SettingSource("Approach Rate", "Override a beatmap's set AR.")]
|
||||
public BindableNumber<float> ApproachRate { get; } = new BindableFloat
|
||||
{
|
||||
Precision = 0.1f,
|
||||
MinValue = 1,
|
||||
MaxValue = 10,
|
||||
Default = 5,
|
||||
Value = 5,
|
||||
};
|
||||
|
||||
protected override void TransferSettings(BeatmapDifficulty difficulty)
|
||||
{
|
||||
base.TransferSettings(difficulty);
|
||||
|
||||
CircleSize.Value = CircleSize.Default = difficulty.CircleSize;
|
||||
ApproachRate.Value = ApproachRate.Default = difficulty.ApproachRate;
|
||||
}
|
||||
|
||||
protected override void ApplySettings(BeatmapDifficulty difficulty)
|
||||
{
|
||||
base.ApplySettings(difficulty);
|
||||
|
||||
difficulty.CircleSize = CircleSize.Value;
|
||||
difficulty.ApproachRate = ApproachRate.Value;
|
||||
}
|
||||
}
|
||||
}
|
@ -130,6 +130,7 @@ namespace osu.Game.Rulesets.Osu
|
||||
return new Mod[]
|
||||
{
|
||||
new OsuModTarget(),
|
||||
new OsuModDifficultyAdjust(),
|
||||
};
|
||||
|
||||
case ModType.Automation:
|
||||
|
11
osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs
Normal file
11
osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs
Normal file
@ -0,0 +1,11 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Mods
|
||||
{
|
||||
public class TaikoModDifficultyAdjust : ModDifficultyAdjust
|
||||
{
|
||||
}
|
||||
}
|
@ -105,6 +105,12 @@ namespace osu.Game.Rulesets.Taiko
|
||||
new TaikoModFlashlight(),
|
||||
};
|
||||
|
||||
case ModType.Conversion:
|
||||
return new Mod[]
|
||||
{
|
||||
new TaikoModDifficultyAdjust(),
|
||||
};
|
||||
|
||||
case ModType.Automation:
|
||||
return new Mod[]
|
||||
{
|
||||
|
@ -130,7 +130,7 @@ namespace osu.Game.Tests.Gameplay
|
||||
switch (global)
|
||||
{
|
||||
case GlobalSkinConfiguration.ComboColours:
|
||||
return SkinUtils.As<TValue>(new Bindable<List<Color4>>(ComboColours));
|
||||
return SkinUtils.As<TValue>(new Bindable<IReadOnlyList<Color4>>(ComboColours));
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -13,31 +13,22 @@ namespace osu.Game.Tests.Skins
|
||||
[TestFixture]
|
||||
public class LegacySkinDecoderTest
|
||||
{
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestDecodeSkinColours(bool hasColours)
|
||||
[Test]
|
||||
public void TestDecodeSkinColours()
|
||||
{
|
||||
var decoder = new LegacySkinDecoder();
|
||||
|
||||
using (var resStream = TestResources.OpenResource(hasColours ? "skin.ini" : "skin-empty.ini"))
|
||||
using (var resStream = TestResources.OpenResource("skin.ini"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var comboColors = decoder.Decode(stream).ComboColours;
|
||||
|
||||
List<Color4> expectedColors;
|
||||
|
||||
if (hasColours)
|
||||
{
|
||||
expectedColors = new List<Color4>
|
||||
var expectedColors = new List<Color4>
|
||||
{
|
||||
new Color4(142, 199, 255, 255),
|
||||
new Color4(255, 128, 128, 255),
|
||||
new Color4(128, 255, 255, 255),
|
||||
new Color4(100, 100, 100, 100),
|
||||
};
|
||||
}
|
||||
else
|
||||
expectedColors = new DefaultSkin().Configuration.ComboColours;
|
||||
|
||||
Assert.AreEqual(expectedColors.Count, comboColors.Count);
|
||||
for (int i = 0; i < expectedColors.Count; i++)
|
||||
@ -45,6 +36,37 @@ namespace osu.Game.Tests.Skins
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeEmptySkinColours()
|
||||
{
|
||||
var decoder = new LegacySkinDecoder();
|
||||
|
||||
using (var resStream = TestResources.OpenResource("skin-empty.ini"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var comboColors = decoder.Decode(stream).ComboColours;
|
||||
var expectedColors = SkinConfiguration.DefaultComboColours;
|
||||
|
||||
Assert.AreEqual(expectedColors.Count, comboColors.Count);
|
||||
for (int i = 0; i < expectedColors.Count; i++)
|
||||
Assert.AreEqual(expectedColors[i], comboColors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeEmptySkinColoursNoFallback()
|
||||
{
|
||||
var decoder = new LegacySkinDecoder();
|
||||
|
||||
using (var resStream = TestResources.OpenResource("skin-empty.ini"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var skinConfiguration = decoder.Decode(stream);
|
||||
skinConfiguration.AllowDefaultComboColoursFallback = false;
|
||||
Assert.IsNull(skinConfiguration.ComboColours);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeGeneral()
|
||||
{
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Sample;
|
||||
@ -21,8 +22,8 @@ namespace osu.Game.Tests.Skins
|
||||
[HeadlessTest]
|
||||
public class TestSceneSkinConfigurationLookup : OsuTestScene
|
||||
{
|
||||
private LegacySkin source1;
|
||||
private LegacySkin source2;
|
||||
private SkinSource source1;
|
||||
private SkinSource source2;
|
||||
private SkinRequester requester;
|
||||
|
||||
[SetUp]
|
||||
@ -94,7 +95,7 @@ namespace osu.Game.Tests.Skins
|
||||
[Test]
|
||||
public void TestGlobalLookup()
|
||||
{
|
||||
AddAssert("Check combo colours", () => requester.GetConfig<GlobalSkinConfiguration, List<Color4>>(GlobalSkinConfiguration.ComboColours)?.Value?.Count > 0);
|
||||
AddAssert("Check combo colours", () => requester.GetConfig<GlobalSkinConfiguration, IReadOnlyList<Color4>>(GlobalSkinConfiguration.ComboColours)?.Value?.Count > 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -116,6 +117,28 @@ namespace osu.Game.Tests.Skins
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEmptyComboColours()
|
||||
{
|
||||
AddAssert("Check retrieved combo colours is skin default colours", () =>
|
||||
requester.GetConfig<GlobalSkinConfiguration, IReadOnlyList<Color4>>(GlobalSkinConfiguration.ComboColours)?.Value?.SequenceEqual(SkinConfiguration.DefaultComboColours) ?? false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEmptyComboColoursNoFallback()
|
||||
{
|
||||
AddStep("Add custom combo colours to source1", () => source1.Configuration.AddComboColours(
|
||||
new Color4(100, 150, 200, 255),
|
||||
new Color4(55, 110, 166, 255),
|
||||
new Color4(75, 125, 175, 255)
|
||||
));
|
||||
|
||||
AddStep("Disallow default colours fallback in source2", () => source2.Configuration.AllowDefaultComboColoursFallback = false);
|
||||
|
||||
AddAssert("Check retrieved combo colours from source1", () =>
|
||||
requester.GetConfig<GlobalSkinConfiguration, IReadOnlyList<Color4>>(GlobalSkinConfiguration.ComboColours)?.Value?.SequenceEqual(source1.Configuration.ComboColours) ?? false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLegacyVersionLookup()
|
||||
{
|
||||
|
@ -1,237 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Screens.Play.HUD;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.SongSelect
|
||||
{
|
||||
[TestFixture]
|
||||
[System.ComponentModel.Description("PlaySongSelect leaderboard/details area")]
|
||||
public class TestSceneBeatmapDetailArea : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(BeatmapDetails) };
|
||||
|
||||
private ModDisplay modDisplay;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuGameBase game, RulesetStore rulesets)
|
||||
{
|
||||
BeatmapDetailArea detailsArea;
|
||||
Add(detailsArea = new BeatmapDetailArea
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(550f, 450f),
|
||||
});
|
||||
|
||||
Add(modDisplay = new ModDisplay
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Position = new Vector2(0, 25),
|
||||
});
|
||||
|
||||
modDisplay.Current.BindTo(SelectedMods);
|
||||
|
||||
AddStep("all metrics", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
BeatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
|
||||
},
|
||||
Version = "All Metrics",
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Source = "osu!lazer",
|
||||
Tags = "this beatmap has all the metrics",
|
||||
},
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 7,
|
||||
DrainRate = 1,
|
||||
OverallDifficulty = 5.7f,
|
||||
ApproachRate = 3.5f,
|
||||
},
|
||||
StarDifficulty = 5.3f,
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
},
|
||||
}
|
||||
}));
|
||||
|
||||
AddStep("all except source", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
BeatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
|
||||
},
|
||||
Version = "All Metrics",
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Tags = "this beatmap has all the metrics",
|
||||
},
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 7,
|
||||
DrainRate = 1,
|
||||
OverallDifficulty = 5.7f,
|
||||
ApproachRate = 3.5f,
|
||||
},
|
||||
StarDifficulty = 5.3f,
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
},
|
||||
}
|
||||
}));
|
||||
|
||||
AddStep("ratings", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
BeatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
|
||||
},
|
||||
Version = "Only Ratings",
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Source = "osu!lazer",
|
||||
Tags = "this beatmap has ratings metrics but not retries or fails",
|
||||
},
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 6,
|
||||
DrainRate = 9,
|
||||
OverallDifficulty = 6,
|
||||
ApproachRate = 6,
|
||||
},
|
||||
StarDifficulty = 4.8f
|
||||
}
|
||||
}));
|
||||
|
||||
AddStep("fails+retries", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
Version = "Only Retries and Fails",
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Source = "osu!lazer",
|
||||
Tags = "this beatmap has retries and fails but no ratings",
|
||||
},
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 3.7f,
|
||||
DrainRate = 6,
|
||||
OverallDifficulty = 6,
|
||||
ApproachRate = 7,
|
||||
},
|
||||
StarDifficulty = 2.91f,
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
},
|
||||
}
|
||||
}));
|
||||
|
||||
AddStep("null metrics", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
Version = "No Metrics",
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Source = "osu!lazer",
|
||||
Tags = "this beatmap has no metrics",
|
||||
},
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 5,
|
||||
DrainRate = 5,
|
||||
OverallDifficulty = 5.5f,
|
||||
ApproachRate = 6.5f,
|
||||
},
|
||||
StarDifficulty = 1.97f,
|
||||
}
|
||||
}));
|
||||
|
||||
AddStep("null beatmap", () => detailsArea.Beatmap = null);
|
||||
|
||||
Ruleset ruleset = rulesets.AvailableRulesets.First().CreateInstance();
|
||||
|
||||
AddStep("with EZ mod", () =>
|
||||
{
|
||||
detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
Version = "Has Easy Mod",
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Source = "osu!lazer",
|
||||
Tags = "this beatmap has the easy mod enabled",
|
||||
},
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 3,
|
||||
DrainRate = 3,
|
||||
OverallDifficulty = 3,
|
||||
ApproachRate = 3,
|
||||
},
|
||||
StarDifficulty = 1f,
|
||||
}
|
||||
});
|
||||
|
||||
SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModEasy) };
|
||||
});
|
||||
|
||||
AddStep("with HR mod", () =>
|
||||
{
|
||||
detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
Version = "Has Hard Rock Mod",
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Source = "osu!lazer",
|
||||
Tags = "this beatmap has the hard rock mod enabled",
|
||||
},
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 3,
|
||||
DrainRate = 3,
|
||||
OverallDifficulty = 3,
|
||||
ApproachRate = 3,
|
||||
},
|
||||
StarDifficulty = 1f,
|
||||
}
|
||||
});
|
||||
|
||||
SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModHardRock) };
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -3,8 +3,14 @@
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Screens.Select;
|
||||
|
||||
namespace osu.Game.Tests.Visual.SongSelect
|
||||
@ -174,5 +180,27 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
OnlineBeatmapID = 162,
|
||||
});
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; }
|
||||
|
||||
[Test]
|
||||
public void TestModAdjustments()
|
||||
{
|
||||
TestAllMetrics();
|
||||
|
||||
Ruleset ruleset = rulesets.AvailableRulesets.First().CreateInstance();
|
||||
|
||||
AddStep("with EZ mod", () => SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModEasy) });
|
||||
|
||||
AddAssert("first bar coloured blue", () => details.ChildrenOfType<Bar>().Skip(1).First().AccentColour == colours.BlueDark);
|
||||
|
||||
AddStep("with HR mod", () => SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModHardRock) });
|
||||
|
||||
AddAssert("first bar coloured red", () => details.ChildrenOfType<Bar>().Skip(1).First().AccentColour == colours.Red);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,14 @@ namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
public interface IHasComboColours
|
||||
{
|
||||
List<Color4> ComboColours { get; set; }
|
||||
/// <summary>
|
||||
/// Retrieves the list of combo colours for presentation only.
|
||||
/// </summary>
|
||||
IReadOnlyList<Color4> ComboColours { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds combo colours to the list.
|
||||
/// </summary>
|
||||
void AddComboColours(params Color4[] colours);
|
||||
}
|
||||
}
|
||||
|
@ -77,8 +77,6 @@ namespace osu.Game.Beatmaps.Formats
|
||||
return line;
|
||||
}
|
||||
|
||||
private bool hasComboColours;
|
||||
|
||||
private void handleColours(T output, string line)
|
||||
{
|
||||
var pair = SplitKeyVal(line);
|
||||
@ -105,14 +103,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
if (!(output is IHasComboColours tHasComboColours)) return;
|
||||
|
||||
if (!hasComboColours)
|
||||
{
|
||||
// remove default colours.
|
||||
tHasComboColours.ComboColours.Clear();
|
||||
hasComboColours = true;
|
||||
}
|
||||
|
||||
tHasComboColours.ComboColours.Add(colour);
|
||||
tHasComboColours.AddComboColours(colour);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -12,10 +12,12 @@ using osu.Framework.Input.Events;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
public class OsuTextBox : TextBox
|
||||
public class OsuTextBox : BasicTextBox
|
||||
{
|
||||
protected override float LeftRightPadding => 10;
|
||||
|
||||
protected override float CaretWidth => 3;
|
||||
|
||||
protected override SpriteText CreatePlaceholder() => new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(italics: true),
|
||||
@ -41,6 +43,8 @@ namespace osu.Game.Graphics.UserInterface
|
||||
BackgroundCommit = BorderColour = colour.Yellow;
|
||||
}
|
||||
|
||||
protected override Color4 SelectionColour => new Color4(249, 90, 255, 255);
|
||||
|
||||
protected override void OnFocus(FocusEvent e)
|
||||
{
|
||||
BorderThickness = 3;
|
||||
|
13
osu.Game/Overlays/Settings/ISettingsItem.cs
Normal file
13
osu.Game/Overlays/Settings/ISettingsItem.cs
Normal file
@ -0,0 +1,13 @@
|
||||
// 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.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Settings
|
||||
{
|
||||
public interface ISettingsItem : IDrawable, IDisposable
|
||||
{
|
||||
event Action SettingChanged;
|
||||
}
|
||||
}
|
@ -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.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
@ -20,7 +21,7 @@ using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.Settings
|
||||
{
|
||||
public abstract class SettingsItem<T> : Container, IFilterable
|
||||
public abstract class SettingsItem<T> : Container, IFilterable, ISettingsItem
|
||||
{
|
||||
protected abstract Drawable CreateControl();
|
||||
|
||||
@ -34,8 +35,6 @@ namespace osu.Game.Overlays.Settings
|
||||
|
||||
private SpriteText text;
|
||||
|
||||
private readonly RestoreDefaultValueButton restoreDefaultButton;
|
||||
|
||||
public bool ShowsDefaultIndicator = true;
|
||||
|
||||
public virtual string LabelText
|
||||
@ -70,8 +69,12 @@ namespace osu.Game.Overlays.Settings
|
||||
|
||||
public bool FilteringActive { get; set; }
|
||||
|
||||
public event Action SettingChanged;
|
||||
|
||||
protected SettingsItem()
|
||||
{
|
||||
RestoreDefaultValueButton restoreDefaultButton;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS };
|
||||
@ -87,13 +90,12 @@ namespace osu.Game.Overlays.Settings
|
||||
Child = Control = CreateControl()
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
// all bindable logic is in constructor intentionally to support "CreateSettingsControls" being used in a context it is
|
||||
// never loaded, but requires bindable storage.
|
||||
if (controlWithCurrent != null)
|
||||
{
|
||||
controlWithCurrent.Current.ValueChanged += _ => SettingChanged?.Invoke();
|
||||
controlWithCurrent.Current.DisabledChanged += disabled => { Colour = disabled ? Color4.Gray : Color4.White; };
|
||||
|
||||
if (ShowsDefaultIndicator)
|
||||
|
81
osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs
Normal file
81
osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs
Normal file
@ -0,0 +1,81 @@
|
||||
// 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.Beatmaps;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using System;
|
||||
using osu.Game.Configuration;
|
||||
|
||||
namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
public abstract class ModDifficultyAdjust : Mod, IApplicableToDifficulty
|
||||
{
|
||||
public override string Name => @"Difficulty Adjust";
|
||||
|
||||
public override string Description => @"Override a beatmap's difficulty settings.";
|
||||
|
||||
public override string Acronym => "DA";
|
||||
|
||||
public override ModType Type => ModType.Conversion;
|
||||
|
||||
public override IconUsage Icon => FontAwesome.Solid.Hammer;
|
||||
|
||||
public override double ScoreMultiplier => 1.0;
|
||||
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModEasy), typeof(ModHardRock) };
|
||||
|
||||
[SettingSource("Drain Rate", "Override a beatmap's set HP.")]
|
||||
public BindableNumber<float> DrainRate { get; } = new BindableFloat
|
||||
{
|
||||
Precision = 0.1f,
|
||||
MinValue = 1,
|
||||
MaxValue = 10,
|
||||
Default = 5,
|
||||
Value = 5,
|
||||
};
|
||||
|
||||
[SettingSource("Overall Difficulty", "Override a beatmap's set OD.")]
|
||||
public BindableNumber<float> OverallDifficulty { get; } = new BindableFloat
|
||||
{
|
||||
Precision = 0.1f,
|
||||
MinValue = 1,
|
||||
MaxValue = 10,
|
||||
Default = 5,
|
||||
Value = 5,
|
||||
};
|
||||
|
||||
private BeatmapDifficulty difficulty;
|
||||
|
||||
public void ApplyToDifficulty(BeatmapDifficulty difficulty)
|
||||
{
|
||||
if (this.difficulty == null || this.difficulty.ID != difficulty.ID)
|
||||
{
|
||||
this.difficulty = difficulty;
|
||||
TransferSettings(difficulty);
|
||||
}
|
||||
else
|
||||
ApplySettings(difficulty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transfer initial settings from the beatmap to settings.
|
||||
/// </summary>
|
||||
/// <param name="difficulty">The beatmap's initial values.</param>
|
||||
protected virtual void TransferSettings(BeatmapDifficulty difficulty)
|
||||
{
|
||||
DrainRate.Value = DrainRate.Default = difficulty.DrainRate;
|
||||
OverallDifficulty.Value = OverallDifficulty.Default = difficulty.OverallDifficulty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply all custom settings to the provided beatmap.
|
||||
/// </summary>
|
||||
/// <param name="difficulty">The beatmap to have settings applied.</param>
|
||||
protected virtual void ApplySettings(BeatmapDifficulty difficulty)
|
||||
{
|
||||
difficulty.DrainRate = DrainRate.Value;
|
||||
difficulty.OverallDifficulty = OverallDifficulty.Value;
|
||||
}
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override ModType Type => ModType.DifficultyReduction;
|
||||
public override double ScoreMultiplier => 0.5;
|
||||
public override bool Ranked => true;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModHardRock) };
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModHardRock), typeof(ModDifficultyAdjust) };
|
||||
|
||||
private int retries = 2;
|
||||
|
||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override IconUsage Icon => OsuIcon.ModHardrock;
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
public override string Description => "Everything just got a bit harder...";
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModEasy) };
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModEasy), typeof(ModDifficultyAdjust) };
|
||||
|
||||
public void ApplyToDifficulty(BeatmapDifficulty difficulty)
|
||||
{
|
||||
|
@ -356,7 +356,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
{
|
||||
if (HitObject is IHasComboInformation combo)
|
||||
{
|
||||
var comboColours = CurrentSkin.GetConfig<GlobalSkinConfiguration, List<Color4>>(GlobalSkinConfiguration.ComboColours)?.Value;
|
||||
var comboColours = CurrentSkin.GetConfig<GlobalSkinConfiguration, IReadOnlyList<Color4>>(GlobalSkinConfiguration.ComboColours)?.Value;
|
||||
AccentColour.Value = comboColours?.Count > 0 ? comboColours[combo.ComboIndex % comboColours.Count] : Color4.White;
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
@ -132,6 +133,8 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
private void confirmAndExit()
|
||||
{
|
||||
if (exitConfirmed) return;
|
||||
|
||||
exitConfirmed = true;
|
||||
this.Exit();
|
||||
}
|
||||
@ -244,11 +247,19 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
public override bool OnExiting(IScreen next)
|
||||
{
|
||||
if (!exitConfirmed && dialogOverlay != null && !(dialogOverlay.CurrentDialog is ConfirmExitDialog))
|
||||
if (!exitConfirmed && dialogOverlay != null)
|
||||
{
|
||||
if (dialogOverlay.CurrentDialog is ConfirmExitDialog exitDialog)
|
||||
{
|
||||
exitConfirmed = true;
|
||||
exitDialog.Buttons.First().Click();
|
||||
}
|
||||
else
|
||||
{
|
||||
dialogOverlay.Push(new ConfirmExitDialog(confirmAndExit, () => exitConfirmOverlay.Abort()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
buttons.State = ButtonSystemState.Exit;
|
||||
this.FadeOut(3000);
|
||||
|
@ -562,7 +562,7 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
// GameplayClockContainer performs seeks / start / stop operations on the beatmap's track.
|
||||
// as we are no longer the current screen, we cannot guarantee the track is still usable.
|
||||
GameplayClockContainer.StopUsingBeatmapClock();
|
||||
GameplayClockContainer?.StopUsingBeatmapClock();
|
||||
|
||||
fadeOut();
|
||||
return base.OnExiting(next);
|
||||
|
@ -16,6 +16,9 @@ using osu.Framework.Bindables;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using System.Linq;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Overlays.Settings;
|
||||
|
||||
namespace osu.Game.Screens.Select.Details
|
||||
{
|
||||
@ -69,7 +72,37 @@ namespace osu.Game.Screens.Select.Details
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
mods.BindValueChanged(_ => updateStatistics(), true);
|
||||
mods.BindValueChanged(modsChanged, true);
|
||||
}
|
||||
|
||||
private readonly List<ISettingsItem> references = new List<ISettingsItem>();
|
||||
|
||||
private void modsChanged(ValueChangedEvent<IReadOnlyList<Mod>> mods)
|
||||
{
|
||||
// TODO: find a more permanent solution for this if/when it is needed in other components.
|
||||
// this is generating drawables for the only purpose of storing bindable references.
|
||||
foreach (var r in references)
|
||||
r.Dispose();
|
||||
|
||||
references.Clear();
|
||||
|
||||
ScheduledDelegate debounce = null;
|
||||
|
||||
foreach (var mod in mods.NewValue.OfType<IApplicableToDifficulty>())
|
||||
{
|
||||
foreach (var setting in mod.CreateSettingsControls().OfType<ISettingsItem>())
|
||||
{
|
||||
setting.SettingChanged += () =>
|
||||
{
|
||||
debounce?.Cancel();
|
||||
debounce = Scheduler.AddDelayed(updateStatistics, 100);
|
||||
};
|
||||
|
||||
references.Add(setting);
|
||||
}
|
||||
}
|
||||
|
||||
updateStatistics();
|
||||
}
|
||||
|
||||
private void updateStatistics()
|
||||
|
@ -13,13 +13,12 @@ namespace osu.Game.Skinning
|
||||
: base(Info, storage, audioManager, string.Empty)
|
||||
{
|
||||
Configuration.CustomColours["SliderBall"] = new Color4(2, 170, 255, 255);
|
||||
Configuration.ComboColours.AddRange(new[]
|
||||
{
|
||||
Configuration.AddComboColours(
|
||||
new Color4(255, 192, 0, 255),
|
||||
new Color4(0, 202, 0, 255),
|
||||
new Color4(18, 124, 255, 255),
|
||||
new Color4(242, 24, 57, 255),
|
||||
});
|
||||
new Color4(242, 24, 57, 255)
|
||||
);
|
||||
|
||||
Configuration.LegacyVersion = 2.0m;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ namespace osu.Game.Skinning
|
||||
switch (global)
|
||||
{
|
||||
case GlobalSkinConfiguration.ComboColours:
|
||||
return SkinUtils.As<TValue>(new Bindable<List<Color4>>(Configuration.ComboColours));
|
||||
return SkinUtils.As<TValue>(new Bindable<IReadOnlyList<Color4>>(Configuration.ComboColours));
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -1,8 +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 osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Skinning
|
||||
{
|
||||
/// <summary>
|
||||
@ -10,15 +8,5 @@ namespace osu.Game.Skinning
|
||||
/// </summary>
|
||||
public class DefaultSkinConfiguration : SkinConfiguration
|
||||
{
|
||||
public DefaultSkinConfiguration()
|
||||
{
|
||||
ComboColours.AddRange(new[]
|
||||
{
|
||||
new Color4(255, 192, 0, 255),
|
||||
new Color4(0, 202, 0, 255),
|
||||
new Color4(18, 124, 255, 255),
|
||||
new Color4(242, 24, 57, 255),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ namespace osu.Game.Skinning
|
||||
public LegacyBeatmapSkin(BeatmapInfo beatmap, IResourceStore<byte[]> storage, AudioManager audioManager)
|
||||
: base(createSkinInfo(beatmap), new LegacySkinResourceStore<BeatmapSetFileInfo>(beatmap.BeatmapSet, storage), audioManager, beatmap.Path)
|
||||
{
|
||||
// Disallow default colours fallback on beatmap skins to allow using parent skin combo colours. (via SkinProvidingContainer)
|
||||
Configuration.AllowDefaultComboColoursFallback = false;
|
||||
}
|
||||
|
||||
private static SkinInfo createSkinInfo(BeatmapInfo beatmap) =>
|
||||
|
@ -72,7 +72,11 @@ namespace osu.Game.Skinning
|
||||
switch (global)
|
||||
{
|
||||
case GlobalSkinConfiguration.ComboColours:
|
||||
return SkinUtils.As<TValue>(new Bindable<List<Color4>>(Configuration.ComboColours));
|
||||
var comboColours = Configuration.ComboColours;
|
||||
if (comboColours != null)
|
||||
return SkinUtils.As<TValue>(new Bindable<IReadOnlyList<Color4>>(comboColours));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
namespace osu.Game.Skinning
|
||||
{
|
||||
public class LegacySkinConfiguration : DefaultSkinConfiguration
|
||||
public class LegacySkinConfiguration : SkinConfiguration
|
||||
{
|
||||
public const decimal LATEST_VERSION = 2.7m;
|
||||
|
||||
|
@ -14,7 +14,36 @@ namespace osu.Game.Skinning
|
||||
{
|
||||
public readonly SkinInfo SkinInfo = new SkinInfo();
|
||||
|
||||
public List<Color4> ComboColours { get; set; } = new List<Color4>();
|
||||
/// <summary>
|
||||
/// Whether to allow <see cref="DefaultComboColours"/> as a fallback list for when no combo colours are provided.
|
||||
/// </summary>
|
||||
internal bool AllowDefaultComboColoursFallback = true;
|
||||
|
||||
public static List<Color4> DefaultComboColours { get; } = new List<Color4>
|
||||
{
|
||||
new Color4(255, 192, 0, 255),
|
||||
new Color4(0, 202, 0, 255),
|
||||
new Color4(18, 124, 255, 255),
|
||||
new Color4(242, 24, 57, 255),
|
||||
};
|
||||
|
||||
private readonly List<Color4> comboColours = new List<Color4>();
|
||||
|
||||
public IReadOnlyList<Color4> ComboColours
|
||||
{
|
||||
get
|
||||
{
|
||||
if (comboColours.Count > 0)
|
||||
return comboColours;
|
||||
|
||||
if (AllowDefaultComboColoursFallback)
|
||||
return DefaultComboColours;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddComboColours(params Color4[] colours) => comboColours.AddRange(colours);
|
||||
|
||||
public Dictionary<string, Color4> CustomColours { get; set; } = new Dictionary<string, Color4>();
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1215.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2019.1219.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2019.1225.0" />
|
||||
<PackageReference Include="Sentry" Version="1.2.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.24.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
|
@ -74,7 +74,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1215.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.1219.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.1225.0" />
|
||||
</ItemGroup>
|
||||
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->
|
||||
<ItemGroup Label="Transitive Dependencies">
|
||||
@ -82,7 +82,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2019.1219.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2019.1225.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.24.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user