diff --git a/.idea/.idea.osu.Desktop/.idea/runConfigurations/CatchRuleset__Tests_.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/CatchRuleset__Tests_.xml
index a4154623b6..512ac4393a 100644
--- a/.idea/.idea.osu.Desktop/.idea/runConfigurations/CatchRuleset__Tests_.xml
+++ b/.idea/.idea.osu.Desktop/.idea/runConfigurations/CatchRuleset__Tests_.xml
@@ -1,8 +1,8 @@
-
+
-
+
@@ -15,7 +15,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/.idea.osu.Desktop/.idea/runConfigurations/ManiaRuleset__Tests_.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/ManiaRuleset__Tests_.xml
index 080dc04001..dec1ef717f 100644
--- a/.idea/.idea.osu.Desktop/.idea/runConfigurations/ManiaRuleset__Tests_.xml
+++ b/.idea/.idea.osu.Desktop/.idea/runConfigurations/ManiaRuleset__Tests_.xml
@@ -1,8 +1,8 @@
-
+
-
+
@@ -15,7 +15,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/.idea.osu.Desktop/.idea/runConfigurations/OsuRuleset__Tests_.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/OsuRuleset__Tests_.xml
index 3de6a7e609..d9370d5440 100644
--- a/.idea/.idea.osu.Desktop/.idea/runConfigurations/OsuRuleset__Tests_.xml
+++ b/.idea/.idea.osu.Desktop/.idea/runConfigurations/OsuRuleset__Tests_.xml
@@ -1,8 +1,8 @@
-
+
-
+
@@ -15,7 +15,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/.idea.osu.Desktop/.idea/runConfigurations/TaikoRuleset__Tests_.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/TaikoRuleset__Tests_.xml
index da14c2a29e..def4940bb1 100644
--- a/.idea/.idea.osu.Desktop/.idea/runConfigurations/TaikoRuleset__Tests_.xml
+++ b/.idea/.idea.osu.Desktop/.idea/runConfigurations/TaikoRuleset__Tests_.xml
@@ -1,8 +1,8 @@
-
+
-
+
@@ -15,7 +15,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/.idea.osu.Desktop/.idea/runConfigurations/Tournament.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/Tournament.xml
index 45d1ce25e9..1ffa73c257 100644
--- a/.idea/.idea.osu.Desktop/.idea/runConfigurations/Tournament.xml
+++ b/.idea/.idea.osu.Desktop/.idea/runConfigurations/Tournament.xml
@@ -1,8 +1,8 @@
-
+
-
+
@@ -14,7 +14,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/.idea.osu.Desktop/.idea/runConfigurations/Tournament__Tests_.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/Tournament__Tests_.xml
index ba80f7c100..e64da796b7 100644
--- a/.idea/.idea.osu.Desktop/.idea/runConfigurations/Tournament__Tests_.xml
+++ b/.idea/.idea.osu.Desktop/.idea/runConfigurations/Tournament__Tests_.xml
@@ -1,8 +1,8 @@
-
+
-
+
@@ -15,7 +15,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/.idea.osu.Desktop/.idea/runConfigurations/osu_.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/osu_.xml
index 911c3ed9b7..22105e1de2 100644
--- a/.idea/.idea.osu.Desktop/.idea/runConfigurations/osu_.xml
+++ b/.idea/.idea.osu.Desktop/.idea/runConfigurations/osu_.xml
@@ -1,8 +1,8 @@
-
+
-
+
@@ -14,7 +14,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/.idea.osu.Desktop/.idea/runConfigurations/osu_SDL.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/osu_SDL.xml
index d85a0ae44c..31f1fda09d 100644
--- a/.idea/.idea.osu.Desktop/.idea/runConfigurations/osu_SDL.xml
+++ b/.idea/.idea.osu.Desktop/.idea/runConfigurations/osu_SDL.xml
@@ -1,8 +1,8 @@
-
+
-
+
@@ -12,9 +12,9 @@
-
+
-
+
\ No newline at end of file
diff --git a/.idea/.idea.osu.Desktop/.idea/runConfigurations/osu___Tests_.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/osu___Tests_.xml
index ec3c81f4cd..cc243f6901 100644
--- a/.idea/.idea.osu.Desktop/.idea/runConfigurations/osu___Tests_.xml
+++ b/.idea/.idea.osu.Desktop/.idea/runConfigurations/osu___Tests_.xml
@@ -1,8 +1,8 @@
-
+
-
+
@@ -14,7 +14,7 @@
-
+
\ No newline at end of file
diff --git a/osu.Android.props b/osu.Android.props
index 119c309675..493b1f5529 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -51,7 +51,7 @@
-
-
+
+
diff --git a/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs b/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs
index c2f8fb8678..53db676a54 100644
--- a/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs
+++ b/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs
@@ -25,8 +25,10 @@ namespace osu.Game.Rulesets.Mania.Judgements
return 200;
case HitResult.Great:
- case HitResult.Perfect:
return 300;
+
+ case HitResult.Perfect:
+ return 320;
}
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ReverseArrowPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ReverseArrowPiece.cs
index 1a5195acf8..ae43006e76 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ReverseArrowPiece.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ReverseArrowPiece.cs
@@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
};
}
- protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
+ protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
{
if (!drawableRepeat.IsHit)
Child.ScaleTo(1.3f).ScaleTo(1f, timingPoint.BeatLength, Easing.Out);
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs
index b5471e6976..f515a35c18 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using osu.Framework.Audio.Track;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -8,7 +9,6 @@ using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Backgrounds;
using osuTK.Graphics;
using osu.Game.Beatmaps.ControlPoints;
-using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Effects;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
@@ -148,7 +148,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces
};
}
- protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
+ protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
{
if (!effectPoint.KiaiMode)
return;
diff --git a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacyPlayfieldBackgroundRight.cs b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacyPlayfieldBackgroundRight.cs
index 7508c75231..4bbb6be6b1 100644
--- a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacyPlayfieldBackgroundRight.cs
+++ b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacyPlayfieldBackgroundRight.cs
@@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning
};
}
- protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
+ protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
{
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs
index 407ab30e12..b937beae3c 100644
--- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs
+++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs
@@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Taiko.UI
lastObjectHit = result.IsHit;
}
- protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
+ protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
{
kiaiMode = effectPoint.KiaiMode;
}
diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs b/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs
index cce2be7758..6f25a5f662 100644
--- a/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs
+++ b/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs
@@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Taiko.UI
textureAnimation.Seek(0);
}
- protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
+ protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
{
// assume that if the animation is playing on its own, it's independent from the beat and doesn't need to be touched.
if (textureAnimation.FrameCount == 0 || textureAnimation.IsPlaying)
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs
index 387ac42f67..1961a224c1 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs
@@ -174,9 +174,7 @@ namespace osu.Game.Tests.Visual.Gameplay
[Test]
public void TestExitFromGameplay()
{
- AddStep("exit", () => Player.Exit());
- confirmPaused();
-
+ // an externally triggered exit should immediately exit, skipping all pause logic.
AddStep("exit", () => Player.Exit());
confirmExited();
}
diff --git a/osu.Game.Tests/Visual/Menus/TestSceneIntroWelcome.cs b/osu.Game.Tests/Visual/Menus/TestSceneIntroWelcome.cs
new file mode 100644
index 0000000000..905f17ef0b
--- /dev/null
+++ b/osu.Game.Tests/Visual/Menus/TestSceneIntroWelcome.cs
@@ -0,0 +1,15 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Framework.Screens;
+using osu.Game.Screens.Menu;
+
+namespace osu.Game.Tests.Visual.Menus
+{
+ [TestFixture]
+ public class TestSceneIntroWelcome : IntroTestScene
+ {
+ protected override IScreen CreateScreen() => new IntroWelcome();
+ }
+}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs
index 4c32e995e8..dd5ceec739 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs
@@ -177,7 +177,7 @@ namespace osu.Game.Tests.Visual.UserInterface
timeSinceLastBeat.Value = TimeSinceLastBeat;
}
- protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
+ protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
{
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneStablePathSelectScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneStablePathSelectScreen.cs
new file mode 100644
index 0000000000..6e63b2d799
--- /dev/null
+++ b/osu.Game.Tournament.Tests/Screens/TestSceneStablePathSelectScreen.cs
@@ -0,0 +1,28 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Tournament.Screens;
+
+namespace osu.Game.Tournament.Tests.Screens
+{
+ public class TestSceneStablePathSelectScreen : TournamentTestScene
+ {
+ public TestSceneStablePathSelectScreen()
+ {
+ AddStep("Add screen", () => Add(new StablePathSelectTestScreen()));
+ }
+
+ private class StablePathSelectTestScreen : StablePathSelectScreen
+ {
+ protected override void ChangePath()
+ {
+ Expire();
+ }
+
+ protected override void AutoDetect()
+ {
+ Expire();
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tournament/Components/IPCErrorDialog.cs b/osu.Game.Tournament/Components/IPCErrorDialog.cs
new file mode 100644
index 0000000000..dc039cd3bc
--- /dev/null
+++ b/osu.Game.Tournament/Components/IPCErrorDialog.cs
@@ -0,0 +1,26 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Overlays.Dialog;
+
+namespace osu.Game.Tournament.Components
+{
+ public class IPCErrorDialog : PopupDialog
+ {
+ public IPCErrorDialog(string headerText, string bodyText)
+ {
+ Icon = FontAwesome.Regular.SadTear;
+ HeaderText = headerText;
+ BodyText = bodyText;
+ Buttons = new PopupDialogButton[]
+ {
+ new PopupDialogOkButton
+ {
+ Text = @"Alright.",
+ Action = () => Expire()
+ }
+ };
+ }
+ }
+}
diff --git a/osu.Game.Tournament/IPC/FileBasedIPC.cs b/osu.Game.Tournament/IPC/FileBasedIPC.cs
index de4d482d13..999ce61ac8 100644
--- a/osu.Game.Tournament/IPC/FileBasedIPC.cs
+++ b/osu.Game.Tournament/IPC/FileBasedIPC.cs
@@ -4,6 +4,7 @@
using System;
using System.IO;
using System.Linq;
+using JetBrains.Annotations;
using Microsoft.Win32;
using osu.Framework.Allocation;
using osu.Framework.Logging;
@@ -20,6 +21,8 @@ namespace osu.Game.Tournament.IPC
{
public class FileBasedIPC : MatchIPCInfo
{
+ public Storage IPCStorage { get; private set; }
+
[Resolved]
protected IAPIProvider API { get; private set; }
@@ -32,45 +35,46 @@ namespace osu.Game.Tournament.IPC
[Resolved]
private LadderInfo ladder { get; set; }
+ [Resolved]
+ private StableInfo stableInfo { get; set; }
+
private int lastBeatmapId;
private ScheduledDelegate scheduled;
private GetBeatmapRequest beatmapLookupRequest;
- public Storage Storage { get; private set; }
-
[BackgroundDependencyLoader]
private void load()
{
- LocateStableStorage();
+ var stablePath = stableInfo.StablePath ?? findStablePath();
+ initialiseIPCStorage(stablePath);
}
- public Storage LocateStableStorage()
+ [CanBeNull]
+ private Storage initialiseIPCStorage(string path)
{
scheduled?.Cancel();
- Storage = null;
+ IPCStorage = null;
try
{
- var path = findStablePath();
-
if (string.IsNullOrEmpty(path))
return null;
- Storage = new DesktopStorage(path, host as DesktopGameHost);
+ IPCStorage = new DesktopStorage(path, host as DesktopGameHost);
const string file_ipc_filename = "ipc.txt";
const string file_ipc_state_filename = "ipc-state.txt";
const string file_ipc_scores_filename = "ipc-scores.txt";
const string file_ipc_channel_filename = "ipc-channel.txt";
- if (Storage.Exists(file_ipc_filename))
+ if (IPCStorage.Exists(file_ipc_filename))
{
scheduled = Scheduler.AddDelayed(delegate
{
try
{
- using (var stream = Storage.GetStream(file_ipc_filename))
+ using (var stream = IPCStorage.GetStream(file_ipc_filename))
using (var sr = new StreamReader(stream))
{
var beatmapId = int.Parse(sr.ReadLine());
@@ -104,7 +108,7 @@ namespace osu.Game.Tournament.IPC
try
{
- using (var stream = Storage.GetStream(file_ipc_channel_filename))
+ using (var stream = IPCStorage.GetStream(file_ipc_channel_filename))
using (var sr = new StreamReader(stream))
{
ChatChannel.Value = sr.ReadLine();
@@ -117,7 +121,7 @@ namespace osu.Game.Tournament.IPC
try
{
- using (var stream = Storage.GetStream(file_ipc_state_filename))
+ using (var stream = IPCStorage.GetStream(file_ipc_state_filename))
using (var sr = new StreamReader(stream))
{
State.Value = (TourneyState)Enum.Parse(typeof(TourneyState), sr.ReadLine());
@@ -130,7 +134,7 @@ namespace osu.Game.Tournament.IPC
try
{
- using (var stream = Storage.GetStream(file_ipc_scores_filename))
+ using (var stream = IPCStorage.GetStream(file_ipc_scores_filename))
using (var sr = new StreamReader(stream))
{
Score1.Value = int.Parse(sr.ReadLine());
@@ -149,54 +153,106 @@ namespace osu.Game.Tournament.IPC
Logger.Error(e, "Stable installation could not be found; disabling file based IPC");
}
- return Storage;
+ return IPCStorage;
}
+ ///
+ /// Manually sets the path to the directory used for inter-process communication with a cutting-edge install.
+ ///
+ /// Path to the IPC directory
+ /// Whether the supplied path was a valid IPC directory.
+ public bool SetIPCLocation(string path)
+ {
+ if (path == null || !ipcFileExistsInDirectory(path))
+ return false;
+
+ var newStorage = initialiseIPCStorage(stableInfo.StablePath = path);
+ if (newStorage == null)
+ return false;
+
+ stableInfo.SaveChanges();
+ return true;
+ }
+
+ ///
+ /// Tries to automatically detect the path to the directory used for inter-process communication
+ /// with a cutting-edge install.
+ ///
+ /// Whether an IPC directory was successfully auto-detected.
+ public bool AutoDetectIPCLocation() => SetIPCLocation(findStablePath());
+
+ private static bool ipcFileExistsInDirectory(string p) => p != null && File.Exists(Path.Combine(p, "ipc.txt"));
+
+ [CanBeNull]
private string findStablePath()
{
- static bool checkExists(string p) => File.Exists(Path.Combine(p, "ipc.txt"));
+ var stableInstallPath = findFromEnvVar() ??
+ findFromRegistry() ??
+ findFromLocalAppData() ??
+ findFromDotFolder();
- string stableInstallPath = string.Empty;
+ Logger.Log($"Stable path for tourney usage: {stableInstallPath}");
+ return stableInstallPath;
+ }
+
+ private string findFromEnvVar()
+ {
+ try
+ {
+ Logger.Log("Trying to find stable with environment variables");
+ string stableInstallPath = Environment.GetEnvironmentVariable("OSU_STABLE_PATH");
+
+ if (ipcFileExistsInDirectory(stableInstallPath))
+ return stableInstallPath;
+ }
+ catch
+ {
+ }
+
+ return null;
+ }
+
+ private string findFromLocalAppData()
+ {
+ Logger.Log("Trying to find stable in %LOCALAPPDATA%");
+ string stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"osu!");
+
+ if (ipcFileExistsInDirectory(stableInstallPath))
+ return stableInstallPath;
+
+ return null;
+ }
+
+ private string findFromDotFolder()
+ {
+ Logger.Log("Trying to find stable in dotfolders");
+ string stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".osu");
+
+ if (ipcFileExistsInDirectory(stableInstallPath))
+ return stableInstallPath;
+
+ return null;
+ }
+
+ private string findFromRegistry()
+ {
+ Logger.Log("Trying to find stable in registry");
try
{
- try
- {
- stableInstallPath = Environment.GetEnvironmentVariable("OSU_STABLE_PATH");
+ string stableInstallPath;
- if (checkExists(stableInstallPath))
- return stableInstallPath;
- }
- catch
- {
- }
+ using (RegistryKey key = Registry.ClassesRoot.OpenSubKey("osu"))
+ stableInstallPath = key?.OpenSubKey(@"shell\open\command")?.GetValue(string.Empty).ToString().Split('"')[1].Replace("osu!.exe", "");
- try
- {
- using (RegistryKey key = Registry.ClassesRoot.OpenSubKey("osu"))
- stableInstallPath = key?.OpenSubKey(@"shell\open\command")?.GetValue(string.Empty).ToString().Split('"')[1].Replace("osu!.exe", "");
-
- if (checkExists(stableInstallPath))
- return stableInstallPath;
- }
- catch
- {
- }
-
- stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"osu!");
- if (checkExists(stableInstallPath))
+ if (ipcFileExistsInDirectory(stableInstallPath))
return stableInstallPath;
-
- stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".osu");
- if (checkExists(stableInstallPath))
- return stableInstallPath;
-
- return null;
}
- finally
+ catch
{
- Logger.Log($"Stable path for tourney usage: {stableInstallPath}");
}
+
+ return null;
}
}
}
diff --git a/osu.Game.Tournament/Models/StableInfo.cs b/osu.Game.Tournament/Models/StableInfo.cs
new file mode 100644
index 0000000000..0b0050a245
--- /dev/null
+++ b/osu.Game.Tournament/Models/StableInfo.cs
@@ -0,0 +1,62 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.IO;
+using Newtonsoft.Json;
+using osu.Framework.Platform;
+
+namespace osu.Game.Tournament.Models
+{
+ ///
+ /// Holds the path to locate the osu! stable cutting-edge installation.
+ ///
+ [Serializable]
+ public class StableInfo
+ {
+ ///
+ /// Path to the IPC directory used by the stable (cutting-edge) install.
+ ///
+ public string StablePath { get; set; }
+
+ ///
+ /// Fired whenever stable info is successfully saved to file.
+ ///
+ public event Action OnStableInfoSaved;
+
+ private const string config_path = "tournament/stable.json";
+
+ private readonly Storage storage;
+
+ public StableInfo(Storage storage)
+ {
+ this.storage = storage;
+
+ if (!storage.Exists(config_path))
+ return;
+
+ using (Stream stream = storage.GetStream(config_path, FileAccess.Read, FileMode.Open))
+ using (var sr = new StreamReader(stream))
+ {
+ JsonConvert.PopulateObject(sr.ReadToEnd(), this);
+ }
+ }
+
+ public void SaveChanges()
+ {
+ using (var stream = storage.GetStream(config_path, FileAccess.Write, FileMode.Create))
+ using (var sw = new StreamWriter(stream))
+ {
+ sw.Write(JsonConvert.SerializeObject(this,
+ new JsonSerializerSettings
+ {
+ Formatting = Formatting.Indented,
+ NullValueHandling = NullValueHandling.Ignore,
+ DefaultValueHandling = DefaultValueHandling.Ignore,
+ }));
+ }
+
+ OnStableInfoSaved?.Invoke();
+ }
+ }
+}
diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs
index cf8eb8bd6c..98bc292901 100644
--- a/osu.Game.Tournament/Screens/SetupScreen.cs
+++ b/osu.Game.Tournament/Screens/SetupScreen.cs
@@ -15,6 +15,7 @@ using osu.Game.Online.API;
using osu.Game.Overlays;
using osu.Game.Rulesets;
using osu.Game.Tournament.IPC;
+using osu.Game.Tournament.Models;
using osuTK;
using osuTK.Graphics;
@@ -30,12 +31,18 @@ namespace osu.Game.Tournament.Screens
[Resolved]
private MatchIPCInfo ipc { get; set; }
+ [Resolved]
+ private StableInfo stableInfo { get; set; }
+
[Resolved]
private IAPIProvider api { get; set; }
[Resolved]
private RulesetStore rulesets { get; set; }
+ [Resolved(canBeNull: true)]
+ private TournamentSceneManager sceneManager { get; set; }
+
private Bindable windowSize;
[BackgroundDependencyLoader]
@@ -53,6 +60,7 @@ namespace osu.Game.Tournament.Screens
};
api.LocalUser.BindValueChanged(_ => Schedule(reload));
+ stableInfo.OnStableInfoSaved += () => Schedule(reload);
reload();
}
@@ -62,21 +70,16 @@ namespace osu.Game.Tournament.Screens
private void reload()
{
var fileBasedIpc = ipc as FileBasedIPC;
-
fillFlow.Children = new Drawable[]
{
new ActionableInfo
{
Label = "Current IPC source",
- ButtonText = "Refresh",
- Action = () =>
- {
- fileBasedIpc?.LocateStableStorage();
- reload();
- },
- Value = fileBasedIpc?.Storage?.GetFullPath(string.Empty) ?? "Not found",
- Failing = fileBasedIpc?.Storage == null,
- Description = "The osu!stable installation which is currently being used as a data source. If a source is not found, make sure you have created an empty ipc.txt in your stable cutting-edge installation, and that it is registered as the default osu! install."
+ ButtonText = "Change source",
+ Action = () => sceneManager?.SetScreen(new StablePathSelectScreen()),
+ Value = fileBasedIpc?.IPCStorage?.GetFullPath(string.Empty) ?? "Not found",
+ Failing = fileBasedIpc?.IPCStorage == null,
+ Description = "The osu!stable installation which is currently being used as a data source. If a source is not found, make sure you have created an empty ipc.txt in your stable cutting-edge installation."
},
new ActionableInfo
{
diff --git a/osu.Game.Tournament/Screens/StablePathSelectScreen.cs b/osu.Game.Tournament/Screens/StablePathSelectScreen.cs
new file mode 100644
index 0000000000..b4d56f60c7
--- /dev/null
+++ b/osu.Game.Tournament/Screens/StablePathSelectScreen.cs
@@ -0,0 +1,164 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.IO;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Logging;
+using osu.Framework.Platform;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Graphics.UserInterfaceV2;
+using osu.Game.Overlays;
+using osu.Game.Tournament.IPC;
+using osu.Game.Tournament.Components;
+using osuTK;
+
+namespace osu.Game.Tournament.Screens
+{
+ public class StablePathSelectScreen : TournamentScreen
+ {
+ [Resolved]
+ private GameHost host { get; set; }
+
+ [Resolved(canBeNull: true)]
+ private TournamentSceneManager sceneManager { get; set; }
+
+ [Resolved]
+ private MatchIPCInfo ipc { get; set; }
+
+ private DirectorySelector directorySelector;
+ private DialogOverlay overlay;
+
+ [BackgroundDependencyLoader(true)]
+ private void load(Storage storage, OsuColour colours)
+ {
+ var initialStorage = (ipc as FileBasedIPC)?.IPCStorage ?? storage;
+ var initialPath = new DirectoryInfo(initialStorage.GetFullPath(string.Empty)).Parent?.FullName;
+
+ AddRangeInternal(new Drawable[]
+ {
+ new Container
+ {
+ Masking = true,
+ CornerRadius = 10,
+ RelativeSizeAxes = Axes.Both,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(0.5f, 0.8f),
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ Colour = colours.GreySeafoamDark,
+ RelativeSizeAxes = Axes.Both,
+ },
+ new GridContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ RowDimensions = new[]
+ {
+ new Dimension(),
+ new Dimension(GridSizeMode.Relative, 0.8f),
+ new Dimension(),
+ },
+ Content = new[]
+ {
+ new Drawable[]
+ {
+ new OsuSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Text = "Please select a new location",
+ Font = OsuFont.Default.With(size: 40)
+ },
+ },
+ new Drawable[]
+ {
+ directorySelector = new DirectorySelector(initialPath)
+ {
+ RelativeSizeAxes = Axes.Both,
+ }
+ },
+ new Drawable[]
+ {
+ new FillFlowContainer
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Direction = FillDirection.Horizontal,
+ Spacing = new Vector2(20),
+ Children = new Drawable[]
+ {
+ new TriangleButton
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Width = 300,
+ Text = "Select stable path",
+ Action = ChangePath
+ },
+ new TriangleButton
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Width = 300,
+ Text = "Auto detect",
+ Action = AutoDetect
+ },
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ new BackButton
+ {
+ Anchor = Anchor.BottomLeft,
+ Origin = Anchor.BottomLeft,
+ State = { Value = Visibility.Visible },
+ Action = () => sceneManager?.SetScreen(typeof(SetupScreen))
+ }
+ });
+ }
+
+ protected virtual void ChangePath()
+ {
+ var target = directorySelector.CurrentDirectory.Value.FullName;
+ var fileBasedIpc = ipc as FileBasedIPC;
+ Logger.Log($"Changing Stable CE location to {target}");
+
+ if (!fileBasedIpc?.SetIPCLocation(target) ?? true)
+ {
+ overlay = new DialogOverlay();
+ overlay.Push(new IPCErrorDialog("This is an invalid IPC Directory", "Select a directory that contains an osu! stable cutting edge installation and make sure it has an empty ipc.txt file in it."));
+ AddInternal(overlay);
+ Logger.Log("Folder is not an osu! stable CE directory");
+ return;
+ }
+
+ sceneManager?.SetScreen(typeof(SetupScreen));
+ }
+
+ protected virtual void AutoDetect()
+ {
+ var fileBasedIpc = ipc as FileBasedIPC;
+
+ if (!fileBasedIpc?.AutoDetectIPCLocation() ?? true)
+ {
+ overlay = new DialogOverlay();
+ overlay.Push(new IPCErrorDialog("Failed to auto detect", "An osu! stable cutting-edge installation could not be auto detected.\nPlease try and manually point to the directory."));
+ AddInternal(overlay);
+ }
+ else
+ {
+ sceneManager?.SetScreen(typeof(SetupScreen));
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs
index 718c8ee644..5fc1d03f6d 100644
--- a/osu.Game.Tournament/TournamentGameBase.cs
+++ b/osu.Game.Tournament/TournamentGameBase.cs
@@ -53,6 +53,8 @@ namespace osu.Game.Tournament
ladder.CurrentMatch.Value = ladder.Matches.FirstOrDefault(p => p.Current.Value);
+ dependencies.CacheAs(new StableInfo(storage));
+
dependencies.CacheAs(ipc = new FileBasedIPC());
Add(ipc);
}
diff --git a/osu.Game/Configuration/IntroSequence.cs b/osu.Game/Configuration/IntroSequence.cs
index 1ee7da8bac..5672c44bbe 100644
--- a/osu.Game/Configuration/IntroSequence.cs
+++ b/osu.Game/Configuration/IntroSequence.cs
@@ -6,6 +6,7 @@ namespace osu.Game.Configuration
public enum IntroSequence
{
Circles,
+ Welcome,
Triangles,
Random
}
diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs
index 5a613d1a54..dd5c41285a 100644
--- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs
+++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs
@@ -18,7 +18,7 @@ namespace osu.Game.Graphics.Containers
private TimingControlPoint lastTimingPoint;
///
- /// The amount of time before a beat we should fire .
+ /// The amount of time before a beat we should fire .
/// This allows for adding easing to animations that may be synchronised to the beat.
///
protected double EarlyActivationMilliseconds;
@@ -50,7 +50,6 @@ namespace osu.Game.Graphics.Containers
private TimingControlPoint defaultTiming;
private EffectControlPoint defaultEffect;
- private TrackAmplitudes defaultAmplitudes;
protected bool IsBeatSyncedWithTrack { get; private set; }
@@ -107,7 +106,7 @@ namespace osu.Game.Graphics.Containers
return;
using (BeginDelayedSequence(-TimeSinceLastBeat, true))
- OnNewBeat(beatIndex, timingPoint, effectPoint, track?.CurrentAmplitudes ?? defaultAmplitudes);
+ OnNewBeat(beatIndex, timingPoint, effectPoint, track?.CurrentAmplitudes ?? ChannelAmplitudes.Empty);
lastBeat = beatIndex;
lastTimingPoint = timingPoint;
@@ -128,16 +127,9 @@ namespace osu.Game.Graphics.Containers
KiaiMode = false,
OmitFirstBarLine = false
};
-
- defaultAmplitudes = new TrackAmplitudes
- {
- FrequencyAmplitudes = new float[256],
- LeftChannel = 0,
- RightChannel = 0
- };
}
- protected virtual void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
+ protected virtual void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
{
}
}
diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs
index 580177d17a..fd8f016860 100644
--- a/osu.Game/Graphics/Cursor/MenuCursor.cs
+++ b/osu.Game/Graphics/Cursor/MenuCursor.cs
@@ -13,7 +13,6 @@ using JetBrains.Annotations;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Events;
-using osuTK.Input;
using osu.Framework.Utils;
namespace osu.Game.Graphics.Cursor
@@ -74,17 +73,15 @@ namespace osu.Game.Graphics.Cursor
protected override bool OnMouseDown(MouseDownEvent e)
{
// only trigger animation for main mouse buttons
- if (e.Button <= MouseButton.Right)
- {
- activeCursor.Scale = new Vector2(1);
- activeCursor.ScaleTo(0.90f, 800, Easing.OutQuint);
+ activeCursor.Scale = new Vector2(1);
+ activeCursor.ScaleTo(0.90f, 800, Easing.OutQuint);
- activeCursor.AdditiveLayer.Alpha = 0;
- activeCursor.AdditiveLayer.FadeInFromZero(800, Easing.OutQuint);
- }
+ activeCursor.AdditiveLayer.Alpha = 0;
+ activeCursor.AdditiveLayer.FadeInFromZero(800, Easing.OutQuint);
- if (e.Button == MouseButton.Left && cursorRotate.Value)
+ if (cursorRotate.Value && dragRotationState != DragRotationState.Rotating)
{
+ // if cursor is already rotating don't reset its rotate origin
dragRotationState = DragRotationState.DragStarted;
positionMouseDown = e.MousePosition;
}
@@ -94,17 +91,16 @@ namespace osu.Game.Graphics.Cursor
protected override void OnMouseUp(MouseUpEvent e)
{
- if (!e.IsPressed(MouseButton.Left) && !e.IsPressed(MouseButton.Right))
+ if (!e.HasAnyButtonPressed)
{
activeCursor.AdditiveLayer.FadeOutFromOne(500, Easing.OutQuint);
activeCursor.ScaleTo(1, 500, Easing.OutElastic);
- }
- if (e.Button == MouseButton.Left)
- {
- if (dragRotationState == DragRotationState.Rotating)
+ if (dragRotationState != DragRotationState.NotDragging)
+ {
activeCursor.RotateTo(0, 600 * (1 + Math.Abs(activeCursor.Rotation / 720)), Easing.OutElasticHalf);
- dragRotationState = DragRotationState.NotDragging;
+ dragRotationState = DragRotationState.NotDragging;
+ }
}
base.OnMouseUp(e);
diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs
index 6f440d8138..06c46fbb91 100644
--- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs
+++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs
@@ -147,7 +147,7 @@ namespace osu.Game.Graphics.UserInterface
};
}
- protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
+ protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
{
if (!hasSelection)
this.FadeTo(0.7f).FadeTo(0.4f, timingPoint.BeatLength, Easing.InOutSine);
diff --git a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs
index aa96796cf1..120149d8c1 100644
--- a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs
+++ b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs
@@ -230,7 +230,7 @@ namespace osu.Game.Graphics.UserInterface
};
}
- protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
+ protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
{
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
diff --git a/osu.Game/Rulesets/Mods/ModNightcore.cs b/osu.Game/Rulesets/Mods/ModNightcore.cs
index 1df2aeb348..ed8eb2fb66 100644
--- a/osu.Game/Rulesets/Mods/ModNightcore.cs
+++ b/osu.Game/Rulesets/Mods/ModNightcore.cs
@@ -78,7 +78,7 @@ namespace osu.Game.Rulesets.Mods
private const int bars_per_segment = 4;
- protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
+ protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
{
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
index cc417bbb10..c6e228262f 100644
--- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
@@ -13,6 +13,7 @@ using osu.Framework.Graphics.Primitives;
using osu.Framework.Input;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
+using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
@@ -82,6 +83,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
case NotifyCollectionChangedAction.Remove:
foreach (var o in args.OldItems)
SelectionBlueprints.FirstOrDefault(b => b.HitObject == o)?.Deselect();
+
break;
}
};
@@ -250,6 +252,9 @@ namespace osu.Game.Screens.Edit.Compose.Components
blueprint.Deselected -= onBlueprintDeselected;
SelectionBlueprints.Remove(blueprint);
+
+ if (movementBlueprint == blueprint)
+ finishSelectionMovement();
}
protected virtual void AddBlueprintFor(HitObject hitObject)
@@ -320,10 +325,22 @@ namespace osu.Game.Screens.Edit.Compose.Components
{
foreach (var blueprint in SelectionBlueprints)
{
- if (blueprint.IsAlive && blueprint.IsPresent && rect.Contains(blueprint.ScreenSpaceSelectionPoint))
- blueprint.Select();
- else
- blueprint.Deselect();
+ // only run when utmost necessary to avoid unnecessary rect computations.
+ bool isValidForSelection() => blueprint.IsAlive && blueprint.IsPresent && rect.Contains(blueprint.ScreenSpaceSelectionPoint);
+
+ switch (blueprint.State)
+ {
+ case SelectionState.NotSelected:
+ if (isValidForSelection())
+ blueprint.Select();
+ break;
+
+ case SelectionState.Selected:
+ // if the editor is playing, we generally don't want to deselect objects even if outside the selection area.
+ if (!editorClock.IsRunning && !isValidForSelection())
+ blueprint.Deselect();
+ break;
+ }
}
}
diff --git a/osu.Game/Screens/Edit/Compose/Components/DragBox.cs b/osu.Game/Screens/Edit/Compose/Components/DragBox.cs
index c5f1bd1575..0615ebfc20 100644
--- a/osu.Game/Screens/Edit/Compose/Components/DragBox.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/DragBox.cs
@@ -53,6 +53,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
}
};
+ private RectangleF? dragRectangle;
+
///
/// Handle a forwarded mouse event.
///
@@ -66,15 +68,14 @@ namespace osu.Game.Screens.Edit.Compose.Components
var dragQuad = new Quad(dragStartPosition.X, dragStartPosition.Y, dragPosition.X - dragStartPosition.X, dragPosition.Y - dragStartPosition.Y);
// We use AABBFloat instead of RectangleF since it handles negative sizes for us
- var dragRectangle = dragQuad.AABBFloat;
+ var rec = dragQuad.AABBFloat;
+ dragRectangle = rec;
- var topLeft = ToLocalSpace(dragRectangle.TopLeft);
- var bottomRight = ToLocalSpace(dragRectangle.BottomRight);
+ var topLeft = ToLocalSpace(rec.TopLeft);
+ var bottomRight = ToLocalSpace(rec.BottomRight);
Box.Position = topLeft;
Box.Size = bottomRight - topLeft;
-
- PerformSelection?.Invoke(dragRectangle);
return true;
}
@@ -93,7 +94,19 @@ namespace osu.Game.Screens.Edit.Compose.Components
}
}
- public override void Hide() => State = Visibility.Hidden;
+ protected override void Update()
+ {
+ base.Update();
+
+ if (dragRectangle != null)
+ PerformSelection?.Invoke(dragRectangle.Value);
+ }
+
+ public override void Hide()
+ {
+ State = Visibility.Hidden;
+ dragRectangle = null;
+ }
public override void Show() => State = Visibility.Visible;
diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs
index a5b55a24e5..0bfabdaa15 100644
--- a/osu.Game/Screens/Loader.cs
+++ b/osu.Game/Screens/Loader.cs
@@ -51,6 +51,9 @@ namespace osu.Game.Screens
case IntroSequence.Circles:
return new IntroCircles();
+ case IntroSequence.Welcome:
+ return new IntroWelcome();
+
default:
return new IntroTriangles();
}
diff --git a/osu.Game/Screens/Menu/Button.cs b/osu.Game/Screens/Menu/Button.cs
index 6708ce0ba0..be6ed9700c 100644
--- a/osu.Game/Screens/Menu/Button.cs
+++ b/osu.Game/Screens/Menu/Button.cs
@@ -6,6 +6,7 @@ using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
+using osu.Framework.Audio.Track;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -15,7 +16,6 @@ using osuTK.Graphics;
using osuTK.Input;
using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Graphics.Containers;
-using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
@@ -132,7 +132,7 @@ namespace osu.Game.Screens.Menu
private bool rightward;
- protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
+ protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
{
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
diff --git a/osu.Game/Screens/Menu/IntroCircles.cs b/osu.Game/Screens/Menu/IntroCircles.cs
index aa9cee969c..d4cd073b7a 100644
--- a/osu.Game/Screens/Menu/IntroCircles.cs
+++ b/osu.Game/Screens/Menu/IntroCircles.cs
@@ -24,7 +24,7 @@ namespace osu.Game.Screens.Menu
private void load(AudioManager audio)
{
if (MenuVoice.Value)
- welcome = audio.Samples.Get(@"welcome");
+ welcome = audio.Samples.Get(@"Intro/welcome");
}
protected override void LogoArriving(OsuLogo logo, bool resuming)
diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs
index b99d8ae9d1..88d18d0073 100644
--- a/osu.Game/Screens/Menu/IntroScreen.cs
+++ b/osu.Game/Screens/Menu/IntroScreen.cs
@@ -51,6 +51,8 @@ namespace osu.Game.Screens.Menu
private SampleChannel seeya;
+ protected virtual string SeeyaSampleName => "Intro/seeya";
+
private LeasedBindable beatmap;
private MainMenu mainMenu;
@@ -72,7 +74,7 @@ namespace osu.Game.Screens.Menu
MenuVoice = config.GetBindable(OsuSetting.MenuVoice);
MenuMusic = config.GetBindable(OsuSetting.MenuMusic);
- seeya = audio.Samples.Get(@"seeya");
+ seeya = audio.Samples.Get(SeeyaSampleName);
BeatmapSetInfo setInfo = null;
diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs
index 225ad02ec4..9be74a0fd9 100644
--- a/osu.Game/Screens/Menu/IntroTriangles.cs
+++ b/osu.Game/Screens/Menu/IntroTriangles.cs
@@ -47,7 +47,7 @@ namespace osu.Game.Screens.Menu
private void load()
{
if (MenuVoice.Value && !UsingThemedIntro)
- welcome = audio.Samples.Get(@"welcome");
+ welcome = audio.Samples.Get(@"Intro/welcome");
}
protected override void LogoArriving(OsuLogo logo, bool resuming)
diff --git a/osu.Game/Screens/Menu/IntroWelcome.cs b/osu.Game/Screens/Menu/IntroWelcome.cs
new file mode 100644
index 0000000000..abd4a68d4f
--- /dev/null
+++ b/osu.Game/Screens/Menu/IntroWelcome.cs
@@ -0,0 +1,150 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osuTK;
+using osu.Framework.Allocation;
+using osu.Framework.Audio;
+using osu.Framework.Audio.Sample;
+using osu.Framework.Screens;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Textures;
+using osu.Game.Screens.Backgrounds;
+using osuTK.Graphics;
+
+namespace osu.Game.Screens.Menu
+{
+ public class IntroWelcome : IntroScreen
+ {
+ protected override string BeatmapHash => "64e00d7022195959bfa3109d09c2e2276c8f12f486b91fcf6175583e973b48f2";
+ protected override string BeatmapFile => "welcome.osz";
+ private const double delay_step_two = 2142;
+ private SampleChannel welcome;
+ private SampleChannel pianoReverb;
+ protected override string SeeyaSampleName => "Intro/Welcome/seeya";
+
+ protected override BackgroundScreen CreateBackground() => background = new BackgroundScreenDefault(false)
+ {
+ Alpha = 0,
+ };
+
+ private BackgroundScreenDefault background;
+
+ [BackgroundDependencyLoader]
+ private void load(AudioManager audio)
+ {
+ if (MenuVoice.Value)
+ welcome = audio.Samples.Get(@"Intro/Welcome/welcome");
+
+ pianoReverb = audio.Samples.Get(@"Intro/Welcome/welcome_piano");
+ }
+
+ protected override void LogoArriving(OsuLogo logo, bool resuming)
+ {
+ base.LogoArriving(logo, resuming);
+
+ if (!resuming)
+ {
+ LoadComponentAsync(new WelcomeIntroSequence
+ {
+ RelativeSizeAxes = Axes.Both
+ }, intro =>
+ {
+ PrepareMenuLoad();
+
+ intro.LogoVisualisation.AddAmplitudeSource(pianoReverb);
+
+ AddInternal(intro);
+
+ welcome?.Play();
+ pianoReverb?.Play();
+
+ Scheduler.AddDelayed(() =>
+ {
+ StartTrack();
+
+ const float fade_in_time = 200;
+
+ logo.ScaleTo(1);
+ logo.FadeIn(fade_in_time);
+
+ background.FadeIn(fade_in_time);
+
+ LoadMenu();
+ }, delay_step_two);
+ });
+ }
+ }
+
+ public override void OnResuming(IScreen last)
+ {
+ base.OnResuming(last);
+ background.FadeOut(100);
+ }
+
+ private class WelcomeIntroSequence : Container
+ {
+ private Sprite welcomeText;
+ private Container scaleContainer;
+
+ public LogoVisualisation LogoVisualisation { get; private set; }
+
+ [BackgroundDependencyLoader]
+ private void load(TextureStore textures)
+ {
+ Origin = Anchor.Centre;
+ Anchor = Anchor.Centre;
+
+ Children = new Drawable[]
+ {
+ scaleContainer = new Container
+ {
+ AutoSizeAxes = Axes.Both,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Children = new Drawable[]
+ {
+ LogoVisualisation = new LogoVisualisation
+ {
+ RelativeSizeAxes = Axes.Both,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Alpha = 0.5f,
+ AccentColour = Color4.DarkBlue,
+ Size = new Vector2(0.96f)
+ },
+ new Circle
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(480),
+ Colour = Color4.Black
+ },
+ welcomeText = new Sprite
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Texture = textures.Get(@"Intro/Welcome/welcome_text")
+ },
+ }
+ },
+ };
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ using (BeginDelayedSequence(0, true))
+ {
+ scaleContainer.ScaleTo(0.9f).ScaleTo(1, delay_step_two).OnComplete(_ => Expire());
+ scaleContainer.FadeInFromZero(1800);
+
+ welcomeText.ScaleTo(new Vector2(1, 0)).ScaleTo(Vector2.One, 400, Easing.Out);
+ }
+ }
+ }
+ }
+}
diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs
index 6a28740d4e..ebbb19636c 100644
--- a/osu.Game/Screens/Menu/LogoVisualisation.cs
+++ b/osu.Game/Screens/Menu/LogoVisualisation.cs
@@ -13,7 +13,11 @@ using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
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;
@@ -65,6 +69,11 @@ namespace osu.Game.Screens.Menu
public Color4 AccentColour { get; set; }
+ ///
+ /// The relative movement of bars based on input amplification. Defaults to 1.
+ ///
+ public float Magnitude { get; set; } = 1;
+
private readonly float[] frequencyAmplitudes = new float[256];
private IShader shader;
@@ -76,6 +85,13 @@ namespace osu.Game.Screens.Menu
Blending = BlendingParameters.Additive;
}
+ private readonly List amplitudeSources = new List();
+
+ public void AddAmplitudeSource(IHasAmplitudes amplitudeSource)
+ {
+ amplitudeSources.Add(amplitudeSource);
+ }
+
[BackgroundDependencyLoader]
private void load(ShaderManager shaders, IBindable beatmap)
{
@@ -83,27 +99,28 @@ namespace osu.Game.Screens.Menu
shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED);
}
+ private readonly float[] temporalAmplitudes = new float[ChannelAmplitudes.AMPLITUDES_SIZE];
+
private void updateAmplitudes()
{
- var track = beatmap.Value.TrackLoaded ? beatmap.Value.Track : null;
- var effect = beatmap.Value.BeatmapLoaded ? beatmap.Value.Beatmap?.ControlPointInfo.EffectPointAt(track?.CurrentTime ?? Time.Current) : null;
+ var effect = beatmap.Value.BeatmapLoaded && beatmap.Value.TrackLoaded
+ ? beatmap.Value.Beatmap?.ControlPointInfo.EffectPointAt(beatmap.Value.Track.CurrentTime)
+ : null;
- float[] temporalAmplitudes = track?.CurrentAmplitudes.FrequencyAmplitudes;
+ for (int i = 0; i < temporalAmplitudes.Length; i++)
+ temporalAmplitudes[i] = 0;
+
+ if (beatmap.Value.TrackLoaded)
+ addAmplitudesFromSource(beatmap.Value.Track);
+
+ foreach (var source in amplitudeSources)
+ addAmplitudesFromSource(source);
for (int i = 0; i < bars_per_visualiser; i++)
{
- if (track?.IsRunning ?? false)
- {
- float targetAmplitude = (temporalAmplitudes?[(i + indexOffset) % bars_per_visualiser] ?? 0) * (effect?.KiaiMode == true ? 1 : 0.5f);
- if (targetAmplitude > frequencyAmplitudes[i])
- frequencyAmplitudes[i] = targetAmplitude;
- }
- else
- {
- int index = (i + index_change) % bars_per_visualiser;
- if (frequencyAmplitudes[index] > frequencyAmplitudes[i])
- frequencyAmplitudes[i] = frequencyAmplitudes[index];
- }
+ float targetAmplitude = (temporalAmplitudes[(i + indexOffset) % bars_per_visualiser]) * (effect?.KiaiMode == true ? 1 : 0.5f);
+ if (targetAmplitude > frequencyAmplitudes[i])
+ frequencyAmplitudes[i] = targetAmplitude;
}
indexOffset = (indexOffset + index_change) % bars_per_visualiser;
@@ -136,6 +153,19 @@ namespace osu.Game.Screens.Menu
protected override DrawNode CreateDrawNode() => new VisualisationDrawNode(this);
+ private void addAmplitudesFromSource([NotNull] IHasAmplitudes source)
+ {
+ if (source == null) throw new ArgumentNullException(nameof(source));
+
+ var amplitudes = source.CurrentAmplitudes.FrequencyAmplitudes.Span;
+
+ for (int i = 0; i < amplitudes.Length; i++)
+ {
+ if (i < temporalAmplitudes.Length)
+ temporalAmplitudes[i] += amplitudes[i];
+ }
+ }
+
private class VisualisationDrawNode : DrawNode
{
protected new LogoVisualisation Source => (LogoVisualisation)base.Source;
diff --git a/osu.Game/Screens/Menu/MenuSideFlashes.cs b/osu.Game/Screens/Menu/MenuSideFlashes.cs
index 321381ac8d..2ff8132d47 100644
--- a/osu.Game/Screens/Menu/MenuSideFlashes.cs
+++ b/osu.Game/Screens/Menu/MenuSideFlashes.cs
@@ -3,7 +3,6 @@
using osuTK.Graphics;
using osu.Framework.Allocation;
-using osu.Framework.Audio.Track;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
@@ -16,6 +15,7 @@ using osu.Game.Skinning;
using osu.Game.Online.API;
using osu.Game.Users;
using System;
+using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
namespace osu.Game.Screens.Menu
@@ -89,7 +89,7 @@ namespace osu.Game.Screens.Menu
skin.BindValueChanged(_ => updateColour(), true);
}
- protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
+ protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
{
if (beatIndex < 0)
return;
@@ -100,7 +100,7 @@ namespace osu.Game.Screens.Menu
flash(rightBox, timingPoint.BeatLength, effectPoint.KiaiMode, amplitudes);
}
- private void flash(Drawable d, double beatLength, bool kiai, TrackAmplitudes amplitudes)
+ private void flash(Drawable d, double beatLength, bool kiai, ChannelAmplitudes amplitudes)
{
d.FadeTo(Math.Max(0, ((ReferenceEquals(d, leftBox) ? amplitudes.LeftChannel : amplitudes.RightChannel) - amplitude_dead_zone) / (kiai ? kiai_multiplier : alpha_multiplier)), box_fade_in_time)
.Then()
diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs
index 9cadfd7df6..089906c342 100644
--- a/osu.Game/Screens/Menu/OsuLogo.cs
+++ b/osu.Game/Screens/Menu/OsuLogo.cs
@@ -264,7 +264,7 @@ namespace osu.Game.Screens.Menu
private int lastBeatIndex;
- protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
+ protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
{
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index d3b88e56ae..541275cf55 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -656,12 +656,6 @@ namespace osu.Game.Screens.Play
return true;
}
- if (canPause)
- {
- Pause();
- return true;
- }
-
// GameplayClockContainer performs seeks / start / stop operations on the beatmap's track.
// as we are no longer the current screen, we cannot guarantee the track is still usable.
GameplayClockContainer?.StopUsingBeatmapClock();
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index bec3bc9d39..26d81a1004 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -24,8 +24,8 @@
-
-
+
+
diff --git a/osu.iOS.props b/osu.iOS.props
index de5130b66a..72f09ee287 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -70,8 +70,8 @@
-
-
+
+
@@ -80,7 +80,7 @@
-
+