From 42d1379848fa03611cda80eb2336838ddf3165d3 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 29 Sep 2019 20:40:10 +0200 Subject: [PATCH 01/25] Load the rulesets lasily --- osu.Game/Rulesets/RulesetStore.cs | 95 ++++++++++++++++--------------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 2d8c9f5b49..6392f982fb 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -16,17 +16,11 @@ namespace osu.Game.Rulesets /// public class RulesetStore : DatabaseBackedStore { - private static readonly Dictionary loaded_assemblies = new Dictionary(); + private static readonly Lazy> loaded_assemblies = new Lazy>(() => loadRulesets()); static RulesetStore() { AppDomain.CurrentDomain.AssemblyResolve += currentDomain_AssemblyResolve; - - // On android in release configuration assemblies are loaded from the apk directly into memory. - // We cannot read assemblies from cwd, so should check loaded assemblies instead. - loadFromAppDomain(); - - loadFromDisk(); } public RulesetStore(IDatabaseContextFactory factory) @@ -54,7 +48,7 @@ namespace osu.Game.Rulesets /// public IEnumerable AvailableRulesets { get; private set; } - private static Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args) => loaded_assemblies.Keys.FirstOrDefault(a => a.FullName == args.Name); + private static Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args) => loaded_assemblies.Value.Keys.FirstOrDefault(a => a.FullName == args.Name); private const string ruleset_library_prefix = "osu.Game.Rulesets"; @@ -64,7 +58,7 @@ namespace osu.Game.Rulesets { var context = usage.Context; - var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, (RulesetInfo)null)).ToList(); + var instances = loaded_assemblies.Value.Values.Select(r => (Ruleset)Activator.CreateInstance(r, (RulesetInfo)null)).ToList(); //add all legacy modes in correct order foreach (var r in instances.Where(r => r.LegacyID != null).OrderBy(r => r.LegacyID)) @@ -113,8 +107,39 @@ namespace osu.Game.Rulesets } } - private static void loadFromAppDomain() + /// + /// Loads the rulesets that are in the current appdomain an in the current directory. + /// + /// The rulesets that were loaded. + private static Dictionary loadRulesets() { + var rulesets = new Dictionary(); + + foreach (var rulesetAssembly in getRulesetAssemblies()) + { + try + { + rulesets[rulesetAssembly] = rulesetAssembly.GetTypes().First(t => t.IsPublic && t.IsSubclassOf(typeof(Ruleset))); + } + catch (Exception e) + { + Logger.Error(e, $"Failed to add ruleset {rulesetAssembly}"); + } + } + + return rulesets; + } + + /// + /// Scans the current appdomain and current directory for ruleset assemblies. + /// Rulesets that were found in the current directory are automaticly loaded. + /// + /// The ruleset assemblies that were found in the current appdomain or in the current directory. + private static IEnumerable getRulesetAssemblies() + { + var rulesetAssemblies = new HashSet(); + + // load from appdomain foreach (var ruleset in AppDomain.CurrentDomain.GetAssemblies()) { string rulesetName = ruleset.GetName().Name; @@ -122,55 +147,33 @@ namespace osu.Game.Rulesets if (!rulesetName.StartsWith(ruleset_library_prefix, StringComparison.InvariantCultureIgnoreCase) || ruleset.GetName().Name.Contains("Tests")) continue; - addRuleset(ruleset); + rulesetAssemblies.Add(ruleset); } - } - private static void loadFromDisk() - { + // load from current directory try { string[] files = Directory.GetFiles(Environment.CurrentDirectory, $"{ruleset_library_prefix}.*.dll"); foreach (string file in files.Where(f => !Path.GetFileName(f).Contains("Tests"))) - loadRulesetFromFile(file); + { + try + { + rulesetAssemblies.Add(Assembly.LoadFrom(file)); + } + catch (Exception e) + { + Logger.Error(e, $"Failed to load ruleset assembly {Path.GetFileNameWithoutExtension(file)}"); + return null; + } + } } catch { Logger.Log($"Could not load rulesets from directory {Environment.CurrentDirectory}"); } - } - private static void loadRulesetFromFile(string file) - { - var filename = Path.GetFileNameWithoutExtension(file); - - if (loaded_assemblies.Values.Any(t => t.Namespace == filename)) - return; - - try - { - addRuleset(Assembly.LoadFrom(file)); - } - catch (Exception e) - { - Logger.Error(e, $"Failed to load ruleset {filename}"); - } - } - - private static void addRuleset(Assembly assembly) - { - if (loaded_assemblies.ContainsKey(assembly)) - return; - - try - { - loaded_assemblies[assembly] = assembly.GetTypes().First(t => t.IsPublic && t.IsSubclassOf(typeof(Ruleset))); - } - catch (Exception e) - { - Logger.Error(e, $"Failed to add ruleset {assembly}"); - } + return rulesetAssemblies; } } } From b6047e46135cd099a1d21ebcd492d38cac7f5a3b Mon Sep 17 00:00:00 2001 From: HoLLy-HaCKeR Date: Tue, 8 Oct 2019 19:39:54 +0200 Subject: [PATCH 02/25] Move OsuCursor resize logic to OsuCursorContainer --- osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs | 36 ++----------------- .../UI/Cursor/OsuCursorContainer.cs | 34 ++++++++++++++++-- 2 files changed, 34 insertions(+), 36 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs index 41a02deaca..0aa8661fd3 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs @@ -2,14 +2,11 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; -using osu.Game.Beatmaps; -using osu.Game.Configuration; using osu.Game.Rulesets.Osu.Skinning; using osu.Game.Skinning; using osuTK; @@ -23,12 +20,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor private bool cursorExpand; - private Bindable cursorScale; - private Bindable autoCursorScale; - private readonly IBindable beatmap = new Bindable(); - private Container expandTarget; - private Drawable scaleTarget; public OsuCursor() { @@ -43,43 +35,19 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor } [BackgroundDependencyLoader] - private void load(OsuConfigManager config, IBindable beatmap) + private void load() { InternalChild = expandTarget = new Container { RelativeSizeAxes = Axes.Both, Origin = Anchor.Centre, Anchor = Anchor.Centre, - Child = scaleTarget = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.Cursor), _ => new DefaultCursor(), confineMode: ConfineMode.NoScaling) + Child = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.Cursor), _ => new DefaultCursor(), confineMode: ConfineMode.NoScaling) { Origin = Anchor.Centre, Anchor = Anchor.Centre, } }; - - this.beatmap.BindTo(beatmap); - this.beatmap.ValueChanged += _ => calculateScale(); - - cursorScale = config.GetBindable(OsuSetting.GameplayCursorSize); - cursorScale.ValueChanged += _ => calculateScale(); - - autoCursorScale = config.GetBindable(OsuSetting.AutoCursorSize); - autoCursorScale.ValueChanged += _ => calculateScale(); - - calculateScale(); - } - - private void calculateScale() - { - float scale = cursorScale.Value; - - if (autoCursorScale.Value && beatmap.Value != null) - { - // if we have a beatmap available, let's get its circle size to figure out an automatic cursor scale modifier. - scale *= 1f - 0.7f * (1f + beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY; - } - - scaleTarget.Scale = new Vector2(scale); } private const float pressed_scale = 1.2f; diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index 6dbdf0114d..e24ab3a7cb 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -8,6 +8,8 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; using osu.Framework.Input.Bindings; +using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.UI; using osu.Game.Skinning; @@ -27,6 +29,10 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor private readonly Drawable cursorTrail; + private Bindable cursorScale; + private Bindable autoCursorScale; + private readonly IBindable beatmap = new Bindable(); + public OsuCursorContainer() { InternalChild = fadeContainer = new Container @@ -37,9 +43,33 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor } [BackgroundDependencyLoader(true)] - private void load(OsuRulesetConfigManager config) + private void load(OsuConfigManager config, OsuRulesetConfigManager rulesetConfig, IBindable beatmap) { - config?.BindWith(OsuRulesetSetting.ShowCursorTrail, showTrail); + rulesetConfig?.BindWith(OsuRulesetSetting.ShowCursorTrail, showTrail); + + this.beatmap.BindTo(beatmap); + this.beatmap.ValueChanged += _ => calculateScale(); + + cursorScale = config.GetBindable(OsuSetting.GameplayCursorSize); + cursorScale.ValueChanged += _ => calculateScale(); + + autoCursorScale = config.GetBindable(OsuSetting.AutoCursorSize); + autoCursorScale.ValueChanged += _ => calculateScale(); + + calculateScale(); + } + + private void calculateScale() + { + float scale = cursorScale.Value; + + if (autoCursorScale.Value && beatmap.Value != null) + { + // if we have a beatmap available, let's get its circle size to figure out an automatic cursor scale modifier. + scale *= 1f - 0.7f * (1f + beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY; + } + + ActiveCursor.Scale = new Vector2(scale); } protected override void LoadComplete() From 1c22fb485fa2cc8b75f230c5a5ddcd40fa090534 Mon Sep 17 00:00:00 2001 From: HoLLy-HaCKeR Date: Tue, 8 Oct 2019 19:40:46 +0200 Subject: [PATCH 03/25] Scale cursortrail along with cursor --- osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index e24ab3a7cb..371c2983fc 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor scale *= 1f - 0.7f * (1f + beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY; } - ActiveCursor.Scale = new Vector2(scale); + ActiveCursor.Scale = cursorTrail.Scale = new Vector2(scale); } protected override void LoadComplete() From 13924174c4950a173c575217484006046cfaccf4 Mon Sep 17 00:00:00 2001 From: HoLLy-HaCKeR Date: Sat, 12 Oct 2019 10:04:14 +0200 Subject: [PATCH 04/25] Fix PopIn and PopOut resetting cursor scale --- osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index 371c2983fc..2b499064fb 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -31,6 +31,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor private Bindable cursorScale; private Bindable autoCursorScale; + private float calculatedCursorScale; private readonly IBindable beatmap = new Bindable(); public OsuCursorContainer() @@ -69,6 +70,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor scale *= 1f - 0.7f * (1f + beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY; } + calculatedCursorScale = scale; ActiveCursor.Scale = cursorTrail.Scale = new Vector2(scale); } @@ -125,13 +127,13 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor protected override void PopIn() { fadeContainer.FadeTo(1, 300, Easing.OutQuint); - ActiveCursor.ScaleTo(1, 400, Easing.OutQuint); + ActiveCursor.ScaleTo(calculatedCursorScale, 400, Easing.OutQuint); } protected override void PopOut() { fadeContainer.FadeTo(0.05f, 450, Easing.OutQuint); - ActiveCursor.ScaleTo(0.8f, 450, Easing.OutQuint); + ActiveCursor.ScaleTo(calculatedCursorScale * 0.8f, 450, Easing.OutQuint); } private class DefaultCursorTrail : CursorTrail From fdc17d2adb07d81c22f7d1b6ad3c44f277917429 Mon Sep 17 00:00:00 2001 From: HoLLy-HaCKeR Date: Sat, 12 Oct 2019 11:51:14 +0200 Subject: [PATCH 05/25] Scale OsuResumeCursor with gameplay cursor --- .../UI/Cursor/OsuCursorContainer.cs | 13 ++++++++----- osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs | 14 +++++++++++--- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index 2b499064fb..8ea11d0a4b 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -29,9 +29,10 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor private readonly Drawable cursorTrail; + public IBindable CalculatedCursorScale => calculatedCursorScale; + private Bindable calculatedCursorScale; private Bindable cursorScale; private Bindable autoCursorScale; - private float calculatedCursorScale; private readonly IBindable beatmap = new Bindable(); public OsuCursorContainer() @@ -57,6 +58,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor autoCursorScale = config.GetBindable(OsuSetting.AutoCursorSize); autoCursorScale.ValueChanged += _ => calculateScale(); + calculatedCursorScale = new Bindable(); + calculatedCursorScale.ValueChanged += e => ActiveCursor.Scale = cursorTrail.Scale = new Vector2(e.NewValue); + calculateScale(); } @@ -70,8 +74,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor scale *= 1f - 0.7f * (1f + beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY; } - calculatedCursorScale = scale; - ActiveCursor.Scale = cursorTrail.Scale = new Vector2(scale); + calculatedCursorScale.Value = scale; } protected override void LoadComplete() @@ -127,13 +130,13 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor protected override void PopIn() { fadeContainer.FadeTo(1, 300, Easing.OutQuint); - ActiveCursor.ScaleTo(calculatedCursorScale, 400, Easing.OutQuint); + ActiveCursor.ScaleTo(calculatedCursorScale.Value, 400, Easing.OutQuint); } protected override void PopOut() { fadeContainer.FadeTo(0.05f, 450, Easing.OutQuint); - ActiveCursor.ScaleTo(calculatedCursorScale * 0.8f, 450, Easing.OutQuint); + ActiveCursor.ScaleTo(calculatedCursorScale.Value * 0.8f, 450, Easing.OutQuint); } private class DefaultCursorTrail : CursorTrail diff --git a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs index 9e5df0d6b1..9033817115 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs @@ -38,7 +38,13 @@ namespace osu.Game.Rulesets.Osu.UI clickToResumeCursor.ShowAt(GameplayCursor.ActiveCursor.Position); if (localCursorContainer == null) - Add(localCursorContainer = new OsuCursorContainer()); + { + var newContainer = new OsuCursorContainer(); + Add(localCursorContainer = newContainer); + + clickToResumeCursor.CursorScale = newContainer.CalculatedCursorScale.Value; + newContainer.CalculatedCursorScale.ValueChanged += e => clickToResumeCursor.CursorScale = e.NewValue; + } } public override void Hide() @@ -57,6 +63,8 @@ namespace osu.Game.Rulesets.Osu.UI public Action ResumeRequested; + public float CursorScale; + public OsuClickToResumeCursor() { RelativePositionAxes = Axes.Both; @@ -82,7 +90,7 @@ namespace osu.Game.Rulesets.Osu.UI case OsuAction.RightButton: if (!IsHovered) return false; - this.ScaleTo(new Vector2(2), TRANSITION_TIME, Easing.OutQuint); + this.ScaleTo(2 * CursorScale, TRANSITION_TIME, Easing.OutQuint); ResumeRequested?.Invoke(); return true; @@ -97,7 +105,7 @@ namespace osu.Game.Rulesets.Osu.UI { updateColour(); this.MoveTo(activeCursorPosition); - this.ScaleTo(new Vector2(4)).Then().ScaleTo(Vector2.One, 1000, Easing.OutQuint); + this.ScaleTo(4 * CursorScale).Then().ScaleTo(CursorScale, 1000, Easing.OutQuint); }); private void updateColour() From 7931510d7bda55dc3b54da6d411cd8c4711a7e4e Mon Sep 17 00:00:00 2001 From: HoLLy-HaCKeR Date: Sat, 12 Oct 2019 11:59:22 +0200 Subject: [PATCH 06/25] Ensure OsuResumeCursor can change scale when it is being shown --- osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs index 9033817115..7221e09c35 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs @@ -43,7 +43,13 @@ namespace osu.Game.Rulesets.Osu.UI Add(localCursorContainer = newContainer); clickToResumeCursor.CursorScale = newContainer.CalculatedCursorScale.Value; - newContainer.CalculatedCursorScale.ValueChanged += e => clickToResumeCursor.CursorScale = e.NewValue; + clickToResumeCursor.Scale = new Vector2(newContainer.CalculatedCursorScale.Value); + + newContainer.CalculatedCursorScale.ValueChanged += e => + { + clickToResumeCursor.CursorScale = e.NewValue; + clickToResumeCursor.Scale = new Vector2(e.NewValue); + }; } } From ae2fe62fd9ed27d1ef5bdd60927795b9d509ca97 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Oct 2019 17:13:36 +0900 Subject: [PATCH 07/25] Use BindValueChanged --- osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs index 7221e09c35..1ee2a04a3b 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics.Cursor; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Rulesets.Osu.UI.Cursor; -using osu.Game.Rulesets.UI; using osu.Game.Screens.Play; using osuTK; using osuTK.Graphics; @@ -20,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.UI { private OsuClickToResumeCursor clickToResumeCursor; - private GameplayCursorContainer localCursorContainer; + private OsuCursorContainer localCursorContainer; public override CursorContainer LocalCursor => State.Value == Visibility.Visible ? localCursorContainer : null; @@ -39,17 +38,13 @@ namespace osu.Game.Rulesets.Osu.UI if (localCursorContainer == null) { - var newContainer = new OsuCursorContainer(); - Add(localCursorContainer = newContainer); + Add(localCursorContainer = new OsuCursorContainer()); - clickToResumeCursor.CursorScale = newContainer.CalculatedCursorScale.Value; - clickToResumeCursor.Scale = new Vector2(newContainer.CalculatedCursorScale.Value); - - newContainer.CalculatedCursorScale.ValueChanged += e => + localCursorContainer.CalculatedCursorScale.BindValueChanged(scale => { - clickToResumeCursor.CursorScale = e.NewValue; - clickToResumeCursor.Scale = new Vector2(e.NewValue); - }; + clickToResumeCursor.CursorScale = scale.NewValue; + clickToResumeCursor.Scale = new Vector2(scale.NewValue); + }, true); } } From 6da1b4d0120317643473c61c4e9e9ce6f34f6784 Mon Sep 17 00:00:00 2001 From: miterosan Date: Mon, 14 Oct 2019 21:46:01 +0200 Subject: [PATCH 08/25] Fix incorrect current directory that accours on some devices on android. --- osu.Android/OsuGameActivity.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Android/OsuGameActivity.cs b/osu.Android/OsuGameActivity.cs index 762a9c418d..41531617af 100644 --- a/osu.Android/OsuGameActivity.cs +++ b/osu.Android/OsuGameActivity.cs @@ -16,6 +16,11 @@ namespace osu.Android protected override void OnCreate(Bundle savedInstanceState) { + // The default current directory on android is '/'. + // On some devices '/' maps to the app data directory. On others it maps to the root of the internal storage. + // In order to have a consitend current directory on all devices the full path of the app data directory is set as the current directory. + System.Environment.CurrentDirectory = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); + base.OnCreate(savedInstanceState); Window.AddFlags(WindowManagerFlags.Fullscreen); From 8c671d7fde49cd038378105e029be1fa37113c79 Mon Sep 17 00:00:00 2001 From: HoLLy Date: Tue, 15 Oct 2019 20:12:08 +0200 Subject: [PATCH 09/25] Rename cursorScale and calculatedCursorScale --- .../UI/Cursor/OsuCursorContainer.cs | 20 +++++++++---------- osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index 8ea11d0a4b..52e2e493d5 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -29,9 +29,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor private readonly Drawable cursorTrail; - public IBindable CalculatedCursorScale => calculatedCursorScale; - private Bindable calculatedCursorScale; + public IBindable CursorScale => cursorScale; private Bindable cursorScale; + private Bindable userCursorScale; private Bindable autoCursorScale; private readonly IBindable beatmap = new Bindable(); @@ -52,21 +52,21 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor this.beatmap.BindTo(beatmap); this.beatmap.ValueChanged += _ => calculateScale(); - cursorScale = config.GetBindable(OsuSetting.GameplayCursorSize); - cursorScale.ValueChanged += _ => calculateScale(); + userCursorScale = config.GetBindable(OsuSetting.GameplayCursorSize); + userCursorScale.ValueChanged += _ => calculateScale(); autoCursorScale = config.GetBindable(OsuSetting.AutoCursorSize); autoCursorScale.ValueChanged += _ => calculateScale(); - calculatedCursorScale = new Bindable(); - calculatedCursorScale.ValueChanged += e => ActiveCursor.Scale = cursorTrail.Scale = new Vector2(e.NewValue); + cursorScale = new Bindable(); + cursorScale.ValueChanged += e => ActiveCursor.Scale = cursorTrail.Scale = new Vector2(e.NewValue); calculateScale(); } private void calculateScale() { - float scale = cursorScale.Value; + float scale = userCursorScale.Value; if (autoCursorScale.Value && beatmap.Value != null) { @@ -74,7 +74,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor scale *= 1f - 0.7f * (1f + beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY; } - calculatedCursorScale.Value = scale; + cursorScale.Value = scale; } protected override void LoadComplete() @@ -130,13 +130,13 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor protected override void PopIn() { fadeContainer.FadeTo(1, 300, Easing.OutQuint); - ActiveCursor.ScaleTo(calculatedCursorScale.Value, 400, Easing.OutQuint); + ActiveCursor.ScaleTo(cursorScale.Value, 400, Easing.OutQuint); } protected override void PopOut() { fadeContainer.FadeTo(0.05f, 450, Easing.OutQuint); - ActiveCursor.ScaleTo(calculatedCursorScale.Value * 0.8f, 450, Easing.OutQuint); + ActiveCursor.ScaleTo(cursorScale.Value * 0.8f, 450, Easing.OutQuint); } private class DefaultCursorTrail : CursorTrail diff --git a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs index 1ee2a04a3b..64821ac24f 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.UI { Add(localCursorContainer = new OsuCursorContainer()); - localCursorContainer.CalculatedCursorScale.BindValueChanged(scale => + localCursorContainer.CursorScale.BindValueChanged(scale => { clickToResumeCursor.CursorScale = scale.NewValue; clickToResumeCursor.Scale = new Vector2(scale.NewValue); From 14c72f85fa56387b3932908c616c0de68e3aee36 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Tue, 15 Oct 2019 23:40:48 +0300 Subject: [PATCH 10/25] Fix incorrect beatmap set info equality check on non-online set info --- osu.Game/Beatmaps/BeatmapSetInfo.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index 03bc7c7312..90346a8c8b 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -63,6 +63,12 @@ namespace osu.Game.Beatmaps public bool Protected { get; set; } - public bool Equals(BeatmapSetInfo other) => OnlineBeatmapSetID == other?.OnlineBeatmapSetID; + public bool Equals(BeatmapSetInfo other) + { + if (!OnlineBeatmapSetID.HasValue || !(other?.OnlineBeatmapSetID.HasValue ?? false)) + return ReferenceEquals(this, other); + + return OnlineBeatmapSetID == other.OnlineBeatmapSetID; + } } } From 13e11992296cbacadebe87ae239f84f201739f41 Mon Sep 17 00:00:00 2001 From: HoLLy Date: Tue, 15 Oct 2019 22:44:04 +0200 Subject: [PATCH 11/25] Move click to resume cursor scaling responsibility to container --- osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs | 25 ++++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs index 64821ac24f..908ad1ce49 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs @@ -17,6 +17,7 @@ namespace osu.Game.Rulesets.Osu.UI { public class OsuResumeOverlay : ResumeOverlay { + private Container cursorScaleContainer; private OsuClickToResumeCursor clickToResumeCursor; private OsuCursorContainer localCursorContainer; @@ -28,23 +29,24 @@ namespace osu.Game.Rulesets.Osu.UI [BackgroundDependencyLoader] private void load() { - Add(clickToResumeCursor = new OsuClickToResumeCursor { ResumeRequested = Resume }); + Add(cursorScaleContainer = new Container + { + RelativePositionAxes = Axes.Both, + Child = clickToResumeCursor = new OsuClickToResumeCursor { ResumeRequested = Resume } + }); } public override void Show() { base.Show(); - clickToResumeCursor.ShowAt(GameplayCursor.ActiveCursor.Position); + cursorScaleContainer.MoveTo(GameplayCursor.ActiveCursor.Position); + clickToResumeCursor.Appear(); if (localCursorContainer == null) { Add(localCursorContainer = new OsuCursorContainer()); - localCursorContainer.CursorScale.BindValueChanged(scale => - { - clickToResumeCursor.CursorScale = scale.NewValue; - clickToResumeCursor.Scale = new Vector2(scale.NewValue); - }, true); + localCursorContainer.CursorScale.BindValueChanged(scale => cursorScaleContainer.Scale = new Vector2(scale.NewValue), true); } } @@ -64,8 +66,6 @@ namespace osu.Game.Rulesets.Osu.UI public Action ResumeRequested; - public float CursorScale; - public OsuClickToResumeCursor() { RelativePositionAxes = Axes.Both; @@ -91,7 +91,7 @@ namespace osu.Game.Rulesets.Osu.UI case OsuAction.RightButton: if (!IsHovered) return false; - this.ScaleTo(2 * CursorScale, TRANSITION_TIME, Easing.OutQuint); + this.ScaleTo(2, TRANSITION_TIME, Easing.OutQuint); ResumeRequested?.Invoke(); return true; @@ -102,11 +102,10 @@ namespace osu.Game.Rulesets.Osu.UI public bool OnReleased(OsuAction action) => false; - public void ShowAt(Vector2 activeCursorPosition) => Schedule(() => + public void Appear() => Schedule(() => { updateColour(); - this.MoveTo(activeCursorPosition); - this.ScaleTo(4 * CursorScale).Then().ScaleTo(CursorScale, 1000, Easing.OutQuint); + this.ScaleTo(4).Then().ScaleTo(1, 1000, Easing.OutQuint); }); private void updateColour() From 405ab07800b204b9cf3b882dfc978378eee1f72c Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 17 Oct 2019 01:18:29 +0300 Subject: [PATCH 12/25] Check equality by ID -> OnlineBeatmapSetID -> Hash -> ReferenceEquals --- osu.Game/Beatmaps/BeatmapSetInfo.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index 90346a8c8b..a8b83dca38 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -65,10 +65,19 @@ namespace osu.Game.Beatmaps public bool Equals(BeatmapSetInfo other) { - if (!OnlineBeatmapSetID.HasValue || !(other?.OnlineBeatmapSetID.HasValue ?? false)) - return ReferenceEquals(this, other); + if (other == null) + return false; - return OnlineBeatmapSetID == other.OnlineBeatmapSetID; + if (ID != 0 && other.ID != 0) + return ID == other.ID; + + if (OnlineBeatmapSetID.HasValue && other.OnlineBeatmapSetID.HasValue) + return OnlineBeatmapSetID == other.OnlineBeatmapSetID; + + if (!string.IsNullOrEmpty(Hash) && !string.IsNullOrEmpty(other.Hash)) + return Hash == other.Hash; + + return ReferenceEquals(this, other); } } } From 40fc655b50244d0b0d588abb1b97f3ae9cbde831 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 17 Oct 2019 01:19:50 +0300 Subject: [PATCH 13/25] Add equality check test to ensure correct values --- .../NonVisual/BeatmapSetInfoEqualityTest.cs | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs diff --git a/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs b/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs new file mode 100644 index 0000000000..42a3b4cf43 --- /dev/null +++ b/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs @@ -0,0 +1,48 @@ +// 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.Game.Beatmaps; + +namespace osu.Game.Tests.NonVisual +{ + [TestFixture] + public class BeatmapSetInfoEqualityTest + { + [Test] + public void TestOnlineWithOnline() + { + var ourInfo = new BeatmapSetInfo { OnlineBeatmapSetID = 123 }; + var otherInfo = new BeatmapSetInfo { OnlineBeatmapSetID = 123 }; + + Assert.AreEqual(ourInfo, otherInfo); + } + + [Test] + public void TestDatabasedWithDatabased() + { + var ourInfo = new BeatmapSetInfo { ID = 123 }; + var otherInfo = new BeatmapSetInfo { ID = 123 }; + + Assert.AreEqual(ourInfo, otherInfo); + } + + [Test] + public void TestDatabasedWithOnline() + { + var ourInfo = new BeatmapSetInfo { ID = 123, OnlineBeatmapSetID = 12 }; + var otherInfo = new BeatmapSetInfo { OnlineBeatmapSetID = 12 }; + + Assert.AreEqual(ourInfo, otherInfo); + } + + [Test] + public void TestCheckNullID() + { + var ourInfo = new BeatmapSetInfo { Status = BeatmapSetOnlineStatus.Loved }; + var otherInfo = new BeatmapSetInfo { Status = BeatmapSetOnlineStatus.Approved }; + + Assert.AreNotEqual(ourInfo, otherInfo); + } + } +} From c4cc960e1564944a18964c606b2b64b8f4d927de Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 17 Oct 2019 18:00:15 +0900 Subject: [PATCH 14/25] Fix mania hitobject selections not moving correctly --- .../Edit/ManiaSelectionHandler.cs | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs index f576c43e52..2fba0639da 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs @@ -65,24 +65,27 @@ namespace osu.Game.Rulesets.Mania.Edit private void performDragMovement(MoveSelectionEvent moveEvent) { + float delta = moveEvent.InstantDelta.Y; + + // When scrolling downwards the anchor position is at the bottom of the screen, however the movement event assumes the anchor is at the top of the screen. + // This causes the delta to assume a positive hitobject position, and which can be corrected for by subtracting the parent height. + if (scrollingInfo.Direction.Value == ScrollingDirection.Down) + delta -= moveEvent.Blueprint.HitObject.Parent.DrawHeight; + foreach (var b in SelectedBlueprints) { var hitObject = b.HitObject; - var objectParent = (HitObjectContainer)hitObject.Parent; - // Using the hitobject position is required since AdjustPosition can be invoked multiple times per frame - // without the position having been updated by the parenting ScrollingHitObjectContainer - hitObject.Y += moveEvent.InstantDelta.Y; + // StartTime could be used to adjust the position if only one movement event was received per frame. + // However this is not the case and ScrollingHitObjectContainer performs movement in UpdateAfterChildren() so the position must also be updated to be valid for further movement events + hitObject.Y += delta; - float targetPosition; + float targetPosition = hitObject.Position.Y; - // If we're scrolling downwards, a position of 0 is actually further away from the hit target - // so we need to flip the vertical coordinate in the hitobject container's space + // The scrolling algorithm always assumes an anchor at the top of the screen, so the position must be flipped when scrolling downwards to reflect a top anchor if (scrollingInfo.Direction.Value == ScrollingDirection.Down) - targetPosition = -hitObject.Position.Y; - else - targetPosition = hitObject.Position.Y; + targetPosition = -targetPosition; objectParent.Remove(hitObject); From 5d3d25d3b69060342deb8ba58dfe192735c809a7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 18 Oct 2019 13:24:25 +0900 Subject: [PATCH 15/25] Make method private for now --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 99b0c07570..18d45f3724 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -126,7 +126,7 @@ namespace osu.Game.Rulesets.Objects.Drawables { base.LoadComplete(); - Apply(HitObject); + apply(HitObject); if (HitObject is IHasComboInformation combo) { @@ -137,7 +137,7 @@ namespace osu.Game.Rulesets.Objects.Drawables updateState(ArmedState.Idle, true); } - protected void Apply(HitObject hitObject) + private void apply(HitObject hitObject) { #pragma warning disable 618 // can be removed 20200417 if (GetType().GetMethod(nameof(AddNested), BindingFlags.NonPublic | BindingFlags.Instance)?.DeclaringType != typeof(DrawableHitObject)) From 6b0976ff1e2e1d13747f0e6a06114ff52b056b26 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 15 Oct 2019 15:07:06 +0900 Subject: [PATCH 16/25] Remove a weird unicode charcter from file --- osu.Game/Overlays/AccountCreation/ScreenWarning.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs index be417f4aac..f91d2e3323 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs @@ -121,7 +121,7 @@ namespace osu.Game.Overlays.AccountCreation multiAccountExplanationText.AddText("? osu! has a policy of "); multiAccountExplanationText.AddText("one account per person!", cp => cp.Colour = colours.Yellow); multiAccountExplanationText.AddText(" Please be aware that creating more than one account per person may result in "); - multiAccountExplanationText.AddText("permanent deactivation of accounts", cp => cp.Colour = colours.Yellow); + multiAccountExplanationText.AddText("permanent deactivation of accounts", cp => cp.Colour = colours.Yellow); multiAccountExplanationText.AddText("."); furtherAssistance.AddText("Need further assistance? Contact us via our "); From 89f50b26f72f56f932df01a99f94f93de621da8e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 18 Oct 2019 17:32:11 +0900 Subject: [PATCH 17/25] Fix hitobject combo colour potentially not getting adjusted --- .../TestSceneHitObjectAccentColour.cs | 143 ++++++++++++++++++ .../Objects/Drawables/DrawableHitObject.cs | 2 +- 2 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs new file mode 100644 index 0000000000..6d7159a825 --- /dev/null +++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs @@ -0,0 +1,143 @@ +// 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.Collections.Generic; +using NUnit.Framework; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Textures; +using osu.Framework.Testing; +using osu.Game.Audio; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Skinning; +using osu.Game.Tests.Visual; +using osuTK.Graphics; + +namespace osu.Game.Tests.Gameplay +{ + [HeadlessTest] + public class TestSceneHitObjectAccentColour : OsuTestScene + { + private Container skinContainer; + + [SetUp] + public void Setup() => Schedule(() => Child = skinContainer = new SkinProvidingContainer(new TestSkin())); + + [Test] + public void TestChangeComboIndexBeforeLoad() + { + TestDrawableHitObject hitObject = null; + + AddStep("set combo and add hitobject", () => + { + hitObject = new TestDrawableHitObject(); + hitObject.HitObject.ComboIndex = 1; + + skinContainer.Add(hitObject); + }); + + AddAssert("combo colour is green", () => hitObject.AccentColour.Value == Color4.Green); + } + + [Test] + public void TestChangeComboIndexDuringLoad() + { + TestDrawableHitObject hitObject = null; + + AddStep("add hitobject and set combo", () => + { + skinContainer.Add(hitObject = new TestDrawableHitObject()); + hitObject.HitObject.ComboIndex = 1; + }); + + AddAssert("combo colour is green", () => hitObject.AccentColour.Value == Color4.Green); + } + + [Test] + public void TestChangeComboIndexAfterLoad() + { + TestDrawableHitObject hitObject = null; + + AddStep("add hitobject", () => skinContainer.Add(hitObject = new TestDrawableHitObject())); + AddAssert("combo colour is red", () => hitObject.AccentColour.Value == Color4.Red); + + AddStep("change combo", () => hitObject.HitObject.ComboIndex = 1); + AddAssert("combo colour is green", () => hitObject.AccentColour.Value == Color4.Green); + } + + private class TestDrawableHitObject : DrawableHitObject + { + public TestDrawableHitObject() + : base(new TestHitObjectWithCombo()) + { + } + } + + private class TestHitObjectWithCombo : HitObject, IHasComboInformation + { + public bool NewCombo { get; } = false; + public int ComboOffset { get; } = 0; + + public Bindable IndexInCurrentComboBindable { get; } = new Bindable(); + + public int IndexInCurrentCombo + { + get => IndexInCurrentComboBindable.Value; + set => IndexInCurrentComboBindable.Value = value; + } + + public Bindable ComboIndexBindable { get; } = new Bindable(); + + public int ComboIndex + { + get => ComboIndexBindable.Value; + set => ComboIndexBindable.Value = value; + } + + public Bindable LastInComboBindable { get; } = new Bindable(); + + public bool LastInCombo + { + get => LastInComboBindable.Value; + set => LastInComboBindable.Value = value; + } + } + + private class TestSkin : ISkin + { + public readonly List ComboColours = new List + { + Color4.Red, + Color4.Green + }; + + public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotImplementedException(); + + public Texture GetTexture(string componentName) => throw new NotImplementedException(); + + public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException(); + + public IBindable GetConfig(TLookup lookup) + { + switch (lookup) + { + case GlobalSkinConfiguration global: + switch (global) + { + case GlobalSkinConfiguration.ComboColours: + return SkinUtils.As(new Bindable>(ComboColours)); + } + + break; + } + + throw new NotImplementedException(); + } + } + } +} diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 7f3bfd3b5c..0948452ceb 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -128,7 +128,7 @@ namespace osu.Game.Rulesets.Objects.Drawables if (HitObject is IHasComboInformation combo) { comboIndexBindable = combo.ComboIndexBindable.GetBoundCopy(); - comboIndexBindable.BindValueChanged(_ => updateAccentColour()); + comboIndexBindable.BindValueChanged(_ => updateAccentColour(), true); } updateState(ArmedState.Idle, true); From 07286c0cfc106dfd49fb8370bfe5490ed2bb597f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Oct 2019 18:21:53 +0900 Subject: [PATCH 18/25] Fix editor's clock not being processed unless composer is loaded --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 3 ++- osu.Game/Screens/Edit/Editor.cs | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index a267d7c44d..038d6a320a 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -57,7 +57,8 @@ namespace osu.Game.Rulesets.Edit { drawableRulesetWrapper = new DrawableEditRulesetWrapper(CreateDrawableRuleset(Ruleset, workingBeatmap, Array.Empty())) { - Clock = framedClock + Clock = framedClock, + ProcessCustomClock = false }; } catch (Exception e) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 7f08c2f8b9..35408e4003 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -173,6 +173,12 @@ namespace osu.Game.Screens.Edit bottomBackground.Colour = colours.Gray2; } + protected override void Update() + { + base.Update(); + clock.ProcessFrame(); + } + protected override bool OnKeyDown(KeyDownEvent e) { switch (e.Key) From ca957f0994cd8e459231ecde6085d939eca2d094 Mon Sep 17 00:00:00 2001 From: HoLLy Date: Sat, 19 Oct 2019 11:52:07 +0200 Subject: [PATCH 19/25] Hide gameplay cursor when resume overlay is shown --- osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs index 908ad1ce49..3d3e0fe49a 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs @@ -39,6 +39,7 @@ namespace osu.Game.Rulesets.Osu.UI public override void Show() { base.Show(); + GameplayCursor.ActiveCursor.Hide(); cursorScaleContainer.MoveTo(GameplayCursor.ActiveCursor.Position); clickToResumeCursor.Appear(); @@ -54,6 +55,7 @@ namespace osu.Game.Rulesets.Osu.UI { localCursorContainer?.Expire(); localCursorContainer = null; + GameplayCursor.ActiveCursor.Show(); base.Hide(); } From 68837d47df136a9ac8a9b1af9fb68bc62b2576ce Mon Sep 17 00:00:00 2001 From: HoLLy Date: Sat, 19 Oct 2019 12:15:31 +0200 Subject: [PATCH 20/25] Use local bindable instead of using BindValueChanged of external one --- .../UI/Cursor/OsuCursorContainer.cs | 13 ++++++------- osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs | 8 ++++++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index 52e2e493d5..6433ced624 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -29,8 +29,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor private readonly Drawable cursorTrail; - public IBindable CursorScale => cursorScale; - private Bindable cursorScale; + public Bindable CursorScale; private Bindable userCursorScale; private Bindable autoCursorScale; private readonly IBindable beatmap = new Bindable(); @@ -58,8 +57,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor autoCursorScale = config.GetBindable(OsuSetting.AutoCursorSize); autoCursorScale.ValueChanged += _ => calculateScale(); - cursorScale = new Bindable(); - cursorScale.ValueChanged += e => ActiveCursor.Scale = cursorTrail.Scale = new Vector2(e.NewValue); + CursorScale = new Bindable(); + CursorScale.ValueChanged += e => ActiveCursor.Scale = cursorTrail.Scale = new Vector2(e.NewValue); calculateScale(); } @@ -74,7 +73,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor scale *= 1f - 0.7f * (1f + beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY; } - cursorScale.Value = scale; + CursorScale.Value = scale; } protected override void LoadComplete() @@ -130,13 +129,13 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor protected override void PopIn() { fadeContainer.FadeTo(1, 300, Easing.OutQuint); - ActiveCursor.ScaleTo(cursorScale.Value, 400, Easing.OutQuint); + ActiveCursor.ScaleTo(CursorScale.Value, 400, Easing.OutQuint); } protected override void PopOut() { fadeContainer.FadeTo(0.05f, 450, Easing.OutQuint); - ActiveCursor.ScaleTo(cursorScale.Value * 0.8f, 450, Easing.OutQuint); + ActiveCursor.ScaleTo(CursorScale.Value * 0.8f, 450, Easing.OutQuint); } private class DefaultCursorTrail : CursorTrail diff --git a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs index 3d3e0fe49a..8347d255fa 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs @@ -1,8 +1,9 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// 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 osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; @@ -21,6 +22,7 @@ namespace osu.Game.Rulesets.Osu.UI private OsuClickToResumeCursor clickToResumeCursor; private OsuCursorContainer localCursorContainer; + private Bindable localCursorScale; public override CursorContainer LocalCursor => State.Value == Visibility.Visible ? localCursorContainer : null; @@ -47,7 +49,9 @@ namespace osu.Game.Rulesets.Osu.UI { Add(localCursorContainer = new OsuCursorContainer()); - localCursorContainer.CursorScale.BindValueChanged(scale => cursorScaleContainer.Scale = new Vector2(scale.NewValue), true); + localCursorScale = new Bindable(); + localCursorScale.BindTo(localCursorContainer.CursorScale); + localCursorScale.BindValueChanged(scale => cursorScaleContainer.Scale = new Vector2(scale.NewValue), true); } } From aa910fb51970a77c3bfaa8db12d2b3028380ad80 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 20 Oct 2019 21:11:16 +0200 Subject: [PATCH 21/25] Revert "Load the rulesets lasily" This reverts commit 42d1379848fa03611cda80eb2336838ddf3165d3. --- osu.Game/Rulesets/RulesetStore.cs | 95 +++++++++++++++---------------- 1 file changed, 46 insertions(+), 49 deletions(-) diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 97a90bf824..47aad43966 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -16,11 +16,17 @@ namespace osu.Game.Rulesets /// public class RulesetStore : DatabaseBackedStore { - private static readonly Lazy> loaded_assemblies = new Lazy>(() => loadRulesets()); + private static readonly Dictionary loaded_assemblies = new Dictionary(); static RulesetStore() { AppDomain.CurrentDomain.AssemblyResolve += currentDomain_AssemblyResolve; + + // On android in release configuration assemblies are loaded from the apk directly into memory. + // We cannot read assemblies from cwd, so should check loaded assemblies instead. + loadFromAppDomain(); + + loadFromDisk(); } public RulesetStore(IDatabaseContextFactory factory) @@ -48,7 +54,7 @@ namespace osu.Game.Rulesets /// public IEnumerable AvailableRulesets { get; private set; } - private static Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args) => loaded_assemblies.Value.Keys.FirstOrDefault(a => a.FullName == args.Name); + private static Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args) => loaded_assemblies.Keys.FirstOrDefault(a => a.FullName == args.Name); private const string ruleset_library_prefix = "osu.Game.Rulesets"; @@ -58,7 +64,7 @@ namespace osu.Game.Rulesets { var context = usage.Context; - var instances = loaded_assemblies.Value.Values.Select(r => (Ruleset)Activator.CreateInstance(r, (RulesetInfo)null)).ToList(); + var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, (RulesetInfo)null)).ToList(); //add all legacy modes in correct order foreach (var r in instances.Where(r => r.LegacyID != null).OrderBy(r => r.LegacyID)) @@ -107,39 +113,8 @@ namespace osu.Game.Rulesets } } - /// - /// Loads the rulesets that are in the current appdomain an in the current directory. - /// - /// The rulesets that were loaded. - private static Dictionary loadRulesets() + private static void loadFromAppDomain() { - var rulesets = new Dictionary(); - - foreach (var rulesetAssembly in getRulesetAssemblies()) - { - try - { - rulesets[rulesetAssembly] = rulesetAssembly.GetTypes().First(t => t.IsPublic && t.IsSubclassOf(typeof(Ruleset))); - } - catch (Exception e) - { - Logger.Error(e, $"Failed to add ruleset {rulesetAssembly}"); - } - } - - return rulesets; - } - - /// - /// Scans the current appdomain and current directory for ruleset assemblies. - /// Rulesets that were found in the current directory are automaticly loaded. - /// - /// The ruleset assemblies that were found in the current appdomain or in the current directory. - private static IEnumerable getRulesetAssemblies() - { - var rulesetAssemblies = new HashSet(); - - // load from appdomain foreach (var ruleset in AppDomain.CurrentDomain.GetAssemblies()) { string rulesetName = ruleset.GetName().Name; @@ -147,33 +122,55 @@ namespace osu.Game.Rulesets if (!rulesetName.StartsWith(ruleset_library_prefix, StringComparison.InvariantCultureIgnoreCase) || ruleset.GetName().Name.Contains("Tests")) continue; - rulesetAssemblies.Add(ruleset); + addRuleset(ruleset); } + } - // load from current directory + private static void loadFromDisk() + { try { string[] files = Directory.GetFiles(Environment.CurrentDirectory, $"{ruleset_library_prefix}.*.dll"); foreach (string file in files.Where(f => !Path.GetFileName(f).Contains("Tests"))) - { - try - { - rulesetAssemblies.Add(Assembly.LoadFrom(file)); - } - catch (Exception e) - { - Logger.Error(e, $"Failed to load ruleset assembly {Path.GetFileNameWithoutExtension(file)}"); - return null; - } - } + loadRulesetFromFile(file); } catch (Exception e) { Logger.Error(e, $"Could not load rulesets from directory {Environment.CurrentDirectory}"); } + } - return rulesetAssemblies; + private static void loadRulesetFromFile(string file) + { + var filename = Path.GetFileNameWithoutExtension(file); + + if (loaded_assemblies.Values.Any(t => t.Namespace == filename)) + return; + + try + { + addRuleset(Assembly.LoadFrom(file)); + } + catch (Exception e) + { + Logger.Error(e, $"Failed to load ruleset {filename}"); + } + } + + private static void addRuleset(Assembly assembly) + { + if (loaded_assemblies.ContainsKey(assembly)) + return; + + try + { + loaded_assemblies[assembly] = assembly.GetTypes().First(t => t.IsPublic && t.IsSubclassOf(typeof(Ruleset))); + } + catch (Exception e) + { + Logger.Error(e, $"Failed to add ruleset {assembly}"); + } } } } From 6e32557be3d36f8c867e95d1f7527fcc2bbb95ca Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 20 Oct 2019 22:29:29 +0200 Subject: [PATCH 22/25] Fix spelling error --- osu.Android/OsuGameActivity.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Android/OsuGameActivity.cs b/osu.Android/OsuGameActivity.cs index 41531617af..2e5fa59d20 100644 --- a/osu.Android/OsuGameActivity.cs +++ b/osu.Android/OsuGameActivity.cs @@ -18,7 +18,7 @@ namespace osu.Android { // The default current directory on android is '/'. // On some devices '/' maps to the app data directory. On others it maps to the root of the internal storage. - // In order to have a consitend current directory on all devices the full path of the app data directory is set as the current directory. + // In order to have a consistent current directory on all devices the full path of the app data directory is set as the current directory. System.Environment.CurrentDirectory = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); base.OnCreate(savedInstanceState); From dc222b5e4d00b3eac3d6e46405731e2b1050642b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Oct 2019 13:52:02 +0900 Subject: [PATCH 23/25] Add common path for duplicated code --- .../Objects/Drawables/DrawableHitObject.cs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 156d4178e2..b472c880c0 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -154,11 +154,7 @@ namespace osu.Game.Rulesets.Objects.Drawables { var drawableNested = CreateNestedHitObject(h) ?? throw new InvalidOperationException($"{nameof(CreateNestedHitObject)} returned null for {h.GetType().ReadableName()}."); - drawableNested.OnNewResult += (d, r) => OnNewResult?.Invoke(d, r); - drawableNested.OnRevertResult += (d, r) => OnRevertResult?.Invoke(d, r); - drawableNested.ApplyCustomUpdateState += (d, j) => ApplyCustomUpdateState?.Invoke(d, j); - - nestedHitObjects.Value.Add(drawableNested); + addNested(drawableNested); AddNestedHitObject(drawableNested); } } @@ -176,14 +172,7 @@ namespace osu.Game.Rulesets.Objects.Drawables /// /// [Obsolete("Use AddNestedHitObject() / ClearNestedHitObjects() / CreateNestedHitObject() instead.")] // can be removed 20200417 - protected virtual void AddNested(DrawableHitObject h) - { - h.OnNewResult += (d, r) => OnNewResult?.Invoke(d, r); - h.OnRevertResult += (d, r) => OnRevertResult?.Invoke(d, r); - h.ApplyCustomUpdateState += (d, j) => ApplyCustomUpdateState?.Invoke(d, j); - - nestedHitObjects.Value.Add(h); - } + protected virtual void AddNested(DrawableHitObject h) => addNested(h); /// /// Invoked by the base to remove all previously-added nested s. @@ -199,6 +188,17 @@ namespace osu.Game.Rulesets.Objects.Drawables /// The drawable representation for . protected virtual DrawableHitObject CreateNestedHitObject(HitObject hitObject) => null; + private void addNested(DrawableHitObject hitObject) + { + // Todo: Exists for legacy purposes, can be removed 20200417 + + hitObject.OnNewResult += (d, r) => OnNewResult?.Invoke(d, r); + hitObject.OnRevertResult += (d, r) => OnRevertResult?.Invoke(d, r); + hitObject.ApplyCustomUpdateState += (d, j) => ApplyCustomUpdateState?.Invoke(d, j); + + nestedHitObjects.Value.Add(hitObject); + } + #region State / Transform Management /// From 74b6e691d82631c6f2ad8edc73db42d2490c748f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Oct 2019 14:01:52 +0900 Subject: [PATCH 24/25] Remove unnecessary schedule --- .../Compose/Components/BlueprintContainer.cs | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index cb3d3b71fc..2de5ecf633 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -123,20 +123,12 @@ namespace osu.Game.Screens.Edit.Compose.Components if (blueprint == null) return; - if (hitObject.IsLoaded) - addBlueprint(); - else - hitObject.OnLoadComplete += _ => addBlueprint(); + blueprint.Selected += onBlueprintSelected; + blueprint.Deselected += onBlueprintDeselected; + blueprint.SelectionRequested += onSelectionRequested; + blueprint.DragRequested += onDragRequested; - void addBlueprint() - { - blueprint.Selected += onBlueprintSelected; - blueprint.Deselected += onBlueprintDeselected; - blueprint.SelectionRequested += onSelectionRequested; - blueprint.DragRequested += onDragRequested; - - selectionBlueprints.Add(blueprint); - } + selectionBlueprints.Add(blueprint); } private void removeBlueprintFor(DrawableHitObject hitObject) => removeBlueprintFor(hitObject.HitObject); From 96649e0a6a8d803cfdb68bce00f403ceaf59b83d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Oct 2019 15:03:49 +0900 Subject: [PATCH 25/25] Fix selection blueprints not respecting stacking --- .../TestSceneHitCircleSelectionBlueprint.cs | 7 +++++++ osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs index d4cdabdb07..cf24306623 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs @@ -52,6 +52,13 @@ namespace osu.Game.Rulesets.Osu.Tests AddAssert("blueprint positioned over hitobject", () => blueprint.CirclePiece.Position == hitCircle.Position); } + [Test] + public void TestStackedHitObject() + { + AddStep("set stacking", () => hitCircle.StackHeight = 5); + AddAssert("blueprint positioned over hitobject", () => blueprint.CirclePiece.Position == hitCircle.StackedPosition); + } + private class TestBlueprint : HitCircleSelectionBlueprint { public new HitCirclePiece CirclePiece => base.CirclePiece; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs index 95e926fdfa..b9c77d3f56 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints /// The to reference properties from. public virtual void UpdateFrom(T hitObject) { - Position = hitObject.Position; + Position = hitObject.StackedPosition; } } }