mirror of
https://github.com/ppy/osu.git
synced 2025-01-12 21:02:54 +08:00
Merge remote-tracking branch 'upstream/master' into fix-mod-buttons-not-copying-settings
This commit is contained in:
commit
375ecf92ed
@ -15,7 +15,7 @@
|
||||
]
|
||||
},
|
||||
"jetbrains.resharper.globaltools": {
|
||||
"version": "2020.2.4",
|
||||
"version": "2020.3.2",
|
||||
"commands": [
|
||||
"jb"
|
||||
]
|
||||
|
@ -16,7 +16,7 @@
|
||||
<EmbeddedResource Include="Resources\**\*.*" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Code Analysis">
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.1" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.2" PrivateAssets="All" />
|
||||
<AdditionalFiles Include="$(MSBuildThisFileDirectory)CodeAnalysis\BannedSymbols.txt" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.1" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
@ -40,7 +40,7 @@
|
||||
<RepositoryUrl>https://github.com/ppy/osu</RepositoryUrl>
|
||||
<PackageReleaseNotes>Automated release.</PackageReleaseNotes>
|
||||
<Company>ppy Pty Ltd</Company>
|
||||
<Copyright>Copyright (c) 2020 ppy Pty Ltd</Copyright>
|
||||
<Copyright>Copyright (c) 2021 ppy Pty Ltd</Copyright>
|
||||
<PackageTags>osu game</PackageTags>
|
||||
</PropertyGroup>
|
||||
</Project>
|
2
LICENCE
2
LICENCE
@ -1,4 +1,4 @@
|
||||
Copyright (c) 2020 ppy Pty Ltd <contact@ppy.sh>.
|
||||
Copyright (c) 2021 ppy Pty Ltd <contact@ppy.sh>.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -52,6 +52,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1202.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.1229.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.106.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -16,7 +16,9 @@ using osu.Framework.Android;
|
||||
namespace osu.Android
|
||||
{
|
||||
[Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.FullUser, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = false, LaunchMode = LaunchMode.SingleInstance)]
|
||||
[IntentFilter(new[] { Intent.ActionDefault, Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataPathPatterns = new[] { ".*\\.osz", ".*\\.osk" }, DataMimeType = "application/*")]
|
||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osz", DataHost = "*", DataMimeType = "*/*")]
|
||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osk", DataHost = "*", DataMimeType = "*/*")]
|
||||
[IntentFilter(new[] { Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataMimeTypes = new[] { "application/zip", "application/octet-stream" })]
|
||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault }, DataSchemes = new[] { "osu", "osump" })]
|
||||
public class OsuGameActivity : AndroidGameActivity
|
||||
{
|
||||
|
@ -9,6 +9,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Users;
|
||||
@ -31,13 +32,15 @@ namespace osu.Desktop
|
||||
private readonly IBindable<UserStatus> status = new Bindable<UserStatus>();
|
||||
private readonly IBindable<UserActivity> activity = new Bindable<UserActivity>();
|
||||
|
||||
private readonly Bindable<DiscordRichPresenceMode> privacyMode = new Bindable<DiscordRichPresenceMode>();
|
||||
|
||||
private readonly RichPresence presence = new RichPresence
|
||||
{
|
||||
Assets = new Assets { LargeImageKey = "osu_logo_lazer", }
|
||||
};
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IAPIProvider provider)
|
||||
private void load(IAPIProvider provider, OsuConfigManager config)
|
||||
{
|
||||
client = new DiscordRpcClient(client_id)
|
||||
{
|
||||
@ -51,6 +54,8 @@ namespace osu.Desktop
|
||||
|
||||
client.OnError += (_, e) => Logger.Log($"An error occurred with Discord RPC Client: {e.Code} {e.Message}", LoggingTarget.Network);
|
||||
|
||||
config.BindWith(OsuSetting.DiscordRichPresence, privacyMode);
|
||||
|
||||
(user = provider.LocalUser.GetBoundCopy()).BindValueChanged(u =>
|
||||
{
|
||||
status.UnbindBindings();
|
||||
@ -63,6 +68,7 @@ namespace osu.Desktop
|
||||
ruleset.BindValueChanged(_ => updateStatus());
|
||||
status.BindValueChanged(_ => updateStatus());
|
||||
activity.BindValueChanged(_ => updateStatus());
|
||||
privacyMode.BindValueChanged(_ => updateStatus());
|
||||
|
||||
client.Initialize();
|
||||
}
|
||||
@ -78,7 +84,7 @@ namespace osu.Desktop
|
||||
if (!client.IsInitialized)
|
||||
return;
|
||||
|
||||
if (status.Value is UserStatusOffline)
|
||||
if (status.Value is UserStatusOffline || privacyMode.Value == DiscordRichPresenceMode.Off)
|
||||
{
|
||||
client.ClearPresence();
|
||||
return;
|
||||
@ -96,6 +102,9 @@ namespace osu.Desktop
|
||||
}
|
||||
|
||||
// update user information
|
||||
if (privacyMode.Value == DiscordRichPresenceMode.Limited)
|
||||
presence.Assets.LargeImageText = string.Empty;
|
||||
else
|
||||
presence.Assets.LargeImageText = $"{user.Value.Username}" + (user.Value.Statistics?.Ranks.Global > 0 ? $" (rank #{user.Value.Statistics.Ranks.Global:N0})" : string.Empty);
|
||||
|
||||
// update ruleset
|
||||
@ -137,7 +146,7 @@ namespace osu.Desktop
|
||||
return edit.Beatmap.ToString();
|
||||
|
||||
case UserActivity.InLobby lobby:
|
||||
return lobby.Room.Name.Value;
|
||||
return privacyMode.Value == DiscordRichPresenceMode.Limited ? string.Empty : lobby.Room.Name.Value;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
|
@ -26,9 +26,11 @@ namespace osu.Desktop.Overlays
|
||||
|
||||
Alpha = 0;
|
||||
|
||||
FillFlowContainer mainFill;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
mainFill = new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
@ -55,6 +57,14 @@ namespace osu.Desktop.Overlays
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!game.IsDeployedBuild)
|
||||
{
|
||||
mainFill.AddRange(new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
@ -69,10 +79,9 @@ namespace osu.Desktop.Overlays
|
||||
Origin = Anchor.TopCentre,
|
||||
Texture = textures.Get(@"Menu/dev-build-footer"),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void PopIn()
|
||||
{
|
||||
|
@ -11,7 +11,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>A free-to-win rhythm game. Rhythm is just a *click* away!</description>
|
||||
<releaseNotes>testing</releaseNotes>
|
||||
<copyright>Copyright (c) 2020 ppy Pty Ltd</copyright>
|
||||
<copyright>Copyright (c) 2021 ppy Pty Ltd</copyright>
|
||||
<language>en-AU</language>
|
||||
</metadata>
|
||||
<files>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
|
@ -59,8 +59,8 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
base.ApplySettings(difficulty);
|
||||
|
||||
difficulty.CircleSize = CircleSize.Value;
|
||||
difficulty.ApproachRate = ApproachRate.Value;
|
||||
ApplySetting(CircleSize, cs => difficulty.CircleSize = cs);
|
||||
ApplySetting(ApproachRate, ar => difficulty.ApproachRate = ar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
|
@ -1,13 +1,17 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
@ -18,8 +22,23 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
public void TestNoAdjustment() => CreateModTest(new ModTestData
|
||||
{
|
||||
Mod = new OsuModDifficultyAdjust(),
|
||||
Beatmap = new Beatmap
|
||||
{
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
{
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 8
|
||||
}
|
||||
},
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
new HitCircle { StartTime = 1000 },
|
||||
new HitCircle { StartTime = 2000 }
|
||||
}
|
||||
},
|
||||
Autoplay = true,
|
||||
PassCondition = checkSomeHit
|
||||
PassCondition = () => checkSomeHit() && checkObjectsScale(0.29f)
|
||||
});
|
||||
|
||||
[Test]
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
|
@ -59,8 +59,8 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
base.ApplySettings(difficulty);
|
||||
|
||||
difficulty.CircleSize = CircleSize.Value;
|
||||
difficulty.ApproachRate = ApproachRate.Value;
|
||||
ApplySetting(CircleSize, cs => difficulty.CircleSize = cs);
|
||||
ApplySetting(ApproachRate, ar => difficulty.ApproachRate = ar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
|
@ -95,6 +95,26 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOutOfOrderStartTimes()
|
||||
{
|
||||
var decoder = new LegacyStoryboardDecoder();
|
||||
|
||||
using (var resStream = TestResources.OpenResource("out-of-order-starttimes.osb"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var storyboard = decoder.Decode(stream);
|
||||
|
||||
StoryboardLayer background = storyboard.Layers.Single(l => l.Depth == 3);
|
||||
Assert.AreEqual(2, background.Elements.Count);
|
||||
|
||||
Assert.AreEqual(1500, background.Elements[0].StartTime);
|
||||
Assert.AreEqual(1000, background.Elements[1].StartTime);
|
||||
|
||||
Assert.AreEqual(1000, storyboard.EarliestEventTime);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeVariableWithSuffix()
|
||||
{
|
||||
|
@ -246,5 +246,32 @@ namespace osu.Game.Tests.NonVisual
|
||||
Assert.That(cpi.DifficultyPoints.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.AllControlPoints.Count, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCreateCopyIsDeepClone()
|
||||
{
|
||||
var cpi = new ControlPointInfo();
|
||||
|
||||
cpi.Add(1000, new TimingControlPoint { BeatLength = 500 });
|
||||
|
||||
var cpiCopy = cpi.CreateCopy();
|
||||
|
||||
cpiCopy.Add(2000, new TimingControlPoint { BeatLength = 500 });
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(1));
|
||||
Assert.That(cpiCopy.Groups.Count, Is.EqualTo(2));
|
||||
|
||||
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(1));
|
||||
Assert.That(cpiCopy.TimingPoints.Count, Is.EqualTo(2));
|
||||
|
||||
Assert.That(cpi.TimingPoints[0], Is.Not.SameAs(cpiCopy.TimingPoints[0]));
|
||||
Assert.That(cpi.TimingPoints[0].BeatLengthBindable, Is.Not.SameAs(cpiCopy.TimingPoints[0].BeatLengthBindable));
|
||||
|
||||
Assert.That(cpi.TimingPoints[0].BeatLength, Is.EqualTo(cpiCopy.TimingPoints[0].BeatLength));
|
||||
|
||||
cpi.TimingPoints[0].BeatLength = 800;
|
||||
|
||||
Assert.That(cpi.TimingPoints[0].BeatLength, Is.Not.EqualTo(cpiCopy.TimingPoints[0].BeatLength));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
6
osu.Game.Tests/Resources/out-of-order-starttimes.osb
Normal file
6
osu.Game.Tests/Resources/out-of-order-starttimes.osb
Normal file
@ -0,0 +1,6 @@
|
||||
[Events]
|
||||
//Storyboard Layer 0 (Background)
|
||||
Sprite,Background,TopCentre,"img.jpg",320,240
|
||||
F,0,1500,1600,0,1
|
||||
Sprite,Background,TopCentre,"img.jpg",320,240
|
||||
F,0,1000,1100,0,1
|
@ -82,7 +82,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
});
|
||||
AddUntilStep("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
AddStep("Stop background preview", () => InputManager.MoveMouseTo(playerLoader.ScreenPos));
|
||||
AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && playerLoader.IsBlurCorrect());
|
||||
AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.CheckBackgroundBlur(playerLoader.ExpectedBackgroundBlur));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -106,6 +106,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
public void TestStoryboardBackgroundVisibility()
|
||||
{
|
||||
performFullSetup();
|
||||
AddAssert("Background retained from song select", () => songSelect.IsBackgroundCurrent());
|
||||
createFakeStoryboard();
|
||||
AddStep("Enable Storyboard", () =>
|
||||
{
|
||||
@ -198,8 +199,9 @@ namespace osu.Game.Tests.Visual.Background
|
||||
})));
|
||||
|
||||
AddUntilStep("Wait for results is current", () => results.IsCurrentScreen());
|
||||
|
||||
AddUntilStep("Screen is undimmed, original background retained", () =>
|
||||
songSelect.IsBackgroundUndimmed() && songSelect.IsBackgroundCurrent() && results.IsBlurCorrect());
|
||||
songSelect.IsBackgroundUndimmed() && songSelect.IsBackgroundCurrent() && songSelect.CheckBackgroundBlur(results.ExpectedBackgroundBlur));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -224,7 +226,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
AddStep("Resume PlayerLoader", () => player.Restart());
|
||||
AddUntilStep("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||
AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos));
|
||||
AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && playerLoader.IsBlurCorrect());
|
||||
AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.CheckBackgroundBlur(playerLoader.ExpectedBackgroundBlur));
|
||||
}
|
||||
|
||||
private void createFakeStoryboard() => AddStep("Create storyboard", () =>
|
||||
@ -274,9 +276,11 @@ namespace osu.Game.Tests.Visual.Background
|
||||
|
||||
private class DummySongSelect : PlaySongSelect
|
||||
{
|
||||
private FadeAccessibleBackground background;
|
||||
|
||||
protected override BackgroundScreen CreateBackground()
|
||||
{
|
||||
FadeAccessibleBackground background = new FadeAccessibleBackground(Beatmap.Value);
|
||||
background = new FadeAccessibleBackground(Beatmap.Value);
|
||||
DimEnabled.BindTo(background.EnableUserDim);
|
||||
return background;
|
||||
}
|
||||
@ -294,25 +298,27 @@ namespace osu.Game.Tests.Visual.Background
|
||||
config.BindWith(OsuSetting.BlurLevel, BlurLevel);
|
||||
}
|
||||
|
||||
public bool IsBackgroundDimmed() => ((FadeAccessibleBackground)Background).CurrentColour == OsuColour.Gray(1f - ((FadeAccessibleBackground)Background).CurrentDim);
|
||||
public bool IsBackgroundDimmed() => background.CurrentColour == OsuColour.Gray(1f - background.CurrentDim);
|
||||
|
||||
public bool IsBackgroundUndimmed() => ((FadeAccessibleBackground)Background).CurrentColour == Color4.White;
|
||||
public bool IsBackgroundUndimmed() => background.CurrentColour == Color4.White;
|
||||
|
||||
public bool IsUserBlurApplied() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2((float)BlurLevel.Value * BackgroundScreenBeatmap.USER_BLUR_FACTOR);
|
||||
public bool IsUserBlurApplied() => background.CurrentBlur == new Vector2((float)BlurLevel.Value * BackgroundScreenBeatmap.USER_BLUR_FACTOR);
|
||||
|
||||
public bool IsUserBlurDisabled() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(0);
|
||||
public bool IsUserBlurDisabled() => background.CurrentBlur == new Vector2(0);
|
||||
|
||||
public bool IsBackgroundInvisible() => ((FadeAccessibleBackground)Background).CurrentAlpha == 0;
|
||||
public bool IsBackgroundInvisible() => background.CurrentAlpha == 0;
|
||||
|
||||
public bool IsBackgroundVisible() => ((FadeAccessibleBackground)Background).CurrentAlpha == 1;
|
||||
public bool IsBackgroundVisible() => background.CurrentAlpha == 1;
|
||||
|
||||
public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR);
|
||||
public bool IsBlurCorrect() => background.CurrentBlur == new Vector2(BACKGROUND_BLUR);
|
||||
|
||||
public bool CheckBackgroundBlur(Vector2 expected) => background.CurrentBlur == expected;
|
||||
|
||||
/// <summary>
|
||||
/// Make sure every time a screen gets pushed, the background doesn't get replaced
|
||||
/// </summary>
|
||||
/// <returns>Whether or not the original background (The one created in DummySongSelect) is still the current background</returns>
|
||||
public bool IsBackgroundCurrent() => ((FadeAccessibleBackground)Background).IsCurrentScreen();
|
||||
public bool IsBackgroundCurrent() => background?.IsCurrentScreen() == true;
|
||||
}
|
||||
|
||||
private class FadeAccessibleResults : ResultsScreen
|
||||
@ -324,12 +330,20 @@ namespace osu.Game.Tests.Visual.Background
|
||||
|
||||
protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value);
|
||||
|
||||
public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR);
|
||||
public Vector2 ExpectedBackgroundBlur => new Vector2(BACKGROUND_BLUR);
|
||||
}
|
||||
|
||||
private class LoadBlockingTestPlayer : TestPlayer
|
||||
{
|
||||
protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value);
|
||||
protected override BackgroundScreen CreateBackground() =>
|
||||
new FadeAccessibleBackground(Beatmap.Value);
|
||||
|
||||
public override void OnEntering(IScreen last)
|
||||
{
|
||||
base.OnEntering(last);
|
||||
|
||||
ApplyToBackground(b => ReplacesBackground.BindTo(b.StoryboardReplacesBackground));
|
||||
}
|
||||
|
||||
public new DimmableStoryboard DimmableStoryboard => base.DimmableStoryboard;
|
||||
|
||||
@ -354,15 +368,16 @@ namespace osu.Game.Tests.Visual.Background
|
||||
Thread.Sleep(1);
|
||||
|
||||
StoryboardEnabled = config.GetBindable<bool>(OsuSetting.ShowStoryboard);
|
||||
ReplacesBackground.BindTo(Background.StoryboardReplacesBackground);
|
||||
DrawableRuleset.IsPaused.BindTo(IsPaused);
|
||||
}
|
||||
}
|
||||
|
||||
private class TestPlayerLoader : PlayerLoader
|
||||
{
|
||||
private FadeAccessibleBackground background;
|
||||
|
||||
public VisualSettings VisualSettingsPos => VisualSettings;
|
||||
public BackgroundScreen ScreenPos => Background;
|
||||
public BackgroundScreen ScreenPos => background;
|
||||
|
||||
public TestPlayerLoader(Player player)
|
||||
: base(() => player)
|
||||
@ -371,9 +386,9 @@ namespace osu.Game.Tests.Visual.Background
|
||||
|
||||
public void TriggerOnHover() => OnHover(new HoverEvent(new InputState()));
|
||||
|
||||
public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR);
|
||||
public Vector2 ExpectedBackgroundBlur => new Vector2(BACKGROUND_BLUR);
|
||||
|
||||
protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value);
|
||||
protected override BackgroundScreen CreateBackground() => background = new FadeAccessibleBackground(Beatmap.Value);
|
||||
}
|
||||
|
||||
private class FadeAccessibleBackground : BackgroundScreenBeatmap
|
||||
|
@ -8,7 +8,6 @@ using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using static osu.Game.Tests.Visual.Components.TestScenePreviewTrackManager.TestPreviewTrackManager;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Components
|
||||
{
|
||||
@ -100,7 +99,7 @@ namespace osu.Game.Tests.Visual.Components
|
||||
[Test]
|
||||
public void TestNonPresentTrack()
|
||||
{
|
||||
TestPreviewTrack track = null;
|
||||
TestPreviewTrackManager.TestPreviewTrack track = null;
|
||||
|
||||
AddStep("get non-present track", () =>
|
||||
{
|
||||
@ -182,9 +181,9 @@ namespace osu.Game.Tests.Visual.Components
|
||||
AddAssert("track stopped", () => !track.IsRunning);
|
||||
}
|
||||
|
||||
private TestPreviewTrack getTrack() => (TestPreviewTrack)trackManager.Get(null);
|
||||
private TestPreviewTrackManager.TestPreviewTrack getTrack() => (TestPreviewTrackManager.TestPreviewTrack)trackManager.Get(null);
|
||||
|
||||
private TestPreviewTrack getOwnedTrack()
|
||||
private TestPreviewTrackManager.TestPreviewTrack getOwnedTrack()
|
||||
{
|
||||
var track = getTrack();
|
||||
|
||||
|
@ -7,8 +7,10 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Rulesets;
|
||||
@ -23,6 +25,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
public class TestSceneMultiplayerReadyButton : MultiplayerTestScene
|
||||
{
|
||||
private MultiplayerReadyButton button;
|
||||
private BeatmapSetInfo importedSet;
|
||||
|
||||
private BeatmapManager beatmaps;
|
||||
private RulesetStore rulesets;
|
||||
@ -38,9 +41,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
[SetUp]
|
||||
public new void Setup() => Schedule(() =>
|
||||
{
|
||||
var beatmap = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First().Beatmaps.First();
|
||||
|
||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap);
|
||||
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
|
||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First());
|
||||
|
||||
Child = button = new MultiplayerReadyButton
|
||||
{
|
||||
@ -51,13 +53,30 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
Value = new PlaylistItem
|
||||
{
|
||||
Beatmap = { Value = beatmap },
|
||||
Ruleset = { Value = beatmap.Ruleset }
|
||||
Beatmap = { Value = Beatmap.Value.BeatmapInfo },
|
||||
Ruleset = { Value = Beatmap.Value.BeatmapInfo.Ruleset }
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestDeletedBeatmapDisableReady()
|
||||
{
|
||||
OsuButton readyButton = null;
|
||||
|
||||
AddAssert("ensure ready button enabled", () =>
|
||||
{
|
||||
readyButton = button.ChildrenOfType<OsuButton>().Single();
|
||||
return readyButton.Enabled.Value;
|
||||
});
|
||||
|
||||
AddStep("delete beatmap", () => beatmaps.Delete(importedSet));
|
||||
AddAssert("ready button disabled", () => !readyButton.Enabled.Value);
|
||||
AddStep("undelete beatmap", () => beatmaps.Undelete(importedSet));
|
||||
AddAssert("ready button enabled back", () => readyButton.Enabled.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestToggleStateWhenNotHost()
|
||||
{
|
||||
|
@ -11,6 +11,7 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Screens.Select.Details;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -141,16 +142,12 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddStep("select changed Difficulty Adjust mod", () =>
|
||||
{
|
||||
var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
|
||||
var difficultyAdjustMod = ruleset.GetAllMods().OfType<ModDifficultyAdjust>().Single();
|
||||
var difficultyAdjustMod = ruleset.GetAllMods().OfType<OsuModDifficultyAdjust>().Single();
|
||||
var originalDifficulty = advancedStats.Beatmap.BaseDifficulty;
|
||||
var adjustedDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = originalDifficulty.CircleSize,
|
||||
DrainRate = originalDifficulty.DrainRate - 0.5f,
|
||||
OverallDifficulty = originalDifficulty.OverallDifficulty,
|
||||
ApproachRate = originalDifficulty.ApproachRate + 2.2f,
|
||||
};
|
||||
difficultyAdjustMod.ReadFromDifficulty(adjustedDifficulty);
|
||||
|
||||
difficultyAdjustMod.ReadFromDifficulty(originalDifficulty);
|
||||
difficultyAdjustMod.DrainRate.Value = originalDifficulty.DrainRate - 0.5f;
|
||||
difficultyAdjustMod.ApproachRate.Value = originalDifficulty.ApproachRate + 2.2f;
|
||||
SelectedMods.Value = new[] { difficultyAdjustMod };
|
||||
});
|
||||
|
||||
|
@ -5,6 +5,7 @@ using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK;
|
||||
@ -14,8 +15,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestSceneLoadingLayer : OsuTestScene
|
||||
{
|
||||
private Drawable dimContent;
|
||||
private LoadingLayer overlay;
|
||||
private TestLoadingLayer overlay;
|
||||
|
||||
private Container content;
|
||||
|
||||
@ -29,14 +29,14 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
Size = new Vector2(300),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Children = new[]
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.SlateGray,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
dimContent = new FillFlowContainer
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@ -51,7 +51,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
new TriangleButton { Text = "puush me", Width = 200, Action = () => { } },
|
||||
}
|
||||
},
|
||||
overlay = new LoadingLayer(dimContent),
|
||||
overlay = new TestLoadingLayer(true),
|
||||
}
|
||||
},
|
||||
};
|
||||
@ -64,25 +64,11 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
AddStep("show", () => overlay.Show());
|
||||
|
||||
AddUntilStep("wait for content dim", () => dimContent.Colour != Color4.White);
|
||||
AddUntilStep("wait for content dim", () => overlay.BackgroundDimLayer.Alpha > 0);
|
||||
|
||||
AddStep("hide", () => overlay.Hide());
|
||||
|
||||
AddUntilStep("wait for content restore", () => dimContent.Colour == Color4.White);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestContentRestoreOnDispose()
|
||||
{
|
||||
AddAssert("not visible", () => !overlay.IsPresent);
|
||||
|
||||
AddStep("show", () => overlay.Show());
|
||||
|
||||
AddUntilStep("wait for content dim", () => dimContent.Colour != Color4.White);
|
||||
|
||||
AddStep("expire", () => overlay.Expire());
|
||||
|
||||
AddUntilStep("wait for content restore", () => dimContent.Colour == Color4.White);
|
||||
AddUntilStep("wait for content restore", () => Precision.AlmostEquals(overlay.BackgroundDimLayer.Alpha, 0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -98,5 +84,15 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
AddStep("hide", () => overlay.Hide());
|
||||
}
|
||||
|
||||
private class TestLoadingLayer : LoadingLayer
|
||||
{
|
||||
public new Box BackgroundDimLayer => base.BackgroundDimLayer;
|
||||
|
||||
public TestLoadingLayer(bool dimBackground = false, bool withBox = true)
|
||||
: base(dimBackground, withBox)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="DeepEqual" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
|
@ -5,7 +5,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
</ItemGroup>
|
||||
|
65
osu.Game.Tournament/JsonPointConverter.cs
Normal file
65
osu.Game.Tournament/JsonPointConverter.cs
Normal file
@ -0,0 +1,65 @@
|
||||
// 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 System.Drawing;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace osu.Game.Tournament
|
||||
{
|
||||
/// <summary>
|
||||
/// We made a change from using SixLabors.ImageSharp.Point to System.Drawing.Point at some stage.
|
||||
/// This handles converting to a standardised format on json serialize/deserialize operations.
|
||||
/// </summary>
|
||||
internal class JsonPointConverter : JsonConverter<Point>
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, Point value, JsonSerializer serializer)
|
||||
{
|
||||
// use the format of LaborSharp's Point since it is nicer.
|
||||
serializer.Serialize(writer, new { value.X, value.Y });
|
||||
}
|
||||
|
||||
public override Point ReadJson(JsonReader reader, Type objectType, Point existingValue, bool hasExistingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.TokenType != JsonToken.StartObject)
|
||||
{
|
||||
// if there's no object present then this is using string representation (System.Drawing.Point serializes to "x,y")
|
||||
string str = (string)reader.Value;
|
||||
|
||||
Debug.Assert(str != null);
|
||||
|
||||
return new PointConverter().ConvertFromString(str) as Point? ?? new Point();
|
||||
}
|
||||
|
||||
var point = new Point();
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.TokenType == JsonToken.EndObject) break;
|
||||
|
||||
if (reader.TokenType == JsonToken.PropertyName)
|
||||
{
|
||||
var name = reader.Value?.ToString();
|
||||
int? val = reader.ReadAsInt32();
|
||||
|
||||
if (val == null)
|
||||
continue;
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case "X":
|
||||
point.X = val.Value;
|
||||
break;
|
||||
|
||||
case "Y":
|
||||
point.Y = val.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return point;
|
||||
}
|
||||
}
|
||||
}
|
@ -8,12 +8,12 @@ using Newtonsoft.Json;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Tournament.IPC;
|
||||
using osu.Game.Tournament.IO;
|
||||
using osu.Game.Tournament.IPC;
|
||||
using osu.Game.Tournament.Models;
|
||||
using osu.Game.Users;
|
||||
using osuTK.Input;
|
||||
@ -60,7 +60,7 @@ namespace osu.Game.Tournament
|
||||
{
|
||||
using (Stream stream = storage.GetStream(bracket_filename, FileAccess.Read, FileMode.Open))
|
||||
using (var sr = new StreamReader(stream))
|
||||
ladder = JsonConvert.DeserializeObject<LadderInfo>(sr.ReadToEnd());
|
||||
ladder = JsonConvert.DeserializeObject<LadderInfo>(sr.ReadToEnd(), new JsonPointConverter());
|
||||
}
|
||||
|
||||
ladder ??= new LadderInfo();
|
||||
@ -251,6 +251,7 @@ namespace osu.Game.Tournament
|
||||
Formatting = Formatting.Indented,
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
DefaultValueHandling = DefaultValueHandling.Ignore,
|
||||
Converters = new JsonConverter[] { new JsonPointConverter() }
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,15 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
IBeatmap IBeatmap.Clone() => Clone();
|
||||
|
||||
public Beatmap<T> Clone() => (Beatmap<T>)MemberwiseClone();
|
||||
public Beatmap<T> Clone()
|
||||
{
|
||||
var clone = (Beatmap<T>)MemberwiseClone();
|
||||
|
||||
clone.ControlPointInfo = ControlPointInfo.CreateCopy();
|
||||
// todo: deep clone other elements as required.
|
||||
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
|
||||
public class Beatmap : Beatmap<HitObject>
|
||||
|
@ -28,5 +28,21 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
/// <param name="existing">An existing control point to compare with.</param>
|
||||
/// <returns>Whether this <see cref="ControlPoint"/> is redundant when placed alongside <paramref name="existing"/>.</returns>
|
||||
public abstract bool IsRedundant(ControlPoint existing);
|
||||
|
||||
/// <summary>
|
||||
/// Create an unbound copy of this control point.
|
||||
/// </summary>
|
||||
public ControlPoint CreateCopy()
|
||||
{
|
||||
var copy = (ControlPoint)Activator.CreateInstance(GetType());
|
||||
|
||||
copy.CopyFrom(this);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
public virtual void CopyFrom(ControlPoint other)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -297,5 +297,15 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public ControlPointInfo CreateCopy()
|
||||
{
|
||||
var controlPointInfo = new ControlPointInfo();
|
||||
|
||||
foreach (var point in AllControlPoints)
|
||||
controlPointInfo.Add(point.Time, point.CreateCopy());
|
||||
|
||||
return controlPointInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,5 +39,12 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
public override bool IsRedundant(ControlPoint existing)
|
||||
=> existing is DifficultyControlPoint existingDifficulty
|
||||
&& SpeedMultiplier == existingDifficulty.SpeedMultiplier;
|
||||
|
||||
public override void CopyFrom(ControlPoint other)
|
||||
{
|
||||
SpeedMultiplier = ((DifficultyControlPoint)other).SpeedMultiplier;
|
||||
|
||||
base.CopyFrom(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,5 +50,13 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
&& existing is EffectControlPoint existingEffect
|
||||
&& KiaiMode == existingEffect.KiaiMode
|
||||
&& OmitFirstBarLine == existingEffect.OmitFirstBarLine;
|
||||
|
||||
public override void CopyFrom(ControlPoint other)
|
||||
{
|
||||
KiaiMode = ((EffectControlPoint)other).KiaiMode;
|
||||
OmitFirstBarLine = ((EffectControlPoint)other).OmitFirstBarLine;
|
||||
|
||||
base.CopyFrom(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,5 +72,13 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
=> existing is SampleControlPoint existingSample
|
||||
&& SampleBank == existingSample.SampleBank
|
||||
&& SampleVolume == existingSample.SampleVolume;
|
||||
|
||||
public override void CopyFrom(ControlPoint other)
|
||||
{
|
||||
SampleVolume = ((SampleControlPoint)other).SampleVolume;
|
||||
SampleBank = ((SampleControlPoint)other).SampleBank;
|
||||
|
||||
base.CopyFrom(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,5 +69,13 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
|
||||
// Timing points are never redundant as they can change the time signature.
|
||||
public override bool IsRedundant(ControlPoint existing) => false;
|
||||
|
||||
public override void CopyFrom(ControlPoint other)
|
||||
{
|
||||
TimeSignature = ((TimingControlPoint)other).TimeSignature;
|
||||
BeatLength = ((TimingControlPoint)other).BeatLength;
|
||||
|
||||
base.CopyFrom(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,13 +164,24 @@ namespace osu.Game.Beatmaps.Formats
|
||||
/// Legacy BPM multiplier that introduces floating-point errors for rulesets that depend on it.
|
||||
/// DO NOT USE THIS UNLESS 100% SURE.
|
||||
/// </summary>
|
||||
public readonly float BpmMultiplier;
|
||||
public float BpmMultiplier { get; private set; }
|
||||
|
||||
public LegacyDifficultyControlPoint(double beatLength)
|
||||
: this()
|
||||
{
|
||||
BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 10000) / 100f : 1;
|
||||
}
|
||||
|
||||
public LegacyDifficultyControlPoint()
|
||||
{
|
||||
SpeedMultiplierBindable.Precision = double.Epsilon;
|
||||
}
|
||||
|
||||
BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 10000) / 100f : 1;
|
||||
public override void CopyFrom(ControlPoint other)
|
||||
{
|
||||
base.CopyFrom(other);
|
||||
|
||||
BpmMultiplier = ((LegacyDifficultyControlPoint)other).BpmMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,6 +203,13 @@ namespace osu.Game.Beatmaps.Formats
|
||||
=> base.IsRedundant(existing)
|
||||
&& existing is LegacySampleControlPoint existingSample
|
||||
&& CustomSampleBank == existingSample.CustomSampleBank;
|
||||
|
||||
public override void CopyFrom(ControlPoint other)
|
||||
{
|
||||
base.CopyFrom(other);
|
||||
|
||||
CustomSampleBank = ((LegacySampleControlPoint)other).CustomSampleBank;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
17
osu.Game/Configuration/DiscordRichPresenceMode.cs
Normal file
17
osu.Game/Configuration/DiscordRichPresenceMode.cs
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace osu.Game.Configuration
|
||||
{
|
||||
public enum DiscordRichPresenceMode
|
||||
{
|
||||
Off,
|
||||
|
||||
[Description("Hide identifiable information")]
|
||||
Limited,
|
||||
|
||||
Full
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// 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;
|
||||
@ -138,6 +138,8 @@ namespace osu.Game.Configuration
|
||||
Set(OsuSetting.MenuBackgroundSource, BackgroundSource.Skin);
|
||||
Set(OsuSetting.SeasonalBackgroundMode, SeasonalBackgroundMode.Sometimes);
|
||||
|
||||
Set(OsuSetting.DiscordRichPresence, DiscordRichPresenceMode.Full);
|
||||
|
||||
Set(OsuSetting.EditorWaveformOpacity, 1f);
|
||||
}
|
||||
|
||||
@ -266,6 +268,7 @@ namespace osu.Game.Configuration
|
||||
GameplayDisableWinKey,
|
||||
SeasonalBackgroundMode,
|
||||
EditorWaveformOpacity,
|
||||
DiscordRichPresence,
|
||||
AutomaticallyDownloadWhenSpectating,
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
// 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.Graphics.UserInterface;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays;
|
||||
|
||||
namespace osu.Game.Configuration
|
||||
{
|
||||
@ -14,6 +16,7 @@ namespace osu.Game.Configuration
|
||||
{
|
||||
Set(Static.LoginOverlayDisplayed, false);
|
||||
Set(Static.MutedAudioNotificationShownOnce, false);
|
||||
Set(Static.LastHoverSoundPlaybackTime, (double?)null);
|
||||
Set<APISeasonalBackgrounds>(Static.SeasonalBackgrounds, null);
|
||||
}
|
||||
}
|
||||
@ -28,5 +31,11 @@ namespace osu.Game.Configuration
|
||||
/// Value under this lookup can be <c>null</c> if there are no backgrounds available (or API is not reachable).
|
||||
/// </summary>
|
||||
SeasonalBackgrounds,
|
||||
|
||||
/// <summary>
|
||||
/// The last playback time in milliseconds of a hover sample (from <see cref="HoverSounds"/>).
|
||||
/// Used to debounce hover sounds game-wide to avoid volume saturation, especially in scrolling views with many UI controls like <see cref="SettingsOverlay"/>.
|
||||
/// </summary>
|
||||
LastHoverSoundPlaybackTime
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +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.
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Extensions.ExceptionExtensions;
|
||||
using osu.Framework.Logging;
|
||||
|
||||
namespace osu.Game.Extensions
|
||||
@ -13,13 +17,19 @@ namespace osu.Game.Extensions
|
||||
/// Avoids unobserved exceptions from being fired.
|
||||
/// </summary>
|
||||
/// <param name="task">The task.</param>
|
||||
/// <param name="logOnError">Whether errors should be logged as important, or silently ignored.</param>
|
||||
public static void CatchUnobservedExceptions(this Task task, bool logOnError = false)
|
||||
/// <param name="logAsError">
|
||||
/// Whether errors should be logged as errors visible to users, or as debug messages.
|
||||
/// Logging as debug will essentially silence the errors on non-release builds.
|
||||
/// </param>
|
||||
public static void CatchUnobservedExceptions(this Task task, bool logAsError = false)
|
||||
{
|
||||
task.ContinueWith(t =>
|
||||
{
|
||||
if (logOnError)
|
||||
Logger.Log($"Error running task: {t.Exception?.Message ?? "unknown"}", LoggingTarget.Runtime, LogLevel.Important);
|
||||
Exception? exception = t.Exception?.AsSingular();
|
||||
if (logAsError)
|
||||
Logger.Error(exception, $"Error running task: {exception?.Message ?? "(unknown)"}", LoggingTarget.Runtime, true);
|
||||
else
|
||||
Logger.Log($"Error running task: {exception}", LoggingTarget.Runtime, LogLevel.Debug);
|
||||
}, TaskContinuationOptions.NotOnRanToCompletion);
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,12 @@ using System.ComponentModel;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Configuration;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
@ -22,36 +23,39 @@ namespace osu.Game.Graphics.UserInterface
|
||||
private SampleChannel sampleHover;
|
||||
|
||||
/// <summary>
|
||||
/// Length of debounce for hover sound playback, in milliseconds. Default is 50ms.
|
||||
/// Length of debounce for hover sound playback, in milliseconds.
|
||||
/// </summary>
|
||||
public double HoverDebounceTime { get; } = 50;
|
||||
public double HoverDebounceTime { get; } = 20;
|
||||
|
||||
protected readonly HoverSampleSet SampleSet;
|
||||
|
||||
private Bindable<double?> lastPlaybackTime;
|
||||
|
||||
public HoverSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal)
|
||||
{
|
||||
SampleSet = sampleSet;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
private ScheduledDelegate playDelegate;
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio, SessionStatics statics)
|
||||
{
|
||||
lastPlaybackTime = statics.GetBindable<double?>(Static.LastHoverSoundPlaybackTime);
|
||||
|
||||
sampleHover = audio.Samples.Get($@"UI/generic-hover{SampleSet.GetDescription()}");
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
playDelegate?.Cancel();
|
||||
bool enoughTimePassedSinceLastPlayback = !lastPlaybackTime.Value.HasValue || Time.Current - lastPlaybackTime.Value >= HoverDebounceTime;
|
||||
|
||||
if (HoverDebounceTime <= 0)
|
||||
if (enoughTimePassedSinceLastPlayback)
|
||||
{
|
||||
sampleHover?.Play();
|
||||
else
|
||||
playDelegate = Scheduler.AddDelayed(() => sampleHover?.Play(), HoverDebounceTime);
|
||||
|
||||
return base.OnHover(e);
|
||||
lastPlaybackTime.Value = Time.Current;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
sampleHover = audio.Samples.Get($@"UI/generic-hover{SampleSet.GetDescription()}");
|
||||
return base.OnHover(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,9 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Events;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
@ -17,22 +18,32 @@ namespace osu.Game.Graphics.UserInterface
|
||||
/// </summary>
|
||||
public class LoadingLayer : LoadingSpinner
|
||||
{
|
||||
private readonly Drawable dimTarget;
|
||||
[CanBeNull]
|
||||
protected Box BackgroundDimLayer { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Constuct a new loading spinner.
|
||||
/// Construct a new loading spinner.
|
||||
/// </summary>
|
||||
/// <param name="dimTarget">An optional target to dim when displayed.</param>
|
||||
/// <param name="dimBackground">Whether the full background area should be dimmed while loading.</param>
|
||||
/// <param name="withBox">Whether the spinner should have a surrounding black box for visibility.</param>
|
||||
public LoadingLayer(Drawable dimTarget = null, bool withBox = true)
|
||||
public LoadingLayer(bool dimBackground = false, bool withBox = true)
|
||||
: base(withBox)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
Size = new Vector2(1);
|
||||
|
||||
this.dimTarget = dimTarget;
|
||||
|
||||
MainContents.RelativeSizeAxes = Axes.None;
|
||||
|
||||
if (dimBackground)
|
||||
{
|
||||
AddInternal(BackgroundDimLayer = new Box
|
||||
{
|
||||
Depth = float.MaxValue,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override bool HandleNonPositionalInput => false;
|
||||
@ -56,31 +67,21 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
protected override void PopIn()
|
||||
{
|
||||
dimTarget?.FadeColour(OsuColour.Gray(0.5f), TRANSITION_DURATION, Easing.OutQuint);
|
||||
BackgroundDimLayer?.FadeTo(0.5f, TRANSITION_DURATION * 2, Easing.OutQuint);
|
||||
base.PopIn();
|
||||
}
|
||||
|
||||
protected override void PopOut()
|
||||
{
|
||||
dimTarget?.FadeColour(Color4.White, TRANSITION_DURATION, Easing.OutQuint);
|
||||
BackgroundDimLayer?.FadeOut(TRANSITION_DURATION, Easing.OutQuint);
|
||||
base.PopOut();
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
MainContents.Size = new Vector2(Math.Clamp(Math.Min(DrawWidth, DrawHeight) * 0.25f, 30, 100));
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
if (State.Value == Visibility.Visible)
|
||||
{
|
||||
// ensure we don't leave the target in a bad state.
|
||||
dimTarget?.FadeColour(Color4.White, TRANSITION_DURATION, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Input.Bindings
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.T }, GlobalAction.ToggleToolbar),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleDirect),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleBeatmapListing),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.N }, GlobalAction.ToggleNotifications),
|
||||
|
||||
new KeyBinding(InputKey.Escape, GlobalAction.Back),
|
||||
@ -112,8 +112,8 @@ namespace osu.Game.Input.Bindings
|
||||
[Description("Toggle settings")]
|
||||
ToggleSettings,
|
||||
|
||||
[Description("Toggle osu!direct")]
|
||||
ToggleDirect,
|
||||
[Description("Toggle beatmap listing")]
|
||||
ToggleBeatmapListing,
|
||||
|
||||
[Description("Increase volume")]
|
||||
IncreaseVolume,
|
||||
|
@ -31,7 +31,12 @@ namespace osu.Game.Online.API
|
||||
Acronym = mod.Acronym;
|
||||
|
||||
foreach (var (_, property) in mod.GetSettingsSourceProperties())
|
||||
Settings.Add(property.Name.Underscore(), property.GetValue(mod));
|
||||
{
|
||||
var bindable = (IBindable)property.GetValue(mod);
|
||||
|
||||
if (!bindable.IsDefault)
|
||||
Settings.Add(property.Name.Underscore(), bindable);
|
||||
}
|
||||
}
|
||||
|
||||
public Mod ToMod(Ruleset ruleset)
|
||||
@ -46,7 +51,7 @@ namespace osu.Game.Online.API
|
||||
if (!Settings.TryGetValue(property.Name.Underscore(), out object settingValue))
|
||||
continue;
|
||||
|
||||
((IBindable)property.GetValue(resultMod)).Parse(settingValue);
|
||||
resultMod.CopyAdjustedSetting((IBindable)property.GetValue(resultMod), settingValue);
|
||||
}
|
||||
|
||||
return resultMod;
|
||||
|
@ -88,11 +88,12 @@ namespace osu.Game.Online.Multiplayer
|
||||
{
|
||||
isConnected.Value = false;
|
||||
|
||||
if (ex != null)
|
||||
{
|
||||
Logger.Log($"Multiplayer client lost connection: {ex}", LoggingTarget.Network);
|
||||
Logger.Log(ex != null
|
||||
? $"Multiplayer client lost connection: {ex}"
|
||||
: "Multiplayer client disconnected", LoggingTarget.Network);
|
||||
|
||||
if (connection != null)
|
||||
await tryUntilConnected();
|
||||
}
|
||||
};
|
||||
|
||||
await tryUntilConnected();
|
||||
|
@ -151,11 +151,11 @@ namespace osu.Game
|
||||
updateBlockingOverlayFade();
|
||||
}
|
||||
|
||||
public void RemoveBlockingOverlay(OverlayContainer overlay)
|
||||
public void RemoveBlockingOverlay(OverlayContainer overlay) => Schedule(() =>
|
||||
{
|
||||
visibleBlockingOverlays.Remove(overlay);
|
||||
updateBlockingOverlayFade();
|
||||
}
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// Close all game-wide overlays.
|
||||
|
@ -48,11 +48,9 @@ namespace osu.Game.Overlays.AccountCreation
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
FillFlowContainer mainContent;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
mainContent = new FillFlowContainer
|
||||
new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
@ -124,7 +122,7 @@ namespace osu.Game.Overlays.AccountCreation
|
||||
},
|
||||
},
|
||||
},
|
||||
loadingLayer = new LoadingLayer(mainContent)
|
||||
loadingLayer = new LoadingLayer(true)
|
||||
};
|
||||
|
||||
textboxes = new[] { usernameTextBox, emailTextBox, passwordTextBox };
|
||||
|
@ -92,14 +92,14 @@ namespace osu.Game.Overlays
|
||||
{
|
||||
foundContent = new FillFlowContainer<BeatmapPanel>(),
|
||||
notFoundContent = new NotFoundDrawable(),
|
||||
loadingLayer = new LoadingLayer(panelTarget)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
loadingLayer = new LoadingLayer(true)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
Size = new Vector2(18),
|
||||
Shadow = false,
|
||||
},
|
||||
loading = new LoadingLayer(icon, false),
|
||||
loading = new LoadingLayer(true, false),
|
||||
});
|
||||
|
||||
Action = () =>
|
||||
|
@ -157,11 +157,11 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
loading = new LoadingLayer()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -228,7 +228,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
{
|
||||
Scores = null;
|
||||
notSupporterPlaceholder.Show();
|
||||
|
||||
loading.Hide();
|
||||
loading.FinishTransforms();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -241,6 +243,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
getScoresRequest.Success += scores =>
|
||||
{
|
||||
loading.Hide();
|
||||
loading.FinishTransforms();
|
||||
|
||||
Scores = scores;
|
||||
|
||||
if (!scores.Scores.Any())
|
||||
|
@ -128,7 +128,7 @@ namespace osu.Game.Overlays.Dashboard.Friends
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding { Horizontal = 50 }
|
||||
},
|
||||
loading = new LoadingLayer(itemsPlaceholder)
|
||||
loading = new LoadingLayer(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
}
|
||||
},
|
||||
loading = new LoadingLayer(content),
|
||||
loading = new LoadingLayer(true),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -52,9 +52,10 @@ namespace osu.Game.Overlays.Mods
|
||||
if (newIndex == selectedIndex) return false;
|
||||
|
||||
int direction = newIndex < selectedIndex ? -1 : 1;
|
||||
|
||||
bool beforeSelected = Selected;
|
||||
|
||||
Mod modBefore = SelectedMod ?? Mods[0];
|
||||
Mod previousSelection = SelectedMod ?? Mods[0];
|
||||
|
||||
if (newIndex >= Mods.Length)
|
||||
newIndex = -1;
|
||||
@ -65,22 +66,25 @@ namespace osu.Game.Overlays.Mods
|
||||
return false;
|
||||
|
||||
selectedIndex = newIndex;
|
||||
Mod modAfter = SelectedMod ?? Mods[0];
|
||||
|
||||
Mod newSelection = SelectedMod ?? Mods[0];
|
||||
|
||||
Schedule(() =>
|
||||
{
|
||||
if (beforeSelected != Selected)
|
||||
{
|
||||
iconsContainer.RotateTo(Selected ? 5f : 0f, 300, Easing.OutElastic);
|
||||
iconsContainer.ScaleTo(Selected ? 1.1f : 1f, 300, Easing.OutElastic);
|
||||
}
|
||||
|
||||
if (modBefore != modAfter)
|
||||
if (previousSelection != newSelection)
|
||||
{
|
||||
const float rotate_angle = 16;
|
||||
|
||||
foregroundIcon.RotateTo(rotate_angle * direction, mod_switch_duration, mod_switch_easing);
|
||||
backgroundIcon.RotateTo(-rotate_angle * direction, mod_switch_duration, mod_switch_easing);
|
||||
|
||||
backgroundIcon.Mod = modAfter;
|
||||
backgroundIcon.Mod = newSelection;
|
||||
|
||||
using (BeginDelayedSequence(mod_switch_duration, true))
|
||||
{
|
||||
@ -92,13 +96,15 @@ namespace osu.Game.Overlays.Mods
|
||||
.RotateTo(rotate_angle * direction)
|
||||
.RotateTo(0f, mod_switch_duration, mod_switch_easing);
|
||||
|
||||
Schedule(() => displayMod(modAfter));
|
||||
Schedule(() => displayMod(newSelection));
|
||||
}
|
||||
}
|
||||
|
||||
foregroundIcon.Selected.Value = Selected;
|
||||
});
|
||||
|
||||
SelectionChanged?.Invoke(SelectedMod);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -249,7 +249,7 @@ namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
Width = 180,
|
||||
Text = "Deselect All",
|
||||
Action = DeselectAll,
|
||||
Action = deselectAll,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
},
|
||||
@ -318,7 +318,7 @@ namespace osu.Game.Overlays.Mods
|
||||
sampleOff = audio.Samples.Get(@"UI/check-off");
|
||||
}
|
||||
|
||||
public void DeselectAll()
|
||||
private void deselectAll()
|
||||
{
|
||||
foreach (var section in ModSectionsContainer.Children)
|
||||
section.DeselectAll();
|
||||
@ -331,7 +331,7 @@ namespace osu.Game.Overlays.Mods
|
||||
/// </summary>
|
||||
/// <param name="modTypes">The types of <see cref="Mod"/>s which should be deselected.</param>
|
||||
/// <param name="immediate">Set to true to bypass animations and update selections immediately.</param>
|
||||
public void DeselectTypes(Type[] modTypes, bool immediate = false)
|
||||
private void deselectTypes(Type[] modTypes, bool immediate = false)
|
||||
{
|
||||
if (modTypes.Length == 0) return;
|
||||
|
||||
@ -438,7 +438,7 @@ namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
if (State.Value == Visibility.Visible) sampleOn?.Play();
|
||||
|
||||
DeselectTypes(selectedMod.IncompatibleMods, true);
|
||||
deselectTypes(selectedMod.IncompatibleMods, true);
|
||||
|
||||
if (selectedMod.RequiresConfiguration) ModSettingsContainer.Show();
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ namespace osu.Game.Overlays
|
||||
},
|
||||
},
|
||||
},
|
||||
loading = new LoadingLayer(content),
|
||||
loading = new LoadingLayer(true),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,7 @@ namespace osu.Game.Overlays.Rankings
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
InternalChild = new ReverseChildIDFillFlowContainer<Drawable>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
@ -68,7 +69,7 @@ namespace osu.Game.Overlays.Rankings
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Margin = new MarginPadding { Vertical = 10 }
|
||||
},
|
||||
loading = new LoadingLayer(content)
|
||||
loading = new LoadingLayer(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,8 @@ namespace osu.Game.Overlays
|
||||
Depth = -float.MaxValue
|
||||
})
|
||||
{
|
||||
loading = new LoadingLayer(true);
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
background = new Box
|
||||
@ -74,12 +76,12 @@ namespace osu.Game.Overlays
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Margin = new MarginPadding { Bottom = 10 }
|
||||
},
|
||||
loading = new LoadingLayer(contentContainer),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
loading
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -132,6 +132,15 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
scalingSettings.ForEach(s => bindPreviewEvent(s.Current));
|
||||
|
||||
windowModeDropdown.Current.ValueChanged += _ => updateResolutionDropdown();
|
||||
|
||||
windowModes.BindCollectionChanged((sender, args) =>
|
||||
{
|
||||
@ -141,8 +150,6 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
windowModeDropdown.Hide();
|
||||
}, true);
|
||||
|
||||
windowModeDropdown.Current.ValueChanged += _ => updateResolutionDropdown();
|
||||
|
||||
currentDisplay.BindValueChanged(display => Schedule(() =>
|
||||
{
|
||||
resolutions.RemoveRange(1, resolutions.Count - 1);
|
||||
@ -159,8 +166,6 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
updateResolutionDropdown();
|
||||
}), true);
|
||||
|
||||
scalingSettings.ForEach(s => bindPreviewEvent(s.Current));
|
||||
|
||||
scalingMode.BindValueChanged(mode =>
|
||||
{
|
||||
scalingSettings.ClearTransforms();
|
||||
@ -181,11 +186,6 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a delayed bindable which only updates when a condition is met.
|
||||
/// </summary>
|
||||
/// <param name="bindable">The config bindable.</param>
|
||||
/// <returns>A bindable which will propagate updates with a delay.</returns>
|
||||
private void bindPreviewEvent(Bindable<float> bindable)
|
||||
{
|
||||
bindable.ValueChanged += _ =>
|
||||
|
@ -0,0 +1,27 @@
|
||||
// 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.Game.Configuration;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Online
|
||||
{
|
||||
public class IntegrationSettings : SettingsSubsection
|
||||
{
|
||||
protected override string Header => "Integrations";
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new SettingsEnumDropdown<DiscordRichPresenceMode>
|
||||
{
|
||||
LabelText = "Discord Rich Presence",
|
||||
Current = config.GetBindable<DiscordRichPresenceMode>(OsuSetting.DiscordRichPresence)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -20,7 +20,8 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new WebSettings()
|
||||
new WebSettings(),
|
||||
new IntegrationSettings()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -2,15 +2,18 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Input.Bindings;
|
||||
|
||||
namespace osu.Game.Overlays.Toolbar
|
||||
{
|
||||
public class ToolbarBeatmapListingButton : ToolbarOverlayToggleButton
|
||||
{
|
||||
protected override Anchor TooltipAnchor => Anchor.TopRight;
|
||||
|
||||
public ToolbarBeatmapListingButton()
|
||||
{
|
||||
Hotkey = GlobalAction.ToggleDirect;
|
||||
Hotkey = GlobalAction.ToggleBeatmapListing;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
|
@ -2,11 +2,14 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Toolbar
|
||||
{
|
||||
public class ToolbarChangelogButton : ToolbarOverlayToggleButton
|
||||
{
|
||||
protected override Anchor TooltipAnchor => Anchor.TopRight;
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(ChangelogOverlay changelog)
|
||||
{
|
||||
|
@ -2,12 +2,15 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Input.Bindings;
|
||||
|
||||
namespace osu.Game.Overlays.Toolbar
|
||||
{
|
||||
public class ToolbarChatButton : ToolbarOverlayToggleButton
|
||||
{
|
||||
protected override Anchor TooltipAnchor => Anchor.TopRight;
|
||||
|
||||
public ToolbarChatButton()
|
||||
{
|
||||
Hotkey = GlobalAction.ToggleChat;
|
||||
|
@ -2,11 +2,14 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Toolbar
|
||||
{
|
||||
public class ToolbarNewsButton : ToolbarOverlayToggleButton
|
||||
{
|
||||
protected override Anchor TooltipAnchor => Anchor.TopRight;
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(NewsOverlay news)
|
||||
{
|
||||
|
@ -2,11 +2,14 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Toolbar
|
||||
{
|
||||
public class ToolbarRankingsButton : ToolbarOverlayToggleButton
|
||||
{
|
||||
protected override Anchor TooltipAnchor => Anchor.TopRight;
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(RankingsOverlay rankings)
|
||||
{
|
||||
|
@ -2,12 +2,15 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Input.Bindings;
|
||||
|
||||
namespace osu.Game.Overlays.Toolbar
|
||||
{
|
||||
public class ToolbarSocialButton : ToolbarOverlayToggleButton
|
||||
{
|
||||
protected override Anchor TooltipAnchor => Anchor.TopRight;
|
||||
|
||||
public ToolbarSocialButton()
|
||||
{
|
||||
Hotkey = GlobalAction.ToggleSocial;
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
@ -84,12 +83,10 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
foreach ((SettingSourceAttribute attr, PropertyInfo property) in this.GetOrderedSettingsSourceProperties())
|
||||
{
|
||||
object bindableObj = property.GetValue(this);
|
||||
var bindable = (IBindable)property.GetValue(this);
|
||||
|
||||
if ((bindableObj as IHasDefaultValue)?.IsDefault == true)
|
||||
continue;
|
||||
|
||||
tooltipTexts.Add($"{attr.Label} {bindableObj}");
|
||||
if (!bindable.IsDefault)
|
||||
tooltipTexts.Add($"{attr.Label} {bindable}");
|
||||
}
|
||||
|
||||
return string.Join(", ", tooltipTexts.Where(s => !string.IsNullOrEmpty(s)));
|
||||
@ -147,17 +144,36 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
foreach (var (_, prop) in this.GetSettingsSourceProperties())
|
||||
{
|
||||
var ourBindable = prop.GetValue(this);
|
||||
var theirBindable = prop.GetValue(them);
|
||||
var origBindable = (IBindable)prop.GetValue(this);
|
||||
var copyBindable = (IBindable)prop.GetValue(copy);
|
||||
|
||||
// The bindables themselves are readonly, so the value must be transferred through the Bindable<T>.Value property.
|
||||
var valueProperty = ourBindable.GetType().GetProperty(nameof(Bindable<object>.Value), BindingFlags.Public | BindingFlags.Instance);
|
||||
Debug.Assert(valueProperty != null);
|
||||
|
||||
valueProperty.SetValue(ourBindable, valueProperty.GetValue(theirBindable));
|
||||
// we only care about changes that have been made away from defaults.
|
||||
if (!origBindable.IsDefault)
|
||||
copy.CopyAdjustedSetting(copyBindable, origBindable);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When creating copies or clones of a Mod, this method will be called
|
||||
/// to copy explicitly adjusted user settings from <paramref name="target"/>.
|
||||
/// The base implementation will transfer the value via <see cref="Bindable{T}.Parse"/>
|
||||
/// or by binding and unbinding (if <paramref name="source"/> is an <see cref="IBindable"/>)
|
||||
/// and should be called unless replaced with custom logic.
|
||||
/// </summary>
|
||||
/// <param name="target">The target bindable to apply the adjustment to.</param>
|
||||
/// <param name="source">The adjustment to apply.</param>
|
||||
internal virtual void CopyAdjustedSetting(IBindable target, object source)
|
||||
{
|
||||
if (source is IBindable sourceBindable)
|
||||
{
|
||||
// copy including transfer of default values.
|
||||
target.BindTo(sourceBindable);
|
||||
target.UnbindFrom(sourceBindable);
|
||||
}
|
||||
else
|
||||
target.Parse(source);
|
||||
}
|
||||
|
||||
public bool Equals(IMod other) => GetType() == other?.GetType();
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
public void ApplyToPlayer(Player player)
|
||||
{
|
||||
player.Background.EnableUserDim.Value = false;
|
||||
player.ApplyToBackground(b => b.EnableUserDim.Value = false);
|
||||
|
||||
player.DimmableStoryboard.IgnoreUserSettings.Value = true;
|
||||
|
||||
|
@ -114,14 +114,32 @@ namespace osu.Game.Rulesets.Mods
|
||||
bindable.ValueChanged += _ => userChangedSettings[bindable] = !bindable.IsDefault;
|
||||
}
|
||||
|
||||
internal override void CopyAdjustedSetting(IBindable target, object source)
|
||||
{
|
||||
// if the value is non-bindable, it's presumably coming from an external source (like the API) - therefore presume it is not default.
|
||||
// if the value is bindable, defer to the source's IsDefault to be able to tell.
|
||||
userChangedSettings[target] = !(source is IBindable bindableSource) || !bindableSource.IsDefault;
|
||||
base.CopyAdjustedSetting(target, source);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a setting from a configuration bindable using <paramref name="applyFunc"/>, if it has been changed by the user.
|
||||
/// </summary>
|
||||
protected void ApplySetting<T>(BindableNumber<T> setting, Action<T> applyFunc)
|
||||
where T : struct, IComparable<T>, IConvertible, IEquatable<T>
|
||||
{
|
||||
if (userChangedSettings.TryGetValue(setting, out bool userChangedSetting) && userChangedSetting)
|
||||
applyFunc.Invoke(setting.Value);
|
||||
}
|
||||
|
||||
/// <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;
|
||||
ApplySetting(DrainRate, dr => difficulty.DrainRate = dr);
|
||||
ApplySetting(OverallDifficulty, od => difficulty.OverallDifficulty = od);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -750,7 +750,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
if (Result.Type != originalType)
|
||||
{
|
||||
Logger.Log($"{GetType().ReadableName()} applied an invalid hit result ({originalType}) when {nameof(HitResult.IgnoreMiss)} or {nameof(HitResult.IgnoreHit)} is expected.\n"
|
||||
+ $"This has been automatically adjusted to {Result.Type}, and support will be removed from 2020-03-28 onwards.", level: LogLevel.Important);
|
||||
+ $"This has been automatically adjusted to {Result.Type}, and support will be removed from 2021-03-28 onwards.", level: LogLevel.Important);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,10 +10,7 @@ using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Legacy
|
||||
{
|
||||
internal abstract class ConvertSlider : ConvertHitObject, IHasPathWithRepeats, IHasLegacyLastTickOffset,
|
||||
#pragma warning disable 618
|
||||
IHasCurve
|
||||
#pragma warning restore 618
|
||||
internal abstract class ConvertSlider : ConvertHitObject, IHasPathWithRepeats, IHasLegacyLastTickOffset
|
||||
{
|
||||
/// <summary>
|
||||
/// Scoring distance with a speed-adjusted beat length of 1 second.
|
||||
|
@ -1,55 +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 osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Types
|
||||
{
|
||||
[Obsolete("Use IHasPathWithRepeats instead.")] // can be removed 20201126
|
||||
public interface IHasCurve : IHasDistance, IHasRepeats
|
||||
{
|
||||
/// <summary>
|
||||
/// The curve.
|
||||
/// </summary>
|
||||
SliderPath Path { get; }
|
||||
}
|
||||
|
||||
#pragma warning disable 618
|
||||
[Obsolete("Use IHasPathWithRepeats instead.")] // can be removed 20201126
|
||||
public static class HasCurveExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Computes the position on the curve relative to how much of the <see cref="HitObject"/> has been completed.
|
||||
/// </summary>
|
||||
/// <param name="obj">The curve.</param>
|
||||
/// <param name="progress">[0, 1] where 0 is the start time of the <see cref="HitObject"/> and 1 is the end time of the <see cref="HitObject"/>.</param>
|
||||
/// <returns>The position on the curve.</returns>
|
||||
public static Vector2 CurvePositionAt(this IHasCurve obj, double progress)
|
||||
=> obj.Path.PositionAt(obj.ProgressAt(progress));
|
||||
|
||||
/// <summary>
|
||||
/// Computes the progress along the curve relative to how much of the <see cref="HitObject"/> has been completed.
|
||||
/// </summary>
|
||||
/// <param name="obj">The curve.</param>
|
||||
/// <param name="progress">[0, 1] where 0 is the start time of the <see cref="HitObject"/> and 1 is the end time of the <see cref="HitObject"/>.</param>
|
||||
/// <returns>[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</returns>
|
||||
public static double ProgressAt(this IHasCurve obj, double progress)
|
||||
{
|
||||
double p = progress * obj.SpanCount() % 1;
|
||||
if (obj.SpanAt(progress) % 2 == 1)
|
||||
p = 1 - p;
|
||||
return p;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines which span of the curve the progress point is on.
|
||||
/// </summary>
|
||||
/// <param name="obj">The curve.</param>
|
||||
/// <param name="progress">[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</param>
|
||||
/// <returns>[0, SpanCount) where 0 is the first run.</returns>
|
||||
public static int SpanAt(this IHasCurve obj, double progress)
|
||||
=> (int)(progress * obj.SpanCount());
|
||||
}
|
||||
#pragma warning restore 618
|
||||
}
|
@ -6,26 +6,16 @@ namespace osu.Game.Rulesets.Objects.Types
|
||||
/// <summary>
|
||||
/// A HitObject that ends at a different time than its start time.
|
||||
/// </summary>
|
||||
#pragma warning disable 618
|
||||
public interface IHasDuration : IHasEndTime
|
||||
#pragma warning restore 618
|
||||
public interface IHasDuration
|
||||
{
|
||||
double IHasEndTime.EndTime
|
||||
{
|
||||
get => EndTime;
|
||||
set => Duration = (Duration - EndTime) + value;
|
||||
}
|
||||
|
||||
double IHasEndTime.Duration => Duration;
|
||||
|
||||
/// <summary>
|
||||
/// The time at which the HitObject ends.
|
||||
/// </summary>
|
||||
new double EndTime { get; }
|
||||
double EndTime { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The duration of the HitObject.
|
||||
/// </summary>
|
||||
new double Duration { get; set; }
|
||||
double Duration { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// A HitObject that ends at a different time than its start time.
|
||||
/// </summary>
|
||||
[Obsolete("Use IHasDuration instead.")] // can be removed 20201126
|
||||
public interface IHasEndTime
|
||||
{
|
||||
/// <summary>
|
||||
/// The time at which the HitObject ends.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
double EndTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The duration of the HitObject.
|
||||
/// </summary>
|
||||
double Duration { get; }
|
||||
}
|
||||
}
|
@ -100,9 +100,7 @@ namespace osu.Game.Rulesets
|
||||
|
||||
foreach (var r in instances.Where(r => !(r is ILegacyRuleset)))
|
||||
{
|
||||
// todo: StartsWith can be changed to Equals on 2020-11-08
|
||||
// This is to give users enough time to have their database use new abbreviated info).
|
||||
if (existingRulesets.FirstOrDefault(ri => ri.InstantiationInfo.StartsWith(r.RulesetInfo.InstantiationInfo, StringComparison.Ordinal)) == null)
|
||||
if (existingRulesets.FirstOrDefault(ri => ri.InstantiationInfo.Equals(r.RulesetInfo.InstantiationInfo, StringComparison.Ordinal)) == null)
|
||||
context.RulesetInfo.Add(r.RulesetInfo);
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,12 @@ namespace osu.Game.Screens
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply arbitrary changes to this background in a thread safe manner.
|
||||
/// </summary>
|
||||
/// <param name="action">The operation to perform.</param>
|
||||
public void ApplyToBackground(Action<BackgroundScreen> action) => Schedule(() => action.Invoke(this));
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
@ -16,6 +16,9 @@ namespace osu.Game.Screens.Edit.Compose
|
||||
{
|
||||
public class ComposeScreen : EditorScreenWithTimeline
|
||||
{
|
||||
[Resolved]
|
||||
private IBindable<WorkingBeatmap> beatmap { get; set; }
|
||||
|
||||
private HitObjectComposer composer;
|
||||
|
||||
public ComposeScreen()
|
||||
@ -59,7 +62,7 @@ namespace osu.Game.Screens.Edit.Compose
|
||||
{
|
||||
Debug.Assert(ruleset != null);
|
||||
|
||||
var beatmapSkinProvider = new BeatmapSkinProvidingContainer(Beatmap.Value.Skin);
|
||||
var beatmapSkinProvider = new BeatmapSkinProvidingContainer(beatmap.Value.Skin);
|
||||
|
||||
// the beatmapSkinProvider is used as the fallback source here to allow the ruleset-specific skin implementation
|
||||
// full access to all skin sources.
|
||||
|
@ -444,11 +444,14 @@ namespace osu.Game.Screens.Edit
|
||||
{
|
||||
base.OnEntering(last);
|
||||
|
||||
ApplyToBackground(b =>
|
||||
{
|
||||
// todo: temporary. we want to be applying dim using the UserDimContainer eventually.
|
||||
Background.FadeColour(Color4.DarkGray, 500);
|
||||
b.FadeColour(Color4.DarkGray, 500);
|
||||
|
||||
Background.EnableUserDim.Value = false;
|
||||
Background.BlurAmount.Value = 0;
|
||||
b.EnableUserDim.Value = false;
|
||||
b.BlurAmount.Value = 0;
|
||||
});
|
||||
|
||||
resetTrack(true);
|
||||
}
|
||||
@ -480,9 +483,11 @@ namespace osu.Game.Screens.Edit
|
||||
}
|
||||
}
|
||||
|
||||
Background.FadeColour(Color4.White, 500);
|
||||
ApplyToBackground(b => b.FadeColour(Color4.White, 500));
|
||||
resetTrack();
|
||||
|
||||
Beatmap.Value = beatmapManager.GetWorkingBeatmap(Beatmap.Value.BeatmapInfo);
|
||||
|
||||
return base.OnExiting(next);
|
||||
}
|
||||
|
||||
|
@ -2,10 +2,8 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
|
||||
namespace osu.Game.Screens.Edit
|
||||
{
|
||||
@ -14,9 +12,6 @@ namespace osu.Game.Screens.Edit
|
||||
/// </summary>
|
||||
public abstract class EditorScreen : Container
|
||||
{
|
||||
[Resolved]
|
||||
protected IBindable<WorkingBeatmap> Beatmap { get; private set; }
|
||||
|
||||
[Resolved]
|
||||
protected EditorBeatmap EditorBeatmap { get; private set; }
|
||||
|
||||
|
@ -30,16 +30,16 @@ namespace osu.Game.Screens.Edit
|
||||
{
|
||||
}
|
||||
|
||||
private Container mainContent;
|
||||
|
||||
private LoadingSpinner spinner;
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load([CanBeNull] BindableBeatDivisor beatDivisor)
|
||||
{
|
||||
if (beatDivisor != null)
|
||||
this.beatDivisor.BindTo(beatDivisor);
|
||||
|
||||
Container mainContent;
|
||||
|
||||
LoadingSpinner spinner;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
mainContent = new Container
|
||||
@ -99,6 +99,11 @@ namespace osu.Game.Screens.Edit
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
LoadComponentAsync(CreateMainContent(), content =>
|
||||
{
|
||||
|
@ -13,9 +13,6 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
{
|
||||
internal class DifficultySection : SetupSection
|
||||
{
|
||||
[Resolved]
|
||||
private EditorBeatmap editorBeatmap { get; set; }
|
||||
|
||||
private LabelledSliderBar<float> circleSizeSlider;
|
||||
private LabelledSliderBar<float> healthDrainSlider;
|
||||
private LabelledSliderBar<float> approachRateSlider;
|
||||
@ -34,7 +31,7 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
{
|
||||
Label = "Object Size",
|
||||
Description = "The size of all hit objects",
|
||||
Current = new BindableFloat(Beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize)
|
||||
Current = new BindableFloat(Beatmap.BeatmapInfo.BaseDifficulty.CircleSize)
|
||||
{
|
||||
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
|
||||
MinValue = 0,
|
||||
@ -46,7 +43,7 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
{
|
||||
Label = "Health Drain",
|
||||
Description = "The rate of passive health drain throughout playable time",
|
||||
Current = new BindableFloat(Beatmap.Value.BeatmapInfo.BaseDifficulty.DrainRate)
|
||||
Current = new BindableFloat(Beatmap.BeatmapInfo.BaseDifficulty.DrainRate)
|
||||
{
|
||||
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
|
||||
MinValue = 0,
|
||||
@ -58,7 +55,7 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
{
|
||||
Label = "Approach Rate",
|
||||
Description = "The speed at which objects are presented to the player",
|
||||
Current = new BindableFloat(Beatmap.Value.BeatmapInfo.BaseDifficulty.ApproachRate)
|
||||
Current = new BindableFloat(Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate)
|
||||
{
|
||||
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
|
||||
MinValue = 0,
|
||||
@ -70,7 +67,7 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
{
|
||||
Label = "Overall Difficulty",
|
||||
Description = "The harshness of hit windows and difficulty of special objects (ie. spinners)",
|
||||
Current = new BindableFloat(Beatmap.Value.BeatmapInfo.BaseDifficulty.OverallDifficulty)
|
||||
Current = new BindableFloat(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty)
|
||||
{
|
||||
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
|
||||
MinValue = 0,
|
||||
@ -88,12 +85,12 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
{
|
||||
// for now, update these on commit rather than making BeatmapMetadata bindables.
|
||||
// after switching database engines we can reconsider if switching to bindables is a good direction.
|
||||
Beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize = circleSizeSlider.Current.Value;
|
||||
Beatmap.Value.BeatmapInfo.BaseDifficulty.DrainRate = healthDrainSlider.Current.Value;
|
||||
Beatmap.Value.BeatmapInfo.BaseDifficulty.ApproachRate = approachRateSlider.Current.Value;
|
||||
Beatmap.Value.BeatmapInfo.BaseDifficulty.OverallDifficulty = overallDifficultySlider.Current.Value;
|
||||
Beatmap.BeatmapInfo.BaseDifficulty.CircleSize = circleSizeSlider.Current.Value;
|
||||
Beatmap.BeatmapInfo.BaseDifficulty.DrainRate = healthDrainSlider.Current.Value;
|
||||
Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate = approachRateSlider.Current.Value;
|
||||
Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty = overallDifficultySlider.Current.Value;
|
||||
|
||||
editorBeatmap.UpdateAllHitObjects();
|
||||
Beatmap.UpdateAllHitObjects();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,25 +29,25 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
artistTextBox = new LabelledTextBox
|
||||
{
|
||||
Label = "Artist",
|
||||
Current = { Value = Beatmap.Value.Metadata.Artist },
|
||||
Current = { Value = Beatmap.Metadata.Artist },
|
||||
TabbableContentContainer = this
|
||||
},
|
||||
titleTextBox = new LabelledTextBox
|
||||
{
|
||||
Label = "Title",
|
||||
Current = { Value = Beatmap.Value.Metadata.Title },
|
||||
Current = { Value = Beatmap.Metadata.Title },
|
||||
TabbableContentContainer = this
|
||||
},
|
||||
creatorTextBox = new LabelledTextBox
|
||||
{
|
||||
Label = "Creator",
|
||||
Current = { Value = Beatmap.Value.Metadata.AuthorString },
|
||||
Current = { Value = Beatmap.Metadata.AuthorString },
|
||||
TabbableContentContainer = this
|
||||
},
|
||||
difficultyTextBox = new LabelledTextBox
|
||||
{
|
||||
Label = "Difficulty Name",
|
||||
Current = { Value = Beatmap.Value.BeatmapInfo.Version },
|
||||
Current = { Value = Beatmap.BeatmapInfo.Version },
|
||||
TabbableContentContainer = this
|
||||
},
|
||||
};
|
||||
@ -62,10 +62,10 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
|
||||
// for now, update these on commit rather than making BeatmapMetadata bindables.
|
||||
// after switching database engines we can reconsider if switching to bindables is a good direction.
|
||||
Beatmap.Value.Metadata.Artist = artistTextBox.Current.Value;
|
||||
Beatmap.Value.Metadata.Title = titleTextBox.Current.Value;
|
||||
Beatmap.Value.Metadata.AuthorString = creatorTextBox.Current.Value;
|
||||
Beatmap.Value.BeatmapInfo.Version = difficultyTextBox.Current.Value;
|
||||
Beatmap.Metadata.Artist = artistTextBox.Current.Value;
|
||||
Beatmap.Metadata.Title = titleTextBox.Current.Value;
|
||||
Beatmap.Metadata.AuthorString = creatorTextBox.Current.Value;
|
||||
Beatmap.BeatmapInfo.Version = difficultyTextBox.Current.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,9 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
[Resolved]
|
||||
private BeatmapManager beatmaps { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private IBindable<WorkingBeatmap> working { get; set; }
|
||||
|
||||
[Resolved(canBeNull: true)]
|
||||
private Editor editor { get; set; }
|
||||
|
||||
@ -70,7 +73,7 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
audioTrackTextBox = new FileChooserLabelledTextBox
|
||||
{
|
||||
Label = "Audio Track",
|
||||
Current = { Value = Beatmap.Value.Metadata.AudioFile ?? "Click to select a track" },
|
||||
Current = { Value = working.Value.Metadata.AudioFile ?? "Click to select a track" },
|
||||
Target = audioTrackFileChooserContainer,
|
||||
TabbableContentContainer = this
|
||||
},
|
||||
@ -115,11 +118,11 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
if (!info.Exists)
|
||||
return false;
|
||||
|
||||
var set = Beatmap.Value.BeatmapSetInfo;
|
||||
var set = working.Value.BeatmapSetInfo;
|
||||
|
||||
// remove the previous background for now.
|
||||
// in the future we probably want to check if this is being used elsewhere (other difficulties?)
|
||||
var oldFile = set.Files.FirstOrDefault(f => f.Filename == Beatmap.Value.Metadata.BackgroundFile);
|
||||
var oldFile = set.Files.FirstOrDefault(f => f.Filename == working.Value.Metadata.BackgroundFile);
|
||||
|
||||
using (var stream = info.OpenRead())
|
||||
{
|
||||
@ -129,7 +132,7 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
beatmaps.AddFile(set, stream, info.Name);
|
||||
}
|
||||
|
||||
Beatmap.Value.Metadata.BackgroundFile = info.Name;
|
||||
working.Value.Metadata.BackgroundFile = info.Name;
|
||||
updateBackgroundSprite();
|
||||
|
||||
return true;
|
||||
@ -148,11 +151,11 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
if (!info.Exists)
|
||||
return false;
|
||||
|
||||
var set = Beatmap.Value.BeatmapSetInfo;
|
||||
var set = working.Value.BeatmapSetInfo;
|
||||
|
||||
// remove the previous audio track for now.
|
||||
// in the future we probably want to check if this is being used elsewhere (other difficulties?)
|
||||
var oldFile = set.Files.FirstOrDefault(f => f.Filename == Beatmap.Value.Metadata.AudioFile);
|
||||
var oldFile = set.Files.FirstOrDefault(f => f.Filename == working.Value.Metadata.AudioFile);
|
||||
|
||||
using (var stream = info.OpenRead())
|
||||
{
|
||||
@ -162,7 +165,7 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
beatmaps.AddFile(set, stream, info.Name);
|
||||
}
|
||||
|
||||
Beatmap.Value.Metadata.AudioFile = info.Name;
|
||||
working.Value.Metadata.AudioFile = info.Name;
|
||||
|
||||
music.ReloadCurrentTrack();
|
||||
|
||||
@ -178,7 +181,7 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
|
||||
private void updateBackgroundSprite()
|
||||
{
|
||||
LoadComponentAsync(new BeatmapBackgroundSprite(Beatmap.Value)
|
||||
LoadComponentAsync(new BeatmapBackgroundSprite(working.Value)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.Centre,
|
||||
|
@ -2,10 +2,8 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osuTK;
|
||||
|
||||
@ -19,7 +17,7 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
protected OsuColour Colours { get; private set; }
|
||||
|
||||
[Resolved]
|
||||
protected IBindable<WorkingBeatmap> Beatmap { get; private set; }
|
||||
protected EditorBeatmap Beatmap { get; private set; }
|
||||
|
||||
protected override Container<Drawable> Content => flow;
|
||||
|
||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
|
||||
protected override DifficultyControlPoint CreatePoint()
|
||||
{
|
||||
var reference = Beatmap.Value.Beatmap.ControlPointInfo.DifficultyPointAt(SelectedGroup.Value.Time);
|
||||
var reference = Beatmap.ControlPointInfo.DifficultyPointAt(SelectedGroup.Value.Time);
|
||||
|
||||
return new DifficultyControlPoint
|
||||
{
|
||||
|
@ -37,7 +37,7 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
|
||||
protected override EffectControlPoint CreatePoint()
|
||||
{
|
||||
var reference = Beatmap.Value.Beatmap.ControlPointInfo.EffectPointAt(SelectedGroup.Value.Time);
|
||||
var reference = Beatmap.ControlPointInfo.EffectPointAt(SelectedGroup.Value.Time);
|
||||
|
||||
return new EffectControlPoint
|
||||
{
|
||||
|
@ -6,7 +6,6 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.UserInterfaceV2;
|
||||
@ -24,7 +23,7 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
protected Bindable<ControlPointGroup> SelectedGroup { get; private set; }
|
||||
|
||||
[Resolved]
|
||||
protected IBindable<WorkingBeatmap> Beatmap { get; private set; }
|
||||
protected EditorBeatmap Beatmap { get; private set; }
|
||||
|
||||
[Resolved]
|
||||
private EditorClock clock { get; set; }
|
||||
@ -107,13 +106,13 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
|
||||
var currentGroupItems = SelectedGroup.Value.ControlPoints.ToArray();
|
||||
|
||||
Beatmap.Value.Beatmap.ControlPointInfo.RemoveGroup(SelectedGroup.Value);
|
||||
Beatmap.ControlPointInfo.RemoveGroup(SelectedGroup.Value);
|
||||
|
||||
foreach (var cp in currentGroupItems)
|
||||
Beatmap.Value.Beatmap.ControlPointInfo.Add(time, cp);
|
||||
Beatmap.ControlPointInfo.Add(time, cp);
|
||||
|
||||
// the control point might not necessarily exist yet, if currentGroupItems was empty.
|
||||
SelectedGroup.Value = Beatmap.Value.Beatmap.ControlPointInfo.GroupAt(time, true);
|
||||
SelectedGroup.Value = Beatmap.ControlPointInfo.GroupAt(time, true);
|
||||
|
||||
changeHandler?.EndChange();
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
|
||||
protected override SampleControlPoint CreatePoint()
|
||||
{
|
||||
var reference = Beatmap.Value.Beatmap.ControlPointInfo.SamplePointAt(SelectedGroup.Value.Time);
|
||||
var reference = Beatmap.ControlPointInfo.SamplePointAt(SelectedGroup.Value.Time);
|
||||
|
||||
return new SampleControlPoint
|
||||
{
|
||||
|
@ -7,7 +7,6 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
@ -27,7 +26,7 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
private const float header_height = 20;
|
||||
|
||||
[Resolved]
|
||||
protected IBindable<WorkingBeatmap> Beatmap { get; private set; }
|
||||
protected EditorBeatmap Beatmap { get; private set; }
|
||||
|
||||
[Resolved]
|
||||
protected Bindable<ControlPointGroup> SelectedGroup { get; private set; }
|
||||
|
@ -7,7 +7,6 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
@ -62,7 +61,7 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
private EditorClock clock { get; set; }
|
||||
|
||||
[Resolved]
|
||||
protected IBindable<WorkingBeatmap> Beatmap { get; private set; }
|
||||
protected EditorBeatmap Beatmap { get; private set; }
|
||||
|
||||
[Resolved]
|
||||
private Bindable<ControlPointGroup> selectedGroup { get; set; }
|
||||
@ -124,7 +123,7 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
|
||||
selectedGroup.BindValueChanged(selected => { deleteButton.Enabled.Value = selected.NewValue != null; }, true);
|
||||
|
||||
controlPointGroups.BindTo(Beatmap.Value.Beatmap.ControlPointInfo.Groups);
|
||||
controlPointGroups.BindTo(Beatmap.ControlPointInfo.Groups);
|
||||
controlPointGroups.BindCollectionChanged((sender, args) =>
|
||||
{
|
||||
table.ControlGroups = controlPointGroups;
|
||||
@ -137,14 +136,14 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
if (selectedGroup.Value == null)
|
||||
return;
|
||||
|
||||
Beatmap.Value.Beatmap.ControlPointInfo.RemoveGroup(selectedGroup.Value);
|
||||
Beatmap.ControlPointInfo.RemoveGroup(selectedGroup.Value);
|
||||
|
||||
selectedGroup.Value = Beatmap.Value.Beatmap.ControlPointInfo.Groups.FirstOrDefault(g => g.Time >= clock.CurrentTime);
|
||||
selectedGroup.Value = Beatmap.ControlPointInfo.Groups.FirstOrDefault(g => g.Time >= clock.CurrentTime);
|
||||
}
|
||||
|
||||
private void addNew()
|
||||
{
|
||||
selectedGroup.Value = Beatmap.Value.Beatmap.ControlPointInfo.GroupAt(clock.CurrentTime, true);
|
||||
selectedGroup.Value = Beatmap.ControlPointInfo.GroupAt(clock.CurrentTime, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
|
||||
protected override TimingControlPoint CreatePoint()
|
||||
{
|
||||
var reference = Beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(SelectedGroup.Value.Time);
|
||||
var reference = Beatmap.ControlPointInfo.TimingPointAt(SelectedGroup.Value.Time);
|
||||
|
||||
return new TimingControlPoint
|
||||
{
|
||||
|
@ -129,8 +129,8 @@ namespace osu.Game.Screens.Menu
|
||||
buttonsPlay.ForEach(b => b.VisibleState = ButtonSystemState.Play);
|
||||
|
||||
buttonsTopLevel.Add(new Button(@"play", @"button-play-select", OsuIcon.Logo, new Color4(102, 68, 204, 255), () => State = ButtonSystemState.Play, WEDGE_WIDTH, Key.P));
|
||||
buttonsTopLevel.Add(new Button(@"osu!editor", @"button-generic-select", OsuIcon.EditCircle, new Color4(238, 170, 0, 255), () => OnEdit?.Invoke(), 0, Key.E));
|
||||
buttonsTopLevel.Add(new Button(@"osu!direct", @"button-direct-select", OsuIcon.ChevronDownCircle, new Color4(165, 204, 0, 255), () => OnBeatmapListing?.Invoke(), 0, Key.D));
|
||||
buttonsTopLevel.Add(new Button(@"edit", @"button-generic-select", OsuIcon.EditCircle, new Color4(238, 170, 0, 255), () => OnEdit?.Invoke(), 0, Key.E));
|
||||
buttonsTopLevel.Add(new Button(@"browse", @"button-direct-select", OsuIcon.ChevronDownCircle, new Color4(165, 204, 0, 255), () => OnBeatmapListing?.Invoke(), 0, Key.D));
|
||||
|
||||
if (host.CanExit)
|
||||
buttonsTopLevel.Add(new Button(@"exit", string.Empty, OsuIcon.CrossCircle, new Color4(238, 51, 153, 255), () => OnExit?.Invoke(), 0, Key.Q));
|
||||
|
@ -201,7 +201,7 @@ namespace osu.Game.Screens.Menu
|
||||
"New features are coming online every update. Make sure to stay up-to-date!",
|
||||
"If you find the UI too large or small, try adjusting UI scale in settings!",
|
||||
"Try adjusting the \"Screen Scaling\" mode to change your gameplay or UI area, even in fullscreen!",
|
||||
"For now, osu!direct is available to all users on lazer. You can access it anywhere using Ctrl-D!",
|
||||
"For now, what used to be \"osu!direct\" is available to all users on lazer. You can access it anywhere using Ctrl-D!",
|
||||
"Seeking in replays is available by dragging on the difficulty bar at the bottom of the screen!",
|
||||
"Multithreading support means that even with low \"FPS\" your input and judgements will be accurate!",
|
||||
"Try scrolling down in the mod select panel to find a bunch of new fun mods!",
|
||||
|
@ -127,11 +127,11 @@ namespace osu.Game.Screens.Menu
|
||||
{
|
||||
case ButtonSystemState.Initial:
|
||||
case ButtonSystemState.Exit:
|
||||
Background.FadeColour(Color4.White, 500, Easing.OutSine);
|
||||
ApplyToBackground(b => b.FadeColour(Color4.White, 500, Easing.OutSine));
|
||||
break;
|
||||
|
||||
default:
|
||||
Background.FadeColour(OsuColour.Gray(0.8f), 500, Easing.OutSine);
|
||||
ApplyToBackground(b => b.FadeColour(OsuColour.Gray(0.8f), 500, Easing.OutSine));
|
||||
break;
|
||||
}
|
||||
};
|
||||
@ -256,7 +256,7 @@ namespace osu.Game.Screens.Menu
|
||||
{
|
||||
base.OnResuming(last);
|
||||
|
||||
(Background as BackgroundScreenDefault)?.Next();
|
||||
ApplyToBackground(b => (b as BackgroundScreenDefault)?.Next());
|
||||
|
||||
// we may have consumed our preloaded instance, so let's make another.
|
||||
preloadSongSelect();
|
||||
|
@ -2,8 +2,6 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -41,38 +39,21 @@ namespace osu.Game.Screens.OnlinePlay.Components
|
||||
SelectedItem.BindValueChanged(item => updateSelectedItem(item.NewValue), true);
|
||||
}
|
||||
|
||||
private void updateSelectedItem(PlaylistItem item)
|
||||
{
|
||||
hasBeatmap = findBeatmap(expr => beatmaps.QueryBeatmap(expr));
|
||||
}
|
||||
private void updateSelectedItem(PlaylistItem _) => Scheduler.AddOnce(updateBeatmapState);
|
||||
private void beatmapUpdated(ValueChangedEvent<WeakReference<BeatmapSetInfo>> _) => Scheduler.AddOnce(updateBeatmapState);
|
||||
private void beatmapRemoved(ValueChangedEvent<WeakReference<BeatmapSetInfo>> _) => Scheduler.AddOnce(updateBeatmapState);
|
||||
|
||||
private void beatmapUpdated(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakSet)
|
||||
{
|
||||
if (weakSet.NewValue.TryGetTarget(out var set))
|
||||
{
|
||||
if (findBeatmap(expr => set.Beatmaps.AsQueryable().FirstOrDefault(expr)))
|
||||
Schedule(() => hasBeatmap = true);
|
||||
}
|
||||
}
|
||||
|
||||
private void beatmapRemoved(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakSet)
|
||||
{
|
||||
if (weakSet.NewValue.TryGetTarget(out var set))
|
||||
{
|
||||
if (findBeatmap(expr => set.Beatmaps.AsQueryable().FirstOrDefault(expr)))
|
||||
Schedule(() => hasBeatmap = false);
|
||||
}
|
||||
}
|
||||
|
||||
private bool findBeatmap(Func<Expression<Func<BeatmapInfo, bool>>, BeatmapInfo> expression)
|
||||
private void updateBeatmapState()
|
||||
{
|
||||
int? beatmapId = SelectedItem.Value?.Beatmap.Value?.OnlineBeatmapID;
|
||||
string checksum = SelectedItem.Value?.Beatmap.Value?.MD5Hash;
|
||||
|
||||
if (beatmapId == null || checksum == null)
|
||||
return false;
|
||||
return;
|
||||
|
||||
return expression(b => b.OnlineBeatmapID == beatmapId && b.MD5Hash == checksum) != null;
|
||||
var databasedBeatmap = beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == beatmapId && b.MD5Hash == checksum);
|
||||
|
||||
hasBeatmap = databasedBeatmap?.BeatmapSet?.DeletePending == false;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
|
@ -65,7 +65,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
||||
Padding = new MarginPadding(10),
|
||||
Child = roomsContainer = new RoomsContainer { JoinRequested = joinRequested }
|
||||
},
|
||||
loadingLayer = new LoadingLayer(roomsContainer),
|
||||
loadingLayer = new LoadingLayer(true),
|
||||
}
|
||||
},
|
||||
new RoomInspector
|
||||
|
@ -71,14 +71,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
Container dimContent;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
dimContent = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
@ -263,9 +256,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
loadingLayer = new LoadingLayer(dimContent)
|
||||
loadingLayer = new LoadingLayer(true)
|
||||
};
|
||||
|
||||
TypePicker.Current.BindValueChanged(type => typeLabel.Text = type.NewValue?.Name ?? string.Empty, true);
|
||||
|
@ -47,7 +47,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
AddInternal(loadingLayer = new LoadingLayer(Carousel));
|
||||
AddInternal(loadingLayer = new LoadingLayer(true));
|
||||
initialBeatmap = Beatmap.Value;
|
||||
initialRuleset = Ruleset.Value;
|
||||
initialMods = Mods.Value.ToList();
|
||||
|
@ -62,7 +62,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
// todo: this should be implemented via a custom HUD implementation, and correctly masked to the main content area.
|
||||
LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(ScoreProcessor, userIds), HUDOverlay.Add);
|
||||
|
||||
HUDOverlay.Add(loadingDisplay = new LoadingLayer(DrawableRuleset) { Depth = float.MaxValue });
|
||||
HUDOverlay.Add(loadingDisplay = new LoadingLayer(true) { Depth = float.MaxValue });
|
||||
|
||||
if (Token == null)
|
||||
return; // Todo: Somehow handle token retrieval failure.
|
||||
|
@ -64,14 +64,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
Container dimContent;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
dimContent = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
@ -298,9 +291,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
loadingLayer = new LoadingLayer(dimContent)
|
||||
loadingLayer = new LoadingLayer(true)
|
||||
};
|
||||
|
||||
TypePicker.Current.BindValueChanged(type => typeLabel.Text = type.NewValue?.Name ?? string.Empty, true);
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
@ -114,11 +115,17 @@ namespace osu.Game.Screens
|
||||
Mods = screenDependencies.Mods;
|
||||
}
|
||||
|
||||
protected BackgroundScreen Background => backgroundStack?.CurrentScreen as BackgroundScreen;
|
||||
/// <summary>
|
||||
/// The background created and owned by this screen. May be null if the background didn't change.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
private BackgroundScreen ownedBackground;
|
||||
|
||||
private BackgroundScreen localBackground;
|
||||
[CanBeNull]
|
||||
private BackgroundScreen background;
|
||||
|
||||
[Resolved(canBeNull: true)]
|
||||
[CanBeNull]
|
||||
private BackgroundScreenStack backgroundStack { get; set; }
|
||||
|
||||
[Resolved(canBeNull: true)]
|
||||
@ -140,6 +147,21 @@ namespace osu.Game.Screens
|
||||
Activity.Value ??= InitialActivity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply arbitrary changes to the current background screen in a thread safe manner.
|
||||
/// </summary>
|
||||
/// <param name="action">The operation to perform.</param>
|
||||
public void ApplyToBackground(Action<BackgroundScreen> action)
|
||||
{
|
||||
if (backgroundStack == null)
|
||||
throw new InvalidOperationException("Attempted to apply to background without a background stack being available.");
|
||||
|
||||
if (background == null)
|
||||
throw new InvalidOperationException("Attempted to apply to background before screen is pushed.");
|
||||
|
||||
background.ApplyToBackground(action);
|
||||
}
|
||||
|
||||
public override void OnResuming(IScreen last)
|
||||
{
|
||||
if (PlayResumeSound)
|
||||
@ -160,7 +182,16 @@ namespace osu.Game.Screens
|
||||
{
|
||||
applyArrivingDefaults(false);
|
||||
|
||||
backgroundStack?.Push(localBackground = CreateBackground());
|
||||
backgroundStack?.Push(ownedBackground = CreateBackground());
|
||||
|
||||
background = backgroundStack?.CurrentScreen as BackgroundScreen;
|
||||
|
||||
if (background != ownedBackground)
|
||||
{
|
||||
// background may have not been replaced, at which point we don't want to track the background lifetime.
|
||||
ownedBackground?.Dispose();
|
||||
ownedBackground = null;
|
||||
}
|
||||
|
||||
base.OnEntering(last);
|
||||
}
|
||||
@ -173,7 +204,7 @@ namespace osu.Game.Screens
|
||||
if (base.OnExiting(next))
|
||||
return true;
|
||||
|
||||
if (localBackground != null && backgroundStack?.CurrentScreen == localBackground)
|
||||
if (ownedBackground != null && backgroundStack?.CurrentScreen == ownedBackground)
|
||||
backgroundStack?.Exit();
|
||||
|
||||
return false;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user