mirror of
https://github.com/ppy/osu.git
synced 2025-03-23 03:47:19 +08:00
Merge branch 'master' into irenderer-glwrapper
This commit is contained in:
commit
c4b9b2a14b
osu.Desktop
DiscordRichPresence.cs
LegacyIpc
LegacyIpcDifficultyCalculationRequest.csLegacyIpcDifficultyCalculationResponse.csLegacyIpcMessage.cs
Program.csSecurity
Updater
Windows
osu.Game.Tests
Skins
Visual
osu.Game
Audio
Beatmaps
Database
Graphics
IO
Localisation
Online/API/Requests/Responses
OsuGameBase.csOverlays
BeatmapSet/Buttons
Mods
Screens
Edit
Menu
Play
Skinning
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscordRPC;
|
||||
@ -26,15 +24,15 @@ namespace osu.Desktop
|
||||
{
|
||||
private const string client_id = "367827983903490050";
|
||||
|
||||
private DiscordRpcClient client;
|
||||
private DiscordRpcClient client = null!;
|
||||
|
||||
[Resolved]
|
||||
private IBindable<RulesetInfo> ruleset { get; set; }
|
||||
private IBindable<RulesetInfo> ruleset { get; set; } = null!;
|
||||
|
||||
private IBindable<APIUser> user;
|
||||
private IBindable<APIUser> user = null!;
|
||||
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; }
|
||||
private IAPIProvider api { get; set; } = null!;
|
||||
|
||||
private readonly IBindable<UserStatus> status = new Bindable<UserStatus>();
|
||||
private readonly IBindable<UserActivity> activity = new Bindable<UserActivity>();
|
||||
@ -130,7 +128,7 @@ namespace osu.Desktop
|
||||
presence.Assets.LargeImageText = string.Empty;
|
||||
else
|
||||
{
|
||||
if (user.Value.RulesetsStatistics != null && user.Value.RulesetsStatistics.TryGetValue(ruleset.Value.ShortName, out UserStatistics statistics))
|
||||
if (user.Value.RulesetsStatistics != null && user.Value.RulesetsStatistics.TryGetValue(ruleset.Value.ShortName, out UserStatistics? statistics))
|
||||
presence.Assets.LargeImageText = $"{user.Value.Username}" + (statistics.GlobalRank > 0 ? $" (rank #{statistics.GlobalRank:N0})" : string.Empty);
|
||||
else
|
||||
presence.Assets.LargeImageText = $"{user.Value.Username}" + (user.Value.Statistics?.GlobalRank > 0 ? $" (rank #{user.Value.Statistics.GlobalRank:N0})" : string.Empty);
|
||||
@ -164,7 +162,7 @@ namespace osu.Desktop
|
||||
});
|
||||
}
|
||||
|
||||
private IBeatmapInfo getBeatmap(UserActivity activity)
|
||||
private IBeatmapInfo? getBeatmap(UserActivity activity)
|
||||
{
|
||||
switch (activity)
|
||||
{
|
||||
@ -183,10 +181,10 @@ namespace osu.Desktop
|
||||
switch (activity)
|
||||
{
|
||||
case UserActivity.InGame game:
|
||||
return game.BeatmapInfo.ToString();
|
||||
return game.BeatmapInfo.ToString() ?? string.Empty;
|
||||
|
||||
case UserActivity.Editing edit:
|
||||
return edit.BeatmapInfo.ToString();
|
||||
return edit.BeatmapInfo.ToString() ?? string.Empty;
|
||||
|
||||
case UserActivity.InLobby lobby:
|
||||
return privacyMode.Value == DiscordRichPresenceMode.Limited ? string.Empty : lobby.Room.Name.Value;
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace osu.Desktop.LegacyIpc
|
||||
{
|
||||
/// <summary>
|
||||
@ -13,7 +11,7 @@ namespace osu.Desktop.LegacyIpc
|
||||
/// </remarks>
|
||||
public class LegacyIpcDifficultyCalculationRequest
|
||||
{
|
||||
public string BeatmapFile { get; set; }
|
||||
public string BeatmapFile { get; set; } = string.Empty;
|
||||
public int RulesetId { get; set; }
|
||||
public int Mods { get; set; }
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace osu.Desktop.LegacyIpc
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using osu.Framework.Platform;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
@ -39,17 +37,20 @@ namespace osu.Desktop.LegacyIpc
|
||||
public new object Value
|
||||
{
|
||||
get => base.Value;
|
||||
set => base.Value = new Data
|
||||
{
|
||||
MessageType = value.GetType().Name,
|
||||
MessageData = value
|
||||
};
|
||||
set => base.Value = new Data(value.GetType().Name, value);
|
||||
}
|
||||
|
||||
public class Data
|
||||
{
|
||||
public string MessageType { get; set; }
|
||||
public object MessageData { get; set; }
|
||||
public string MessageType { get; }
|
||||
|
||||
public object MessageData { get; }
|
||||
|
||||
public Data(string messageType, object messageData)
|
||||
{
|
||||
MessageType = messageType;
|
||||
MessageData = messageData;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.Versioning;
|
||||
@ -27,7 +25,7 @@ namespace osu.Desktop
|
||||
private const string base_game_name = @"osu";
|
||||
#endif
|
||||
|
||||
private static LegacyTcpIpcProvider legacyIpc;
|
||||
private static LegacyTcpIpcProvider? legacyIpc;
|
||||
|
||||
[STAThread]
|
||||
public static void Main(string[] args)
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Security.Principal;
|
||||
using osu.Framework;
|
||||
@ -21,7 +19,7 @@ namespace osu.Desktop.Security
|
||||
public class ElevatedPrivilegesChecker : Component
|
||||
{
|
||||
[Resolved]
|
||||
private INotificationOverlay notifications { get; set; }
|
||||
private INotificationOverlay notifications { get; set; } = null!;
|
||||
|
||||
private bool elevated;
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading.Tasks;
|
||||
@ -26,8 +24,8 @@ namespace osu.Desktop.Updater
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class SquirrelUpdateManager : osu.Game.Updater.UpdateManager
|
||||
{
|
||||
private UpdateManager updateManager;
|
||||
private INotificationOverlay notificationOverlay;
|
||||
private UpdateManager? updateManager;
|
||||
private INotificationOverlay notificationOverlay = null!;
|
||||
|
||||
public Task PrepareUpdateAsync() => UpdateManager.RestartAppWhenExited();
|
||||
|
||||
@ -50,12 +48,12 @@ namespace osu.Desktop.Updater
|
||||
|
||||
protected override async Task<bool> PerformUpdateCheck() => await checkForUpdateAsync().ConfigureAwait(false);
|
||||
|
||||
private async Task<bool> checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification notification = null)
|
||||
private async Task<bool> checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification? notification = null)
|
||||
{
|
||||
// should we schedule a retry on completion of this check?
|
||||
bool scheduleRecheck = true;
|
||||
|
||||
const string github_token = null; // TODO: populate.
|
||||
const string? github_token = null; // TODO: populate.
|
||||
|
||||
try
|
||||
{
|
||||
@ -145,7 +143,7 @@ namespace osu.Desktop.Updater
|
||||
private class UpdateCompleteNotification : ProgressCompletionNotification
|
||||
{
|
||||
[Resolved]
|
||||
private OsuGame game { get; set; }
|
||||
private OsuGame game { get; set; } = null!;
|
||||
|
||||
public UpdateCompleteNotification(SquirrelUpdateManager updateManager)
|
||||
{
|
||||
@ -154,7 +152,7 @@ namespace osu.Desktop.Updater
|
||||
Activated = () =>
|
||||
{
|
||||
updateManager.PrepareUpdateAsync()
|
||||
.ContinueWith(_ => updateManager.Schedule(() => game?.AttemptExit()));
|
||||
.ContinueWith(_ => updateManager.Schedule(() => game.AttemptExit()));
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
@ -14,12 +12,12 @@ namespace osu.Desktop.Windows
|
||||
{
|
||||
public class GameplayWinKeyBlocker : Component
|
||||
{
|
||||
private Bindable<bool> disableWinKey;
|
||||
private IBindable<bool> localUserPlaying;
|
||||
private IBindable<bool> isActive;
|
||||
private Bindable<bool> disableWinKey = null!;
|
||||
private IBindable<bool> localUserPlaying = null!;
|
||||
private IBindable<bool> isActive = null!;
|
||||
|
||||
[Resolved]
|
||||
private GameHost host { get; set; }
|
||||
private GameHost host { get; set; } = null!;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ILocalUserPlayInfo localUserInfo, OsuConfigManager config)
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
@ -21,7 +19,7 @@ namespace osu.Desktop.Windows
|
||||
private const int wm_syskeyup = 261;
|
||||
|
||||
//Resharper disable once NotAccessedField.Local
|
||||
private static LowLevelKeyboardProcDelegate keyboardHookDelegate; // keeping a reference alive for the GC
|
||||
private static LowLevelKeyboardProcDelegate? keyboardHookDelegate; // keeping a reference alive for the GC
|
||||
private static IntPtr keyHook;
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
|
@ -1,14 +1,23 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.IO;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osu.Game.Tests.Visual;
|
||||
@ -19,9 +28,9 @@ namespace osu.Game.Tests.Skins
|
||||
public class TestSceneSkinResources : OsuTestScene
|
||||
{
|
||||
[Resolved]
|
||||
private SkinManager skins { get; set; }
|
||||
private SkinManager skins { get; set; } = null!;
|
||||
|
||||
private ISkin skin;
|
||||
private ISkin skin = null!;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
@ -32,5 +41,55 @@ namespace osu.Game.Tests.Skins
|
||||
|
||||
[Test]
|
||||
public void TestRetrieveOggSample() => AddAssert("sample is non-null", () => skin.GetSample(new SampleInfo("sample")) != null);
|
||||
|
||||
[Test]
|
||||
public void TestSampleRetrievalOrder()
|
||||
{
|
||||
Mock<IStorageResourceProvider> mockResourceProvider = null!;
|
||||
Mock<IResourceStore<byte[]>> mockResourceStore = null!;
|
||||
List<string> lookedUpFileNames = null!;
|
||||
|
||||
AddStep("setup mock providers provider", () =>
|
||||
{
|
||||
lookedUpFileNames = new List<string>();
|
||||
mockResourceProvider = new Mock<IStorageResourceProvider>();
|
||||
mockResourceProvider.Setup(m => m.AudioManager).Returns(Audio);
|
||||
mockResourceStore = new Mock<IResourceStore<byte[]>>();
|
||||
mockResourceStore.Setup(r => r.Get(It.IsAny<string>()))
|
||||
.Callback<string>(n => lookedUpFileNames.Add(n))
|
||||
.Returns<byte>(null);
|
||||
});
|
||||
|
||||
AddStep("query sample", () =>
|
||||
{
|
||||
TestSkin testSkin = new TestSkin(new SkinInfo(), mockResourceProvider.Object, new ResourceStore<byte[]>(mockResourceStore.Object));
|
||||
testSkin.GetSample(new SampleInfo());
|
||||
});
|
||||
|
||||
AddAssert("sample lookups were in correct order", () =>
|
||||
{
|
||||
string[] lookups = lookedUpFileNames.Where(f => f.StartsWith(TestSkin.SAMPLE_NAME, StringComparison.Ordinal)).ToArray();
|
||||
return Path.GetExtension(lookups[0]) == string.Empty
|
||||
&& Path.GetExtension(lookups[1]) == ".wav"
|
||||
&& Path.GetExtension(lookups[2]) == ".mp3"
|
||||
&& Path.GetExtension(lookups[3]) == ".ogg";
|
||||
});
|
||||
}
|
||||
|
||||
private class TestSkin : Skin
|
||||
{
|
||||
public const string SAMPLE_NAME = "test-sample";
|
||||
|
||||
public TestSkin(SkinInfo skin, IStorageResourceProvider? resources, IResourceStore<byte[]>? storage = null, string configurationFilename = "skin.ini")
|
||||
: base(skin, resources, storage, configurationFilename)
|
||||
{
|
||||
}
|
||||
|
||||
public override Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException();
|
||||
|
||||
public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
|
||||
|
||||
public override ISample GetSample(ISampleInfo sampleInfo) => Samples.AsNonNull().Get(SAMPLE_NAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,13 +150,14 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
AddStep("add collection", () => writeAndRefresh(r => r.Add(new BeatmapCollection(name: "1"))));
|
||||
assertCollectionDropdownContains("1");
|
||||
AddAssert("button is plus", () => getAddOrRemoveButton(1).Icon.Equals(FontAwesome.Solid.PlusSquare));
|
||||
|
||||
assertFirstButtonIs(FontAwesome.Solid.PlusSquare);
|
||||
|
||||
AddStep("add beatmap to collection", () => writeAndRefresh(r => getFirstCollection().BeatmapMD5Hashes.Add(Beatmap.Value.BeatmapInfo.MD5Hash)));
|
||||
AddAssert("button is minus", () => getAddOrRemoveButton(1).Icon.Equals(FontAwesome.Solid.MinusSquare));
|
||||
assertFirstButtonIs(FontAwesome.Solid.MinusSquare);
|
||||
|
||||
AddStep("remove beatmap from collection", () => writeAndRefresh(r => getFirstCollection().BeatmapMD5Hashes.Clear()));
|
||||
AddAssert("button is plus", () => getAddOrRemoveButton(1).Icon.Equals(FontAwesome.Solid.PlusSquare));
|
||||
assertFirstButtonIs(FontAwesome.Solid.PlusSquare);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -168,15 +169,15 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
AddStep("add collection", () => writeAndRefresh(r => r.Add(new BeatmapCollection(name: "1"))));
|
||||
assertCollectionDropdownContains("1");
|
||||
AddAssert("button is plus", () => getAddOrRemoveButton(1).Icon.Equals(FontAwesome.Solid.PlusSquare));
|
||||
assertFirstButtonIs(FontAwesome.Solid.PlusSquare);
|
||||
|
||||
addClickAddOrRemoveButtonStep(1);
|
||||
AddAssert("collection contains beatmap", () => getFirstCollection().BeatmapMD5Hashes.Contains(Beatmap.Value.BeatmapInfo.MD5Hash));
|
||||
AddAssert("button is minus", () => getAddOrRemoveButton(1).Icon.Equals(FontAwesome.Solid.MinusSquare));
|
||||
assertFirstButtonIs(FontAwesome.Solid.MinusSquare);
|
||||
|
||||
addClickAddOrRemoveButtonStep(1);
|
||||
AddAssert("collection does not contain beatmap", () => !getFirstCollection().BeatmapMD5Hashes.Contains(Beatmap.Value.BeatmapInfo.MD5Hash));
|
||||
AddAssert("button is plus", () => getAddOrRemoveButton(1).Icon.Equals(FontAwesome.Solid.PlusSquare));
|
||||
assertFirstButtonIs(FontAwesome.Solid.PlusSquare);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -226,6 +227,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
=> AddUntilStep($"collection dropdown header displays '{collectionName}'",
|
||||
() => shouldDisplay == (control.ChildrenOfType<CollectionDropdown.CollectionDropdownHeader>().Single().ChildrenOfType<SpriteText>().First().Text == collectionName));
|
||||
|
||||
private void assertFirstButtonIs(IconUsage icon) => AddUntilStep($"button is {icon.Icon.ToString()}", () => getAddOrRemoveButton(1).Icon.Equals(icon));
|
||||
|
||||
private void assertCollectionDropdownContains(string collectionName, bool shouldContain = true) =>
|
||||
AddUntilStep($"collection dropdown {(shouldContain ? "contains" : "does not contain")} '{collectionName}'",
|
||||
// A bit of a roundabout way of going about this, see: https://github.com/ppy/osu-framework/issues/3871 + https://github.com/ppy/osu-framework/issues/3872
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
@ -9,19 +10,26 @@ using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.UserInterfaceV2;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Mods;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mania.Mods;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestSceneModPresetColumn : OsuTestScene
|
||||
public class TestSceneModPresetColumn : OsuManualInputManagerTestScene
|
||||
{
|
||||
protected override bool UseFreshStoragePerRun => true;
|
||||
|
||||
private Container<Drawable> content = null!;
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
private RulesetStore rulesets = null!;
|
||||
|
||||
[Cached]
|
||||
@ -32,6 +40,12 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
|
||||
Dependencies.Cache(Realm);
|
||||
|
||||
base.Content.Add(content = new PopoverContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding(30),
|
||||
});
|
||||
}
|
||||
|
||||
[SetUpSteps]
|
||||
@ -57,15 +71,10 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
public void TestBasicOperation()
|
||||
{
|
||||
AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0));
|
||||
AddStep("create content", () => Child = new Container
|
||||
AddStep("create content", () => Child = new ModPresetColumn
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding(30),
|
||||
Child = new ModPresetColumn
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
AddUntilStep("3 panels visible", () => this.ChildrenOfType<ModPresetPanel>().Count() == 3);
|
||||
|
||||
@ -112,15 +121,10 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
public void TestSoftDeleteSupport()
|
||||
{
|
||||
AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0));
|
||||
AddStep("create content", () => Child = new Container
|
||||
AddStep("create content", () => Child = new ModPresetColumn
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding(30),
|
||||
Child = new ModPresetColumn
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
AddUntilStep("3 panels visible", () => this.ChildrenOfType<ModPresetPanel>().Count() == 3);
|
||||
|
||||
@ -146,6 +150,61 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
AddUntilStep("3 panels visible", () => this.ChildrenOfType<ModPresetPanel>().Count() == 3);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddingFlow()
|
||||
{
|
||||
ModPresetColumn modPresetColumn = null!;
|
||||
|
||||
AddStep("clear mods", () => SelectedMods.Value = Array.Empty<Mod>());
|
||||
AddStep("create content", () => Child = modPresetColumn = new ModPresetColumn
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
|
||||
AddUntilStep("items loaded", () => modPresetColumn.IsLoaded && modPresetColumn.ItemsLoaded);
|
||||
AddAssert("add preset button disabled", () => !this.ChildrenOfType<AddPresetButton>().Single().Enabled.Value);
|
||||
|
||||
AddStep("set mods", () => SelectedMods.Value = new Mod[] { new OsuModDaycore(), new OsuModClassic() });
|
||||
AddAssert("add preset button enabled", () => this.ChildrenOfType<AddPresetButton>().Single().Enabled.Value);
|
||||
|
||||
AddStep("click add preset button", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(this.ChildrenOfType<AddPresetButton>().Single());
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
OsuPopover? popover = null;
|
||||
AddUntilStep("wait for popover", () => (popover = this.ChildrenOfType<OsuPopover>().FirstOrDefault()) != null);
|
||||
AddStep("attempt preset creation", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(popover.ChildrenOfType<ShearedButton>().Single());
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
AddWaitStep("wait some", 3);
|
||||
AddAssert("preset creation did not occur", () => this.ChildrenOfType<ModPresetPanel>().Count() == 3);
|
||||
AddUntilStep("popover is unchanged", () => this.ChildrenOfType<OsuPopover>().FirstOrDefault() == popover);
|
||||
|
||||
AddStep("fill preset name", () => popover.ChildrenOfType<LabelledTextBox>().First().Current.Value = "new preset");
|
||||
AddStep("attempt preset creation", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(popover.ChildrenOfType<ShearedButton>().Single());
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
AddUntilStep("popover closed", () => !this.ChildrenOfType<OsuPopover>().Any());
|
||||
AddUntilStep("preset creation occurred", () => this.ChildrenOfType<ModPresetPanel>().Count() == 4);
|
||||
|
||||
AddStep("click add preset button", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(this.ChildrenOfType<AddPresetButton>().Single());
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddUntilStep("wait for popover", () => (popover = this.ChildrenOfType<OsuPopover>().FirstOrDefault()) != null);
|
||||
AddStep("clear mods", () => SelectedMods.Value = Array.Empty<Mod>());
|
||||
AddUntilStep("popover closed", () => !this.ChildrenOfType<OsuPopover>().Any());
|
||||
}
|
||||
|
||||
private ICollection<ModPreset> createTestPresets() => new[]
|
||||
{
|
||||
new ModPreset
|
||||
|
@ -105,5 +105,11 @@ namespace osu.Game.Audio
|
||||
/// Retrieves the audio track.
|
||||
/// </summary>
|
||||
protected abstract Track? GetTrack();
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
Track?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
18
osu.Game/Beatmaps/BeatSyncProviderExtensions.cs
Normal file
18
osu.Game/Beatmaps/BeatSyncProviderExtensions.cs
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
public static class BeatSyncProviderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Check whether beat sync is currently available.
|
||||
/// </summary>
|
||||
public static bool CheckBeatSyncAvailable(this IBeatSyncProvider provider) => provider.Clock != null;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the beat sync provider is currently in a kiai section. Should make everything more epic.
|
||||
/// </summary>
|
||||
public static bool CheckIsKiaiTime(this IBeatSyncProvider provider) => provider.Clock != null && provider.ControlPoints?.EffectPointAt(provider.Clock.CurrentTime).KiaiMode == true;
|
||||
}
|
||||
}
|
@ -118,7 +118,10 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
|
||||
// another async load might have completed before this one.
|
||||
// if so, do not make any changes.
|
||||
if (loadedPreview != previewTrack)
|
||||
{
|
||||
loadedPreview.Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
AddInternal(loadedPreview);
|
||||
toggleLoading(false);
|
||||
|
@ -2,7 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Graphics.Containers;
|
||||
@ -14,12 +14,16 @@ namespace osu.Game.Beatmaps
|
||||
/// Primarily intended for use with <see cref="BeatSyncedContainer"/>.
|
||||
/// </summary>
|
||||
[Cached]
|
||||
public interface IBeatSyncProvider
|
||||
public interface IBeatSyncProvider : IHasAmplitudes
|
||||
{
|
||||
/// <summary>
|
||||
/// Access any available control points from a beatmap providing beat sync. If <c>null</c>, no current provider is available.
|
||||
/// </summary>
|
||||
ControlPointInfo? ControlPoints { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Access a clock currently responsible for providing beat sync. If <c>null</c>, no current provider is available.
|
||||
/// </summary>
|
||||
IClock? Clock { get; }
|
||||
|
||||
ChannelAmplitudes? Amplitudes { get; }
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Humanizer;
|
||||
using osu.Framework.Logging;
|
||||
@ -107,7 +108,15 @@ namespace osu.Game.Database
|
||||
notification.State = ProgressNotificationState.Cancelled;
|
||||
|
||||
if (!(error is OperationCanceledException))
|
||||
Logger.Error(error, $"{importer.HumanisedModelName.Titleize()} download failed!");
|
||||
{
|
||||
if (error is WebException webException && webException.Message == @"TooManyRequests")
|
||||
{
|
||||
notification.Close();
|
||||
PostNotification?.Invoke(new TooManyDownloadsNotification());
|
||||
}
|
||||
else
|
||||
Logger.Error(error, $"{importer.HumanisedModelName.Titleize()} download failed!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
26
osu.Game/Database/TooManyDownloadsNotification.cs
Normal file
26
osu.Game/Database/TooManyDownloadsNotification.cs
Normal file
@ -0,0 +1,26 @@
|
||||
// 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.Sprites;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
|
||||
namespace osu.Game.Database
|
||||
{
|
||||
public class TooManyDownloadsNotification : SimpleNotification
|
||||
{
|
||||
public TooManyDownloadsNotification()
|
||||
{
|
||||
Text = BeatmapsetsStrings.DownloadLimitExceeded;
|
||||
Icon = FontAwesome.Solid.ExclamationCircle;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
IconBackground.Colour = colours.RedDark;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using osu.Framework.Allocation;
|
||||
@ -10,13 +8,12 @@ using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
namespace osu.Game.Graphics.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// A container which fires a callback when a new beat is reached.
|
||||
/// Consumes a parent <see cref="GameplayClock"/> or <see cref="Beatmap"/> (whichever is first available).
|
||||
/// Consumes a parent <see cref="IBeatSyncProvider"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This container does not set its own clock to the source used for beat matching.
|
||||
@ -28,8 +25,10 @@ namespace osu.Game.Graphics.Containers
|
||||
public class BeatSyncedContainer : Container
|
||||
{
|
||||
private int lastBeat;
|
||||
protected TimingControlPoint LastTimingPoint { get; private set; }
|
||||
protected EffectControlPoint LastEffectPoint { get; private set; }
|
||||
|
||||
private TimingControlPoint? lastTimingPoint { get; set; }
|
||||
|
||||
protected bool IsKiaiTime { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The amount of time before a beat we should fire <see cref="OnNewBeat(int, TimingControlPoint, EffectControlPoint, ChannelAmplitudes)"/>.
|
||||
@ -71,12 +70,12 @@ namespace osu.Game.Graphics.Containers
|
||||
public double MinimumBeatLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this container is currently tracking a beatmap's timing data.
|
||||
/// Whether this container is currently tracking a beat sync provider.
|
||||
/// </summary>
|
||||
protected bool IsBeatSyncedWithTrack { get; private set; }
|
||||
|
||||
[Resolved]
|
||||
protected IBeatSyncProvider BeatSyncSource { get; private set; }
|
||||
protected IBeatSyncProvider BeatSyncSource { get; private set; } = null!;
|
||||
|
||||
protected virtual void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
|
||||
{
|
||||
@ -87,19 +86,18 @@ namespace osu.Game.Graphics.Containers
|
||||
TimingControlPoint timingPoint;
|
||||
EffectControlPoint effectPoint;
|
||||
|
||||
IsBeatSyncedWithTrack = BeatSyncSource.Clock?.IsRunning == true && BeatSyncSource.ControlPoints != null;
|
||||
IsBeatSyncedWithTrack = BeatSyncSource.CheckBeatSyncAvailable() && BeatSyncSource.Clock?.IsRunning == true;
|
||||
|
||||
double currentTrackTime;
|
||||
|
||||
if (IsBeatSyncedWithTrack)
|
||||
{
|
||||
Debug.Assert(BeatSyncSource.ControlPoints != null);
|
||||
Debug.Assert(BeatSyncSource.Clock != null);
|
||||
|
||||
currentTrackTime = BeatSyncSource.Clock.CurrentTime + EarlyActivationMilliseconds;
|
||||
|
||||
timingPoint = BeatSyncSource.ControlPoints.TimingPointAt(currentTrackTime);
|
||||
effectPoint = BeatSyncSource.ControlPoints.EffectPointAt(currentTrackTime);
|
||||
timingPoint = BeatSyncSource.ControlPoints?.TimingPointAt(currentTrackTime) ?? TimingControlPoint.DEFAULT;
|
||||
effectPoint = BeatSyncSource.ControlPoints?.EffectPointAt(currentTrackTime) ?? EffectControlPoint.DEFAULT;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -128,7 +126,7 @@ namespace osu.Game.Graphics.Containers
|
||||
|
||||
TimeSinceLastBeat = beatLength - TimeUntilNextBeat;
|
||||
|
||||
if (ReferenceEquals(timingPoint, LastTimingPoint) && beatIndex == lastBeat)
|
||||
if (ReferenceEquals(timingPoint, lastTimingPoint) && beatIndex == lastBeat)
|
||||
return;
|
||||
|
||||
// as this event is sometimes used for sound triggers where `BeginDelayedSequence` has no effect, avoid firing it if too far away from the beat.
|
||||
@ -136,12 +134,13 @@ namespace osu.Game.Graphics.Containers
|
||||
if (AllowMistimedEventFiring || Math.Abs(TimeSinceLastBeat) < MISTIMED_ALLOWANCE)
|
||||
{
|
||||
using (BeginDelayedSequence(-TimeSinceLastBeat))
|
||||
OnNewBeat(beatIndex, timingPoint, effectPoint, BeatSyncSource.Amplitudes ?? ChannelAmplitudes.Empty);
|
||||
OnNewBeat(beatIndex, timingPoint, effectPoint, BeatSyncSource.CurrentAmplitudes);
|
||||
}
|
||||
|
||||
lastBeat = beatIndex;
|
||||
LastTimingPoint = timingPoint;
|
||||
LastEffectPoint = effectPoint;
|
||||
lastTimingPoint = timingPoint;
|
||||
|
||||
IsKiaiTime = effectPoint.KiaiMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,15 +49,15 @@ namespace osu.Game.Graphics.UserInterface
|
||||
Active.BindDisabledChanged(disabled => Action = disabled ? null : Active.Toggle, true);
|
||||
Active.BindValueChanged(_ =>
|
||||
{
|
||||
updateActiveState();
|
||||
UpdateActiveState();
|
||||
playSample();
|
||||
});
|
||||
|
||||
updateActiveState();
|
||||
UpdateActiveState();
|
||||
base.LoadComplete();
|
||||
}
|
||||
|
||||
private void updateActiveState()
|
||||
protected virtual void UpdateActiveState()
|
||||
{
|
||||
DarkerColour = Active.Value ? ColourProvider.Highlight1 : ColourProvider.Background3;
|
||||
LighterColour = Active.Value ? ColourProvider.Colour0 : ColourProvider.Background1;
|
||||
|
@ -26,6 +26,11 @@ namespace osu.Game.IO
|
||||
/// </summary>
|
||||
public virtual string[] IgnoreFiles => Array.Empty<string>();
|
||||
|
||||
/// <summary>
|
||||
/// A list of file/directory suffixes which should not be migrated.
|
||||
/// </summary>
|
||||
public virtual string[] IgnoreSuffixes => Array.Empty<string>();
|
||||
|
||||
protected MigratableStorage(Storage storage, string subPath = null)
|
||||
: base(storage, subPath)
|
||||
{
|
||||
@ -73,6 +78,9 @@ namespace osu.Game.IO
|
||||
if (topLevelExcludes && IgnoreFiles.Contains(fi.Name))
|
||||
continue;
|
||||
|
||||
if (IgnoreSuffixes.Any(suffix => fi.Name.EndsWith(suffix, StringComparison.Ordinal)))
|
||||
continue;
|
||||
|
||||
allFilesDeleted &= AttemptOperation(() => fi.Delete(), throwOnFailure: false);
|
||||
}
|
||||
|
||||
@ -81,6 +89,9 @@ namespace osu.Game.IO
|
||||
if (topLevelExcludes && IgnoreDirectories.Contains(dir.Name))
|
||||
continue;
|
||||
|
||||
if (IgnoreSuffixes.Any(suffix => dir.Name.EndsWith(suffix, StringComparison.Ordinal)))
|
||||
continue;
|
||||
|
||||
allFilesDeleted &= AttemptOperation(() => dir.Delete(true), throwOnFailure: false);
|
||||
}
|
||||
|
||||
@ -101,6 +112,9 @@ namespace osu.Game.IO
|
||||
if (topLevelExcludes && IgnoreFiles.Contains(fileInfo.Name))
|
||||
continue;
|
||||
|
||||
if (IgnoreSuffixes.Any(suffix => fileInfo.Name.EndsWith(suffix, StringComparison.Ordinal)))
|
||||
continue;
|
||||
|
||||
AttemptOperation(() =>
|
||||
{
|
||||
fileInfo.Refresh();
|
||||
@ -119,6 +133,9 @@ namespace osu.Game.IO
|
||||
if (topLevelExcludes && IgnoreDirectories.Contains(dir.Name))
|
||||
continue;
|
||||
|
||||
if (IgnoreSuffixes.Any(suffix => dir.Name.EndsWith(suffix, StringComparison.Ordinal)))
|
||||
continue;
|
||||
|
||||
CopyRecursive(dir, destination.CreateSubdirectory(dir.Name), false);
|
||||
}
|
||||
}
|
||||
|
@ -38,15 +38,20 @@ namespace osu.Game.IO
|
||||
public override string[] IgnoreDirectories => new[]
|
||||
{
|
||||
"cache",
|
||||
$"{OsuGameBase.CLIENT_DATABASE_FILENAME}.management",
|
||||
};
|
||||
|
||||
public override string[] IgnoreFiles => new[]
|
||||
{
|
||||
"framework.ini",
|
||||
"storage.ini",
|
||||
$"{OsuGameBase.CLIENT_DATABASE_FILENAME}.note",
|
||||
$"{OsuGameBase.CLIENT_DATABASE_FILENAME}.lock",
|
||||
};
|
||||
|
||||
public override string[] IgnoreSuffixes => new[]
|
||||
{
|
||||
// Realm pipe files don't play well with copy operations
|
||||
".note",
|
||||
".lock",
|
||||
".management",
|
||||
};
|
||||
|
||||
public OsuStorage(GameHost host, Storage defaultStorage)
|
||||
|
@ -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 osu.Framework.Localisation;
|
||||
@ -89,6 +89,16 @@ namespace osu.Game.Localisation
|
||||
/// </summary>
|
||||
public static LocalisableString Collections => new TranslatableString(getKey(@"collections"), @"Collections");
|
||||
|
||||
/// <summary>
|
||||
/// "Name"
|
||||
/// </summary>
|
||||
public static LocalisableString Name => new TranslatableString(getKey(@"name"), @"Name");
|
||||
|
||||
/// <summary>
|
||||
/// "Description"
|
||||
/// </summary>
|
||||
public static LocalisableString Description => new TranslatableString(getKey(@"description"), @"Description");
|
||||
|
||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||
}
|
||||
}
|
||||
}
|
@ -29,6 +29,11 @@ namespace osu.Game.Localisation
|
||||
/// </summary>
|
||||
public static LocalisableString PersonalPresets => new TranslatableString(getKey(@"personal_presets"), @"Personal Presets");
|
||||
|
||||
/// <summary>
|
||||
/// "Add preset"
|
||||
/// </summary>
|
||||
public static LocalisableString AddPreset => new TranslatableString(getKey(@"add_preset"), @"Add preset");
|
||||
|
||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||
}
|
||||
}
|
||||
|
@ -102,6 +102,14 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
[JsonProperty("pp")]
|
||||
public double? PP { get; set; }
|
||||
|
||||
public bool ShouldSerializeID() => false;
|
||||
public bool ShouldSerializeUser() => false;
|
||||
public bool ShouldSerializeBeatmap() => false;
|
||||
public bool ShouldSerializeBeatmapSet() => false;
|
||||
public bool ShouldSerializePP() => false;
|
||||
public bool ShouldSerializeOnlineID() => false;
|
||||
public bool ShouldSerializeHasReplay() => false;
|
||||
|
||||
#endregion
|
||||
|
||||
public override string ToString() => $"score_id: {ID} user_id: {UserID}";
|
||||
@ -165,7 +173,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
RulesetID = score.RulesetID,
|
||||
Passed = score.Passed,
|
||||
Mods = score.APIMods,
|
||||
Statistics = score.Statistics,
|
||||
Statistics = score.Statistics.Where(kvp => kvp.Value != 0).ToDictionary(kvp => kvp.Key, kvp => kvp.Value),
|
||||
};
|
||||
|
||||
public long OnlineID => ID ?? -1;
|
||||
|
@ -588,6 +588,6 @@ namespace osu.Game
|
||||
|
||||
ControlPointInfo IBeatSyncProvider.ControlPoints => Beatmap.Value.BeatmapLoaded ? Beatmap.Value.Beatmap.ControlPointInfo : null;
|
||||
IClock IBeatSyncProvider.Clock => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track : (IClock)null;
|
||||
ChannelAmplitudes? IBeatSyncProvider.Amplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : null;
|
||||
ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : ChannelAmplitudes.Empty;
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +147,10 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
{
|
||||
// beatmapset may have changed.
|
||||
if (Preview != preview)
|
||||
{
|
||||
preview?.Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
AddInternal(preview);
|
||||
loading = false;
|
||||
|
67
osu.Game/Overlays/Mods/AddPresetButton.cs
Normal file
67
osu.Game/Overlays/Mods/AddPresetButton.cs
Normal file
@ -0,0 +1,67 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
public class AddPresetButton : ShearedToggleButton, IHasPopover
|
||||
{
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private Bindable<IReadOnlyList<Mod>> selectedMods { get; set; } = null!;
|
||||
|
||||
public AddPresetButton()
|
||||
: base(1)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = ModSelectPanel.HEIGHT;
|
||||
|
||||
// shear will be applied at a higher level in `ModPresetColumn`.
|
||||
Content.Shear = Vector2.Zero;
|
||||
Padding = new MarginPadding();
|
||||
|
||||
Text = "+";
|
||||
TextSize = 30;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
selectedMods.BindValueChanged(mods => Enabled.Value = mods.NewValue.Any(), true);
|
||||
Enabled.BindValueChanged(enabled =>
|
||||
{
|
||||
if (!enabled.NewValue)
|
||||
Active.Value = false;
|
||||
});
|
||||
}
|
||||
|
||||
protected override void UpdateActiveState()
|
||||
{
|
||||
DarkerColour = Active.Value ? colours.Orange1 : ColourProvider.Background3;
|
||||
LighterColour = Active.Value ? colours.Orange0 : ColourProvider.Background1;
|
||||
TextColour = Active.Value ? ColourProvider.Background6 : ColourProvider.Content1;
|
||||
|
||||
if (Active.Value)
|
||||
this.ShowPopover();
|
||||
else
|
||||
this.HidePopover();
|
||||
}
|
||||
|
||||
public Popover GetPopover() => new AddPresetPopover(this);
|
||||
}
|
||||
}
|
120
osu.Game/Overlays/Mods/AddPresetPopover.cs
Normal file
120
osu.Game/Overlays/Mods/AddPresetPopover.cs
Normal file
@ -0,0 +1,120 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.UserInterfaceV2;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
internal class AddPresetPopover : OsuPopover
|
||||
{
|
||||
private readonly AddPresetButton button;
|
||||
|
||||
private readonly LabelledTextBox nameTextBox;
|
||||
private readonly LabelledTextBox descriptionTextBox;
|
||||
private readonly ShearedButton createButton;
|
||||
|
||||
[Resolved]
|
||||
private Bindable<RulesetInfo> ruleset { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private Bindable<IReadOnlyList<Mod>> selectedMods { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private RealmAccess realm { get; set; } = null!;
|
||||
|
||||
public AddPresetPopover(AddPresetButton addPresetButton)
|
||||
{
|
||||
button = addPresetButton;
|
||||
|
||||
Child = new FillFlowContainer
|
||||
{
|
||||
Width = 300,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Spacing = new Vector2(7),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
nameTextBox = new LabelledTextBox
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Label = CommonStrings.Name,
|
||||
TabbableContentContainer = this
|
||||
},
|
||||
descriptionTextBox = new LabelledTextBox
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Label = CommonStrings.Description,
|
||||
TabbableContentContainer = this
|
||||
},
|
||||
createButton = new ShearedButton
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Text = ModSelectOverlayStrings.AddPreset,
|
||||
Action = tryCreatePreset
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider, OsuColour colours)
|
||||
{
|
||||
Body.BorderThickness = 3;
|
||||
Body.BorderColour = colours.Orange1;
|
||||
|
||||
createButton.DarkerColour = colours.Orange1;
|
||||
createButton.LighterColour = colours.Orange0;
|
||||
createButton.TextColour = colourProvider.Background6;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
ScheduleAfterChildren(() => GetContainingInputManager().ChangeFocus(nameTextBox));
|
||||
}
|
||||
|
||||
private void tryCreatePreset()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(nameTextBox.Current.Value))
|
||||
{
|
||||
Body.Shake();
|
||||
return;
|
||||
}
|
||||
|
||||
realm.Write(r => r.Add(new ModPreset
|
||||
{
|
||||
Name = nameTextBox.Current.Value,
|
||||
Description = descriptionTextBox.Current.Value,
|
||||
Mods = selectedMods.Value.ToArray(),
|
||||
Ruleset = r.Find<RulesetInfo>(ruleset.Value.ShortName)
|
||||
}));
|
||||
|
||||
this.HidePopover();
|
||||
}
|
||||
|
||||
protected override void UpdateState(ValueChangedEvent<Visibility> state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
if (state.NewValue == Visibility.Hidden)
|
||||
button.Active.Value = false;
|
||||
}
|
||||
}
|
||||
}
|
@ -31,6 +31,10 @@ namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
AccentColour = colours.Orange1;
|
||||
HeaderText = ModSelectOverlayStrings.PersonalPresets;
|
||||
|
||||
AddPresetButton addPresetButton;
|
||||
ItemsFlow.Add(addPresetButton = new AddPresetButton());
|
||||
ItemsFlow.SetLayoutPosition(addPresetButton, float.PositiveInfinity);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
@ -64,7 +68,7 @@ namespace osu.Game.Overlays.Mods
|
||||
|
||||
if (!presets.Any())
|
||||
{
|
||||
ItemsFlow.Clear();
|
||||
ItemsFlow.RemoveAll(panel => panel is ModPresetPanel);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -77,7 +81,8 @@ namespace osu.Game.Overlays.Mods
|
||||
|
||||
latestLoadTask = loadTask = LoadComponentsAsync(panels, loaded =>
|
||||
{
|
||||
ItemsFlow.ChildrenEnumerable = loaded;
|
||||
ItemsFlow.RemoveAll(panel => panel is ModPresetPanel);
|
||||
ItemsFlow.AddRange(loaded);
|
||||
}, (cancellationTokenSource = new CancellationTokenSource()).Token);
|
||||
loadTask.ContinueWith(_ =>
|
||||
{
|
||||
|
@ -43,8 +43,7 @@ namespace osu.Game.Overlays.Mods
|
||||
}
|
||||
|
||||
public const float CORNER_RADIUS = 7;
|
||||
|
||||
protected const float HEIGHT = 42;
|
||||
public const float HEIGHT = 42;
|
||||
|
||||
protected virtual float IdleSwitchWidth => 14;
|
||||
protected virtual float ExpandedSwitchWidth => 30;
|
||||
|
@ -10,6 +10,7 @@ using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
@ -949,7 +950,7 @@ namespace osu.Game.Screens.Edit
|
||||
|
||||
ControlPointInfo IBeatSyncProvider.ControlPoints => editorBeatmap.ControlPointInfo;
|
||||
IClock IBeatSyncProvider.Clock => clock;
|
||||
ChannelAmplitudes? IBeatSyncProvider.Amplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : null;
|
||||
ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : ChannelAmplitudes.Empty;
|
||||
|
||||
private class BeatmapEditorToast : Toast
|
||||
{
|
||||
|
@ -1,27 +1,23 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.OpenGL.Vertices;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Framework.Graphics.Shaders;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Beatmaps;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics.Rendering;
|
||||
using osu.Game.Beatmaps;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Screens.Menu
|
||||
{
|
||||
@ -30,8 +26,6 @@ namespace osu.Game.Screens.Menu
|
||||
/// </summary>
|
||||
public class LogoVisualisation : Drawable
|
||||
{
|
||||
private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
|
||||
|
||||
/// <summary>
|
||||
/// The number of bars to jump each update iteration.
|
||||
/// </summary>
|
||||
@ -76,8 +70,8 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
private readonly float[] frequencyAmplitudes = new float[256];
|
||||
|
||||
private IShader shader;
|
||||
private Texture texture;
|
||||
private IShader shader = null!;
|
||||
private Texture texture = null!;
|
||||
|
||||
public LogoVisualisation()
|
||||
{
|
||||
@ -92,33 +86,31 @@ namespace osu.Game.Screens.Menu
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IRenderer renderer, ShaderManager shaders, IBindable<WorkingBeatmap> beatmap)
|
||||
private void load(IRenderer renderer, ShaderManager shaders)
|
||||
{
|
||||
this.beatmap.BindTo(beatmap);
|
||||
texture = renderer.WhitePixel;
|
||||
shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED);
|
||||
}
|
||||
|
||||
private readonly float[] temporalAmplitudes = new float[ChannelAmplitudes.AMPLITUDES_SIZE];
|
||||
|
||||
[Resolved]
|
||||
private IBeatSyncProvider beatSyncProvider { get; set; } = null!;
|
||||
|
||||
private void updateAmplitudes()
|
||||
{
|
||||
var effect = beatmap.Value.BeatmapLoaded && beatmap.Value.TrackLoaded
|
||||
? beatmap.Value.Beatmap?.ControlPointInfo.EffectPointAt(beatmap.Value.Track.CurrentTime)
|
||||
: null;
|
||||
|
||||
for (int i = 0; i < temporalAmplitudes.Length; i++)
|
||||
temporalAmplitudes[i] = 0;
|
||||
|
||||
if (beatmap.Value.TrackLoaded)
|
||||
addAmplitudesFromSource(beatmap.Value.Track);
|
||||
if (beatSyncProvider.Clock != null)
|
||||
addAmplitudesFromSource(beatSyncProvider);
|
||||
|
||||
foreach (var source in amplitudeSources)
|
||||
addAmplitudesFromSource(source);
|
||||
|
||||
for (int i = 0; i < bars_per_visualiser; i++)
|
||||
{
|
||||
float targetAmplitude = (temporalAmplitudes[(i + indexOffset) % bars_per_visualiser]) * (effect?.KiaiMode == true ? 1 : 0.5f);
|
||||
float targetAmplitude = (temporalAmplitudes[(i + indexOffset) % bars_per_visualiser]) * (beatSyncProvider.CheckIsKiaiTime() ? 1 : 0.5f);
|
||||
if (targetAmplitude > frequencyAmplitudes[i])
|
||||
frequencyAmplitudes[i] = targetAmplitude;
|
||||
}
|
||||
@ -153,7 +145,7 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
protected override DrawNode CreateDrawNode() => new VisualisationDrawNode(this);
|
||||
|
||||
private void addAmplitudesFromSource([NotNull] IHasAmplitudes source)
|
||||
private void addAmplitudesFromSource(IHasAmplitudes source)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException(nameof(source));
|
||||
|
||||
@ -170,8 +162,8 @@ namespace osu.Game.Screens.Menu
|
||||
{
|
||||
protected new LogoVisualisation Source => (LogoVisualisation)base.Source;
|
||||
|
||||
private IShader shader;
|
||||
private Texture texture;
|
||||
private IShader shader = null!;
|
||||
private Texture texture = null!;
|
||||
|
||||
// Assuming the logo is a circle, we don't need a second dimension.
|
||||
private float size;
|
||||
@ -180,7 +172,7 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
private readonly float[] audioData = new float[256];
|
||||
|
||||
private IVertexBatch<TexturedVertex2D> vertexBatch;
|
||||
private IVertexBatch<TexturedVertex2D>? vertexBatch;
|
||||
|
||||
public VisualisationDrawNode(LogoVisualisation source)
|
||||
: base(source)
|
||||
@ -211,43 +203,40 @@ namespace osu.Game.Screens.Menu
|
||||
ColourInfo colourInfo = DrawColourInfo.Colour;
|
||||
colourInfo.ApplyChild(transparent_white);
|
||||
|
||||
if (audioData != null)
|
||||
for (int j = 0; j < visualiser_rounds; j++)
|
||||
{
|
||||
for (int j = 0; j < visualiser_rounds; j++)
|
||||
for (int i = 0; i < bars_per_visualiser; i++)
|
||||
{
|
||||
for (int i = 0; i < bars_per_visualiser; i++)
|
||||
{
|
||||
if (audioData[i] < amplitude_dead_zone)
|
||||
continue;
|
||||
if (audioData[i] < amplitude_dead_zone)
|
||||
continue;
|
||||
|
||||
float rotation = MathUtils.DegreesToRadians(i / (float)bars_per_visualiser * 360 + j * 360 / visualiser_rounds);
|
||||
float rotationCos = MathF.Cos(rotation);
|
||||
float rotationSin = MathF.Sin(rotation);
|
||||
// taking the cos and sin to the 0..1 range
|
||||
var barPosition = new Vector2(rotationCos / 2 + 0.5f, rotationSin / 2 + 0.5f) * size;
|
||||
float rotation = MathUtils.DegreesToRadians(i / (float)bars_per_visualiser * 360 + j * 360 / visualiser_rounds);
|
||||
float rotationCos = MathF.Cos(rotation);
|
||||
float rotationSin = MathF.Sin(rotation);
|
||||
// taking the cos and sin to the 0..1 range
|
||||
var barPosition = new Vector2(rotationCos / 2 + 0.5f, rotationSin / 2 + 0.5f) * size;
|
||||
|
||||
var barSize = new Vector2(size * MathF.Sqrt(2 * (1 - MathF.Cos(MathUtils.DegreesToRadians(360f / bars_per_visualiser)))) / 2f, bar_length * audioData[i]);
|
||||
// The distance between the position and the sides of the bar.
|
||||
var bottomOffset = new Vector2(-rotationSin * barSize.X / 2, rotationCos * barSize.X / 2);
|
||||
// The distance between the bottom side of the bar and the top side.
|
||||
var amplitudeOffset = new Vector2(rotationCos * barSize.Y, rotationSin * barSize.Y);
|
||||
var barSize = new Vector2(size * MathF.Sqrt(2 * (1 - MathF.Cos(MathUtils.DegreesToRadians(360f / bars_per_visualiser)))) / 2f, bar_length * audioData[i]);
|
||||
// The distance between the position and the sides of the bar.
|
||||
var bottomOffset = new Vector2(-rotationSin * barSize.X / 2, rotationCos * barSize.X / 2);
|
||||
// The distance between the bottom side of the bar and the top side.
|
||||
var amplitudeOffset = new Vector2(rotationCos * barSize.Y, rotationSin * barSize.Y);
|
||||
|
||||
var rectangle = new Quad(
|
||||
Vector2Extensions.Transform(barPosition - bottomOffset, DrawInfo.Matrix),
|
||||
Vector2Extensions.Transform(barPosition - bottomOffset + amplitudeOffset, DrawInfo.Matrix),
|
||||
Vector2Extensions.Transform(barPosition + bottomOffset, DrawInfo.Matrix),
|
||||
Vector2Extensions.Transform(barPosition + bottomOffset + amplitudeOffset, DrawInfo.Matrix)
|
||||
);
|
||||
var rectangle = new Quad(
|
||||
Vector2Extensions.Transform(barPosition - bottomOffset, DrawInfo.Matrix),
|
||||
Vector2Extensions.Transform(barPosition - bottomOffset + amplitudeOffset, DrawInfo.Matrix),
|
||||
Vector2Extensions.Transform(barPosition + bottomOffset, DrawInfo.Matrix),
|
||||
Vector2Extensions.Transform(barPosition + bottomOffset + amplitudeOffset, DrawInfo.Matrix)
|
||||
);
|
||||
|
||||
renderer.DrawQuad(
|
||||
texture,
|
||||
rectangle,
|
||||
colourInfo,
|
||||
null,
|
||||
vertexBatch.AddAction,
|
||||
// barSize by itself will make it smooth more in the X axis than in the Y axis, this reverts that.
|
||||
Vector2.Divide(inflation, barSize.Yx));
|
||||
}
|
||||
renderer.DrawQuad(
|
||||
texture,
|
||||
rectangle,
|
||||
colourInfo,
|
||||
null,
|
||||
vertexBatch.AddAction,
|
||||
// barSize by itself will make it smooth more in the X axis than in the Y axis, this reverts that.
|
||||
Vector2.Divide(inflation, barSize.Yx));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -353,7 +353,7 @@ namespace osu.Game.Screens.Menu
|
||||
float maxAmplitude = lastBeatIndex >= 0 ? musicController.CurrentTrack.CurrentAmplitudes.Maximum : 0;
|
||||
logoAmplitudeContainer.Scale = new Vector2((float)Interpolation.Damp(logoAmplitudeContainer.Scale.X, 1 - Math.Max(0, maxAmplitude - scale_adjust_cutoff) * 0.04f, 0.9f, Time.Elapsed));
|
||||
|
||||
triangles.Velocity = (float)Interpolation.Damp(triangles.Velocity, triangles_paused_velocity * (LastEffectPoint.KiaiMode ? 4 : 2), 0.995f, Time.Elapsed);
|
||||
triangles.Velocity = (float)Interpolation.Damp(triangles.Velocity, triangles_paused_velocity * (IsKiaiTime ? 4 : 2), 0.995f, Time.Elapsed);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -40,8 +40,6 @@ namespace osu.Game.Screens.Play.HUD
|
||||
public override bool HandleNonPositionalInput => AllowSeeking.Value;
|
||||
public override bool HandlePositionalInput => AllowSeeking.Value;
|
||||
|
||||
protected override bool BlockScrollInput => false;
|
||||
|
||||
[Resolved]
|
||||
private Player? player { get; set; }
|
||||
|
||||
|
@ -14,6 +14,12 @@ namespace osu.Game.Screens.Play.HUD
|
||||
{
|
||||
public abstract class SongProgress : OverlayContainer, ISkinnableDrawable
|
||||
{
|
||||
// Some implementations of this element allow seeking during gameplay playback.
|
||||
// Set a sane default of never handling input to override the behaviour provided by OverlayContainer.
|
||||
public override bool HandleNonPositionalInput => false;
|
||||
public override bool HandlePositionalInput => false;
|
||||
protected override bool BlockScrollInput => false;
|
||||
|
||||
public bool UsesFixedAnchor { get; set; }
|
||||
|
||||
[Resolved]
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -53,21 +51,21 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
private readonly WorkingBeatmap beatmap;
|
||||
|
||||
private HardwareCorrectionOffsetClock userGlobalOffsetClock;
|
||||
private HardwareCorrectionOffsetClock userBeatmapOffsetClock;
|
||||
private HardwareCorrectionOffsetClock platformOffsetClock;
|
||||
private MasterGameplayClock masterGameplayClock;
|
||||
private Bindable<double> userAudioOffset;
|
||||
private HardwareCorrectionOffsetClock userGlobalOffsetClock = null!;
|
||||
private HardwareCorrectionOffsetClock userBeatmapOffsetClock = null!;
|
||||
private HardwareCorrectionOffsetClock platformOffsetClock = null!;
|
||||
private MasterGameplayClock masterGameplayClock = null!;
|
||||
private Bindable<double> userAudioOffset = null!;
|
||||
|
||||
private IDisposable beatmapOffsetSubscription;
|
||||
private IDisposable? beatmapOffsetSubscription;
|
||||
|
||||
private readonly double skipTargetTime;
|
||||
|
||||
[Resolved]
|
||||
private RealmAccess realm { get; set; }
|
||||
private RealmAccess realm { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private OsuConfigManager config { get; set; }
|
||||
private OsuConfigManager config { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new master gameplay clock container.
|
||||
@ -255,7 +253,7 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
ControlPointInfo IBeatSyncProvider.ControlPoints => beatmap.Beatmap.ControlPointInfo;
|
||||
IClock IBeatSyncProvider.Clock => GameplayClock;
|
||||
ChannelAmplitudes? IBeatSyncProvider.Amplitudes => beatmap.TrackLoaded ? beatmap.Track.CurrentAmplitudes : null;
|
||||
ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => beatmap.TrackLoaded ? beatmap.Track.CurrentAmplitudes : ChannelAmplitudes.Empty;
|
||||
|
||||
private class HardwareCorrectionOffsetClock : FramedOffsetClock
|
||||
{
|
||||
|
@ -68,12 +68,14 @@ namespace osu.Game.Skinning
|
||||
|
||||
storage ??= realmBackedStorage = new RealmBackedResourceStore<SkinInfo>(SkinInfo, resources.Files, resources.RealmAccess);
|
||||
|
||||
(storage as ResourceStore<byte[]>)?.AddExtension("ogg");
|
||||
|
||||
var samples = resources.AudioManager?.GetSampleStore(storage);
|
||||
if (samples != null)
|
||||
samples.PlaybackConcurrency = OsuGameBase.SAMPLE_CONCURRENCY;
|
||||
|
||||
// osu-stable performs audio lookups in order of wav -> mp3 -> ogg.
|
||||
// The GetSampleStore() call above internally adds wav and mp3, so ogg is added at the end to ensure expected ordering.
|
||||
(storage as ResourceStore<byte[]>)?.AddExtension("ogg");
|
||||
|
||||
Samples = samples;
|
||||
Textures = new TextureStore(resources.Renderer, resources.CreateTextureLoaderStore(storage));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user