mirror of
https://github.com/osukey/osukey.git
synced 2025-08-05 15:44:04 +09:00
Merge branch 'master' into irenderer-glwrapper
This commit is contained in:
@ -1,8 +1,6 @@
|
|||||||
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using DiscordRPC;
|
using DiscordRPC;
|
||||||
@ -26,15 +24,15 @@ namespace osu.Desktop
|
|||||||
{
|
{
|
||||||
private const string client_id = "367827983903490050";
|
private const string client_id = "367827983903490050";
|
||||||
|
|
||||||
private DiscordRpcClient client;
|
private DiscordRpcClient client = null!;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IBindable<RulesetInfo> ruleset { get; set; }
|
private IBindable<RulesetInfo> ruleset { get; set; } = null!;
|
||||||
|
|
||||||
private IBindable<APIUser> user;
|
private IBindable<APIUser> user = null!;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IAPIProvider api { get; set; }
|
private IAPIProvider api { get; set; } = null!;
|
||||||
|
|
||||||
private readonly IBindable<UserStatus> status = new Bindable<UserStatus>();
|
private readonly IBindable<UserStatus> status = new Bindable<UserStatus>();
|
||||||
private readonly IBindable<UserActivity> activity = new Bindable<UserActivity>();
|
private readonly IBindable<UserActivity> activity = new Bindable<UserActivity>();
|
||||||
@ -130,7 +128,7 @@ namespace osu.Desktop
|
|||||||
presence.Assets.LargeImageText = string.Empty;
|
presence.Assets.LargeImageText = string.Empty;
|
||||||
else
|
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);
|
presence.Assets.LargeImageText = $"{user.Value.Username}" + (statistics.GlobalRank > 0 ? $" (rank #{statistics.GlobalRank:N0})" : string.Empty);
|
||||||
else
|
else
|
||||||
presence.Assets.LargeImageText = $"{user.Value.Username}" + (user.Value.Statistics?.GlobalRank > 0 ? $" (rank #{user.Value.Statistics.GlobalRank:N0})" : string.Empty);
|
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)
|
switch (activity)
|
||||||
{
|
{
|
||||||
@ -183,10 +181,10 @@ namespace osu.Desktop
|
|||||||
switch (activity)
|
switch (activity)
|
||||||
{
|
{
|
||||||
case UserActivity.InGame game:
|
case UserActivity.InGame game:
|
||||||
return game.BeatmapInfo.ToString();
|
return game.BeatmapInfo.ToString() ?? string.Empty;
|
||||||
|
|
||||||
case UserActivity.Editing edit:
|
case UserActivity.Editing edit:
|
||||||
return edit.BeatmapInfo.ToString();
|
return edit.BeatmapInfo.ToString() ?? string.Empty;
|
||||||
|
|
||||||
case UserActivity.InLobby lobby:
|
case UserActivity.InLobby lobby:
|
||||||
return privacyMode.Value == DiscordRichPresenceMode.Limited ? string.Empty : lobby.Room.Name.Value;
|
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.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace osu.Desktop.LegacyIpc
|
namespace osu.Desktop.LegacyIpc
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -13,7 +11,7 @@ namespace osu.Desktop.LegacyIpc
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class LegacyIpcDifficultyCalculationRequest
|
public class LegacyIpcDifficultyCalculationRequest
|
||||||
{
|
{
|
||||||
public string BeatmapFile { get; set; }
|
public string BeatmapFile { get; set; } = string.Empty;
|
||||||
public int RulesetId { get; set; }
|
public int RulesetId { get; set; }
|
||||||
public int Mods { get; set; }
|
public int Mods { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace osu.Desktop.LegacyIpc
|
namespace osu.Desktop.LegacyIpc
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
@ -39,17 +37,20 @@ namespace osu.Desktop.LegacyIpc
|
|||||||
public new object Value
|
public new object Value
|
||||||
{
|
{
|
||||||
get => base.Value;
|
get => base.Value;
|
||||||
set => base.Value = new Data
|
set => base.Value = new Data(value.GetType().Name, value);
|
||||||
{
|
|
||||||
MessageType = value.GetType().Name,
|
|
||||||
MessageData = value
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Data
|
public class Data
|
||||||
{
|
{
|
||||||
public string MessageType { get; set; }
|
public string MessageType { get; }
|
||||||
public object MessageData { get; set; }
|
|
||||||
|
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.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
@ -27,7 +25,7 @@ namespace osu.Desktop
|
|||||||
private const string base_game_name = @"osu";
|
private const string base_game_name = @"osu";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private static LegacyTcpIpcProvider legacyIpc;
|
private static LegacyTcpIpcProvider? legacyIpc;
|
||||||
|
|
||||||
[STAThread]
|
[STAThread]
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
@ -21,7 +19,7 @@ namespace osu.Desktop.Security
|
|||||||
public class ElevatedPrivilegesChecker : Component
|
public class ElevatedPrivilegesChecker : Component
|
||||||
{
|
{
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private INotificationOverlay notifications { get; set; }
|
private INotificationOverlay notifications { get; set; } = null!;
|
||||||
|
|
||||||
private bool elevated;
|
private bool elevated;
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -26,8 +24,8 @@ namespace osu.Desktop.Updater
|
|||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
public class SquirrelUpdateManager : osu.Game.Updater.UpdateManager
|
public class SquirrelUpdateManager : osu.Game.Updater.UpdateManager
|
||||||
{
|
{
|
||||||
private UpdateManager updateManager;
|
private UpdateManager? updateManager;
|
||||||
private INotificationOverlay notificationOverlay;
|
private INotificationOverlay notificationOverlay = null!;
|
||||||
|
|
||||||
public Task PrepareUpdateAsync() => UpdateManager.RestartAppWhenExited();
|
public Task PrepareUpdateAsync() => UpdateManager.RestartAppWhenExited();
|
||||||
|
|
||||||
@ -50,12 +48,12 @@ namespace osu.Desktop.Updater
|
|||||||
|
|
||||||
protected override async Task<bool> PerformUpdateCheck() => await checkForUpdateAsync().ConfigureAwait(false);
|
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?
|
// should we schedule a retry on completion of this check?
|
||||||
bool scheduleRecheck = true;
|
bool scheduleRecheck = true;
|
||||||
|
|
||||||
const string github_token = null; // TODO: populate.
|
const string? github_token = null; // TODO: populate.
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -145,7 +143,7 @@ namespace osu.Desktop.Updater
|
|||||||
private class UpdateCompleteNotification : ProgressCompletionNotification
|
private class UpdateCompleteNotification : ProgressCompletionNotification
|
||||||
{
|
{
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuGame game { get; set; }
|
private OsuGame game { get; set; } = null!;
|
||||||
|
|
||||||
public UpdateCompleteNotification(SquirrelUpdateManager updateManager)
|
public UpdateCompleteNotification(SquirrelUpdateManager updateManager)
|
||||||
{
|
{
|
||||||
@ -154,7 +152,7 @@ namespace osu.Desktop.Updater
|
|||||||
Activated = () =>
|
Activated = () =>
|
||||||
{
|
{
|
||||||
updateManager.PrepareUpdateAsync()
|
updateManager.PrepareUpdateAsync()
|
||||||
.ContinueWith(_ => updateManager.Schedule(() => game?.AttemptExit()));
|
.ContinueWith(_ => updateManager.Schedule(() => game.AttemptExit()));
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -14,12 +12,12 @@ namespace osu.Desktop.Windows
|
|||||||
{
|
{
|
||||||
public class GameplayWinKeyBlocker : Component
|
public class GameplayWinKeyBlocker : Component
|
||||||
{
|
{
|
||||||
private Bindable<bool> disableWinKey;
|
private Bindable<bool> disableWinKey = null!;
|
||||||
private IBindable<bool> localUserPlaying;
|
private IBindable<bool> localUserPlaying = null!;
|
||||||
private IBindable<bool> isActive;
|
private IBindable<bool> isActive = null!;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private GameHost host { get; set; }
|
private GameHost host { get; set; } = null!;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(ILocalUserPlayInfo localUserInfo, OsuConfigManager config)
|
private void load(ILocalUserPlayInfo localUserInfo, OsuConfigManager config)
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
@ -21,7 +19,7 @@ namespace osu.Desktop.Windows
|
|||||||
private const int wm_syskeyup = 261;
|
private const int wm_syskeyup = 261;
|
||||||
|
|
||||||
//Resharper disable once NotAccessedField.Local
|
//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;
|
private static IntPtr keyHook;
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Explicit)]
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
@ -1,14 +1,23 @@
|
|||||||
// 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.
|
// 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 NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio.Sample;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions;
|
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.Framework.Testing;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
|
using osu.Game.IO;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
@ -19,9 +28,9 @@ namespace osu.Game.Tests.Skins
|
|||||||
public class TestSceneSkinResources : OsuTestScene
|
public class TestSceneSkinResources : OsuTestScene
|
||||||
{
|
{
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private SkinManager skins { get; set; }
|
private SkinManager skins { get; set; } = null!;
|
||||||
|
|
||||||
private ISkin skin;
|
private ISkin skin = null!;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
@ -32,5 +41,55 @@ namespace osu.Game.Tests.Skins
|
|||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestRetrieveOggSample() => AddAssert("sample is non-null", () => skin.GetSample(new SampleInfo("sample")) != null);
|
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"))));
|
AddStep("add collection", () => writeAndRefresh(r => r.Add(new BeatmapCollection(name: "1"))));
|
||||||
assertCollectionDropdownContains("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)));
|
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()));
|
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]
|
[Test]
|
||||||
@ -168,15 +169,15 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
AddStep("add collection", () => writeAndRefresh(r => r.Add(new BeatmapCollection(name: "1"))));
|
AddStep("add collection", () => writeAndRefresh(r => r.Add(new BeatmapCollection(name: "1"))));
|
||||||
assertCollectionDropdownContains("1");
|
assertCollectionDropdownContains("1");
|
||||||
AddAssert("button is plus", () => getAddOrRemoveButton(1).Icon.Equals(FontAwesome.Solid.PlusSquare));
|
assertFirstButtonIs(FontAwesome.Solid.PlusSquare);
|
||||||
|
|
||||||
addClickAddOrRemoveButtonStep(1);
|
addClickAddOrRemoveButtonStep(1);
|
||||||
AddAssert("collection contains beatmap", () => getFirstCollection().BeatmapMD5Hashes.Contains(Beatmap.Value.BeatmapInfo.MD5Hash));
|
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);
|
addClickAddOrRemoveButtonStep(1);
|
||||||
AddAssert("collection does not contain beatmap", () => !getFirstCollection().BeatmapMD5Hashes.Contains(Beatmap.Value.BeatmapInfo.MD5Hash));
|
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]
|
[Test]
|
||||||
@ -226,6 +227,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
=> AddUntilStep($"collection dropdown header displays '{collectionName}'",
|
=> AddUntilStep($"collection dropdown header displays '{collectionName}'",
|
||||||
() => shouldDisplay == (control.ChildrenOfType<CollectionDropdown.CollectionDropdownHeader>().Single().ChildrenOfType<SpriteText>().First().Text == 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) =>
|
private void assertCollectionDropdownContains(string collectionName, bool shouldContain = true) =>
|
||||||
AddUntilStep($"collection dropdown {(shouldContain ? "contains" : "does not contain")} '{collectionName}'",
|
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
|
// 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.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
@ -9,19 +10,26 @@ using osu.Framework.Extensions.ObjectExtensions;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Testing;
|
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;
|
||||||
using osu.Game.Overlays.Mods;
|
using osu.Game.Overlays.Mods;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mania.Mods;
|
using osu.Game.Rulesets.Mania.Mods;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.UserInterface
|
namespace osu.Game.Tests.Visual.UserInterface
|
||||||
{
|
{
|
||||||
public class TestSceneModPresetColumn : OsuTestScene
|
public class TestSceneModPresetColumn : OsuManualInputManagerTestScene
|
||||||
{
|
{
|
||||||
protected override bool UseFreshStoragePerRun => true;
|
protected override bool UseFreshStoragePerRun => true;
|
||||||
|
|
||||||
|
private Container<Drawable> content = null!;
|
||||||
|
protected override Container<Drawable> Content => content;
|
||||||
|
|
||||||
private RulesetStore rulesets = null!;
|
private RulesetStore rulesets = null!;
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
@ -32,6 +40,12 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
{
|
{
|
||||||
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
|
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
|
||||||
Dependencies.Cache(Realm);
|
Dependencies.Cache(Realm);
|
||||||
|
|
||||||
|
base.Content.Add(content = new PopoverContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding(30),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
@ -57,15 +71,10 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
public void TestBasicOperation()
|
public void TestBasicOperation()
|
||||||
{
|
{
|
||||||
AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0));
|
AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0));
|
||||||
AddStep("create content", () => Child = new Container
|
AddStep("create content", () => Child = new ModPresetColumn
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
Anchor = Anchor.Centre,
|
||||||
Padding = new MarginPadding(30),
|
Origin = Anchor.Centre,
|
||||||
Child = new ModPresetColumn
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
AddUntilStep("3 panels visible", () => this.ChildrenOfType<ModPresetPanel>().Count() == 3);
|
AddUntilStep("3 panels visible", () => this.ChildrenOfType<ModPresetPanel>().Count() == 3);
|
||||||
|
|
||||||
@ -112,15 +121,10 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
public void TestSoftDeleteSupport()
|
public void TestSoftDeleteSupport()
|
||||||
{
|
{
|
||||||
AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0));
|
AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0));
|
||||||
AddStep("create content", () => Child = new Container
|
AddStep("create content", () => Child = new ModPresetColumn
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
Anchor = Anchor.Centre,
|
||||||
Padding = new MarginPadding(30),
|
Origin = Anchor.Centre,
|
||||||
Child = new ModPresetColumn
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
AddUntilStep("3 panels visible", () => this.ChildrenOfType<ModPresetPanel>().Count() == 3);
|
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);
|
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[]
|
private ICollection<ModPreset> createTestPresets() => new[]
|
||||||
{
|
{
|
||||||
new ModPreset
|
new ModPreset
|
||||||
|
@ -105,5 +105,11 @@ namespace osu.Game.Audio
|
|||||||
/// Retrieves the audio track.
|
/// Retrieves the audio track.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected abstract Track? GetTrack();
|
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.
|
// another async load might have completed before this one.
|
||||||
// if so, do not make any changes.
|
// if so, do not make any changes.
|
||||||
if (loadedPreview != previewTrack)
|
if (loadedPreview != previewTrack)
|
||||||
|
{
|
||||||
|
loadedPreview.Dispose();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
AddInternal(loadedPreview);
|
AddInternal(loadedPreview);
|
||||||
toggleLoading(false);
|
toggleLoading(false);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
@ -14,12 +14,16 @@ namespace osu.Game.Beatmaps
|
|||||||
/// Primarily intended for use with <see cref="BeatSyncedContainer"/>.
|
/// Primarily intended for use with <see cref="BeatSyncedContainer"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Cached]
|
[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; }
|
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; }
|
IClock? Clock { get; }
|
||||||
|
|
||||||
ChannelAmplitudes? Amplitudes { get; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Humanizer;
|
using Humanizer;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
@ -107,7 +108,15 @@ namespace osu.Game.Database
|
|||||||
notification.State = ProgressNotificationState.Cancelled;
|
notification.State = ProgressNotificationState.Cancelled;
|
||||||
|
|
||||||
if (!(error is OperationCanceledException))
|
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.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -10,13 +8,12 @@ using osu.Framework.Audio.Track;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Screens.Play;
|
|
||||||
|
|
||||||
namespace osu.Game.Graphics.Containers
|
namespace osu.Game.Graphics.Containers
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A container which fires a callback when a new beat is reached.
|
/// 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>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This container does not set its own clock to the source used for beat matching.
|
/// 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
|
public class BeatSyncedContainer : Container
|
||||||
{
|
{
|
||||||
private int lastBeat;
|
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>
|
/// <summary>
|
||||||
/// The amount of time before a beat we should fire <see cref="OnNewBeat(int, TimingControlPoint, EffectControlPoint, ChannelAmplitudes)"/>.
|
/// 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; }
|
public double MinimumBeatLength { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this container is currently tracking a beatmap's timing data.
|
/// Whether this container is currently tracking a beat sync provider.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected bool IsBeatSyncedWithTrack { get; private set; }
|
protected bool IsBeatSyncedWithTrack { get; private set; }
|
||||||
|
|
||||||
[Resolved]
|
[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)
|
protected virtual void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
|
||||||
{
|
{
|
||||||
@ -87,19 +86,18 @@ namespace osu.Game.Graphics.Containers
|
|||||||
TimingControlPoint timingPoint;
|
TimingControlPoint timingPoint;
|
||||||
EffectControlPoint effectPoint;
|
EffectControlPoint effectPoint;
|
||||||
|
|
||||||
IsBeatSyncedWithTrack = BeatSyncSource.Clock?.IsRunning == true && BeatSyncSource.ControlPoints != null;
|
IsBeatSyncedWithTrack = BeatSyncSource.CheckBeatSyncAvailable() && BeatSyncSource.Clock?.IsRunning == true;
|
||||||
|
|
||||||
double currentTrackTime;
|
double currentTrackTime;
|
||||||
|
|
||||||
if (IsBeatSyncedWithTrack)
|
if (IsBeatSyncedWithTrack)
|
||||||
{
|
{
|
||||||
Debug.Assert(BeatSyncSource.ControlPoints != null);
|
|
||||||
Debug.Assert(BeatSyncSource.Clock != null);
|
Debug.Assert(BeatSyncSource.Clock != null);
|
||||||
|
|
||||||
currentTrackTime = BeatSyncSource.Clock.CurrentTime + EarlyActivationMilliseconds;
|
currentTrackTime = BeatSyncSource.Clock.CurrentTime + EarlyActivationMilliseconds;
|
||||||
|
|
||||||
timingPoint = BeatSyncSource.ControlPoints.TimingPointAt(currentTrackTime);
|
timingPoint = BeatSyncSource.ControlPoints?.TimingPointAt(currentTrackTime) ?? TimingControlPoint.DEFAULT;
|
||||||
effectPoint = BeatSyncSource.ControlPoints.EffectPointAt(currentTrackTime);
|
effectPoint = BeatSyncSource.ControlPoints?.EffectPointAt(currentTrackTime) ?? EffectControlPoint.DEFAULT;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -128,7 +126,7 @@ namespace osu.Game.Graphics.Containers
|
|||||||
|
|
||||||
TimeSinceLastBeat = beatLength - TimeUntilNextBeat;
|
TimeSinceLastBeat = beatLength - TimeUntilNextBeat;
|
||||||
|
|
||||||
if (ReferenceEquals(timingPoint, LastTimingPoint) && beatIndex == lastBeat)
|
if (ReferenceEquals(timingPoint, lastTimingPoint) && beatIndex == lastBeat)
|
||||||
return;
|
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.
|
// 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)
|
if (AllowMistimedEventFiring || Math.Abs(TimeSinceLastBeat) < MISTIMED_ALLOWANCE)
|
||||||
{
|
{
|
||||||
using (BeginDelayedSequence(-TimeSinceLastBeat))
|
using (BeginDelayedSequence(-TimeSinceLastBeat))
|
||||||
OnNewBeat(beatIndex, timingPoint, effectPoint, BeatSyncSource.Amplitudes ?? ChannelAmplitudes.Empty);
|
OnNewBeat(beatIndex, timingPoint, effectPoint, BeatSyncSource.CurrentAmplitudes);
|
||||||
}
|
}
|
||||||
|
|
||||||
lastBeat = beatIndex;
|
lastBeat = beatIndex;
|
||||||
LastTimingPoint = timingPoint;
|
lastTimingPoint = timingPoint;
|
||||||
LastEffectPoint = effectPoint;
|
|
||||||
|
IsKiaiTime = effectPoint.KiaiMode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,15 +49,15 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
Active.BindDisabledChanged(disabled => Action = disabled ? null : Active.Toggle, true);
|
Active.BindDisabledChanged(disabled => Action = disabled ? null : Active.Toggle, true);
|
||||||
Active.BindValueChanged(_ =>
|
Active.BindValueChanged(_ =>
|
||||||
{
|
{
|
||||||
updateActiveState();
|
UpdateActiveState();
|
||||||
playSample();
|
playSample();
|
||||||
});
|
});
|
||||||
|
|
||||||
updateActiveState();
|
UpdateActiveState();
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateActiveState()
|
protected virtual void UpdateActiveState()
|
||||||
{
|
{
|
||||||
DarkerColour = Active.Value ? ColourProvider.Highlight1 : ColourProvider.Background3;
|
DarkerColour = Active.Value ? ColourProvider.Highlight1 : ColourProvider.Background3;
|
||||||
LighterColour = Active.Value ? ColourProvider.Colour0 : ColourProvider.Background1;
|
LighterColour = Active.Value ? ColourProvider.Colour0 : ColourProvider.Background1;
|
||||||
|
@ -26,6 +26,11 @@ namespace osu.Game.IO
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual string[] IgnoreFiles => Array.Empty<string>();
|
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)
|
protected MigratableStorage(Storage storage, string subPath = null)
|
||||||
: base(storage, subPath)
|
: base(storage, subPath)
|
||||||
{
|
{
|
||||||
@ -73,6 +78,9 @@ namespace osu.Game.IO
|
|||||||
if (topLevelExcludes && IgnoreFiles.Contains(fi.Name))
|
if (topLevelExcludes && IgnoreFiles.Contains(fi.Name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (IgnoreSuffixes.Any(suffix => fi.Name.EndsWith(suffix, StringComparison.Ordinal)))
|
||||||
|
continue;
|
||||||
|
|
||||||
allFilesDeleted &= AttemptOperation(() => fi.Delete(), throwOnFailure: false);
|
allFilesDeleted &= AttemptOperation(() => fi.Delete(), throwOnFailure: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,6 +89,9 @@ namespace osu.Game.IO
|
|||||||
if (topLevelExcludes && IgnoreDirectories.Contains(dir.Name))
|
if (topLevelExcludes && IgnoreDirectories.Contains(dir.Name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (IgnoreSuffixes.Any(suffix => dir.Name.EndsWith(suffix, StringComparison.Ordinal)))
|
||||||
|
continue;
|
||||||
|
|
||||||
allFilesDeleted &= AttemptOperation(() => dir.Delete(true), throwOnFailure: false);
|
allFilesDeleted &= AttemptOperation(() => dir.Delete(true), throwOnFailure: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +112,9 @@ namespace osu.Game.IO
|
|||||||
if (topLevelExcludes && IgnoreFiles.Contains(fileInfo.Name))
|
if (topLevelExcludes && IgnoreFiles.Contains(fileInfo.Name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (IgnoreSuffixes.Any(suffix => fileInfo.Name.EndsWith(suffix, StringComparison.Ordinal)))
|
||||||
|
continue;
|
||||||
|
|
||||||
AttemptOperation(() =>
|
AttemptOperation(() =>
|
||||||
{
|
{
|
||||||
fileInfo.Refresh();
|
fileInfo.Refresh();
|
||||||
@ -119,6 +133,9 @@ namespace osu.Game.IO
|
|||||||
if (topLevelExcludes && IgnoreDirectories.Contains(dir.Name))
|
if (topLevelExcludes && IgnoreDirectories.Contains(dir.Name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (IgnoreSuffixes.Any(suffix => dir.Name.EndsWith(suffix, StringComparison.Ordinal)))
|
||||||
|
continue;
|
||||||
|
|
||||||
CopyRecursive(dir, destination.CreateSubdirectory(dir.Name), false);
|
CopyRecursive(dir, destination.CreateSubdirectory(dir.Name), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,15 +38,20 @@ namespace osu.Game.IO
|
|||||||
public override string[] IgnoreDirectories => new[]
|
public override string[] IgnoreDirectories => new[]
|
||||||
{
|
{
|
||||||
"cache",
|
"cache",
|
||||||
$"{OsuGameBase.CLIENT_DATABASE_FILENAME}.management",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public override string[] IgnoreFiles => new[]
|
public override string[] IgnoreFiles => new[]
|
||||||
{
|
{
|
||||||
"framework.ini",
|
"framework.ini",
|
||||||
"storage.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)
|
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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
@ -89,6 +89,16 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString Collections => new TranslatableString(getKey(@"collections"), @"Collections");
|
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}";
|
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -29,6 +29,11 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString PersonalPresets => new TranslatableString(getKey(@"personal_presets"), @"Personal Presets");
|
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}";
|
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,6 +102,14 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
[JsonProperty("pp")]
|
[JsonProperty("pp")]
|
||||||
public double? PP { get; set; }
|
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
|
#endregion
|
||||||
|
|
||||||
public override string ToString() => $"score_id: {ID} user_id: {UserID}";
|
public override string ToString() => $"score_id: {ID} user_id: {UserID}";
|
||||||
@ -165,7 +173,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
RulesetID = score.RulesetID,
|
RulesetID = score.RulesetID,
|
||||||
Passed = score.Passed,
|
Passed = score.Passed,
|
||||||
Mods = score.APIMods,
|
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;
|
public long OnlineID => ID ?? -1;
|
||||||
|
@ -588,6 +588,6 @@ namespace osu.Game
|
|||||||
|
|
||||||
ControlPointInfo IBeatSyncProvider.ControlPoints => Beatmap.Value.BeatmapLoaded ? Beatmap.Value.Beatmap.ControlPointInfo : null;
|
ControlPointInfo IBeatSyncProvider.ControlPoints => Beatmap.Value.BeatmapLoaded ? Beatmap.Value.Beatmap.ControlPointInfo : null;
|
||||||
IClock IBeatSyncProvider.Clock => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track : (IClock)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.
|
// beatmapset may have changed.
|
||||||
if (Preview != preview)
|
if (Preview != preview)
|
||||||
|
{
|
||||||
|
preview?.Dispose();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
AddInternal(preview);
|
AddInternal(preview);
|
||||||
loading = false;
|
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;
|
AccentColour = colours.Orange1;
|
||||||
HeaderText = ModSelectOverlayStrings.PersonalPresets;
|
HeaderText = ModSelectOverlayStrings.PersonalPresets;
|
||||||
|
|
||||||
|
AddPresetButton addPresetButton;
|
||||||
|
ItemsFlow.Add(addPresetButton = new AddPresetButton());
|
||||||
|
ItemsFlow.SetLayoutPosition(addPresetButton, float.PositiveInfinity);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -64,7 +68,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
if (!presets.Any())
|
if (!presets.Any())
|
||||||
{
|
{
|
||||||
ItemsFlow.Clear();
|
ItemsFlow.RemoveAll(panel => panel is ModPresetPanel);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +81,8 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
latestLoadTask = loadTask = LoadComponentsAsync(panels, loaded =>
|
latestLoadTask = loadTask = LoadComponentsAsync(panels, loaded =>
|
||||||
{
|
{
|
||||||
ItemsFlow.ChildrenEnumerable = loaded;
|
ItemsFlow.RemoveAll(panel => panel is ModPresetPanel);
|
||||||
|
ItemsFlow.AddRange(loaded);
|
||||||
}, (cancellationTokenSource = new CancellationTokenSource()).Token);
|
}, (cancellationTokenSource = new CancellationTokenSource()).Token);
|
||||||
loadTask.ContinueWith(_ =>
|
loadTask.ContinueWith(_ =>
|
||||||
{
|
{
|
||||||
|
@ -43,8 +43,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
}
|
}
|
||||||
|
|
||||||
public const float CORNER_RADIUS = 7;
|
public const float CORNER_RADIUS = 7;
|
||||||
|
public const float HEIGHT = 42;
|
||||||
protected const float HEIGHT = 42;
|
|
||||||
|
|
||||||
protected virtual float IdleSwitchWidth => 14;
|
protected virtual float IdleSwitchWidth => 14;
|
||||||
protected virtual float ExpandedSwitchWidth => 30;
|
protected virtual float ExpandedSwitchWidth => 30;
|
||||||
|
@ -10,6 +10,7 @@ using System.Linq;
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -949,7 +950,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
ControlPointInfo IBeatSyncProvider.ControlPoints => editorBeatmap.ControlPointInfo;
|
ControlPointInfo IBeatSyncProvider.ControlPoints => editorBeatmap.ControlPointInfo;
|
||||||
IClock IBeatSyncProvider.Clock => clock;
|
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
|
private class BeatmapEditorToast : Toast
|
||||||
{
|
{
|
||||||
|
@ -1,27 +1,23 @@
|
|||||||
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using osuTK;
|
using osu.Framework.Allocation;
|
||||||
using osuTK.Graphics;
|
using osu.Framework.Audio;
|
||||||
|
using osu.Framework.Audio.Track;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Graphics.OpenGL.Vertices;
|
using osu.Framework.Graphics.OpenGL.Vertices;
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
|
using osu.Framework.Graphics.Rendering;
|
||||||
using osu.Framework.Graphics.Shaders;
|
using osu.Framework.Graphics.Shaders;
|
||||||
using osu.Framework.Graphics.Textures;
|
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.Utils;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Framework.Graphics.Rendering;
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Menu
|
namespace osu.Game.Screens.Menu
|
||||||
{
|
{
|
||||||
@ -30,8 +26,6 @@ namespace osu.Game.Screens.Menu
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class LogoVisualisation : Drawable
|
public class LogoVisualisation : Drawable
|
||||||
{
|
{
|
||||||
private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The number of bars to jump each update iteration.
|
/// The number of bars to jump each update iteration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -76,8 +70,8 @@ namespace osu.Game.Screens.Menu
|
|||||||
|
|
||||||
private readonly float[] frequencyAmplitudes = new float[256];
|
private readonly float[] frequencyAmplitudes = new float[256];
|
||||||
|
|
||||||
private IShader shader;
|
private IShader shader = null!;
|
||||||
private Texture texture;
|
private Texture texture = null!;
|
||||||
|
|
||||||
public LogoVisualisation()
|
public LogoVisualisation()
|
||||||
{
|
{
|
||||||
@ -92,33 +86,31 @@ namespace osu.Game.Screens.Menu
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[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;
|
texture = renderer.WhitePixel;
|
||||||
shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED);
|
shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly float[] temporalAmplitudes = new float[ChannelAmplitudes.AMPLITUDES_SIZE];
|
private readonly float[] temporalAmplitudes = new float[ChannelAmplitudes.AMPLITUDES_SIZE];
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IBeatSyncProvider beatSyncProvider { get; set; } = null!;
|
||||||
|
|
||||||
private void updateAmplitudes()
|
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++)
|
for (int i = 0; i < temporalAmplitudes.Length; i++)
|
||||||
temporalAmplitudes[i] = 0;
|
temporalAmplitudes[i] = 0;
|
||||||
|
|
||||||
if (beatmap.Value.TrackLoaded)
|
if (beatSyncProvider.Clock != null)
|
||||||
addAmplitudesFromSource(beatmap.Value.Track);
|
addAmplitudesFromSource(beatSyncProvider);
|
||||||
|
|
||||||
foreach (var source in amplitudeSources)
|
foreach (var source in amplitudeSources)
|
||||||
addAmplitudesFromSource(source);
|
addAmplitudesFromSource(source);
|
||||||
|
|
||||||
for (int i = 0; i < bars_per_visualiser; i++)
|
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])
|
if (targetAmplitude > frequencyAmplitudes[i])
|
||||||
frequencyAmplitudes[i] = targetAmplitude;
|
frequencyAmplitudes[i] = targetAmplitude;
|
||||||
}
|
}
|
||||||
@ -153,7 +145,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
|
|
||||||
protected override DrawNode CreateDrawNode() => new VisualisationDrawNode(this);
|
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));
|
if (source == null) throw new ArgumentNullException(nameof(source));
|
||||||
|
|
||||||
@ -170,8 +162,8 @@ namespace osu.Game.Screens.Menu
|
|||||||
{
|
{
|
||||||
protected new LogoVisualisation Source => (LogoVisualisation)base.Source;
|
protected new LogoVisualisation Source => (LogoVisualisation)base.Source;
|
||||||
|
|
||||||
private IShader shader;
|
private IShader shader = null!;
|
||||||
private Texture texture;
|
private Texture texture = null!;
|
||||||
|
|
||||||
// Assuming the logo is a circle, we don't need a second dimension.
|
// Assuming the logo is a circle, we don't need a second dimension.
|
||||||
private float size;
|
private float size;
|
||||||
@ -180,7 +172,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
|
|
||||||
private readonly float[] audioData = new float[256];
|
private readonly float[] audioData = new float[256];
|
||||||
|
|
||||||
private IVertexBatch<TexturedVertex2D> vertexBatch;
|
private IVertexBatch<TexturedVertex2D>? vertexBatch;
|
||||||
|
|
||||||
public VisualisationDrawNode(LogoVisualisation source)
|
public VisualisationDrawNode(LogoVisualisation source)
|
||||||
: base(source)
|
: base(source)
|
||||||
@ -211,43 +203,40 @@ namespace osu.Game.Screens.Menu
|
|||||||
ColourInfo colourInfo = DrawColourInfo.Colour;
|
ColourInfo colourInfo = DrawColourInfo.Colour;
|
||||||
colourInfo.ApplyChild(transparent_white);
|
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 rotation = MathUtils.DegreesToRadians(i / (float)bars_per_visualiser * 360 + j * 360 / visualiser_rounds);
|
||||||
float rotationCos = MathF.Cos(rotation);
|
float rotationCos = MathF.Cos(rotation);
|
||||||
float rotationSin = MathF.Sin(rotation);
|
float rotationSin = MathF.Sin(rotation);
|
||||||
// taking the cos and sin to the 0..1 range
|
// taking the cos and sin to the 0..1 range
|
||||||
var barPosition = new Vector2(rotationCos / 2 + 0.5f, rotationSin / 2 + 0.5f) * size;
|
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]);
|
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.
|
// The distance between the position and the sides of the bar.
|
||||||
var bottomOffset = new Vector2(-rotationSin * barSize.X / 2, rotationCos * barSize.X / 2);
|
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.
|
// The distance between the bottom side of the bar and the top side.
|
||||||
var amplitudeOffset = new Vector2(rotationCos * barSize.Y, rotationSin * barSize.Y);
|
var amplitudeOffset = new Vector2(rotationCos * barSize.Y, rotationSin * barSize.Y);
|
||||||
|
|
||||||
var rectangle = new Quad(
|
var rectangle = new Quad(
|
||||||
Vector2Extensions.Transform(barPosition - bottomOffset, DrawInfo.Matrix),
|
Vector2Extensions.Transform(barPosition - bottomOffset, DrawInfo.Matrix),
|
||||||
Vector2Extensions.Transform(barPosition - bottomOffset + amplitudeOffset, DrawInfo.Matrix),
|
Vector2Extensions.Transform(barPosition - bottomOffset + amplitudeOffset, DrawInfo.Matrix),
|
||||||
Vector2Extensions.Transform(barPosition + bottomOffset, DrawInfo.Matrix),
|
Vector2Extensions.Transform(barPosition + bottomOffset, DrawInfo.Matrix),
|
||||||
Vector2Extensions.Transform(barPosition + bottomOffset + amplitudeOffset, DrawInfo.Matrix)
|
Vector2Extensions.Transform(barPosition + bottomOffset + amplitudeOffset, DrawInfo.Matrix)
|
||||||
);
|
);
|
||||||
|
|
||||||
renderer.DrawQuad(
|
renderer.DrawQuad(
|
||||||
texture,
|
texture,
|
||||||
rectangle,
|
rectangle,
|
||||||
colourInfo,
|
colourInfo,
|
||||||
null,
|
null,
|
||||||
vertexBatch.AddAction,
|
vertexBatch.AddAction,
|
||||||
// barSize by itself will make it smooth more in the X axis than in the Y axis, this reverts that.
|
// 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));
|
Vector2.Divide(inflation, barSize.Yx));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,7 +353,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
float maxAmplitude = lastBeatIndex >= 0 ? musicController.CurrentTrack.CurrentAmplitudes.Maximum : 0;
|
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));
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -40,8 +40,6 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
public override bool HandleNonPositionalInput => AllowSeeking.Value;
|
public override bool HandleNonPositionalInput => AllowSeeking.Value;
|
||||||
public override bool HandlePositionalInput => AllowSeeking.Value;
|
public override bool HandlePositionalInput => AllowSeeking.Value;
|
||||||
|
|
||||||
protected override bool BlockScrollInput => false;
|
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private Player? player { get; set; }
|
private Player? player { get; set; }
|
||||||
|
|
||||||
|
@ -14,6 +14,12 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
{
|
{
|
||||||
public abstract class SongProgress : OverlayContainer, ISkinnableDrawable
|
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; }
|
public bool UsesFixedAnchor { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -53,21 +51,21 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
private readonly WorkingBeatmap beatmap;
|
private readonly WorkingBeatmap beatmap;
|
||||||
|
|
||||||
private HardwareCorrectionOffsetClock userGlobalOffsetClock;
|
private HardwareCorrectionOffsetClock userGlobalOffsetClock = null!;
|
||||||
private HardwareCorrectionOffsetClock userBeatmapOffsetClock;
|
private HardwareCorrectionOffsetClock userBeatmapOffsetClock = null!;
|
||||||
private HardwareCorrectionOffsetClock platformOffsetClock;
|
private HardwareCorrectionOffsetClock platformOffsetClock = null!;
|
||||||
private MasterGameplayClock masterGameplayClock;
|
private MasterGameplayClock masterGameplayClock = null!;
|
||||||
private Bindable<double> userAudioOffset;
|
private Bindable<double> userAudioOffset = null!;
|
||||||
|
|
||||||
private IDisposable beatmapOffsetSubscription;
|
private IDisposable? beatmapOffsetSubscription;
|
||||||
|
|
||||||
private readonly double skipTargetTime;
|
private readonly double skipTargetTime;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private RealmAccess realm { get; set; }
|
private RealmAccess realm { get; set; } = null!;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuConfigManager config { get; set; }
|
private OsuConfigManager config { get; set; } = null!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new master gameplay clock container.
|
/// Create a new master gameplay clock container.
|
||||||
@ -255,7 +253,7 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
ControlPointInfo IBeatSyncProvider.ControlPoints => beatmap.Beatmap.ControlPointInfo;
|
ControlPointInfo IBeatSyncProvider.ControlPoints => beatmap.Beatmap.ControlPointInfo;
|
||||||
IClock IBeatSyncProvider.Clock => GameplayClock;
|
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
|
private class HardwareCorrectionOffsetClock : FramedOffsetClock
|
||||||
{
|
{
|
||||||
|
@ -68,12 +68,14 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
storage ??= realmBackedStorage = new RealmBackedResourceStore<SkinInfo>(SkinInfo, resources.Files, resources.RealmAccess);
|
storage ??= realmBackedStorage = new RealmBackedResourceStore<SkinInfo>(SkinInfo, resources.Files, resources.RealmAccess);
|
||||||
|
|
||||||
(storage as ResourceStore<byte[]>)?.AddExtension("ogg");
|
|
||||||
|
|
||||||
var samples = resources.AudioManager?.GetSampleStore(storage);
|
var samples = resources.AudioManager?.GetSampleStore(storage);
|
||||||
if (samples != null)
|
if (samples != null)
|
||||||
samples.PlaybackConcurrency = OsuGameBase.SAMPLE_CONCURRENCY;
|
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;
|
Samples = samples;
|
||||||
Textures = new TextureStore(resources.Renderer, resources.CreateTextureLoaderStore(storage));
|
Textures = new TextureStore(resources.Renderer, resources.CreateTextureLoaderStore(storage));
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user